2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2006 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include <utils/linked_list.h>
23 #include <utils/identification.h>
24 #include <utils/lexparser.h>
25 #include <crypto/transform.h>
26 #include <crypto/prfs/prf.h>
27 #include <crypto/crypters/crypter.h>
28 #include <crypto/signers/signer.h>
29 #include <crypto/proposal/proposal_keywords.h>
31 ENUM(protocol_id_names
, PROTO_NONE
, PROTO_ESP
,
38 ENUM(extended_sequence_numbers_names
, NO_EXT_SEQ_NUMBERS
, EXT_SEQ_NUMBERS
,
43 typedef struct private_proposal_t private_proposal_t
;
44 typedef struct algorithm_t algorithm_t
;
47 * Private data of an proposal_t object
49 struct private_proposal_t
{
57 * protocol (ESP or AH)
59 protocol_id_t protocol
;
62 * priority ordered list of encryption algorithms
64 linked_list_t
*encryption_algos
;
67 * priority ordered list of integrity algorithms
69 linked_list_t
*integrity_algos
;
72 * priority ordered list of pseudo random functions
74 linked_list_t
*prf_algos
;
77 * priority ordered list of dh groups
79 linked_list_t
*dh_groups
;
82 * priority ordered list of extended sequence number flags
93 * Struct used to store different kinds of algorithms.
97 * Value from an encryption_algorithm_t/integrity_algorithm_t/...
102 * the associated key size in bits, or zero if not needed
108 * Add algorithm/keysize to a algorithm list
110 static void add_algo(linked_list_t
*list
, u_int16_t algo
, u_int16_t key_size
)
112 algorithm_t
*algo_key
;
114 algo_key
= malloc_thing(algorithm_t
);
115 algo_key
->algorithm
= algo
;
116 algo_key
->key_size
= key_size
;
117 list
->insert_last(list
, (void*)algo_key
);
121 * Implements proposal_t.add_algorithm
123 static void add_algorithm(private_proposal_t
*this, transform_type_t type
,
124 u_int16_t algo
, u_int16_t key_size
)
128 case ENCRYPTION_ALGORITHM
:
129 add_algo(this->encryption_algos
, algo
, key_size
);
131 case INTEGRITY_ALGORITHM
:
132 add_algo(this->integrity_algos
, algo
, key_size
);
134 case PSEUDO_RANDOM_FUNCTION
:
135 add_algo(this->prf_algos
, algo
, key_size
);
137 case DIFFIE_HELLMAN_GROUP
:
138 add_algo(this->dh_groups
, algo
, 0);
140 case EXTENDED_SEQUENCE_NUMBERS
:
141 add_algo(this->esns
, algo
, 0);
149 * filter function for peer configs
151 static bool alg_filter(void *null
, algorithm_t
**in
, u_int16_t
*alg
,
152 void **unused
, u_int16_t
*key_size
)
154 algorithm_t
*algo
= *in
;
155 *alg
= algo
->algorithm
;
158 *key_size
= algo
->key_size
;
164 * Implements proposal_t.create_enumerator.
166 static enumerator_t
*create_enumerator(private_proposal_t
*this,
167 transform_type_t type
)
173 case ENCRYPTION_ALGORITHM
:
174 list
= this->encryption_algos
;
176 case INTEGRITY_ALGORITHM
:
177 list
= this->integrity_algos
;
179 case PSEUDO_RANDOM_FUNCTION
:
180 list
= this->prf_algos
;
182 case DIFFIE_HELLMAN_GROUP
:
183 list
= this->dh_groups
;
185 case EXTENDED_SEQUENCE_NUMBERS
:
191 return enumerator_create_filter(list
->create_enumerator(list
),
192 (void*)alg_filter
, NULL
, NULL
);
196 * Implements proposal_t.get_algorithm.
198 static bool get_algorithm(private_proposal_t
*this, transform_type_t type
,
199 u_int16_t
*alg
, u_int16_t
*key_size
)
201 enumerator_t
*enumerator
;
204 enumerator
= create_enumerator(this, type
);
205 if (enumerator
->enumerate(enumerator
, alg
, key_size
))
209 enumerator
->destroy(enumerator
);
214 * Implements proposal_t.has_dh_group
216 static bool has_dh_group(private_proposal_t
*this, diffie_hellman_group_t group
)
220 if (this->dh_groups
->get_count(this->dh_groups
))
222 algorithm_t
*current
;
223 enumerator_t
*enumerator
;
225 enumerator
= this->dh_groups
->create_enumerator(this->dh_groups
);
226 while (enumerator
->enumerate(enumerator
, (void**)¤t
))
228 if (current
->algorithm
== group
)
234 enumerator
->destroy(enumerator
);
236 else if (group
== MODP_NONE
)
244 * Implementation of proposal_t.strip_dh.
246 static void strip_dh(private_proposal_t
*this)
250 while (this->dh_groups
->remove_last(this->dh_groups
, (void**)&alg
) == SUCCESS
)
257 * Returns true if the given alg is an authenticated encryption algorithm
259 static bool is_authenticated_encryption(u_int16_t alg
)
263 case ENCR_AES_CCM_ICV8
:
264 case ENCR_AES_CCM_ICV12
:
265 case ENCR_AES_CCM_ICV16
:
266 case ENCR_AES_GCM_ICV8
:
267 case ENCR_AES_GCM_ICV12
:
268 case ENCR_AES_GCM_ICV16
:
269 case ENCR_CAMELLIA_CCM_ICV8
:
270 case ENCR_CAMELLIA_CCM_ICV12
:
271 case ENCR_CAMELLIA_CCM_ICV16
:
272 case ENCR_NULL_AUTH_AES_GMAC
:
279 * Find a matching alg/keysize in two linked lists
281 static bool select_algo(linked_list_t
*first
, linked_list_t
*second
, bool priv
,
282 bool *add
, u_int16_t
*alg
, size_t *key_size
)
284 enumerator_t
*e1
, *e2
;
285 algorithm_t
*alg1
, *alg2
;
287 /* if in both are zero algorithms specified, we HAVE a match */
288 if (first
->get_count(first
) == 0 && second
->get_count(second
) == 0)
294 e1
= first
->create_enumerator(first
);
295 e2
= second
->create_enumerator(second
);
296 /* compare algs, order of algs in "first" is preferred */
297 while (e1
->enumerate(e1
, &alg1
))
300 e2
= second
->create_enumerator(second
);
301 while (e2
->enumerate(e2
, &alg2
))
303 if (alg1
->algorithm
== alg2
->algorithm
&&
304 alg1
->key_size
== alg2
->key_size
)
306 if (!priv
&& alg1
->algorithm
>= 1024)
308 /* accept private use algorithms only if requested */
309 DBG1(DBG_CFG
, "an algorithm from private space would match, "
310 "but peer implementation is unknown, skipped");
313 /* ok, we have an algorithm */
314 *alg
= alg1
->algorithm
;
315 *key_size
= alg1
->key_size
;
323 /* no match in all comparisons */
330 * Implements proposal_t.select.
332 static proposal_t
*select_proposal(private_proposal_t
*this,
333 private_proposal_t
*other
, bool private)
335 proposal_t
*selected
;
340 DBG2(DBG_CFG
, "selecting proposal:");
343 if (this->protocol
!= other
->protocol
)
345 DBG2(DBG_CFG
, " protocol mismatch, skipping");
349 selected
= proposal_create(this->protocol
);
351 /* select encryption algorithm */
352 if (select_algo(this->encryption_algos
, other
->encryption_algos
, private,
353 &add
, &algo
, &key_size
))
357 selected
->add_algorithm(selected
, ENCRYPTION_ALGORITHM
,
363 selected
->destroy(selected
);
364 DBG2(DBG_CFG
, " no acceptable %N found",
365 transform_type_names
, ENCRYPTION_ALGORITHM
);
368 /* select integrity algorithm */
369 if (!is_authenticated_encryption(algo
))
371 if (select_algo(this->integrity_algos
, other
->integrity_algos
, private,
372 &add
, &algo
, &key_size
))
376 selected
->add_algorithm(selected
, INTEGRITY_ALGORITHM
,
382 selected
->destroy(selected
);
383 DBG2(DBG_CFG
, " no acceptable %N found",
384 transform_type_names
, INTEGRITY_ALGORITHM
);
388 /* select prf algorithm */
389 if (select_algo(this->prf_algos
, other
->prf_algos
, private,
390 &add
, &algo
, &key_size
))
394 selected
->add_algorithm(selected
, PSEUDO_RANDOM_FUNCTION
,
400 selected
->destroy(selected
);
401 DBG2(DBG_CFG
, " no acceptable %N found",
402 transform_type_names
, PSEUDO_RANDOM_FUNCTION
);
405 /* select a DH-group */
406 if (select_algo(this->dh_groups
, other
->dh_groups
, private,
407 &add
, &algo
, &key_size
))
411 selected
->add_algorithm(selected
, DIFFIE_HELLMAN_GROUP
, algo
, 0);
416 selected
->destroy(selected
);
417 DBG2(DBG_CFG
, " no acceptable %N found",
418 transform_type_names
, DIFFIE_HELLMAN_GROUP
);
421 /* select if we use ESNs (has no private use space) */
422 if (select_algo(this->esns
, other
->esns
, TRUE
, &add
, &algo
, &key_size
))
426 selected
->add_algorithm(selected
, EXTENDED_SEQUENCE_NUMBERS
, algo
, 0);
431 selected
->destroy(selected
);
432 DBG2(DBG_CFG
, " no acceptable %N found",
433 transform_type_names
, EXTENDED_SEQUENCE_NUMBERS
);
436 DBG2(DBG_CFG
, " proposal matches");
438 /* apply SPI from "other" */
439 selected
->set_spi(selected
, other
->spi
);
441 /* everything matched, return new proposal */
446 * Implements proposal_t.get_protocols.
448 static protocol_id_t
get_protocol(private_proposal_t
*this)
450 return this->protocol
;
454 * Implements proposal_t.set_spi.
456 static void set_spi(private_proposal_t
*this, u_int64_t spi
)
462 * Implements proposal_t.get_spi.
464 static u_int64_t
get_spi(private_proposal_t
*this)
470 * Clone a algorithm list
472 static void clone_algo_list(linked_list_t
*list
, linked_list_t
*clone_list
)
474 algorithm_t
*algo
, *clone_algo
;
475 enumerator_t
*enumerator
;
477 enumerator
= list
->create_enumerator(list
);
478 while (enumerator
->enumerate(enumerator
, &algo
))
480 clone_algo
= malloc_thing(algorithm_t
);
481 memcpy(clone_algo
, algo
, sizeof(algorithm_t
));
482 clone_list
->insert_last(clone_list
, (void*)clone_algo
);
484 enumerator
->destroy(enumerator
);
488 * check if an algorithm list equals
490 static bool algo_list_equals(linked_list_t
*l1
, linked_list_t
*l2
)
492 enumerator_t
*e1
, *e2
;
493 algorithm_t
*alg1
, *alg2
;
496 if (l1
->get_count(l1
) != l2
->get_count(l2
))
501 e1
= l1
->create_enumerator(l1
);
502 e2
= l2
->create_enumerator(l2
);
503 while (e1
->enumerate(e1
, &alg1
) && e2
->enumerate(e2
, &alg2
))
505 if (alg1
->algorithm
!= alg2
->algorithm
||
506 alg1
->key_size
!= alg2
->key_size
)
518 * Implementation of proposal_t.equals.
520 static bool equals(private_proposal_t
*this, private_proposal_t
*other
)
526 if (this->public.equals
!= other
->public.equals
)
531 algo_list_equals(this->encryption_algos
, other
->encryption_algos
) &&
532 algo_list_equals(this->integrity_algos
, other
->integrity_algos
) &&
533 algo_list_equals(this->prf_algos
, other
->prf_algos
) &&
534 algo_list_equals(this->dh_groups
, other
->dh_groups
) &&
535 algo_list_equals(this->esns
, other
->esns
));
539 * Implements proposal_t.clone
541 static proposal_t
*clone_(private_proposal_t
*this)
543 private_proposal_t
*clone
= (private_proposal_t
*)proposal_create(this->protocol
);
545 clone_algo_list(this->encryption_algos
, clone
->encryption_algos
);
546 clone_algo_list(this->integrity_algos
, clone
->integrity_algos
);
547 clone_algo_list(this->prf_algos
, clone
->prf_algos
);
548 clone_algo_list(this->dh_groups
, clone
->dh_groups
);
549 clone_algo_list(this->esns
, clone
->esns
);
551 clone
->spi
= this->spi
;
553 return &clone
->public;
557 * Checks the proposal read from a string.
559 static void check_proposal(private_proposal_t
*this)
563 bool all_aead
= TRUE
;
565 e
= this->encryption_algos
->create_enumerator(this->encryption_algos
);
566 while (e
->enumerate(e
, &alg
))
568 if (!is_authenticated_encryption(alg
->algorithm
))
578 /* if all encryption algorithms in the proposal are authenticated encryption
579 * algorithms we MUST NOT propose any integrity algorithms */
580 while (this->integrity_algos
->remove_last(this->integrity_algos
,
581 (void**)&alg
) == SUCCESS
)
589 * add a algorithm identified by a string to the proposal.
591 static status_t
add_string_algo(private_proposal_t
*this, chunk_t alg
)
593 const proposal_token_t
*token
= proposal_get_token(alg
.ptr
, alg
.len
);
600 add_algorithm(this, token
->type
, token
->algorithm
, token
->keysize
);
602 if (this->protocol
== PROTO_IKE
&& token
->type
== INTEGRITY_ALGORITHM
)
604 pseudo_random_function_t prf
;
606 switch (token
->algorithm
)
608 case AUTH_HMAC_SHA1_96
:
611 case AUTH_HMAC_SHA2_256_128
:
612 prf
= PRF_HMAC_SHA2_256
;
614 case AUTH_HMAC_SHA2_384_192
:
615 prf
= PRF_HMAC_SHA2_384
;
617 case AUTH_HMAC_SHA2_512_256
:
618 prf
= PRF_HMAC_SHA2_512
;
620 case AUTH_HMAC_MD5_96
:
623 case AUTH_AES_XCBC_96
:
624 prf
= PRF_AES128_XCBC
;
629 if (prf
!= PRF_UNDEFINED
)
631 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, prf
, 0);
638 * print all algorithms of a kind to buffer
640 static int print_alg(private_proposal_t
*this, char **dst
, size_t *len
,
641 u_int kind
, void *names
, bool *first
)
643 enumerator_t
*enumerator
;
647 enumerator
= create_enumerator(this, kind
);
648 while (enumerator
->enumerate(enumerator
, &alg
, &size
))
652 written
+= print_in_hook(*dst
, *len
, "%N", names
, alg
);
657 written
+= print_in_hook(*dst
, *len
, "/%N", names
, alg
);
661 written
+= print_in_hook(*dst
, *len
, "_%u", size
);
664 enumerator
->destroy(enumerator
);
669 * Described in header.
671 int proposal_printf_hook(char *dst
, size_t len
, printf_hook_spec_t
*spec
,
672 const void *const *args
)
674 private_proposal_t
*this = *((private_proposal_t
**)(args
[0]));
675 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
676 enumerator_t
*enumerator
;
682 return print_in_hook(dst
, len
, "(null)");
687 enumerator
= list
->create_enumerator(list
);
688 while (enumerator
->enumerate(enumerator
, &this))
689 { /* call recursivly */
692 written
+= print_in_hook(dst
, len
, "%P", this);
697 written
+= print_in_hook(dst
, len
, ", %P", this);
700 enumerator
->destroy(enumerator
);
704 written
= print_in_hook(dst
, len
, "%N:", protocol_id_names
, this->protocol
);
705 written
+= print_alg(this, &dst
, &len
, ENCRYPTION_ALGORITHM
,
706 encryption_algorithm_names
, &first
);
707 written
+= print_alg(this, &dst
, &len
, INTEGRITY_ALGORITHM
,
708 integrity_algorithm_names
, &first
);
709 written
+= print_alg(this, &dst
, &len
, PSEUDO_RANDOM_FUNCTION
,
710 pseudo_random_function_names
, &first
);
711 written
+= print_alg(this, &dst
, &len
, DIFFIE_HELLMAN_GROUP
,
712 diffie_hellman_group_names
, &first
);
713 written
+= print_alg(this, &dst
, &len
, EXTENDED_SEQUENCE_NUMBERS
,
714 extended_sequence_numbers_names
, &first
);
719 * Implements proposal_t.destroy.
721 static void destroy(private_proposal_t
*this)
723 this->encryption_algos
->destroy_function(this->encryption_algos
, free
);
724 this->integrity_algos
->destroy_function(this->integrity_algos
, free
);
725 this->prf_algos
->destroy_function(this->prf_algos
, free
);
726 this->dh_groups
->destroy_function(this->dh_groups
, free
);
727 this->esns
->destroy_function(this->esns
, free
);
732 * Describtion in header-file
734 proposal_t
*proposal_create(protocol_id_t protocol
)
736 private_proposal_t
*this = malloc_thing(private_proposal_t
);
738 this->public.add_algorithm
= (void (*)(proposal_t
*,transform_type_t
,u_int16_t
,u_int16_t
))add_algorithm
;
739 this->public.create_enumerator
= (enumerator_t
* (*)(proposal_t
*,transform_type_t
))create_enumerator
;
740 this->public.get_algorithm
= (bool (*)(proposal_t
*,transform_type_t
,u_int16_t
*,u_int16_t
*))get_algorithm
;
741 this->public.has_dh_group
= (bool (*)(proposal_t
*,diffie_hellman_group_t
))has_dh_group
;
742 this->public.strip_dh
= (void(*)(proposal_t
*))strip_dh
;
743 this->public.select
= (proposal_t
* (*)(proposal_t
*,proposal_t
*,bool))select_proposal
;
744 this->public.get_protocol
= (protocol_id_t(*)(proposal_t
*))get_protocol
;
745 this->public.set_spi
= (void(*)(proposal_t
*,u_int64_t
))set_spi
;
746 this->public.get_spi
= (u_int64_t(*)(proposal_t
*))get_spi
;
747 this->public.equals
= (bool(*)(proposal_t
*, proposal_t
*other
))equals
;
748 this->public.clone
= (proposal_t
*(*)(proposal_t
*))clone_
;
749 this->public.destroy
= (void(*)(proposal_t
*))destroy
;
752 this->protocol
= protocol
;
754 this->encryption_algos
= linked_list_create();
755 this->integrity_algos
= linked_list_create();
756 this->prf_algos
= linked_list_create();
757 this->dh_groups
= linked_list_create();
758 this->esns
= linked_list_create();
760 return &this->public;
764 * Add supported IKE algorithms to proposal
766 static void proposal_add_supported_ike(private_proposal_t
*this)
768 enumerator_t
*enumerator
;
769 encryption_algorithm_t encryption
;
770 integrity_algorithm_t integrity
;
771 pseudo_random_function_t prf
;
772 diffie_hellman_group_t group
;
774 enumerator
= lib
->crypto
->create_crypter_enumerator(lib
->crypto
);
775 while (enumerator
->enumerate(enumerator
, &encryption
))
780 /* we assume that we support all AES sizes */
781 add_algorithm(this, ENCRYPTION_ALGORITHM
, encryption
, 128);
782 add_algorithm(this, ENCRYPTION_ALGORITHM
, encryption
, 192);
783 add_algorithm(this, ENCRYPTION_ALGORITHM
, encryption
, 256);
787 case ENCR_AES_CCM_ICV8
:
788 case ENCR_AES_CCM_ICV12
:
789 case ENCR_AES_CCM_ICV16
:
790 case ENCR_AES_GCM_ICV8
:
791 case ENCR_AES_GCM_ICV12
:
792 case ENCR_AES_GCM_ICV16
:
793 add_algorithm(this, ENCRYPTION_ALGORITHM
, encryption
, 0);
802 enumerator
->destroy(enumerator
);
804 enumerator
= lib
->crypto
->create_signer_enumerator(lib
->crypto
);
805 while (enumerator
->enumerate(enumerator
, &integrity
))
809 case AUTH_HMAC_SHA1_96
:
810 case AUTH_HMAC_SHA2_256_128
:
811 case AUTH_HMAC_SHA2_384_192
:
812 case AUTH_HMAC_SHA2_512_256
:
813 case AUTH_HMAC_MD5_96
:
814 case AUTH_AES_XCBC_96
:
815 add_algorithm(this, INTEGRITY_ALGORITHM
, integrity
, 0);
821 enumerator
->destroy(enumerator
);
823 enumerator
= lib
->crypto
->create_prf_enumerator(lib
->crypto
);
824 while (enumerator
->enumerate(enumerator
, &prf
))
829 case PRF_HMAC_SHA2_256
:
830 case PRF_HMAC_SHA2_384
:
831 case PRF_HMAC_SHA2_512
:
833 case PRF_AES128_XCBC
:
834 add_algorithm(this, PSEUDO_RANDOM_FUNCTION
, prf
, 0);
840 enumerator
->destroy(enumerator
);
842 enumerator
= lib
->crypto
->create_dh_enumerator(lib
->crypto
);
843 while (enumerator
->enumerate(enumerator
, &group
))
848 /* only for testing purposes */
866 add_algorithm(this, DIFFIE_HELLMAN_GROUP
, group
, 0);
872 enumerator
->destroy(enumerator
);
876 * Describtion in header-file
878 proposal_t
*proposal_create_default(protocol_id_t protocol
)
880 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
885 proposal_add_supported_ike(this);
888 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 128);
889 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 192);
890 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_AES_CBC
, 256);
891 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_3DES
, 0);
892 add_algorithm(this, ENCRYPTION_ALGORITHM
, ENCR_BLOWFISH
, 256);
893 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
894 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_AES_XCBC_96
, 0);
895 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
896 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
899 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_SHA1_96
, 0);
900 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_AES_XCBC_96
, 0);
901 add_algorithm(this, INTEGRITY_ALGORITHM
, AUTH_HMAC_MD5_96
, 0);
902 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
907 return &this->public;
911 * Describtion in header-file
913 proposal_t
*proposal_create_from_string(protocol_id_t protocol
, const char *algs
)
915 private_proposal_t
*this = (private_proposal_t
*)proposal_create(protocol
);
916 chunk_t string
= {(void*)algs
, strlen(algs
)};
918 status_t status
= SUCCESS
;
920 eat_whitespace(&string
);
927 /* get all tokens, separated by '-' */
928 while (extract_token(&alg
, '-', &string
))
930 status
|= add_string_algo(this, alg
);
934 status
|= add_string_algo(this, string
);
936 if (status
!= SUCCESS
)
942 check_proposal(this);
944 if (protocol
== PROTO_AH
|| protocol
== PROTO_ESP
)
946 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS
, NO_EXT_SEQ_NUMBERS
, 0);
948 return &this->public;