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/lexparser.h>
30 #include <crypto/prfs/prf.h>
31 #include <crypto/crypters/crypter.h>
32 #include <crypto/signers/signer.h>
35 ENUM(protocol_id_names
, PROTO_NONE
, PROTO_ESP
,
42 ENUM_BEGIN(transform_type_names
, UNDEFINED_TRANSFORM_TYPE
, UNDEFINED_TRANSFORM_TYPE
,
43 "UNDEFINED_TRANSFORM_TYPE");
44 ENUM_NEXT(transform_type_names
, ENCRYPTION_ALGORITHM
, EXTENDED_SEQUENCE_NUMBERS
, UNDEFINED_TRANSFORM_TYPE
,
45 "ENCRYPTION_ALGORITHM",
46 "PSEUDO_RANDOM_FUNCTION",
47 "INTEGRITY_ALGORITHM",
48 "DIFFIE_HELLMAN_GROUP",
49 "EXTENDED_SEQUENCE_NUMBERS");
50 ENUM_END(transform_type_names
, EXTENDED_SEQUENCE_NUMBERS
);
52 ENUM(extended_sequence_numbers_names
, NO_EXT_SEQ_NUMBERS
, EXT_SEQ_NUMBERS
,
57 typedef struct private_proposal_t private_proposal_t
;
60 * Private data of an proposal_t object
62 struct private_proposal_t
{
70 * protocol (ESP or AH)
72 protocol_id_t protocol
;
75 * priority ordered list of encryption algorithms
77 linked_list_t
*encryption_algos
;
80 * priority ordered list of integrity algorithms
82 linked_list_t
*integrity_algos
;
85 * priority ordered list of pseudo random functions
87 linked_list_t
*prf_algos
;
90 * priority ordered list of dh groups
92 linked_list_t
*dh_groups
;
95 * priority ordered list of extended sequence number flags
106 * Add algorithm/keysize to a algorithm list
108 static void add_algo(linked_list_t
*list
, u_int16_t algo
, size_t key_size
)
110 algorithm_t
*algo_key
;
112 algo_key
= malloc_thing(algorithm_t
);
113 algo_key
->algorithm
= algo
;
114 algo_key
->key_size
= key_size
;
115 list
->insert_last(list
, (void*)algo_key
);
119 * Implements proposal_t.add_algorithm
121 static void add_algorithm(private_proposal_t
*this, transform_type_t type
, u_int16_t algo
, size_t key_size
)
125 case ENCRYPTION_ALGORITHM
:
126 add_algo(this->encryption_algos
, algo
, key_size
);
128 case INTEGRITY_ALGORITHM
:
129 add_algo(this->integrity_algos
, algo
, key_size
);
131 case PSEUDO_RANDOM_FUNCTION
:
132 add_algo(this->prf_algos
, algo
, key_size
);
134 case DIFFIE_HELLMAN_GROUP
:
135 add_algo(this->dh_groups
, algo
, 0);
137 case EXTENDED_SEQUENCE_NUMBERS
:
138 add_algo(this->esns
, algo
, 0);
146 * Implements proposal_t.get_algorithm.
148 static bool get_algorithm(private_proposal_t
*this, transform_type_t type
, algorithm_t
** algo
)
153 case ENCRYPTION_ALGORITHM
:
154 list
= this->encryption_algos
;
156 case INTEGRITY_ALGORITHM
:
157 list
= this->integrity_algos
;
159 case PSEUDO_RANDOM_FUNCTION
:
160 list
= this->prf_algos
;
162 case DIFFIE_HELLMAN_GROUP
:
163 list
= this->dh_groups
;
165 case EXTENDED_SEQUENCE_NUMBERS
:
171 if (list
->get_first(list
, (void**)algo
) != SUCCESS
)
179 * Implements proposal_t.create_algorithm_iterator.
181 static iterator_t
*create_algorithm_iterator(private_proposal_t
*this, transform_type_t type
)
185 case ENCRYPTION_ALGORITHM
:
186 return this->encryption_algos
->create_iterator(this->encryption_algos
, TRUE
);
187 case INTEGRITY_ALGORITHM
:
188 return this->integrity_algos
->create_iterator(this->integrity_algos
, TRUE
);
189 case PSEUDO_RANDOM_FUNCTION
:
190 return this->prf_algos
->create_iterator(this->prf_algos
, TRUE
);
191 case DIFFIE_HELLMAN_GROUP
:
192 return this->dh_groups
->create_iterator(this->dh_groups
, TRUE
);
193 case EXTENDED_SEQUENCE_NUMBERS
:
194 return this->esns
->create_iterator(this->esns
, TRUE
);
202 * Find a matching alg/keysize in two linked lists
204 static bool select_algo(linked_list_t
*first
, linked_list_t
*second
, bool *add
, u_int16_t
*alg
, size_t *key_size
)
206 iterator_t
*first_iter
, *second_iter
;
207 algorithm_t
*first_alg
, *second_alg
;
209 /* if in both are zero algorithms specified, we HAVE a match */
210 if (first
->get_count(first
) == 0 && second
->get_count(second
) == 0)
216 first_iter
= first
->create_iterator(first
, TRUE
);
217 second_iter
= second
->create_iterator(second
, TRUE
);
218 /* compare algs, order of algs in "first" is preferred */
219 while (first_iter
->iterate(first_iter
, (void**)&first_alg
))
221 second_iter
->reset(second_iter
);
222 while (second_iter
->iterate(second_iter
, (void**)&second_alg
))
224 if (first_alg
->algorithm
== second_alg
->algorithm
&&
225 first_alg
->key_size
== second_alg
->key_size
)
227 /* ok, we have an algorithm */
228 *alg
= first_alg
->algorithm
;
229 *key_size
= first_alg
->key_size
;
231 first_iter
->destroy(first_iter
);
232 second_iter
->destroy(second_iter
);
237 /* no match in all comparisons */
238 first_iter
->destroy(first_iter
);
239 second_iter
->destroy(second_iter
);
244 * Implements proposal_t.select.
246 static proposal_t
*select_proposal(private_proposal_t
*this, private_proposal_t
*other
)
248 proposal_t
*selected
;
254 if (this->protocol
!= other
->protocol
)
259 selected
= proposal_create(this->protocol
);
261 /* select encryption algorithm */
262 if (select_algo(this->encryption_algos
, other
->encryption_algos
, &add
, &algo
, &key_size
))
266 selected
->add_algorithm(selected
, ENCRYPTION_ALGORITHM
, algo
, key_size
);
271 selected
->destroy(selected
);
274 /* select integrity algorithm */
275 if (select_algo(this->integrity_algos
, other
->integrity_algos
, &add
, &algo
, &key_size
))
279 selected
->add_algorithm(selected
, INTEGRITY_ALGORITHM
, algo
, key_size
);
284 selected
->destroy(selected
);
287 /* select prf algorithm */
288 if (select_algo(this->prf_algos
, other
->prf_algos
, &add
, &algo
, &key_size
))
292 selected
->add_algorithm(selected
, PSEUDO_RANDOM_FUNCTION
, algo
, key_size
);
297 selected
->destroy(selected
);
300 /* select a DH-group */
301 if (select_algo(this->dh_groups
, other
->dh_groups
, &add
, &algo
, &key_size
))
305 selected
->add_algorithm(selected
, DIFFIE_HELLMAN_GROUP
, algo
, 0);
310 selected
->destroy(selected
);
313 /* select if we use ESNs */
314 if (select_algo(this->esns
, other
->esns
, &add
, &algo
, &key_size
))
318 selected
->add_algorithm(selected
, EXTENDED_SEQUENCE_NUMBERS
, algo
, 0);
323 selected
->destroy(selected
);
327 /* apply SPI from "other" */
328 selected
->set_spi(selected
, other
->spi
);
330 /* everything matched, return new proposal */
335 * Implements proposal_t.get_protocols.
337 static protocol_id_t
get_protocol(private_proposal_t
*this)
339 return this->protocol
;
343 * Implements proposal_t.set_spi.
345 static void set_spi(private_proposal_t
*this, u_int64_t spi
)
351 * Implements proposal_t.get_spi.
353 static u_int64_t
get_spi(private_proposal_t
*this)
359 * Clone a algorithm list
361 static void clone_algo_list(linked_list_t
*list
, linked_list_t
*clone_list
)
363 algorithm_t
*algo
, *clone_algo
;
364 iterator_t
*iterator
= list
->create_iterator(list
, TRUE
);
365 while (iterator
->iterate(iterator
, (void**)&algo
))
367 clone_algo
= malloc_thing(algorithm_t
);
368 memcpy(clone_algo
, algo
, sizeof(algorithm_t
));
369 clone_list
->insert_last(clone_list
, (void*)clone_algo
);
371 iterator
->destroy(iterator
);
375 * Implements proposal_t.clone
377 static proposal_t
*clone_(private_proposal_t
*this)
379 private_proposal_t
*clone
= (private_proposal_t
*)proposal_create(this->protocol
);
381 clone_algo_list(this->encryption_algos
, clone
->encryption_algos
);
382 clone_algo_list(this->integrity_algos
, clone
->integrity_algos
);
383 clone_algo_list(this->prf_algos
, clone
->prf_algos
);
384 clone_algo_list(this->dh_groups
, clone
->dh_groups
);
385 clone_algo_list(this->esns
, clone
->esns
);
387 clone
->spi
= this->spi
;
389 return &clone
->public;
392 static status_t
add_string_algo(private_proposal_t
*this, chunk_t alg
)
394 if (strncmp(alg
.ptr
, "null", alg
.len
) == 0)
396 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_NULL
, 0);
398 else if (strncmp(alg
.ptr
, "aes128", alg
.len
) == 0)
400 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
402 else if (strncmp(alg
.ptr
, "aes192", alg
.len
) == 0)
404 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
406 else if (strncmp(alg
.ptr
, "aes256", alg
.len
) == 0)
408 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
410 else if (strncmp(alg
.ptr
, "3des", alg
.len
) == 0)
412 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
414 /* blowfish only uses some predefined key sizes yet */
415 else if (strncmp(alg
.ptr
, "blowfish128", alg
.len
) == 0)
417 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 128);
419 else if (strncmp(alg
.ptr
, "blowfish192", alg
.len
) == 0)
421 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 192);
423 else if (strncmp(alg
.ptr
, "blowfish256", alg
.len
) == 0)
425 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 256);
427 else if (strncmp(alg
.ptr
, "sha", alg
.len
) == 0 ||
428 strncmp(alg
.ptr
, "sha1", alg
.len
) == 0)
430 /* sha means we use SHA for both, PRF and AUTH */
431 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
432 if (this->protocol
== PROTO_IKE
)
434 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA1
, 0);
437 else if (strncmp(alg
.ptr
, "md5", alg
.len
) == 0)
440 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
441 if (this->protocol
== PROTO_IKE
)
443 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_MD5
, 0);
446 else if (strncmp(alg
.ptr
, "modp1024", alg
.len
) == 0)
448 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1024_BIT
, 0);
450 else if (strncmp(alg
.ptr
, "modp1536", alg
.len
) == 0)
452 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1536_BIT
, 0);
454 else if (strncmp(alg
.ptr
, "modp2048", alg
.len
) == 0)
456 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_2048_BIT
, 0);
458 else if (strncmp(alg
.ptr
, "modp4096", alg
.len
) == 0)
460 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_4096_BIT
, 0);
462 else if (strncmp(alg
.ptr
, "modp8192", alg
.len
) == 0)
464 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_8192_BIT
, 0);
474 * Implements proposal_t.destroy.
476 static void destroy(private_proposal_t
*this)
478 this->encryption_algos
->destroy_function(this->encryption_algos
, free
);
479 this->integrity_algos
->destroy_function(this->integrity_algos
, free
);
480 this->prf_algos
->destroy_function(this->prf_algos
, free
);
481 this->dh_groups
->destroy_function(this->dh_groups
, free
);
482 this->esns
->destroy_function(this->esns
, free
);
487 * Describtion in header-file
489 proposal_t
*proposal_create(protocol_id_t protocol
)
491 private_proposal_t
*this = malloc_thing(private_proposal_t
);
493 this->public.add_algorithm
= (void (*)(proposal_t
*,transform_type_t
,u_int16_t
,size_t))add_algorithm
;
494 this->public.create_algorithm_iterator
= (iterator_t
* (*)(proposal_t
*,transform_type_t
))create_algorithm_iterator
;
495 this->public.get_algorithm
= (bool (*)(proposal_t
*,transform_type_t
,algorithm_t
**))get_algorithm
;
496 this->public.select
= (proposal_t
* (*)(proposal_t
*,proposal_t
*))select_proposal
;
497 this->public.get_protocol
= (protocol_id_t(*)(proposal_t
*))get_protocol
;
498 this->public.set_spi
= (void(*)(proposal_t
*,u_int64_t
))set_spi
;
499 this->public.get_spi
= (u_int64_t(*)(proposal_t
*))get_spi
;
500 this->public.clone
= (proposal_t
*(*)(proposal_t
*))clone_
;
501 this->public.destroy
= (void(*)(proposal_t
*))destroy
;
504 this->protocol
= protocol
;
506 this->encryption_algos
= linked_list_create();
507 this->integrity_algos
= linked_list_create();
508 this->prf_algos
= linked_list_create();
509 this->dh_groups
= linked_list_create();
510 this->esns
= linked_list_create();
512 return &this->public;
516 * Describtion in header-file
518 proposal_t
*proposal_create_default(protocol_id_t protocol
)
520 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
525 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
526 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
527 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
528 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
529 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA1
, 0);
530 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_MD5
, 0);
531 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_2048_BIT
, 0);
532 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1536_BIT
, 0);
533 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1024_BIT
, 0);
534 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_4096_BIT
, 0);
535 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_8192_BIT
, 0);
538 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
539 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
540 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
541 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
542 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 256);
543 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
544 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
545 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
548 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
549 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
550 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
556 return &this->public;
560 * Describtion in header-file
562 proposal_t
*proposal_create_from_string(protocol_id_t protocol
, const char *algs
)
564 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
565 chunk_t string
= {(void*)algs
, strlen(algs
)};
567 status_t status
= SUCCESS
;
569 eat_whitespace(&string
);
576 /* get all tokens, separated by '-' */
577 while (extract_token(&alg
, '-', &string
))
579 status
|= add_string_algo(this, alg
);
583 status
|= add_string_algo(this, string
);
585 if (status
!= SUCCESS
)
591 if (protocol
== PROTO_AH
|| protocol
== PROTO_ESP
)
593 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
595 return &this->public;