2 * @file child_proposal.c
4 * @brief Implementation of child_proposal_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
23 #include "child_proposal.h"
25 #include <utils/linked_list.h>
26 #include <utils/allocator.h>
27 #include <utils/identification.h>
28 #include <utils/logger.h>
32 * String mappings for protocol_id_t.
34 mapping_t protocol_id_m
[] = {
35 {UNDEFINED_PROTOCOL_ID
, "UNDEFINED_PROTOCOL_ID"},
43 * String mappings for transform_type_t.
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"},
56 * String mappings for extended_sequence_numbers_t.
58 mapping_t extended_sequence_numbers_m
[] = {
59 {NO_EXT_SEQ_NUMBERS
, "NO_EXT_SEQ_NUMBERS"},
60 {EXT_SEQ_NUMBERS
, "EXT_SEQ_NUMBERS"},
65 typedef struct protocol_proposal_t protocol_proposal_t
;
68 * substructure which holds all data algos for a specific protocol
70 struct protocol_proposal_t
{
72 * protocol (ESP or AH)
74 protocol_id_t protocol
;
77 * priority ordered list of encryption algorithms
79 linked_list_t
*encryption_algos
;
82 * priority ordered list of integrity algorithms
84 linked_list_t
*integrity_algos
;
87 * priority ordered list of pseudo random functions
89 linked_list_t
*prf_algos
;
92 * priority ordered list of dh groups
94 linked_list_t
*dh_groups
;
97 * priority ordered list of extended sequence number flags
108 typedef struct private_child_proposal_t private_child_proposal_t
;
111 * Private data of an child_proposal_t object
113 struct private_child_proposal_t
{
118 child_proposal_t
public;
121 * number of this proposal, as used in the payload
126 * list of protocol_proposal_t's
128 linked_list_t
*protocol_proposals
;
132 * Look up a protocol_proposal, or create one if necessary...
134 static protocol_proposal_t
*get_protocol_proposal(private_child_proposal_t
*this, protocol_id_t proto
, bool create
)
136 protocol_proposal_t
*proto_proposal
= NULL
, *current_proto_proposal
;;
137 iterator_t
*iterator
;
139 /* find our protocol in the proposals */
140 iterator
= this->protocol_proposals
->create_iterator(this->protocol_proposals
, TRUE
);
141 while (iterator
->has_next(iterator
))
143 iterator
->current(iterator
, (void**)¤t_proto_proposal
);
144 if (current_proto_proposal
->protocol
== proto
)
146 proto_proposal
= current_proto_proposal
;
150 iterator
->destroy(iterator
);
152 if (!proto_proposal
&& create
)
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();
164 proto_proposal
->spi
.len
= 8;
168 proto_proposal
->spi
.len
= 4;
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
);
174 return proto_proposal
;
178 * Add algorithm/keysize to a algorithm list
180 static void add_algo(linked_list_t
*list
, u_int8_t algo
, size_t key_size
)
182 algorithm_t
*algo_key
= allocator_alloc_thing(algorithm_t
);
184 algo_key
->algorithm
= algo
;
185 algo_key
->key_size
= key_size
;
186 list
->insert_last(list
, (void*)algo_key
);
190 * Implements child_proposal_t.add_algorithm
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
)
194 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, TRUE
);
198 case ENCRYPTION_ALGORITHM
:
199 add_algo(proto_proposal
->encryption_algos
, algo
, key_size
);
201 case INTEGRITY_ALGORITHM
:
202 add_algo(proto_proposal
->integrity_algos
, algo
, key_size
);
204 case PSEUDO_RANDOM_FUNCTION
:
205 add_algo(proto_proposal
->prf_algos
, algo
, key_size
);
207 case DIFFIE_HELLMAN_GROUP
:
208 add_algo(proto_proposal
->dh_groups
, algo
, 0);
210 case EXTENDED_SEQUENCE_NUMBERS
:
211 add_algo(proto_proposal
->esns
, algo
, 0);
219 * Implements child_proposal_t.get_algorithm.
221 static bool get_algorithm(private_child_proposal_t
*this, protocol_id_t proto
, transform_type_t type
, algorithm_t
** algo
)
223 linked_list_t
* list
;
224 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
226 if (proto_proposal
== NULL
)
232 case ENCRYPTION_ALGORITHM
:
233 list
= proto_proposal
->encryption_algos
;
235 case INTEGRITY_ALGORITHM
:
236 list
= proto_proposal
->integrity_algos
;
238 case PSEUDO_RANDOM_FUNCTION
:
239 list
= proto_proposal
->prf_algos
;
241 case DIFFIE_HELLMAN_GROUP
:
242 list
= proto_proposal
->dh_groups
;
244 case EXTENDED_SEQUENCE_NUMBERS
:
245 list
= proto_proposal
->esns
;
250 if (list
->get_first(list
, (void**)algo
) != SUCCESS
)
258 * Implements child_proposal_t.create_algorithm_iterator.
260 static iterator_t
*create_algorithm_iterator(private_child_proposal_t
*this, protocol_id_t proto
, transform_type_t type
)
262 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
263 if (proto_proposal
== NULL
)
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
);
287 * Find a matching alg/keysize in two linked lists
289 static bool select_algo(linked_list_t
*first
, linked_list_t
*second
, bool *add
, u_int16_t
*alg
, size_t *key_size
)
291 iterator_t
*first_iter
, *second_iter
;
292 algorithm_t
*first_alg
, *second_alg
;
294 /* if in both are zero algorithms specified, we HAVE a match */
295 if (first
->get_count(first
) == 0 && second
->get_count(second
) == 0)
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
))
306 first_iter
->current(first_iter
, (void**)&first_alg
);
307 second_iter
->reset(second_iter
);
308 while (second_iter
->has_next(second_iter
))
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
)
314 /* ok, we have an algorithm */
315 *alg
= first_alg
->algorithm
;
316 *key_size
= first_alg
->key_size
;
318 first_iter
->destroy(first_iter
);
319 second_iter
->destroy(second_iter
);
324 /* no match in all comparisons */
325 first_iter
->destroy(first_iter
);
326 second_iter
->destroy(second_iter
);
331 * Implements child_proposal_t.select.
333 static child_proposal_t
*select_proposal(private_child_proposal_t
*this, private_child_proposal_t
*other
)
335 child_proposal_t
*selected
;
338 iterator_t
*iterator
;
339 protocol_proposal_t
*this_prop
, *other_prop
;
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)
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
))
356 selected
= child_proposal_create(this->number
);
358 /* iterate over supplied proposals */
359 iterator
= other
->protocol_proposals
->create_iterator(other
->protocol_proposals
, TRUE
);
360 while (iterator
->has_next(iterator
))
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
);
367 if (this_prop
== NULL
)
369 iterator
->destroy(iterator
);
370 selected
->destroy(selected
);
374 /* select encryption algorithm */
375 if (select_algo(this_prop
->encryption_algos
, other_prop
->encryption_algos
, &add
, &algo
, &key_size
))
379 selected
->add_algorithm(selected
, proto
, ENCRYPTION_ALGORITHM
, algo
, key_size
);
384 iterator
->destroy(iterator
);
385 selected
->destroy(selected
);
388 /* select integrity algorithm */
389 if (select_algo(this_prop
->integrity_algos
, other_prop
->integrity_algos
, &add
, &algo
, &key_size
))
393 selected
->add_algorithm(selected
, proto
, INTEGRITY_ALGORITHM
, algo
, key_size
);
398 iterator
->destroy(iterator
);
399 selected
->destroy(selected
);
402 /* select prf algorithm */
403 if (select_algo(this_prop
->prf_algos
, other_prop
->prf_algos
, &add
, &algo
, &key_size
))
407 selected
->add_algorithm(selected
, proto
, PSEUDO_RANDOM_FUNCTION
, algo
, key_size
);
412 iterator
->destroy(iterator
);
413 selected
->destroy(selected
);
416 /* select a DH-group */
417 if (select_algo(this_prop
->dh_groups
, other_prop
->dh_groups
, &add
, &algo
, &key_size
))
421 selected
->add_algorithm(selected
, proto
, DIFFIE_HELLMAN_GROUP
, algo
, 0);
426 iterator
->destroy(iterator
);
427 selected
->destroy(selected
);
430 /* select if we use ESNs */
431 if (select_algo(this_prop
->esns
, other_prop
->esns
, &add
, &algo
, &key_size
))
435 selected
->add_algorithm(selected
, proto
, EXTENDED_SEQUENCE_NUMBERS
, algo
, 0);
440 iterator
->destroy(iterator
);
441 selected
->destroy(selected
);
445 iterator
->destroy(iterator
);
446 /* everything matched, return new proposal */
451 * Implements child_proposal_t.get_number.
453 static u_int8_t
get_number(private_child_proposal_t
*this)
459 * Implements child_proposal_t.get_protocols.
461 static void get_protocols(private_child_proposal_t
*this, protocol_id_t ids
[2])
463 iterator_t
*iterator
= this->protocol_proposals
->create_iterator(this->protocol_proposals
, TRUE
);
466 ids
[0] = UNDEFINED_PROTOCOL_ID
;
467 ids
[1] = UNDEFINED_PROTOCOL_ID
;
468 while (iterator
->has_next(iterator
))
470 protocol_proposal_t
*proto_prop
;
471 iterator
->current(iterator
, (void**)&proto_prop
);
472 ids
[i
++] = proto_prop
->protocol
;
475 /* should not happen, but who knows */
479 iterator
->destroy(iterator
);
483 * Implements child_proposal_t.set_spi.
485 static void set_spi(private_child_proposal_t
*this, protocol_id_t proto
, u_int64_t spi
)
487 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
492 *((u_int32_t
*)proto_proposal
->spi
.ptr
) = (u_int32_t
)spi
;
496 *((u_int64_t
*)proto_proposal
->spi
.ptr
) = spi
;
503 * Implements child_proposal_t.get_spi.
505 static u_int64_t
get_spi(private_child_proposal_t
*this, protocol_id_t proto
)
507 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
512 return (u_int64_t
)*((u_int32_t
*)proto_proposal
->spi
.ptr
);
516 return *((u_int64_t
*)proto_proposal
->spi
.ptr
);
523 * Frees all list items and destroys the list
525 static void free_algo_list(linked_list_t
*list
)
529 while(list
->get_count(list
) > 0)
531 list
->remove_last(list
, (void**)&algo
);
532 allocator_free(algo
);
538 * Implements child_proposal_t.destroy.
540 static void destroy(private_child_proposal_t
*this)
542 while(this->protocol_proposals
->get_count(this->protocol_proposals
) > 0)
544 protocol_proposal_t
*proto_prop
;
545 this->protocol_proposals
->remove_last(this->protocol_proposals
, (void**)&proto_prop
);
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
);
553 allocator_free(proto_prop
->spi
.ptr
);
554 allocator_free(proto_prop
);
556 this->protocol_proposals
->destroy(this->protocol_proposals
);
558 allocator_free(this);
562 * Describtion in header-file
564 child_proposal_t
*child_proposal_create(u_int8_t number
)
566 private_child_proposal_t
*this = allocator_alloc_thing(private_child_proposal_t
);
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
;
570 this->public.get_algorithm
= (bool (*)(child_proposal_t
*,protocol_id_t
,transform_type_t
,algorithm_t
**))get_algorithm
;
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
;
578 /* init private members*/
579 this->number
= number
;
580 this->protocol_proposals
= linked_list_create();
582 return (&this->public);