updated copyright information
[strongswan.git] / src / charon / encoding / payloads / sa_payload.c
1 /**
2 * @file sa_payload.c
3 *
4 * @brief Implementation of sa_payload_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <stddef.h>
25
26 #include "sa_payload.h"
27
28 #include <encoding/payloads/encodings.h>
29 #include <utils/linked_list.h>
30 #include <utils/logger_manager.h>
31
32
33 typedef struct private_sa_payload_t private_sa_payload_t;
34
35 /**
36 * Private data of an sa_payload_t object.
37 *
38 */
39 struct private_sa_payload_t {
40 /**
41 * Public sa_payload_t interface.
42 */
43 sa_payload_t public;
44
45 /**
46 * Next payload type.
47 */
48 u_int8_t next_payload;
49
50 /**
51 * Critical flag.
52 */
53 bool critical;
54
55 /**
56 * Length of this payload.
57 */
58 u_int16_t payload_length;
59
60 /**
61 * Proposals in this payload are stored in a linked_list_t.
62 */
63 linked_list_t * proposals;
64
65 /**
66 * Logger for error handling
67 */
68 logger_t *logger;
69
70 /**
71 * @brief Computes the length of this payload.
72 *
73 * @param this calling private_sa_payload_t object
74 */
75 void (*compute_length) (private_sa_payload_t *this);
76 };
77
78 /**
79 * Encoding rules to parse or generate a IKEv2-SA Payload
80 *
81 * The defined offsets are the positions in a object of type
82 * private_sa_payload_t.
83 *
84 */
85 encoding_rule_t sa_payload_encodings[] = {
86 /* 1 Byte next payload type, stored in the field next_payload */
87 { U_INT_8, offsetof(private_sa_payload_t, next_payload) },
88 /* the critical bit */
89 { FLAG, offsetof(private_sa_payload_t, critical) },
90 /* 7 Bit reserved bits, nowhere stored */
91 { RESERVED_BIT, 0 },
92 { RESERVED_BIT, 0 },
93 { RESERVED_BIT, 0 },
94 { RESERVED_BIT, 0 },
95 { RESERVED_BIT, 0 },
96 { RESERVED_BIT, 0 },
97 { RESERVED_BIT, 0 },
98 /* Length of the whole SA payload*/
99 { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
100 /* Proposals are stored in a proposal substructure,
101 offset points to a linked_list_t pointer */
102 { PROPOSALS, offsetof(private_sa_payload_t, proposals) }
103 };
104
105 /*
106 1 2 3
107 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
108 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109 ! Next Payload !C! RESERVED ! Payload Length !
110 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 ! !
112 ~ <Proposals> ~
113 ! !
114 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 */
116
117 /**
118 * Implementation of payload_t.verify.
119 */
120 static status_t verify(private_sa_payload_t *this)
121 {
122 int expected_number = 1, current_number;
123 status_t status = SUCCESS;
124 iterator_t *iterator;
125 bool first = TRUE;
126
127 /* check proposal numbering */
128 iterator = this->proposals->create_iterator(this->proposals,TRUE);
129
130 while(iterator->has_next(iterator))
131 {
132 proposal_substructure_t *current_proposal;
133 iterator->current(iterator,(void **)&current_proposal);
134 current_number = current_proposal->get_proposal_number(current_proposal);
135 if (current_number > expected_number)
136 {
137 if (first)
138 {
139 this->logger->log(this->logger, ERROR, "first proposal is not proposal #1");
140 status = FAILED;
141 break;
142 }
143
144 if (current_number != (expected_number + 1))
145 {
146 this->logger->log(this->logger, ERROR, "proposal number is %d, excepted %d or %d",
147 current_number, expected_number, expected_number + 1);
148 status = FAILED;
149 break;
150 }
151 }
152 else if (current_number < expected_number)
153 {
154 /* must not be smaller then proceeding one */
155 this->logger->log(this->logger, ERROR, "proposal number smaller than that of previous proposal");
156 status = FAILED;
157 break;
158 }
159
160 status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface));
161 if (status != SUCCESS)
162 {
163 this->logger->log(this->logger, ERROR, "proposal substructure verification failed");
164 break;
165 }
166 first = FALSE;
167 expected_number = current_number;
168 }
169
170 iterator->destroy(iterator);
171 return status;
172 }
173
174
175 /**
176 * Implementation of payload_t.destroy and sa_payload_t.destroy.
177 */
178 static status_t destroy(private_sa_payload_t *this)
179 {
180 /* all proposals are getting destroyed */
181 while (this->proposals->get_count(this->proposals) > 0)
182 {
183 proposal_substructure_t *current_proposal;
184 this->proposals->remove_last(this->proposals,(void **)&current_proposal);
185 current_proposal->destroy(current_proposal);
186 }
187 this->proposals->destroy(this->proposals);
188
189 free(this);
190
191 return SUCCESS;
192 }
193
194 /**
195 * Implementation of payload_t.get_encoding_rules.
196 */
197 static void get_encoding_rules(private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
198 {
199 *rules = sa_payload_encodings;
200 *rule_count = sizeof(sa_payload_encodings) / sizeof(encoding_rule_t);
201 }
202
203 /**
204 * Implementation of payload_t.get_type.
205 */
206 static payload_type_t get_type(private_sa_payload_t *this)
207 {
208 return SECURITY_ASSOCIATION;
209 }
210
211 /**
212 * Implementation of payload_t.get_next_type.
213 */
214 static payload_type_t get_next_type(private_sa_payload_t *this)
215 {
216 return (this->next_payload);
217 }
218
219 /**
220 * Implementation of payload_t.set_next_type.
221 */
222 static void set_next_type(private_sa_payload_t *this,payload_type_t type)
223 {
224 this->next_payload = type;
225 }
226
227 /**
228 * Implementation of payload_t.get_length.
229 */
230 static size_t get_length(private_sa_payload_t *this)
231 {
232 this->compute_length(this);
233 return this->payload_length;
234 }
235
236 /**
237 * Implementation of sa_payload_t.create_proposal_substructure_iterator.
238 */
239 static iterator_t *create_proposal_substructure_iterator (private_sa_payload_t *this,bool forward)
240 {
241 return this->proposals->create_iterator(this->proposals,forward);
242 }
243
244 /**
245 * Implementation of sa_payload_t.add_proposal_substructure.
246 */
247 static void add_proposal_substructure(private_sa_payload_t *this,proposal_substructure_t *proposal)
248 {
249 status_t status;
250 u_int proposal_count = this->proposals->get_count(this->proposals);
251
252 if (proposal_count > 0)
253 {
254 proposal_substructure_t *last_proposal;
255 status = this->proposals->get_last(this->proposals,(void **) &last_proposal);
256 /* last transform is now not anymore last one */
257 last_proposal->set_is_last_proposal(last_proposal, FALSE);
258 }
259 proposal->set_is_last_proposal(proposal, TRUE);
260 proposal->set_proposal_number(proposal, proposal_count + 1);
261 this->proposals->insert_last(this->proposals,(void *) proposal);
262 this->compute_length(this);
263 }
264
265 /**
266 * Implementation of sa_payload_t.add_proposal.
267 */
268 static void add_proposal(private_sa_payload_t *this, proposal_t *proposal)
269 {
270 proposal_substructure_t *substructure;
271
272 substructure = proposal_substructure_create_from_proposal(proposal);
273 add_proposal_substructure(this, substructure);
274 }
275
276 /**
277 * Implementation of sa_payload_t.get_proposals.
278 */
279 static linked_list_t *get_proposals(private_sa_payload_t *this)
280 {
281 int struct_number = 0;
282 int ignore_struct_number = 0;
283 iterator_t *iterator;
284 linked_list_t *proposal_list;
285
286 /* this list will hold our proposals */
287 proposal_list = linked_list_create();
288
289 /* we do not support proposals split up to two proposal substructures, as
290 * AH+ESP bundles are not supported in RFC4301 anymore.
291 * To handle such structures safely, we just skip proposals with multiple
292 * protocols.
293 */
294 iterator = this->proposals->create_iterator(this->proposals, TRUE);
295 while (iterator->has_next(iterator))
296 {
297 proposal_t *proposal;
298 proposal_substructure_t *proposal_struct;
299
300 iterator->current(iterator, (void **)&proposal_struct);
301 /* check if a proposal has a single protocol */
302 if (proposal_struct->get_proposal_number(proposal_struct) == struct_number)
303 {
304 if (ignore_struct_number < struct_number)
305 {
306 /* remova an already added, if first of series */
307 proposal_list->remove_last(proposal_list, (void**)&proposal);
308 proposal->destroy(proposal);
309 ignore_struct_number = struct_number;
310 }
311 continue;
312 }
313 struct_number++;
314 proposal = proposal_struct->get_proposal(proposal_struct);
315 if (proposal)
316 {
317 proposal_list->insert_last(proposal_list, proposal);
318 }
319 }
320 iterator->destroy(iterator);
321 return proposal_list;
322 }
323
324 /**
325 * Implementation of private_sa_payload_t.compute_length.
326 */
327 static void compute_length (private_sa_payload_t *this)
328 {
329 iterator_t *iterator;
330 size_t length = SA_PAYLOAD_HEADER_LENGTH;
331 iterator = this->proposals->create_iterator(this->proposals,TRUE);
332 while (iterator->has_next(iterator))
333 {
334 payload_t *current_proposal;
335 iterator->current(iterator,(void **) &current_proposal);
336 length += current_proposal->get_length(current_proposal);
337 }
338 iterator->destroy(iterator);
339
340 this->payload_length = length;
341 }
342
343 /*
344 * Described in header.
345 */
346 sa_payload_t *sa_payload_create()
347 {
348 private_sa_payload_t *this = malloc_thing(private_sa_payload_t);
349
350 /* public interface */
351 this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
352 this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
353 this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
354 this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
355 this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type;
356 this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
357 this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
358
359 /* public functions */
360 this->public.create_proposal_substructure_iterator = (iterator_t* (*) (sa_payload_t *,bool)) create_proposal_substructure_iterator;
361 this->public.add_proposal_substructure = (void (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure;
362 this->public.add_proposal = (void (*) (sa_payload_t*,proposal_t*))add_proposal;
363 this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals;
364 this->public.destroy = (void (*) (sa_payload_t *)) destroy;
365
366 /* private functions */
367 this->compute_length = compute_length;
368
369 /* set default values of the fields */
370 this->critical = FALSE;
371 this->next_payload = NO_PAYLOAD;
372 this->payload_length = SA_PAYLOAD_HEADER_LENGTH;
373 this->logger = logger_manager->get_logger(logger_manager, PARSER);
374
375 this->proposals = linked_list_create();
376 return &this->public;
377 }
378
379 /*
380 * Described in header.
381 */
382 sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
383 {
384 iterator_t *iterator;
385 proposal_t *proposal;
386 sa_payload_t *sa_payload = sa_payload_create();
387
388 /* add every payload from the list */
389 iterator = proposals->create_iterator(proposals, TRUE);
390 while (iterator->has_next(iterator))
391 {
392 iterator->current(iterator, (void**)&proposal);
393 add_proposal((private_sa_payload_t*)sa_payload, proposal);
394 }
395 iterator->destroy(iterator);
396
397 return sa_payload;
398 }
399
400 /*
401 * Described in header.
402 */
403 sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal)
404 {
405 sa_payload_t *sa_payload = sa_payload_create();
406
407 add_proposal((private_sa_payload_t*)sa_payload, proposal);
408
409 return sa_payload;
410 }