]>
Commit | Line | Data |
---|---|---|
c06dbbab MW |
1 | /** |
2 | * @file child_proposal.c | |
3 | * | |
4 | * @brief Implementation of child_proposal_t. | |
5 | * | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2006 Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | */ | |
22 | ||
23 | #include "child_proposal.h" | |
24 | ||
25 | #include <utils/linked_list.h> | |
26 | #include <utils/allocator.h> | |
27 | #include <utils/identification.h> | |
28 | #include <utils/logger.h> | |
29 | ||
30 | ||
31 | /** | |
32 | * String mappings for protocol_id_t. | |
33 | */ | |
34 | mapping_t protocol_id_m[] = { | |
35 | {UNDEFINED_PROTOCOL_ID, "UNDEFINED_PROTOCOL_ID"}, | |
36 | {IKE, "IKE"}, | |
37 | {AH, "AH"}, | |
38 | {ESP, "ESP"}, | |
39 | {MAPPING_END, NULL} | |
40 | }; | |
41 | ||
42 | /** | |
43 | * String mappings for transform_type_t. | |
44 | */ | |
45 | mapping_t transform_type_m[] = { | |
46 | {UNDEFINED_TRANSFORM_TYPE, "UNDEFINED_TRANSFORM_TYPE"}, | |
47 | {ENCRYPTION_ALGORITHM, "ENCRYPTION_ALGORITHM"}, | |
48 | {PSEUDO_RANDOM_FUNCTION, "PSEUDO_RANDOM_FUNCTION"}, | |
49 | {INTEGRITY_ALGORITHM, "INTEGRITY_ALGORITHM"}, | |
50 | {DIFFIE_HELLMAN_GROUP, "DIFFIE_HELLMAN_GROUP"}, | |
51 | {EXTENDED_SEQUENCE_NUMBERS, "EXTENDED_SEQUENCE_NUMBERS"}, | |
52 | {MAPPING_END, NULL} | |
53 | }; | |
54 | ||
55 | /** | |
56 | * String mappings for extended_sequence_numbers_t. | |
57 | */ | |
58 | mapping_t extended_sequence_numbers_m[] = { | |
59 | {NO_EXT_SEQ_NUMBERS, "NO_EXT_SEQ_NUMBERS"}, | |
60 | {EXT_SEQ_NUMBERS, "EXT_SEQ_NUMBERS"}, | |
61 | {MAPPING_END, NULL} | |
62 | }; | |
63 | ||
64 | ||
65 | typedef struct protocol_proposal_t protocol_proposal_t; | |
66 | ||
67 | /** | |
68 | * substructure which holds all data algos for a specific protocol | |
69 | */ | |
70 | struct protocol_proposal_t { | |
71 | /** | |
72 | * protocol (ESP or AH) | |
73 | */ | |
74 | protocol_id_t protocol; | |
75 | ||
76 | /** | |
77 | * priority ordered list of encryption algorithms | |
78 | */ | |
79 | linked_list_t *encryption_algos; | |
80 | ||
81 | /** | |
82 | * priority ordered list of integrity algorithms | |
83 | */ | |
84 | linked_list_t *integrity_algos; | |
85 | ||
86 | /** | |
87 | * priority ordered list of pseudo random functions | |
88 | */ | |
89 | linked_list_t *prf_algos; | |
90 | ||
91 | /** | |
92 | * priority ordered list of dh groups | |
93 | */ | |
94 | linked_list_t *dh_groups; | |
95 | ||
96 | /** | |
97 | * priority ordered list of extended sequence number flags | |
98 | */ | |
99 | linked_list_t *esns; | |
100 | ||
101 | /** | |
102 | * senders SPI | |
103 | */ | |
104 | chunk_t spi; | |
105 | }; | |
106 | ||
107 | ||
108 | typedef struct private_child_proposal_t private_child_proposal_t; | |
109 | ||
110 | /** | |
111 | * Private data of an child_proposal_t object | |
112 | */ | |
113 | struct private_child_proposal_t { | |
114 | ||
115 | /** | |
116 | * Public part | |
117 | */ | |
118 | child_proposal_t public; | |
119 | ||
120 | /** | |
121 | * number of this proposal, as used in the payload | |
122 | */ | |
123 | u_int8_t number; | |
124 | ||
125 | /** | |
126 | * list of protocol_proposal_t's | |
127 | */ | |
128 | linked_list_t *protocol_proposals; | |
129 | }; | |
130 | ||
131 | /** | |
132 | * Look up a protocol_proposal, or create one if necessary... | |
133 | */ | |
134 | static protocol_proposal_t *get_protocol_proposal(private_child_proposal_t *this, protocol_id_t proto, bool create) | |
135 | { | |
136 | protocol_proposal_t *proto_proposal = NULL, *current_proto_proposal;; | |
137 | iterator_t *iterator; | |
138 | ||
139 | /* find our protocol in the proposals */ | |
140 | iterator = this->protocol_proposals->create_iterator(this->protocol_proposals, TRUE); | |
141 | while (iterator->has_next(iterator)) | |
142 | { | |
143 | iterator->current(iterator, (void**)¤t_proto_proposal); | |
144 | if (current_proto_proposal->protocol == proto) | |
145 | { | |
146 | proto_proposal = current_proto_proposal; | |
147 | break; | |
148 | } | |
149 | } | |
150 | iterator->destroy(iterator); | |
151 | ||
152 | if (!proto_proposal && create) | |
153 | { | |
154 | /* nope, create a new one */ | |
155 | proto_proposal = allocator_alloc_thing(protocol_proposal_t); | |
156 | proto_proposal->protocol = proto; | |
157 | proto_proposal->encryption_algos = linked_list_create(); | |
158 | proto_proposal->integrity_algos = linked_list_create(); | |
159 | proto_proposal->prf_algos = linked_list_create(); | |
160 | proto_proposal->dh_groups = linked_list_create(); | |
161 | proto_proposal->esns = linked_list_create(); | |
162 | if (proto == IKE) | |
163 | { | |
164 | proto_proposal->spi.len = 8; | |
165 | } | |
166 | else | |
167 | { | |
168 | proto_proposal->spi.len = 4; | |
169 | } | |
170 | proto_proposal->spi.ptr = allocator_alloc(proto_proposal->spi.len); | |
171 | /* add to the list */ | |
172 | this->protocol_proposals->insert_last(this->protocol_proposals, (void*)proto_proposal); | |
173 | } | |
174 | return proto_proposal; | |
175 | } | |
176 | ||
177 | /** | |
178 | * Add algorithm/keysize to a algorithm list | |
179 | */ | |
180 | static void add_algo(linked_list_t *list, u_int8_t algo, size_t key_size) | |
181 | { | |
182 | algorithm_t *algo_key = allocator_alloc_thing(algorithm_t); | |
183 | ||
184 | algo_key->algorithm = algo; | |
185 | algo_key->key_size = key_size; | |
186 | list->insert_last(list, (void*)algo_key); | |
187 | } | |
188 | ||
189 | /** | |
190 | * Implements child_proposal_t.add_algorithm | |
191 | */ | |
192 | static void add_algorithm(private_child_proposal_t *this, protocol_id_t proto, transform_type_t type, u_int16_t algo, size_t key_size) | |
193 | { | |
194 | protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, TRUE); | |
195 | ||
196 | switch (type) | |
197 | { | |
198 | case ENCRYPTION_ALGORITHM: | |
199 | add_algo(proto_proposal->encryption_algos, algo, key_size); | |
200 | break; | |
201 | case INTEGRITY_ALGORITHM: | |
202 | add_algo(proto_proposal->integrity_algos, algo, key_size); | |
203 | break; | |
204 | case PSEUDO_RANDOM_FUNCTION: | |
205 | add_algo(proto_proposal->prf_algos, algo, key_size); | |
206 | break; | |
207 | case DIFFIE_HELLMAN_GROUP: | |
208 | add_algo(proto_proposal->dh_groups, algo, 0); | |
209 | break; | |
210 | case EXTENDED_SEQUENCE_NUMBERS: | |
211 | add_algo(proto_proposal->esns, algo, 0); | |
212 | break; | |
213 | default: | |
214 | break; | |
215 | } | |
216 | } | |
217 | ||
93df94ac MW |
218 | /** |
219 | * Implements child_proposal_t.get_algorithm. | |
220 | */ | |
221 | static bool get_algorithm(private_child_proposal_t *this, protocol_id_t proto, transform_type_t type, algorithm_t** algo) | |
222 | { | |
223 | linked_list_t * list; | |
224 | protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); | |
225 | ||
226 | if (proto_proposal == NULL) | |
227 | { | |
228 | return FALSE; | |
229 | } | |
230 | switch (type) | |
231 | { | |
232 | case ENCRYPTION_ALGORITHM: | |
233 | list = proto_proposal->encryption_algos; | |
234 | break; | |
235 | case INTEGRITY_ALGORITHM: | |
236 | list = proto_proposal->integrity_algos; | |
237 | break; | |
238 | case PSEUDO_RANDOM_FUNCTION: | |
239 | list = proto_proposal->prf_algos; | |
240 | break; | |
241 | case DIFFIE_HELLMAN_GROUP: | |
242 | list = proto_proposal->dh_groups; | |
243 | break; | |
244 | case EXTENDED_SEQUENCE_NUMBERS: | |
245 | list = proto_proposal->esns; | |
246 | break; | |
247 | default: | |
248 | return FALSE; | |
249 | } | |
250 | if (list->get_first(list, (void**)algo) != SUCCESS) | |
251 | { | |
252 | return FALSE; | |
253 | } | |
254 | return TRUE; | |
255 | } | |
256 | ||
c06dbbab MW |
257 | /** |
258 | * Implements child_proposal_t.create_algorithm_iterator. | |
259 | */ | |
260 | static iterator_t *create_algorithm_iterator(private_child_proposal_t *this, protocol_id_t proto, transform_type_t type) | |
261 | { | |
262 | protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); | |
263 | if (proto_proposal == NULL) | |
264 | { | |
265 | return NULL; | |
93df94ac | 266 | } |
c06dbbab MW |
267 | |
268 | switch (type) | |
269 | { | |
270 | case ENCRYPTION_ALGORITHM: | |
271 | return proto_proposal->encryption_algos->create_iterator(proto_proposal->encryption_algos, TRUE); | |
272 | case INTEGRITY_ALGORITHM: | |
273 | return proto_proposal->integrity_algos->create_iterator(proto_proposal->integrity_algos, TRUE); | |
274 | case PSEUDO_RANDOM_FUNCTION: | |
275 | return proto_proposal->prf_algos->create_iterator(proto_proposal->prf_algos, TRUE); | |
276 | case DIFFIE_HELLMAN_GROUP: | |
277 | return proto_proposal->dh_groups->create_iterator(proto_proposal->dh_groups, TRUE); | |
278 | case EXTENDED_SEQUENCE_NUMBERS: | |
279 | return proto_proposal->esns->create_iterator(proto_proposal->esns, TRUE); | |
280 | default: | |
281 | break; | |
282 | } | |
283 | return NULL; | |
c06dbbab MW |
284 | } |
285 | ||
286 | /** | |
287 | * Find a matching alg/keysize in two linked lists | |
288 | */ | |
93df94ac | 289 | static bool select_algo(linked_list_t *first, linked_list_t *second, bool *add, u_int16_t *alg, size_t *key_size) |
c06dbbab MW |
290 | { |
291 | iterator_t *first_iter, *second_iter; | |
292 | algorithm_t *first_alg, *second_alg; | |
293 | ||
294 | /* if in both are zero algorithms specified, we HAVE a match */ | |
295 | if (first->get_count(first) == 0 && second->get_count(second) == 0) | |
296 | { | |
93df94ac | 297 | *add = FALSE; |
c06dbbab MW |
298 | return TRUE; |
299 | } | |
300 | ||
301 | first_iter = first->create_iterator(first, TRUE); | |
302 | second_iter = second->create_iterator(second, TRUE); | |
303 | /* compare algs, order of algs in "first" is preferred */ | |
304 | while (first_iter->has_next(first_iter)) | |
305 | { | |
306 | first_iter->current(first_iter, (void**)&first_alg); | |
307 | second_iter->reset(second_iter); | |
308 | while (second_iter->has_next(second_iter)) | |
309 | { | |
310 | second_iter->current(second_iter, (void**)&second_alg); | |
311 | if (first_alg->algorithm == second_alg->algorithm && | |
312 | first_alg->key_size == second_alg->key_size) | |
313 | { | |
314 | /* ok, we have an algorithm */ | |
315 | *alg = first_alg->algorithm; | |
316 | *key_size = first_alg->key_size; | |
93df94ac | 317 | *add = TRUE; |
c06dbbab MW |
318 | first_iter->destroy(first_iter); |
319 | second_iter->destroy(second_iter); | |
320 | return TRUE; | |
321 | } | |
322 | } | |
323 | } | |
324 | /* no match in all comparisons */ | |
325 | first_iter->destroy(first_iter); | |
326 | second_iter->destroy(second_iter); | |
327 | return FALSE; | |
328 | } | |
329 | ||
330 | /** | |
331 | * Implements child_proposal_t.select. | |
332 | */ | |
333 | static child_proposal_t *select_proposal(private_child_proposal_t *this, private_child_proposal_t *other) | |
334 | { | |
335 | child_proposal_t *selected; | |
336 | u_int16_t algo; | |
337 | size_t key_size; | |
338 | iterator_t *iterator; | |
339 | protocol_proposal_t *this_prop, *other_prop; | |
340 | protocol_id_t proto; | |
93df94ac | 341 | bool add; |
c06dbbab MW |
342 | |
343 | /* empty proposal? no match */ | |
344 | if (this->protocol_proposals->get_count(this->protocol_proposals) == 0 || | |
345 | other->protocol_proposals->get_count(other->protocol_proposals) == 0) | |
346 | { | |
347 | return NULL; | |
348 | } | |
349 | /* they MUST have the same amount of protocols */ | |
350 | if (this->protocol_proposals->get_count(this->protocol_proposals) != | |
351 | other->protocol_proposals->get_count(other->protocol_proposals)) | |
352 | { | |
353 | return NULL; | |
354 | } | |
355 | ||
356 | selected = child_proposal_create(this->number); | |
357 | ||
358 | /* iterate over supplied proposals */ | |
359 | iterator = other->protocol_proposals->create_iterator(other->protocol_proposals, TRUE); | |
360 | while (iterator->has_next(iterator)) | |
361 | { | |
362 | iterator->current(iterator, (void**)&other_prop); | |
363 | /* get the proposal with the same protocol */ | |
364 | proto = other_prop->protocol; | |
365 | this_prop = get_protocol_proposal(this, proto, FALSE); | |
366 | ||
367 | if (this_prop == NULL) | |
368 | { | |
369 | iterator->destroy(iterator); | |
370 | selected->destroy(selected); | |
371 | return NULL; | |
372 | } | |
373 | ||
374 | /* select encryption algorithm */ | |
93df94ac | 375 | if (select_algo(this_prop->encryption_algos, other_prop->encryption_algos, &add, &algo, &key_size)) |
c06dbbab | 376 | { |
93df94ac | 377 | if (add) |
c06dbbab MW |
378 | { |
379 | selected->add_algorithm(selected, proto, ENCRYPTION_ALGORITHM, algo, key_size); | |
380 | } | |
381 | } | |
382 | else | |
383 | { | |
384 | iterator->destroy(iterator); | |
385 | selected->destroy(selected); | |
386 | return NULL; | |
387 | } | |
388 | /* select integrity algorithm */ | |
93df94ac | 389 | if (select_algo(this_prop->integrity_algos, other_prop->integrity_algos, &add, &algo, &key_size)) |
c06dbbab | 390 | { |
93df94ac | 391 | if (add) |
c06dbbab MW |
392 | { |
393 | selected->add_algorithm(selected, proto, INTEGRITY_ALGORITHM, algo, key_size); | |
394 | } | |
395 | } | |
396 | else | |
397 | { | |
398 | iterator->destroy(iterator); | |
399 | selected->destroy(selected); | |
400 | return NULL; | |
401 | } | |
402 | /* select prf algorithm */ | |
93df94ac | 403 | if (select_algo(this_prop->prf_algos, other_prop->prf_algos, &add, &algo, &key_size)) |
c06dbbab | 404 | { |
93df94ac | 405 | if (add) |
c06dbbab MW |
406 | { |
407 | selected->add_algorithm(selected, proto, PSEUDO_RANDOM_FUNCTION, algo, key_size); | |
408 | } | |
409 | } | |
410 | else | |
411 | { | |
412 | iterator->destroy(iterator); | |
413 | selected->destroy(selected); | |
414 | return NULL; | |
415 | } | |
416 | /* select a DH-group */ | |
93df94ac | 417 | if (select_algo(this_prop->dh_groups, other_prop->dh_groups, &add, &algo, &key_size)) |
c06dbbab | 418 | { |
93df94ac | 419 | if (add) |
c06dbbab MW |
420 | { |
421 | selected->add_algorithm(selected, proto, DIFFIE_HELLMAN_GROUP, algo, 0); | |
422 | } | |
423 | } | |
424 | else | |
425 | { | |
426 | iterator->destroy(iterator); | |
427 | selected->destroy(selected); | |
428 | return NULL; | |
429 | } | |
430 | /* select if we use ESNs */ | |
93df94ac | 431 | if (select_algo(this_prop->esns, other_prop->esns, &add, &algo, &key_size)) |
c06dbbab | 432 | { |
93df94ac | 433 | if (add) |
c06dbbab MW |
434 | { |
435 | selected->add_algorithm(selected, proto, EXTENDED_SEQUENCE_NUMBERS, algo, 0); | |
436 | } | |
437 | } | |
438 | else | |
439 | { | |
440 | iterator->destroy(iterator); | |
441 | selected->destroy(selected); | |
442 | return NULL; | |
443 | } | |
444 | } | |
445 | iterator->destroy(iterator); | |
446 | /* everything matched, return new proposal */ | |
447 | return selected; | |
448 | } | |
449 | ||
450 | /** | |
451 | * Implements child_proposal_t.get_number. | |
452 | */ | |
453 | static u_int8_t get_number(private_child_proposal_t *this) | |
454 | { | |
455 | return this->number; | |
456 | } | |
457 | ||
458 | /** | |
459 | * Implements child_proposal_t.get_protocols. | |
460 | */ | |
461 | static void get_protocols(private_child_proposal_t *this, protocol_id_t ids[2]) | |
462 | { | |
463 | iterator_t *iterator = this->protocol_proposals->create_iterator(this->protocol_proposals, TRUE); | |
464 | u_int i = 0; | |
465 | ||
466 | ids[0] = UNDEFINED_PROTOCOL_ID; | |
467 | ids[1] = UNDEFINED_PROTOCOL_ID; | |
468 | while (iterator->has_next(iterator)) | |
469 | { | |
470 | protocol_proposal_t *proto_prop; | |
471 | iterator->current(iterator, (void**)&proto_prop); | |
472 | ids[i++] = proto_prop->protocol; | |
473 | if (i>1) | |
474 | { | |
475 | /* should not happen, but who knows */ | |
dfa6e086 | 476 | break; |
c06dbbab MW |
477 | } |
478 | } | |
dfa6e086 | 479 | iterator->destroy(iterator); |
c06dbbab MW |
480 | } |
481 | ||
482 | /** | |
483 | * Implements child_proposal_t.set_spi. | |
484 | */ | |
485 | static void set_spi(private_child_proposal_t *this, protocol_id_t proto, u_int64_t spi) | |
486 | { | |
487 | protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); | |
488 | if (proto_proposal) | |
489 | { | |
490 | if (proto == IKE) | |
491 | { | |
492 | *((u_int32_t*)proto_proposal->spi.ptr) = (u_int32_t)spi; | |
493 | } | |
494 | else | |
495 | { | |
496 | *((u_int64_t*)proto_proposal->spi.ptr) = spi; | |
497 | } | |
498 | ||
499 | } | |
500 | } | |
501 | ||
502 | /** | |
503 | * Implements child_proposal_t.get_spi. | |
504 | */ | |
505 | static u_int64_t get_spi(private_child_proposal_t *this, protocol_id_t proto) | |
506 | { | |
507 | protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); | |
508 | if (proto_proposal) | |
509 | { | |
510 | if (proto == IKE) | |
511 | { | |
512 | return (u_int64_t)*((u_int32_t*)proto_proposal->spi.ptr); | |
513 | } | |
514 | else | |
515 | { | |
516 | return *((u_int64_t*)proto_proposal->spi.ptr); | |
517 | } | |
518 | } | |
519 | return 0; | |
520 | } | |
521 | ||
522 | /** | |
523 | * Frees all list items and destroys the list | |
524 | */ | |
525 | static void free_algo_list(linked_list_t *list) | |
526 | { | |
527 | algorithm_t *algo; | |
528 | ||
529 | while(list->get_count(list) > 0) | |
530 | { | |
531 | list->remove_last(list, (void**)&algo); | |
532 | allocator_free(algo); | |
533 | } | |
534 | list->destroy(list); | |
535 | } | |
536 | ||
537 | /** | |
538 | * Implements child_proposal_t.destroy. | |
539 | */ | |
540 | static void destroy(private_child_proposal_t *this) | |
541 | { | |
542 | while(this->protocol_proposals->get_count(this->protocol_proposals) > 0) | |
543 | { | |
544 | protocol_proposal_t *proto_prop; | |
545 | this->protocol_proposals->remove_last(this->protocol_proposals, (void**)&proto_prop); | |
546 | ||
547 | free_algo_list(proto_prop->encryption_algos); | |
548 | free_algo_list(proto_prop->integrity_algos); | |
549 | free_algo_list(proto_prop->prf_algos); | |
550 | free_algo_list(proto_prop->dh_groups); | |
551 | free_algo_list(proto_prop->esns); | |
552 | ||
553 | allocator_free(proto_prop->spi.ptr); | |
554 | allocator_free(proto_prop); | |
555 | } | |
556 | this->protocol_proposals->destroy(this->protocol_proposals); | |
557 | ||
558 | allocator_free(this); | |
559 | } | |
560 | ||
561 | /* | |
562 | * Describtion in header-file | |
563 | */ | |
564 | child_proposal_t *child_proposal_create(u_int8_t number) | |
565 | { | |
566 | private_child_proposal_t *this = allocator_alloc_thing(private_child_proposal_t); | |
567 | ||
568 | this->public.add_algorithm = (void (*)(child_proposal_t*,protocol_id_t,transform_type_t,u_int16_t,size_t))add_algorithm; | |
569 | this->public.create_algorithm_iterator = (iterator_t* (*)(child_proposal_t*,protocol_id_t,transform_type_t))create_algorithm_iterator; | |
93df94ac | 570 | this->public.get_algorithm = (bool (*)(child_proposal_t*,protocol_id_t,transform_type_t,algorithm_t**))get_algorithm; |
c06dbbab MW |
571 | this->public.select = (child_proposal_t* (*)(child_proposal_t*,child_proposal_t*))select_proposal; |
572 | this->public.get_number = (u_int8_t (*)(child_proposal_t*))get_number; | |
573 | this->public.get_protocols = (void(*)(child_proposal_t *this, protocol_id_t ids[2]))get_protocols; | |
574 | this->public.set_spi = (void(*)(child_proposal_t*,protocol_id_t,u_int64_t spi))set_spi; | |
575 | this->public.get_spi = (u_int64_t(*)(child_proposal_t*,protocol_id_t))get_spi; | |
576 | this->public.destroy = (void(*)(child_proposal_t*))destroy; | |
577 | ||
578 | /* init private members*/ | |
579 | this->number = number; | |
580 | this->protocol_proposals = linked_list_create(); | |
581 | ||
582 | return (&this->public); | |
583 | } |