- added compution of all needed keys and also creation of needed
[strongswan.git] / Source / charon / encoding / payloads / proposal_substructure.c
1 /**
2 * @file proposal_substructure.h
3 *
4 * @brief Declaration of the class proposal_substructure_t.
5 *
6 * An object of this type represents an IKEv2 PROPOSAL Substructure and contains transforms.
7 *
8 */
9
10 /*
11 * Copyright (C) 2005 Jan Hutter, Martin Willi
12 * Hochschule fuer Technik Rapperswil
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
23 */
24
25 /* offsetof macro */
26 #include <stddef.h>
27
28 #include "proposal_substructure.h"
29
30 #include <encoding/payloads/encodings.h>
31 #include <encoding/payloads/transform_substructure.h>
32 #include <types.h>
33 #include <utils/allocator.h>
34 #include <utils/linked_list.h>
35
36 typedef struct private_proposal_substructure_t private_proposal_substructure_t;
37
38 /**
39 * Private data of an proposal_substructure_t' Object
40 *
41 */
42 struct private_proposal_substructure_t {
43 /**
44 * public proposal_substructure_t interface
45 */
46 proposal_substructure_t public;
47
48 /**
49 * next payload type
50 */
51 u_int8_t next_payload;
52
53
54 /**
55 * Length of this payload
56 */
57 u_int16_t proposal_length;
58
59
60 /**
61 * Proposal number
62 */
63 u_int8_t proposal_number;
64
65 /**
66 * Protocol ID
67 */
68 u_int8_t protocol_id;
69
70 /**
71 * SPI size of the following SPI
72 */
73 u_int8_t spi_size;
74
75 /**
76 * Number of transforms
77 */
78 u_int8_t transforms_count;
79
80 /**
81 * SPI is stored as chunk
82 */
83 chunk_t spi;
84
85 /**
86 * Transforms are stored in a linked_list_t
87 */
88 linked_list_t * transforms;
89
90 /**
91 * @brief Computes the length of this substructure.
92 *
93 * @param this calling private_proposal_substructure_t object
94 * @return
95 * SUCCESS in any case
96 */
97 status_t (*compute_length) (private_proposal_substructure_t *this);
98 };
99
100 /**
101 * Encoding rules to parse or generate a Proposal substructure
102 *
103 * The defined offsets are the positions in a object of type
104 * private_proposal_substructure_t.
105 *
106 */
107 encoding_rule_t proposal_substructure_encodings[] = {
108 /* 1 Byte next payload type, stored in the field next_payload */
109 { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) },
110 /* Reserved Byte is skipped */
111 { RESERVED_BYTE, 0 },
112 /* Length of the whole proposal substructure payload*/
113 { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) },
114 /* proposal number is a number of 8 bit */
115 { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) },
116 /* protocol ID is a number of 8 bit */
117 { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) },
118 /* SPI Size has its own type */
119 { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) },
120 /* Number of transforms is a number of 8 bit */
121 { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) },
122 /* SPI is a chunk of variable size*/
123 { SPI, offsetof(private_proposal_substructure_t, spi) },
124 /* Transforms are stored in a transform substructure,
125 offset points to a linked_list_t pointer */
126 { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) }
127 };
128
129 /*
130 1 2 3
131 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
132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133 ! 0 (last) or 2 ! RESERVED ! Proposal Length !
134 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135 ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
136 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137 ~ SPI (variable) ~
138 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 ! !
140 ~ <Transforms> ~
141 ! !
142 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143 */
144
145 /**
146 * Implements payload_t's verify function.
147 * See #payload_s.verify for description.
148 */
149 static status_t verify(private_proposal_substructure_t *this)
150 {
151 if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != PROPOSAL_SUBSTRUCTURE))
152 {
153 /* must be 0 or 2 */
154 return FAILED;
155 }
156 if (this->transforms_count != this->transforms->get_count(this->transforms))
157 {
158 /* must be the same! */
159 return FAILED;
160 }
161
162 if (this->protocol_id > 4)
163 {
164 /* reserved are not supported */
165 return FAILED;
166 }
167
168 /* proposal number is checked in SA payload */
169 return SUCCESS;
170 }
171
172 /**
173 * Implements payload_t's get_encoding_rules function.
174 * See #payload_s.get_encoding_rules for description.
175 */
176 static status_t get_encoding_rules(private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count)
177 {
178 *rules = proposal_substructure_encodings;
179 *rule_count = sizeof(proposal_substructure_encodings) / sizeof(encoding_rule_t);
180
181 return SUCCESS;
182 }
183
184 /**
185 * Implements payload_t's get_type function.
186 * See #payload_s.get_type for description.
187 */
188 static payload_type_t get_type(private_proposal_substructure_t *this)
189 {
190 return PROPOSAL_SUBSTRUCTURE;
191 }
192
193 /**
194 * Implements payload_t's get_next_type function.
195 * See #payload_s.get_next_type for description.
196 */
197 static payload_type_t get_next_type(private_proposal_substructure_t *this)
198 {
199 return (this->next_payload);
200 }
201
202 /**
203 * Implements payload_t's set_next_type function.
204 * See #payload_s.set_next_type for description.
205 */
206 static status_t set_next_type(private_proposal_substructure_t *this,payload_type_t type)
207 {
208 return SUCCESS;
209 }
210
211 /**
212 * Implements payload_t's get_length function.
213 * See #payload_s.get_length for description.
214 */
215 static size_t get_length(private_proposal_substructure_t *this)
216 {
217 return this->proposal_length;
218 }
219
220 /**
221 * Implements proposal_substructure_t's create_transform_substructure_iterator function.
222 * See #proposal_substructure_s.create_transform_substructure_iterator for description.
223 */
224 static status_t create_transform_substructure_iterator (private_proposal_substructure_t *this,iterator_t **iterator,bool forward)
225 {
226 return (this->transforms->create_iterator(this->transforms,iterator,forward));
227 }
228
229 /**
230 * Implements proposal_substructure_t's add_transform_substructure function.
231 * See #proposal_substructure_s.add_transform_substructure for description.
232 */
233 static status_t add_transform_substructure (private_proposal_substructure_t *this,transform_substructure_t *transform)
234 {
235 status_t status;
236 if (this->transforms->get_count(this->transforms) > 0)
237 {
238 transform_substructure_t *last_transform;
239 status = this->transforms->get_last(this->transforms,(void **) &last_transform);
240 /* last transform is now not anymore last one */
241 last_transform->set_is_last_transform(last_transform,FALSE);
242
243 }
244 transform->set_is_last_transform(transform,TRUE);
245
246 status = this->transforms->insert_last(this->transforms,(void *) transform);
247 this->compute_length(this);
248 return status;
249 }
250
251 /**
252 * Implements proposal_substructure_t's set_proposal_number function.
253 * See #proposal_substructure_s.set_proposal_number for description.
254 */
255 static status_t set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number)
256 {
257 this->proposal_number = proposal_number;
258 return SUCCESS;
259 }
260
261 /**
262 * Implements proposal_substructure_t's get_proposal_number function.
263 * See #proposal_substructure_s.get_proposal_number for description.
264 */
265 static u_int8_t get_proposal_number (private_proposal_substructure_t *this)
266 {
267 return (this->proposal_number);
268 }
269
270 /**
271 * Implements proposal_substructure_t's set_protocol_id function.
272 * See #proposal_substructure_s.set_protocol_id for description.
273 */
274 static status_t set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id)
275 {
276 this->protocol_id = protocol_id;
277 return SUCCESS;
278 }
279
280 /**
281 * Implements proposal_substructure_t's get_protocol_id function.
282 * See #proposal_substructure_s.get_protocol_id for description.
283 */
284 static u_int8_t get_protocol_id (private_proposal_substructure_t *this)
285 {
286 return (this->protocol_id);
287 }
288
289
290 /**
291 * Implements proposal_substructure_t's set_spi function.
292 * See #proposal_substructure_s.set_spi for description.
293 */
294 static status_t set_spi (private_proposal_substructure_t *this, chunk_t spi)
295 {
296 /* first delete already set spi value */
297 if (this->spi.ptr != NULL)
298 {
299 allocator_free(this->spi.ptr);
300 this->spi.ptr = NULL;
301 this->spi.len = 0;
302 this->compute_length(this);
303 }
304
305 this->spi.ptr = allocator_clone_bytes(spi.ptr,spi.len);
306 if (this->spi.ptr == NULL)
307 {
308 return OUT_OF_RES;
309 }
310 this->spi.len = spi.len;
311 this->spi_size = spi.len;
312 this->compute_length(this);
313
314 return SUCCESS;
315 }
316
317 /**
318 * Implements proposal_substructure_t's get_spi function.
319 * See #proposal_substructure_s.get_spi for description.
320 */
321 static chunk_t get_spi (private_proposal_substructure_t *this)
322 {
323 chunk_t spi;
324 spi.ptr = this->spi.ptr;
325 spi.len = this->spi.len;
326
327 return spi;
328 }
329
330 static status_t get_info_for_transform_type (private_proposal_substructure_t *this,transform_type_t type, u_int16_t *transform_id, u_int16_t *key_length)
331 {
332 iterator_t *iterator;
333 status_t status;
334 u_int16_t found_transform_id;
335 u_int16_t found_key_length;
336
337 status = this->transforms->create_iterator(this->transforms,&iterator,TRUE);
338 if (status != SUCCESS)
339 {
340 return status;
341 }
342 while (iterator->has_next(iterator))
343 {
344 transform_substructure_t *current_transform;
345 status = iterator->current(iterator,(void **) &current_transform);
346 if (status != SUCCESS)
347 {
348 break;
349 }
350 if (current_transform->get_transform_type(current_transform) == type)
351 {
352 /* now get data for specific type */
353 found_transform_id = current_transform->get_transform_id(current_transform);
354 status = current_transform->get_key_length(current_transform,&found_key_length);
355 *transform_id = found_transform_id;
356 *key_length = found_key_length;
357 iterator->destroy(iterator);
358 return status;
359 }
360 }
361 iterator->destroy(iterator);
362 return FAILED;
363 }
364
365 /**
366 * Implements private_proposal_substructure_t's compute_length function.
367 * See #private_proposal_substructure_s.compute_length for description.
368 */
369 static status_t compute_length (private_proposal_substructure_t *this)
370 {
371 iterator_t *iterator;
372 status_t status;
373 size_t transforms_count = 0;
374 size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH;
375 status = this->transforms->create_iterator(this->transforms,&iterator,TRUE);
376 if (status != SUCCESS)
377 {
378 return length;
379 }
380 while (iterator->has_next(iterator))
381 {
382 payload_t * current_transform;
383 iterator->current(iterator,(void **) &current_transform);
384 length += current_transform->get_length(current_transform);
385 transforms_count++;
386 }
387 iterator->destroy(iterator);
388
389 length += this->spi.len;
390 this->transforms_count= transforms_count;
391 this->proposal_length = length;
392
393 return SUCCESS;
394 }
395
396 /**
397 * Implements proposal_substructure_t's clone function.
398 * See #proposal_substructure_s.clone for description.
399 */
400 static status_t clone(private_proposal_substructure_t *this, private_proposal_substructure_t **clone)
401 {
402 private_proposal_substructure_t * new_clone;
403 iterator_t *transforms;
404 status_t status;
405
406 new_clone = (private_proposal_substructure_t *) proposal_substructure_create();
407
408 new_clone->next_payload = this->next_payload;
409 new_clone->proposal_number = this->proposal_number;
410 new_clone->protocol_id = this->protocol_id;
411 new_clone->spi_size = this->spi_size;
412 if (this->spi.ptr != NULL)
413 {
414 new_clone->spi.ptr = allocator_clone_bytes(this->spi.ptr,this->spi.len);
415 if (new_clone->spi.ptr == NULL)
416 {
417 new_clone->public.destroy(&(new_clone->public));
418 return OUT_OF_RES;
419 }
420 new_clone->spi.len = this->spi.len;
421 }
422
423 status = this->transforms->create_iterator(this->transforms,&transforms,FALSE);
424 if (status != SUCCESS)
425 {
426 new_clone->public.destroy(&(new_clone->public));
427 return status;
428 }
429
430 while (transforms->has_next(transforms))
431 {
432 transform_substructure_t *current_transform;
433 transform_substructure_t *current_transform_clone;
434 status = transforms->current(transforms,(void **) &current_transform);
435 if (status != SUCCESS)
436 {
437 transforms->destroy(transforms);
438 new_clone->public.destroy(&(new_clone->public));
439 return status;
440 }
441 status = current_transform->clone(current_transform,&current_transform_clone);
442 if (status != SUCCESS)
443 {
444 transforms->destroy(transforms);
445 new_clone->public.destroy(&(new_clone->public));
446 return status;
447 }
448
449 status = new_clone->public.add_transform_substructure(&(new_clone->public),current_transform_clone);
450 if (status != SUCCESS)
451 {
452 transforms->destroy(transforms);
453 current_transform_clone->destroy(current_transform_clone);
454 new_clone->public.destroy(&(new_clone->public));
455 return status;
456 }
457 }
458
459 transforms->destroy(transforms);
460
461 *clone = new_clone;
462
463 return SUCCESS;
464 }
465
466 /**
467 * Implements payload_t's and proposal_substructure_t's destroy function.
468 * See #payload_s.destroy or proposal_substructure_s.destroy for description.
469 */
470 static status_t destroy(private_proposal_substructure_t *this)
471 {
472 /* all proposals are getting destroyed */
473 while (this->transforms->get_count(this->transforms) > 0)
474 {
475 transform_substructure_t *current_transform;
476 if (this->transforms->remove_last(this->transforms,(void **)&current_transform) != SUCCESS)
477 {
478 break;
479 }
480 current_transform->destroy(current_transform);
481 }
482 this->transforms->destroy(this->transforms);
483
484 if (this->spi.ptr != NULL)
485 {
486 allocator_free(this->spi.ptr);
487 }
488
489 allocator_free(this);
490
491 return SUCCESS;
492 }
493
494 /*
495 * Described in header
496 */
497 proposal_substructure_t *proposal_substructure_create()
498 {
499 private_proposal_substructure_t *this = allocator_alloc_thing(private_proposal_substructure_t);
500 if (this == NULL)
501 {
502 return NULL;
503 }
504
505 /* interface functions */
506 this->public.payload_interface.verify = (status_t (*) (payload_t *))verify;
507 this->public.payload_interface.get_encoding_rules = (status_t (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules;
508 this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length;
509 this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type;
510 this->public.payload_interface.set_next_type = (status_t (*) (payload_t *,payload_type_t)) set_next_type;
511 this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type;
512 this->public.payload_interface.destroy = (status_t (*) (payload_t *))destroy;
513
514 /* public functions */
515 this->public.create_transform_substructure_iterator = (status_t (*) (proposal_substructure_t *,iterator_t **,bool)) create_transform_substructure_iterator;
516 this->public.add_transform_substructure = (status_t (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure;
517 this->public.set_proposal_number = (status_t (*) (proposal_substructure_t *,u_int8_t))set_proposal_number;
518 this->public.get_proposal_number = (u_int8_t (*) (proposal_substructure_t *)) get_proposal_number;
519 this->public.set_protocol_id = (status_t (*) (proposal_substructure_t *,u_int8_t))set_protocol_id;
520 this->public.get_protocol_id = (u_int8_t (*) (proposal_substructure_t *)) get_protocol_id;
521 this->public.get_info_for_transform_type = (status_t (*) (proposal_substructure_t *,transform_type_t,u_int16_t *, u_int16_t *))get_info_for_transform_type;
522 this->public.set_spi = (status_t (*) (proposal_substructure_t *,chunk_t))set_spi;
523 this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi;
524 this->public.clone = (status_t (*) (proposal_substructure_t *, proposal_substructure_t **)) clone;
525 this->public.destroy = (status_t (*) (proposal_substructure_t *)) destroy;
526
527
528 /* private functions */
529 this->compute_length = compute_length;
530
531 /* set default values of the fields */
532 this->next_payload = NO_PAYLOAD;
533 this->proposal_length = 0;
534 this->proposal_number = 0;
535 this->protocol_id = 0;
536 this->transforms_count = 0;
537 this->spi_size = 0;
538 this->spi.ptr = NULL;
539 this->spi.len = 0;
540
541 this->transforms = linked_list_create();
542
543 if (this->transforms == NULL)
544 {
545 allocator_free(this);
546 return NULL;
547 }
548 return (&(this->public));
549 }