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
28 #include <utils/linked_list.h>
29 #include <utils/identification.h>
30 #include <utils/lexparser.h>
31 #include <crypto/prfs/prf.h>
32 #include <crypto/crypters/crypter.h>
33 #include <crypto/signers/signer.h>
36 ENUM(protocol_id_names
, PROTO_NONE
, PROTO_ESP
,
43 ENUM_BEGIN(transform_type_names
, UNDEFINED_TRANSFORM_TYPE
, UNDEFINED_TRANSFORM_TYPE
,
44 "UNDEFINED_TRANSFORM_TYPE");
45 ENUM_NEXT(transform_type_names
, ENCRYPTION_ALGORITHM
, EXTENDED_SEQUENCE_NUMBERS
, UNDEFINED_TRANSFORM_TYPE
,
46 "ENCRYPTION_ALGORITHM",
47 "PSEUDO_RANDOM_FUNCTION",
48 "INTEGRITY_ALGORITHM",
49 "DIFFIE_HELLMAN_GROUP",
50 "EXTENDED_SEQUENCE_NUMBERS");
51 ENUM_END(transform_type_names
, EXTENDED_SEQUENCE_NUMBERS
);
53 ENUM(extended_sequence_numbers_names
, NO_EXT_SEQ_NUMBERS
, EXT_SEQ_NUMBERS
,
58 typedef struct private_proposal_t private_proposal_t
;
61 * Private data of an proposal_t object
63 struct private_proposal_t
{
71 * protocol (ESP or AH)
73 protocol_id_t protocol
;
76 * priority ordered list of encryption algorithms
78 linked_list_t
*encryption_algos
;
81 * priority ordered list of integrity algorithms
83 linked_list_t
*integrity_algos
;
86 * priority ordered list of pseudo random functions
88 linked_list_t
*prf_algos
;
91 * priority ordered list of dh groups
93 linked_list_t
*dh_groups
;
96 * priority ordered list of extended sequence number flags
107 * Add algorithm/keysize to a algorithm list
109 static void add_algo(linked_list_t
*list
, u_int16_t algo
, size_t key_size
)
111 algorithm_t
*algo_key
;
113 algo_key
= malloc_thing(algorithm_t
);
114 algo_key
->algorithm
= algo
;
115 algo_key
->key_size
= key_size
;
116 list
->insert_last(list
, (void*)algo_key
);
120 * Implements proposal_t.add_algorithm
122 static void add_algorithm(private_proposal_t
*this, transform_type_t type
, u_int16_t algo
, size_t key_size
)
126 case ENCRYPTION_ALGORITHM
:
127 add_algo(this->encryption_algos
, algo
, key_size
);
129 case INTEGRITY_ALGORITHM
:
130 add_algo(this->integrity_algos
, algo
, key_size
);
132 case PSEUDO_RANDOM_FUNCTION
:
133 add_algo(this->prf_algos
, algo
, key_size
);
135 case DIFFIE_HELLMAN_GROUP
:
136 add_algo(this->dh_groups
, algo
, 0);
138 case EXTENDED_SEQUENCE_NUMBERS
:
139 add_algo(this->esns
, algo
, 0);
147 * Implements proposal_t.create_algorithm_iterator.
149 static iterator_t
*create_algorithm_iterator(private_proposal_t
*this, transform_type_t type
)
153 case ENCRYPTION_ALGORITHM
:
154 return this->encryption_algos
->create_iterator(this->encryption_algos
, TRUE
);
155 case INTEGRITY_ALGORITHM
:
156 return this->integrity_algos
->create_iterator(this->integrity_algos
, TRUE
);
157 case PSEUDO_RANDOM_FUNCTION
:
158 return this->prf_algos
->create_iterator(this->prf_algos
, TRUE
);
159 case DIFFIE_HELLMAN_GROUP
:
160 return this->dh_groups
->create_iterator(this->dh_groups
, TRUE
);
161 case EXTENDED_SEQUENCE_NUMBERS
:
162 return this->esns
->create_iterator(this->esns
, TRUE
);
170 * Implements proposal_t.get_algorithm.
172 static bool get_algorithm(private_proposal_t
*this, transform_type_t type
, algorithm_t
** algo
)
174 iterator_t
*iterator
= create_algorithm_iterator(this, type
);
175 if (iterator
->iterate(iterator
, (void**)algo
))
177 iterator
->destroy(iterator
);
180 iterator
->destroy(iterator
);
185 * Implements proposal_t.has_dh_group
187 static bool has_dh_group(private_proposal_t
*this, diffie_hellman_group_t group
)
189 algorithm_t
*current
;
190 iterator_t
*iterator
;
193 iterator
= this->dh_groups
->create_iterator(this->dh_groups
, TRUE
);
194 if (iterator
->get_count(iterator
))
196 while (iterator
->iterate(iterator
, (void**)¤t
))
198 if (current
->algorithm
== group
)
205 else if (group
== MODP_NONE
)
209 iterator
->destroy(iterator
);
214 * Find a matching alg/keysize in two linked lists
216 static bool select_algo(linked_list_t
*first
, linked_list_t
*second
, bool *add
, u_int16_t
*alg
, size_t *key_size
)
218 iterator_t
*first_iter
, *second_iter
;
219 algorithm_t
*first_alg
, *second_alg
;
221 /* if in both are zero algorithms specified, we HAVE a match */
222 if (first
->get_count(first
) == 0 && second
->get_count(second
) == 0)
228 first_iter
= first
->create_iterator(first
, TRUE
);
229 second_iter
= second
->create_iterator(second
, TRUE
);
230 /* compare algs, order of algs in "first" is preferred */
231 while (first_iter
->iterate(first_iter
, (void**)&first_alg
))
233 second_iter
->reset(second_iter
);
234 while (second_iter
->iterate(second_iter
, (void**)&second_alg
))
236 if (first_alg
->algorithm
== second_alg
->algorithm
&&
237 first_alg
->key_size
== second_alg
->key_size
)
239 /* ok, we have an algorithm */
240 *alg
= first_alg
->algorithm
;
241 *key_size
= first_alg
->key_size
;
243 first_iter
->destroy(first_iter
);
244 second_iter
->destroy(second_iter
);
249 /* no match in all comparisons */
250 first_iter
->destroy(first_iter
);
251 second_iter
->destroy(second_iter
);
256 * Implements proposal_t.select.
258 static proposal_t
*select_proposal(private_proposal_t
*this, private_proposal_t
*other
)
260 proposal_t
*selected
;
265 DBG2(DBG_CFG
, "selecting proposal:");
268 if (this->protocol
!= other
->protocol
)
270 DBG2(DBG_CFG
, " protocol mismatch, skipping");
274 selected
= proposal_create(this->protocol
);
276 /* select encryption algorithm */
277 if (select_algo(this->encryption_algos
, other
->encryption_algos
, &add
, &algo
, &key_size
))
281 selected
->add_algorithm(selected
, ENCRYPTION_ALGORITHM
, algo
, key_size
);
286 selected
->destroy(selected
);
287 DBG2(DBG_CFG
, " no acceptable ENCRYPTION_ALGORITHM found, skipping");
290 /* select integrity algorithm */
291 if (select_algo(this->integrity_algos
, other
->integrity_algos
, &add
, &algo
, &key_size
))
295 selected
->add_algorithm(selected
, INTEGRITY_ALGORITHM
, algo
, key_size
);
300 selected
->destroy(selected
);
301 DBG2(DBG_CFG
, " no acceptable INTEGRITY_ALGORITHM found, skipping");
304 /* select prf algorithm */
305 if (select_algo(this->prf_algos
, other
->prf_algos
, &add
, &algo
, &key_size
))
309 selected
->add_algorithm(selected
, PSEUDO_RANDOM_FUNCTION
, algo
, key_size
);
314 selected
->destroy(selected
);
315 DBG2(DBG_CFG
, " no acceptable PSEUDO_RANDOM_FUNCTION found, skipping");
318 /* select a DH-group */
319 if (select_algo(this->dh_groups
, other
->dh_groups
, &add
, &algo
, &key_size
))
323 selected
->add_algorithm(selected
, DIFFIE_HELLMAN_GROUP
, algo
, 0);
328 selected
->destroy(selected
);
329 DBG2(DBG_CFG
, " no acceptable DIFFIE_HELLMAN_GROUP found, skipping");
332 /* select if we use ESNs */
333 if (select_algo(this->esns
, other
->esns
, &add
, &algo
, &key_size
))
337 selected
->add_algorithm(selected
, EXTENDED_SEQUENCE_NUMBERS
, algo
, 0);
342 selected
->destroy(selected
);
343 DBG2(DBG_CFG
, " no acceptable EXTENDED_SEQUENCE_NUMBERS found, skipping");
346 DBG2(DBG_CFG
, " proposal matches");
348 /* apply SPI from "other" */
349 selected
->set_spi(selected
, other
->spi
);
351 /* everything matched, return new proposal */
356 * Implements proposal_t.get_protocols.
358 static protocol_id_t
get_protocol(private_proposal_t
*this)
360 return this->protocol
;
364 * Implements proposal_t.set_spi.
366 static void set_spi(private_proposal_t
*this, u_int64_t spi
)
372 * Implements proposal_t.get_spi.
374 static u_int64_t
get_spi(private_proposal_t
*this)
380 * Clone a algorithm list
382 static void clone_algo_list(linked_list_t
*list
, linked_list_t
*clone_list
)
384 algorithm_t
*algo
, *clone_algo
;
385 iterator_t
*iterator
= list
->create_iterator(list
, TRUE
);
386 while (iterator
->iterate(iterator
, (void**)&algo
))
388 clone_algo
= malloc_thing(algorithm_t
);
389 memcpy(clone_algo
, algo
, sizeof(algorithm_t
));
390 clone_list
->insert_last(clone_list
, (void*)clone_algo
);
392 iterator
->destroy(iterator
);
396 * Implements proposal_t.clone
398 static proposal_t
*clone_(private_proposal_t
*this)
400 private_proposal_t
*clone
= (private_proposal_t
*)proposal_create(this->protocol
);
402 clone_algo_list(this->encryption_algos
, clone
->encryption_algos
);
403 clone_algo_list(this->integrity_algos
, clone
->integrity_algos
);
404 clone_algo_list(this->prf_algos
, clone
->prf_algos
);
405 clone_algo_list(this->dh_groups
, clone
->dh_groups
);
406 clone_algo_list(this->esns
, clone
->esns
);
408 clone
->spi
= this->spi
;
410 return &clone
->public;
414 * add a algorithm identified by a string to the proposal.
415 * TODO: we could use gperf here.
417 static status_t
add_string_algo(private_proposal_t
*this, chunk_t alg
)
419 if (strncmp(alg
.ptr
, "null", alg
.len
) == 0)
421 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_NULL
, 0);
423 else if (strncmp(alg
.ptr
, "aes128", alg
.len
) == 0)
425 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
427 else if (strncmp(alg
.ptr
, "aes192", alg
.len
) == 0)
429 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
431 else if (strncmp(alg
.ptr
, "aes256", alg
.len
) == 0)
433 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
435 else if (strncmp(alg
.ptr
, "3des", alg
.len
) == 0)
437 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
439 /* blowfish only uses some predefined key sizes yet */
440 else if (strncmp(alg
.ptr
, "blowfish128", alg
.len
) == 0)
442 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 128);
444 else if (strncmp(alg
.ptr
, "blowfish192", alg
.len
) == 0)
446 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 192);
448 else if (strncmp(alg
.ptr
, "blowfish256", alg
.len
) == 0)
450 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 256);
452 else if (strncmp(alg
.ptr
, "sha", alg
.len
) == 0 ||
453 strncmp(alg
.ptr
, "sha1", alg
.len
) == 0)
455 /* sha means we use SHA for both, PRF and AUTH */
456 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
457 if (this->protocol
== PROTO_IKE
)
459 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA1
, 0);
462 else if (strncmp(alg
.ptr
, "sha256", alg
.len
) == 0 ||
463 strncmp(alg
.ptr
, "sha2_256", alg
.len
) == 0)
465 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_256_128
, 0);
466 if (this->protocol
== PROTO_IKE
)
468 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_256
, 0);
471 else if (strncmp(alg
.ptr
, "sha384", alg
.len
) == 0 ||
472 strncmp(alg
.ptr
, "sha2_384", alg
.len
) == 0)
474 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_384_192
, 0);
475 if (this->protocol
== PROTO_IKE
)
477 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_384
, 0);
480 else if (strncmp(alg
.ptr
, "sha512", alg
.len
) == 0 ||
481 strncmp(alg
.ptr
, "sha2_512", alg
.len
) == 0)
483 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_512_256
, 0);
484 if (this->protocol
== PROTO_IKE
)
486 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_512
, 0);
489 else if (strncmp(alg
.ptr
, "md5", alg
.len
) == 0)
491 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
492 if (this->protocol
== PROTO_IKE
)
494 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_MD5
, 0);
497 else if (strncmp(alg
.ptr
, "aesxcbc", alg
.len
) == 0)
499 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_AES_XCBC_96
, 0);
500 if (this->protocol
== PROTO_IKE
)
502 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, AUTH_AES_XCBC_96
, 0);
505 else if (strncmp(alg
.ptr
, "modp768", alg
.len
) == 0)
507 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_768_BIT
, 0);
509 else if (strncmp(alg
.ptr
, "modp1024", alg
.len
) == 0)
511 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1024_BIT
, 0);
513 else if (strncmp(alg
.ptr
, "modp1536", alg
.len
) == 0)
515 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1536_BIT
, 0);
517 else if (strncmp(alg
.ptr
, "modp2048", alg
.len
) == 0)
519 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_2048_BIT
, 0);
521 else if (strncmp(alg
.ptr
, "modp4096", alg
.len
) == 0)
523 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_4096_BIT
, 0);
525 else if (strncmp(alg
.ptr
, "modp8192", alg
.len
) == 0)
527 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_8192_BIT
, 0);
537 * Implements proposal_t.destroy.
539 static void destroy(private_proposal_t
*this)
541 this->encryption_algos
->destroy_function(this->encryption_algos
, free
);
542 this->integrity_algos
->destroy_function(this->integrity_algos
, free
);
543 this->prf_algos
->destroy_function(this->prf_algos
, free
);
544 this->dh_groups
->destroy_function(this->dh_groups
, free
);
545 this->esns
->destroy_function(this->esns
, free
);
550 * Describtion in header-file
552 proposal_t
*proposal_create(protocol_id_t protocol
)
554 private_proposal_t
*this = malloc_thing(private_proposal_t
);
556 this->public.add_algorithm
= (void (*)(proposal_t
*,transform_type_t
,u_int16_t
,size_t))add_algorithm
;
557 this->public.create_algorithm_iterator
= (iterator_t
* (*)(proposal_t
*,transform_type_t
))create_algorithm_iterator
;
558 this->public.get_algorithm
= (bool (*)(proposal_t
*,transform_type_t
,algorithm_t
**))get_algorithm
;
559 this->public.has_dh_group
= (bool (*)(proposal_t
*,diffie_hellman_group_t
))has_dh_group
;
560 this->public.select
= (proposal_t
* (*)(proposal_t
*,proposal_t
*))select_proposal
;
561 this->public.get_protocol
= (protocol_id_t(*)(proposal_t
*))get_protocol
;
562 this->public.set_spi
= (void(*)(proposal_t
*,u_int64_t
))set_spi
;
563 this->public.get_spi
= (u_int64_t(*)(proposal_t
*))get_spi
;
564 this->public.clone
= (proposal_t
*(*)(proposal_t
*))clone_
;
565 this->public.destroy
= (void(*)(proposal_t
*))destroy
;
568 this->protocol
= protocol
;
570 this->encryption_algos
= linked_list_create();
571 this->integrity_algos
= linked_list_create();
572 this->prf_algos
= linked_list_create();
573 this->dh_groups
= linked_list_create();
574 this->esns
= linked_list_create();
576 return &this->public;
580 * Describtion in header-file
582 proposal_t
*proposal_create_default(protocol_id_t protocol
)
584 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
589 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
590 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
591 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
592 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
593 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_256_128
, 0);
594 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
595 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
596 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_384_192
, 0);
597 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA2_512_256
, 0);
598 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_256
, 0);
599 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA1
, 0);
600 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_MD5
, 0);
601 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_384
, 0);
602 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, PRF_HMAC_SHA2_512
, 0);
603 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_2048_BIT
, 0);
604 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1536_BIT
, 0);
605 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_1024_BIT
, 0);
606 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_4096_BIT
, 0);
607 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, MODP_8192_BIT
, 0);
610 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
611 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
612 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
613 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
614 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 256);
615 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
616 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_AES_XCBC_96
, 0);
617 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
618 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
621 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
622 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_AES_XCBC_96
, 0);
623 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
624 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
630 return &this->public;
634 * Describtion in header-file
636 proposal_t
*proposal_create_from_string(protocol_id_t protocol
, const char *algs
)
638 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
639 chunk_t string
= {(void*)algs
, strlen(algs
)};
641 status_t status
= SUCCESS
;
643 eat_whitespace(&string
);
650 /* get all tokens, separated by '-' */
651 while (extract_token(&alg
, '-', &string
))
653 status
|= add_string_algo(this, alg
);
657 status
|= add_string_algo(this, string
);
659 if (status
!= SUCCESS
)
665 if (protocol
== PROTO_AH
|| protocol
== PROTO_ESP
)
667 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
669 return &this->public;