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