4 * @brief Implementation of 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
27 #include <utils/linked_list.h>
28 #include <utils/identification.h>
29 #include <utils/logger.h>
33 * String mappings for protocol_id_t.
35 mapping_t protocol_id_m
[] = {
36 {PROTO_NONE
, "PROTO_NONE"},
37 {PROTO_IKE
, "PROTO_IKE"},
38 {PROTO_AH
, "PROTO_AH"},
39 {PROTO_ESP
, "PROTO_ESP"},
44 * String mappings for transform_type_t.
46 mapping_t transform_type_m
[] = {
47 {UNDEFINED_TRANSFORM_TYPE
, "UNDEFINED_TRANSFORM_TYPE"},
48 {ENCRYPTION_ALGORITHM
, "ENCRYPTION_ALGORITHM"},
49 {PSEUDO_RANDOM_FUNCTION
, "PSEUDO_RANDOM_FUNCTION"},
50 {INTEGRITY_ALGORITHM
, "INTEGRITY_ALGORITHM"},
51 {DIFFIE_HELLMAN_GROUP
, "DIFFIE_HELLMAN_GROUP"},
52 {EXTENDED_SEQUENCE_NUMBERS
, "EXTENDED_SEQUENCE_NUMBERS"},
57 * String mappings for extended_sequence_numbers_t.
59 mapping_t extended_sequence_numbers_m
[] = {
60 {NO_EXT_SEQ_NUMBERS
, "NO_EXT_SEQ_NUMBERS"},
61 {EXT_SEQ_NUMBERS
, "EXT_SEQ_NUMBERS"},
66 typedef struct protocol_proposal_t protocol_proposal_t
;
69 * substructure which holds all data algos for a specific protocol
71 struct protocol_proposal_t
{
73 * protocol (ESP or AH)
75 protocol_id_t protocol
;
78 * priority ordered list of encryption algorithms
80 linked_list_t
*encryption_algos
;
83 * priority ordered list of integrity algorithms
85 linked_list_t
*integrity_algos
;
88 * priority ordered list of pseudo random functions
90 linked_list_t
*prf_algos
;
93 * priority ordered list of dh groups
95 linked_list_t
*dh_groups
;
98 * priority ordered list of extended sequence number flags
109 typedef struct private_proposal_t private_proposal_t
;
112 * Private data of an proposal_t object
114 struct private_proposal_t
{
122 * number of this proposal, as used in the payload
127 * list of protocol_proposal_t's
129 linked_list_t
*protocol_proposals
;
133 * Look up a protocol_proposal, or create one if necessary...
135 static protocol_proposal_t
*get_protocol_proposal(private_proposal_t
*this, protocol_id_t proto
, bool create
)
137 protocol_proposal_t
*proto_proposal
= NULL
, *current_proto_proposal
;;
138 iterator_t
*iterator
;
140 /* find our protocol in the proposals */
141 iterator
= this->protocol_proposals
->create_iterator(this->protocol_proposals
, TRUE
);
142 while (iterator
->has_next(iterator
))
144 iterator
->current(iterator
, (void**)¤t_proto_proposal
);
145 if (current_proto_proposal
->protocol
== proto
)
147 proto_proposal
= current_proto_proposal
;
151 iterator
->destroy(iterator
);
153 if (!proto_proposal
&& create
)
155 /* nope, create a new one */
156 proto_proposal
= malloc_thing(protocol_proposal_t
);
157 proto_proposal
->protocol
= proto
;
158 proto_proposal
->encryption_algos
= linked_list_create();
159 proto_proposal
->integrity_algos
= linked_list_create();
160 proto_proposal
->prf_algos
= linked_list_create();
161 proto_proposal
->dh_groups
= linked_list_create();
162 proto_proposal
->esns
= linked_list_create();
163 if (proto
== PROTO_IKE
)
165 proto_proposal
->spi
.len
= 8;
169 proto_proposal
->spi
.len
= 4;
171 proto_proposal
->spi
.ptr
= malloc(proto_proposal
->spi
.len
);
172 /* add to the list */
173 this->protocol_proposals
->insert_last(this->protocol_proposals
, (void*)proto_proposal
);
175 return proto_proposal
;
179 * Add algorithm/keysize to a algorithm list
181 static void add_algo(linked_list_t
*list
, u_int8_t algo
, size_t key_size
)
183 algorithm_t
*algo_key
= malloc_thing(algorithm_t
);
185 algo_key
->algorithm
= algo
;
186 algo_key
->key_size
= key_size
;
187 list
->insert_last(list
, (void*)algo_key
);
191 * Implements proposal_t.add_algorithm
193 static void add_algorithm(private_proposal_t
*this, protocol_id_t proto
, transform_type_t type
, u_int16_t algo
, size_t key_size
)
195 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, TRUE
);
199 case ENCRYPTION_ALGORITHM
:
200 add_algo(proto_proposal
->encryption_algos
, algo
, key_size
);
202 case INTEGRITY_ALGORITHM
:
203 add_algo(proto_proposal
->integrity_algos
, algo
, key_size
);
205 case PSEUDO_RANDOM_FUNCTION
:
206 add_algo(proto_proposal
->prf_algos
, algo
, key_size
);
208 case DIFFIE_HELLMAN_GROUP
:
209 add_algo(proto_proposal
->dh_groups
, algo
, 0);
211 case EXTENDED_SEQUENCE_NUMBERS
:
212 add_algo(proto_proposal
->esns
, algo
, 0);
220 * Implements proposal_t.get_algorithm.
222 static bool get_algorithm(private_proposal_t
*this, protocol_id_t proto
, transform_type_t type
, algorithm_t
** algo
)
224 linked_list_t
* list
;
225 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
227 if (proto_proposal
== NULL
)
233 case ENCRYPTION_ALGORITHM
:
234 list
= proto_proposal
->encryption_algos
;
236 case INTEGRITY_ALGORITHM
:
237 list
= proto_proposal
->integrity_algos
;
239 case PSEUDO_RANDOM_FUNCTION
:
240 list
= proto_proposal
->prf_algos
;
242 case DIFFIE_HELLMAN_GROUP
:
243 list
= proto_proposal
->dh_groups
;
245 case EXTENDED_SEQUENCE_NUMBERS
:
246 list
= proto_proposal
->esns
;
251 if (list
->get_first(list
, (void**)algo
) != SUCCESS
)
259 * Implements proposal_t.create_algorithm_iterator.
261 static iterator_t
*create_algorithm_iterator(private_proposal_t
*this, protocol_id_t proto
, transform_type_t type
)
263 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
264 if (proto_proposal
== NULL
)
271 case ENCRYPTION_ALGORITHM
:
272 return proto_proposal
->encryption_algos
->create_iterator(proto_proposal
->encryption_algos
, TRUE
);
273 case INTEGRITY_ALGORITHM
:
274 return proto_proposal
->integrity_algos
->create_iterator(proto_proposal
->integrity_algos
, TRUE
);
275 case PSEUDO_RANDOM_FUNCTION
:
276 return proto_proposal
->prf_algos
->create_iterator(proto_proposal
->prf_algos
, TRUE
);
277 case DIFFIE_HELLMAN_GROUP
:
278 return proto_proposal
->dh_groups
->create_iterator(proto_proposal
->dh_groups
, TRUE
);
279 case EXTENDED_SEQUENCE_NUMBERS
:
280 return proto_proposal
->esns
->create_iterator(proto_proposal
->esns
, TRUE
);
288 * Find a matching alg/keysize in two linked lists
290 static bool select_algo(linked_list_t
*first
, linked_list_t
*second
, bool *add
, u_int16_t
*alg
, size_t *key_size
)
292 iterator_t
*first_iter
, *second_iter
;
293 algorithm_t
*first_alg
, *second_alg
;
295 /* if in both are zero algorithms specified, we HAVE a match */
296 if (first
->get_count(first
) == 0 && second
->get_count(second
) == 0)
302 first_iter
= first
->create_iterator(first
, TRUE
);
303 second_iter
= second
->create_iterator(second
, TRUE
);
304 /* compare algs, order of algs in "first" is preferred */
305 while (first_iter
->has_next(first_iter
))
307 first_iter
->current(first_iter
, (void**)&first_alg
);
308 second_iter
->reset(second_iter
);
309 while (second_iter
->has_next(second_iter
))
311 second_iter
->current(second_iter
, (void**)&second_alg
);
312 if (first_alg
->algorithm
== second_alg
->algorithm
&&
313 first_alg
->key_size
== second_alg
->key_size
)
315 /* ok, we have an algorithm */
316 *alg
= first_alg
->algorithm
;
317 *key_size
= first_alg
->key_size
;
319 first_iter
->destroy(first_iter
);
320 second_iter
->destroy(second_iter
);
325 /* no match in all comparisons */
326 first_iter
->destroy(first_iter
);
327 second_iter
->destroy(second_iter
);
332 * Implements proposal_t.select.
334 static proposal_t
*select_proposal(private_proposal_t
*this, private_proposal_t
*other
)
336 proposal_t
*selected
;
339 iterator_t
*iterator
;
340 protocol_proposal_t
*this_prop
, *other_prop
;
345 /* empty proposal? no match */
346 if (this->protocol_proposals
->get_count(this->protocol_proposals
) == 0 ||
347 other
->protocol_proposals
->get_count(other
->protocol_proposals
) == 0)
351 /* they MUST have the same amount of protocols */
352 if (this->protocol_proposals
->get_count(this->protocol_proposals
) !=
353 other
->protocol_proposals
->get_count(other
->protocol_proposals
))
358 selected
= proposal_create(this->number
);
360 /* iterate over supplied proposals */
361 iterator
= other
->protocol_proposals
->create_iterator(other
->protocol_proposals
, TRUE
);
362 while (iterator
->has_next(iterator
))
364 iterator
->current(iterator
, (void**)&other_prop
);
365 /* get the proposal with the same protocol */
366 proto
= other_prop
->protocol
;
367 this_prop
= get_protocol_proposal(this, proto
, FALSE
);
369 if (this_prop
== NULL
)
371 iterator
->destroy(iterator
);
372 selected
->destroy(selected
);
376 /* select encryption algorithm */
377 if (select_algo(this_prop
->encryption_algos
, other_prop
->encryption_algos
, &add
, &algo
, &key_size
))
381 selected
->add_algorithm(selected
, proto
, ENCRYPTION_ALGORITHM
, algo
, key_size
);
386 iterator
->destroy(iterator
);
387 selected
->destroy(selected
);
390 /* select integrity algorithm */
391 if (select_algo(this_prop
->integrity_algos
, other_prop
->integrity_algos
, &add
, &algo
, &key_size
))
395 selected
->add_algorithm(selected
, proto
, INTEGRITY_ALGORITHM
, algo
, key_size
);
400 iterator
->destroy(iterator
);
401 selected
->destroy(selected
);
404 /* select prf algorithm */
405 if (select_algo(this_prop
->prf_algos
, other_prop
->prf_algos
, &add
, &algo
, &key_size
))
409 selected
->add_algorithm(selected
, proto
, PSEUDO_RANDOM_FUNCTION
, algo
, key_size
);
414 iterator
->destroy(iterator
);
415 selected
->destroy(selected
);
418 /* select a DH-group */
419 if (select_algo(this_prop
->dh_groups
, other_prop
->dh_groups
, &add
, &algo
, &key_size
))
423 selected
->add_algorithm(selected
, proto
, DIFFIE_HELLMAN_GROUP
, algo
, 0);
428 iterator
->destroy(iterator
);
429 selected
->destroy(selected
);
432 /* select if we use ESNs */
433 if (select_algo(this_prop
->esns
, other_prop
->esns
, &add
, &algo
, &key_size
))
437 selected
->add_algorithm(selected
, proto
, EXTENDED_SEQUENCE_NUMBERS
, algo
, 0);
442 iterator
->destroy(iterator
);
443 selected
->destroy(selected
);
447 iterator
->destroy(iterator
);
449 /* apply spis from "other" */
450 spi
= other
->public.get_spi(&(other
->public), PROTO_AH
);
453 selected
->set_spi(selected
, PROTO_AH
, spi
);
455 spi
= other
->public.get_spi(&(other
->public), PROTO_ESP
);
458 selected
->set_spi(selected
, PROTO_ESP
, spi
);
461 /* everything matched, return new proposal */
466 * Implements proposal_t.get_number.
468 static u_int8_t
get_number(private_proposal_t
*this)
474 * Implements proposal_t.get_protocols.
476 static void get_protocols(private_proposal_t
*this, protocol_id_t ids
[2])
478 iterator_t
*iterator
= this->protocol_proposals
->create_iterator(this->protocol_proposals
, TRUE
);
483 while (iterator
->has_next(iterator
))
485 protocol_proposal_t
*proto_prop
;
486 iterator
->current(iterator
, (void**)&proto_prop
);
487 ids
[i
++] = proto_prop
->protocol
;
490 /* should not happen, but who knows */
494 iterator
->destroy(iterator
);
498 * Implements proposal_t.set_spi.
500 static void set_spi(private_proposal_t
*this, protocol_id_t proto
, u_int64_t spi
)
502 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
505 if (proto
== PROTO_AH
|| proto
== PROTO_ESP
)
507 *((u_int32_t
*)proto_proposal
->spi
.ptr
) = (u_int32_t
)spi
;
511 *((u_int64_t
*)proto_proposal
->spi
.ptr
) = spi
;
517 * Implements proposal_t.get_spi.
519 static u_int64_t
get_spi(private_proposal_t
*this, protocol_id_t proto
)
521 protocol_proposal_t
*proto_proposal
= get_protocol_proposal(this, proto
, FALSE
);
524 if (proto
== PROTO_AH
|| proto
== PROTO_ESP
)
526 return (u_int64_t
)*((u_int32_t
*)proto_proposal
->spi
.ptr
);
530 return *((u_int64_t
*)proto_proposal
->spi
.ptr
);
537 * Clone a algorithm list
539 static void clone_algo_list(linked_list_t
*list
, linked_list_t
*clone_list
)
541 algorithm_t
*algo
, *clone_algo
;
542 iterator_t
*iterator
= list
->create_iterator(list
, TRUE
);
543 while (iterator
->has_next(iterator
))
545 iterator
->current(iterator
, (void**)&algo
);
546 clone_algo
= malloc_thing(algorithm_t
);
547 memcpy(clone_algo
, algo
, sizeof(algorithm_t
));
548 clone_list
->insert_last(clone_list
, (void*)clone_algo
);
550 iterator
->destroy(iterator
);
554 * Implements proposal_t.clone
556 static proposal_t
*clone(private_proposal_t
*this)
558 private_proposal_t
*clone
= (private_proposal_t
*)proposal_create(this->number
);
560 iterator_t
*iterator
= this->protocol_proposals
->create_iterator(this->protocol_proposals
, TRUE
);
561 while (iterator
->has_next(iterator
))
563 protocol_proposal_t
*proto_prop
, *clone_proto_prop
;
564 iterator
->current(iterator
, (void**)&proto_prop
);
566 clone_proto_prop
= get_protocol_proposal(clone
, proto_prop
->protocol
, TRUE
);
567 memcpy(clone_proto_prop
->spi
.ptr
, proto_prop
->spi
.ptr
, clone_proto_prop
->spi
.len
);
569 clone_algo_list(proto_prop
->encryption_algos
, clone_proto_prop
->encryption_algos
);
570 clone_algo_list(proto_prop
->integrity_algos
, clone_proto_prop
->integrity_algos
);
571 clone_algo_list(proto_prop
->prf_algos
, clone_proto_prop
->prf_algos
);
572 clone_algo_list(proto_prop
->dh_groups
, clone_proto_prop
->dh_groups
);
573 clone_algo_list(proto_prop
->esns
, clone_proto_prop
->esns
);
575 iterator
->destroy(iterator
);
577 return &clone
->public;
581 * Frees all list items and destroys the list
583 static void free_algo_list(linked_list_t
*list
)
587 while(list
->get_count(list
) > 0)
589 list
->remove_last(list
, (void**)&algo
);
596 * Implements proposal_t.destroy.
598 static void destroy(private_proposal_t
*this)
600 while(this->protocol_proposals
->get_count(this->protocol_proposals
) > 0)
602 protocol_proposal_t
*proto_prop
;
603 this->protocol_proposals
->remove_last(this->protocol_proposals
, (void**)&proto_prop
);
605 free_algo_list(proto_prop
->encryption_algos
);
606 free_algo_list(proto_prop
->integrity_algos
);
607 free_algo_list(proto_prop
->prf_algos
);
608 free_algo_list(proto_prop
->dh_groups
);
609 free_algo_list(proto_prop
->esns
);
611 free(proto_prop
->spi
.ptr
);
614 this->protocol_proposals
->destroy(this->protocol_proposals
);
620 * Describtion in header-file
622 proposal_t
*proposal_create(u_int8_t number
)
624 private_proposal_t
*this = malloc_thing(private_proposal_t
);
626 this->public.add_algorithm
= (void (*)(proposal_t
*,protocol_id_t
,transform_type_t
,u_int16_t
,size_t))add_algorithm
;
627 this->public.create_algorithm_iterator
= (iterator_t
* (*)(proposal_t
*,protocol_id_t
,transform_type_t
))create_algorithm_iterator
;
628 this->public.get_algorithm
= (bool (*)(proposal_t
*,protocol_id_t
,transform_type_t
,algorithm_t
**))get_algorithm
;
629 this->public.select
= (proposal_t
* (*)(proposal_t
*,proposal_t
*))select_proposal
;
630 this->public.get_number
= (u_int8_t (*)(proposal_t
*))get_number
;
631 this->public.get_protocols
= (void(*)(proposal_t
*this, protocol_id_t ids
[2]))get_protocols
;
632 this->public.set_spi
= (void(*)(proposal_t
*,protocol_id_t
,u_int64_t spi
))set_spi
;
633 this->public.get_spi
= (u_int64_t(*)(proposal_t
*,protocol_id_t
))get_spi
;
634 this->public.clone
= (proposal_t
*(*)(proposal_t
*))clone
;
635 this->public.destroy
= (void(*)(proposal_t
*))destroy
;
637 /* init private members*/
638 this->number
= number
;
639 this->protocol_proposals
= linked_list_create();
641 return (&this->public);