]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/config/proposal.c
Migrate all enumerators to venumerate() interface change
[thirdparty/strongswan.git] / src / libcharon / config / proposal.c
CommitLineData
c06dbbab 1/*
aae95101 2 * Copyright (C) 2008-2016 Tobias Brunner
d454c586 3 * Copyright (C) 2006-2010 Martin Willi
a78e1c3b 4 * Copyright (C) 2013-2015 Andreas Steffen
c06dbbab
MW
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
5113680f
MW
18#include <string.h>
19
ce461bbd 20#include "proposal.h"
c06dbbab 21
02b3101b 22#include <daemon.h>
c907b57f 23#include <collections/array.h>
c06dbbab 24#include <utils/identification.h>
99587521 25
433cb51b 26#include <crypto/transform.h>
c095388f
MW
27#include <crypto/prfs/prf.h>
28#include <crypto/crypters/crypter.h>
29#include <crypto/signers/signer.h>
c06dbbab 30
7a75cae8 31ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
60356f33
MW
32 "PROTO_NONE",
33 "IKE",
34 "AH",
35 "ESP",
7a75cae8 36 "IPCOMP",
60356f33 37);
c06dbbab 38
8d77edde 39typedef struct private_proposal_t private_proposal_t;
c06dbbab
MW
40
41/**
8d77edde 42 * Private data of an proposal_t object
c06dbbab 43 */
8d77edde
MW
44struct private_proposal_t {
45
46 /**
47 * Public part
48 */
49 proposal_t public;
7daf5226 50
c06dbbab
MW
51 /**
52 * protocol (ESP or AH)
53 */
54 protocol_id_t protocol;
7daf5226 55
c06dbbab 56 /**
5cd64f97 57 * Priority ordered list of transforms, as entry_t
c06dbbab 58 */
c907b57f 59 array_t *transforms;
7daf5226
MW
60
61 /**
c06dbbab
MW
62 * senders SPI
63 */
b12c53ce 64 uint64_t spi;
bb162175
MW
65
66 /**
67 * Proposal number
68 */
69 u_int number;
c06dbbab
MW
70};
71
3c7e72f5 72/**
7daf5226 73 * Struct used to store different kinds of algorithms.
3c7e72f5 74 */
5cd64f97
MW
75typedef struct {
76 /** Type of the transform */
77 transform_type_t type;
78 /** algorithm identifier */
b12c53ce 79 uint16_t alg;
5cd64f97 80 /** key size in bits, or zero if not needed */
b12c53ce 81 uint16_t key_size;
5cd64f97 82} entry_t;
c06dbbab 83
d454c586
MW
84METHOD(proposal_t, add_algorithm, void,
85 private_proposal_t *this, transform_type_t type,
b12c53ce 86 uint16_t alg, uint16_t key_size)
c06dbbab 87{
c907b57f 88 entry_t entry = {
5cd64f97
MW
89 .type = type,
90 .alg = alg,
91 .key_size = key_size,
c907b57f 92 };
5cd64f97 93
c907b57f 94 array_insert(this->transforms, ARRAY_TAIL, &entry);
c06dbbab
MW
95}
96
97/**
3c7e72f5
MW
98 * filter function for peer configs
99 */
b12c53ce
AS
100static bool alg_filter(uintptr_t type, entry_t **in, uint16_t *alg,
101 void **unused, uint16_t *key_size)
3c7e72f5 102{
5cd64f97
MW
103 entry_t *entry = *in;
104
105 if (entry->type != type)
106 {
107 return FALSE;
108 }
109 if (alg)
110 {
111 *alg = entry->alg;
112 }
3c7e72f5
MW
113 if (key_size)
114 {
5cd64f97 115 *key_size = entry->key_size;
3c7e72f5
MW
116 }
117 return TRUE;
118}
119
d454c586
MW
120METHOD(proposal_t, create_enumerator, enumerator_t*,
121 private_proposal_t *this, transform_type_t type)
c06dbbab 122{
5cd64f97 123 return enumerator_create_filter(
c907b57f 124 array_create_enumerator(this->transforms),
5cd64f97 125 (void*)alg_filter, (void*)(uintptr_t)type, NULL);
c06dbbab
MW
126}
127
d454c586
MW
128METHOD(proposal_t, get_algorithm, bool,
129 private_proposal_t *this, transform_type_t type,
b12c53ce 130 uint16_t *alg, uint16_t *key_size)
1fd5383e 131{
3c7e72f5 132 enumerator_t *enumerator;
9fa5c75f 133 bool found = FALSE;
7daf5226 134
3c7e72f5
MW
135 enumerator = create_enumerator(this, type);
136 if (enumerator->enumerate(enumerator, alg, key_size))
1fd5383e 137 {
3c7e72f5 138 found = TRUE;
1fd5383e 139 }
3c7e72f5 140 enumerator->destroy(enumerator);
5cd64f97 141
3c7e72f5 142 return found;
1fd5383e
MW
143}
144
d454c586
MW
145METHOD(proposal_t, has_dh_group, bool,
146 private_proposal_t *this, diffie_hellman_group_t group)
1fd5383e 147{
5cd64f97
MW
148 bool found = FALSE, any = FALSE;
149 enumerator_t *enumerator;
b12c53ce 150 uint16_t current;
7daf5226 151
5cd64f97
MW
152 enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
153 while (enumerator->enumerate(enumerator, &current, NULL))
1fd5383e 154 {
5cd64f97
MW
155 any = TRUE;
156 if (current == group)
1fd5383e 157 {
5cd64f97
MW
158 found = TRUE;
159 break;
1fd5383e
MW
160 }
161 }
5cd64f97
MW
162 enumerator->destroy(enumerator);
163
164 if (!any && group == MODP_NONE)
1fd5383e 165 {
5cd64f97 166 found = TRUE;
1fd5383e 167 }
5cd64f97 168 return found;
1fd5383e
MW
169}
170
d454c586 171METHOD(proposal_t, strip_dh, void,
4eba7269 172 private_proposal_t *this, diffie_hellman_group_t keep)
3c7e72f5 173{
4eba7269 174 enumerator_t *enumerator;
5cd64f97 175 entry_t *entry;
7daf5226 176
c907b57f 177 enumerator = array_create_enumerator(this->transforms);
5cd64f97 178 while (enumerator->enumerate(enumerator, &entry))
3c7e72f5 179 {
5cd64f97
MW
180 if (entry->type == DIFFIE_HELLMAN_GROUP &&
181 entry->alg != keep)
4eba7269 182 {
c907b57f 183 array_remove_at(this->transforms, enumerator);
4eba7269 184 }
3c7e72f5 185 }
4eba7269 186 enumerator->destroy(enumerator);
3c7e72f5
MW
187}
188
c06dbbab 189/**
5cd64f97 190 * Select a matching proposal from this and other, insert into selected.
c06dbbab 191 */
5cd64f97
MW
192static bool select_algo(private_proposal_t *this, proposal_t *other,
193 proposal_t *selected, transform_type_t type, bool priv)
c06dbbab 194{
3c7e72f5 195 enumerator_t *e1, *e2;
b12c53ce 196 uint16_t alg1, alg2, ks1, ks2;
a213944d 197 bool found = FALSE, optional = FALSE;
7daf5226 198
5cd64f97
MW
199 if (type == INTEGRITY_ALGORITHM &&
200 selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
201 encryption_algorithm_is_aead(alg1))
c06dbbab 202 {
5cd64f97 203 /* no integrity algorithm required, we have an AEAD */
c06dbbab
MW
204 return TRUE;
205 }
a213944d
TB
206 if (type == DIFFIE_HELLMAN_GROUP)
207 {
208 optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
209 }
7daf5226 210
5cd64f97
MW
211 e1 = create_enumerator(this, type);
212 e2 = other->create_enumerator(other, type);
aae95101 213 if (!e1->enumerate(e1, &alg1, NULL))
5cd64f97 214 {
a213944d
TB
215 if (!e2->enumerate(e2, &alg2, NULL))
216 {
217 found = TRUE;
218 }
219 else if (optional)
220 {
221 do
aae95101 222 { /* if NONE is proposed, we accept the proposal */
a213944d
TB
223 found = !alg2;
224 }
225 while (!found && e2->enumerate(e2, &alg2, NULL));
226 }
5cd64f97 227 }
aae95101
TB
228 else if (!e2->enumerate(e2, NULL, NULL))
229 {
230 if (optional)
231 {
232 do
233 { /* if NONE is proposed, we accept the proposal */
234 found = !alg1;
235 }
236 while (!found && e1->enumerate(e1, &alg1, NULL));
237 }
238 }
5cd64f97
MW
239
240 e1->destroy(e1);
241 e1 = create_enumerator(this, type);
c06dbbab 242 /* compare algs, order of algs in "first" is preferred */
5cd64f97 243 while (!found && e1->enumerate(e1, &alg1, &ks1))
c06dbbab 244 {
3c7e72f5 245 e2->destroy(e2);
5cd64f97
MW
246 e2 = other->create_enumerator(other, type);
247 while (e2->enumerate(e2, &alg2, &ks2))
c06dbbab 248 {
5cd64f97 249 if (alg1 == alg2 && ks1 == ks2)
c06dbbab 250 {
5cd64f97 251 if (!priv && alg1 >= 1024)
023fd8f1
MW
252 {
253 /* accept private use algorithms only if requested */
254 DBG1(DBG_CFG, "an algorithm from private space would match, "
255 "but peer implementation is unknown, skipped");
256 continue;
257 }
5cd64f97
MW
258 selected->add_algorithm(selected, type, alg1, ks1);
259 found = TRUE;
260 break;
c06dbbab
MW
261 }
262 }
263 }
264 /* no match in all comparisons */
3c7e72f5
MW
265 e1->destroy(e1);
266 e2->destroy(e2);
5cd64f97
MW
267
268 if (!found)
269 {
270 DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type);
271 }
272 return found;
c06dbbab
MW
273}
274
d454c586 275METHOD(proposal_t, select_proposal, proposal_t*,
22f13dce
TB
276 private_proposal_t *this, proposal_t *other, bool other_remote,
277 bool private)
c06dbbab 278{
ce461bbd 279 proposal_t *selected;
7daf5226 280
02b3101b 281 DBG2(DBG_CFG, "selecting proposal:");
7daf5226 282
5cd64f97 283 if (this->protocol != other->get_protocol(other))
c06dbbab 284 {
02b3101b 285 DBG2(DBG_CFG, " protocol mismatch, skipping");
c06dbbab
MW
286 return NULL;
287 }
7daf5226 288
22f13dce
TB
289 if (other_remote)
290 {
291 selected = proposal_create(this->protocol, other->get_number(other));
292 selected->set_spi(selected, other->get_spi(other));
293 }
294 else
295 {
296 selected = proposal_create(this->protocol, this->number);
297 selected->set_spi(selected, this->spi);
298
299 }
7daf5226 300
5cd64f97
MW
301 if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
302 !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
303 !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
304 !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
305 !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
8d77edde
MW
306 {
307 selected->destroy(selected);
308 return NULL;
309 }
5cd64f97 310
02b3101b 311 DBG2(DBG_CFG, " proposal matches");
c06dbbab
MW
312 return selected;
313}
314
d454c586
MW
315METHOD(proposal_t, get_protocol, protocol_id_t,
316 private_proposal_t *this)
c06dbbab 317{
8d77edde 318 return this->protocol;
c06dbbab
MW
319}
320
d454c586 321METHOD(proposal_t, set_spi, void,
b12c53ce 322 private_proposal_t *this, uint64_t spi)
c06dbbab 323{
8d77edde 324 this->spi = spi;
c06dbbab
MW
325}
326
b12c53ce 327METHOD(proposal_t, get_spi, uint64_t,
d454c586 328 private_proposal_t *this)
c06dbbab 329{
8d77edde 330 return this->spi;
c06dbbab
MW
331}
332
87a217f9 333/**
5cd64f97 334 * Check if two proposals have the same algorithms for a given transform type
3c7e72f5 335 */
5cd64f97
MW
336static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
337 transform_type_t type)
3c7e72f5
MW
338{
339 enumerator_t *e1, *e2;
b12c53ce 340 uint16_t alg1, alg2, ks1, ks2;
3c7e72f5 341 bool equals = TRUE;
7daf5226 342
5cd64f97
MW
343 e1 = create_enumerator(this, type);
344 e2 = other->create_enumerator(other, type);
345 while (e1->enumerate(e1, &alg1, &ks1))
3c7e72f5 346 {
5cd64f97
MW
347 if (!e2->enumerate(e2, &alg2, &ks2))
348 {
349 /* this has more algs */
350 equals = FALSE;
351 break;
352 }
353 if (alg1 != alg2 || ks1 != ks2)
3c7e72f5
MW
354 {
355 equals = FALSE;
356 break;
357 }
358 }
8e52dc27 359 if (e2->enumerate(e2, &alg2, &ks2))
5cd64f97
MW
360 {
361 /* other has more algs */
362 equals = FALSE;
363 }
3c7e72f5
MW
364 e1->destroy(e1);
365 e2->destroy(e2);
5cd64f97 366
3c7e72f5
MW
367 return equals;
368}
369
bb162175
MW
370METHOD(proposal_t, get_number, u_int,
371 private_proposal_t *this)
372{
373 return this->number;
374}
375
d454c586 376METHOD(proposal_t, equals, bool,
5cd64f97 377 private_proposal_t *this, proposal_t *other)
3c7e72f5 378{
5cd64f97 379 if (&this->public == other)
3c7e72f5
MW
380 {
381 return TRUE;
382 }
3c7e72f5 383 return (
5cd64f97
MW
384 algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
385 algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
386 algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
387 algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
388 algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
87a217f9
MW
389}
390
d454c586
MW
391METHOD(proposal_t, clone_, proposal_t*,
392 private_proposal_t *this)
87a217f9 393{
bb162175 394 private_proposal_t *clone;
5cd64f97 395 enumerator_t *enumerator;
c907b57f 396 entry_t *entry;
7daf5226 397
bb162175 398 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
5cd64f97 399
c907b57f
MW
400 enumerator = array_create_enumerator(this->transforms);
401 while (enumerator->enumerate(enumerator, &entry))
5cd64f97 402 {
c907b57f 403 array_insert(clone->transforms, ARRAY_TAIL, entry);
5cd64f97
MW
404 }
405 enumerator->destroy(enumerator);
7daf5226 406
8d77edde 407 clone->spi = this->spi;
bb162175 408 clone->number = this->number;
7daf5226 409
87a217f9
MW
410 return &clone->public;
411}
412
7ee16e4b
MW
413/**
414 * Map integrity algorithms to the PRF functions using the same algorithm.
415 */
416static const struct {
417 integrity_algorithm_t integ;
418 pseudo_random_function_t prf;
419} integ_prf_map[] = {
420 {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
b1ef481c 421 {AUTH_HMAC_SHA1_160, PRF_HMAC_SHA1 },
7ee16e4b
MW
422 {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
423 {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
424 {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
425 {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
b1ef481c 426 {AUTH_HMAC_MD5_128, PRF_HMAC_MD5 },
7ee16e4b
MW
427 {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
428 {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
429 {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
430};
431
e98414ea
TB
432/**
433 * Remove all entries of the given transform type
434 */
435static void remove_transform(private_proposal_t *this, transform_type_t type)
436{
437 enumerator_t *e;
438 entry_t *entry;
439
440 e = array_create_enumerator(this->transforms);
441 while (e->enumerate(e, &entry))
442 {
443 if (entry->type == type)
444 {
445 array_remove_at(this->transforms, e);
446 }
447 }
448 e->destroy(e);
449}
450
3f730ec1
TB
451/**
452 * Checks the proposal read from a string.
453 */
9b191d59 454static bool check_proposal(private_proposal_t *this)
3f730ec1
TB
455{
456 enumerator_t *e;
5cd64f97 457 entry_t *entry;
b12c53ce 458 uint16_t alg, ks;
6a5e6579 459 bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
7ee16e4b
MW
460 int i;
461
5cd64f97
MW
462 if (this->protocol == PROTO_IKE)
463 {
e98414ea
TB
464 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
465 { /* No explicit PRF found. We assume the same algorithm as used
466 * for integrity checking. */
5cd64f97
MW
467 e = create_enumerator(this, INTEGRITY_ALGORITHM);
468 while (e->enumerate(e, &alg, &ks))
7ee16e4b 469 {
5cd64f97 470 for (i = 0; i < countof(integ_prf_map); i++)
7ee16e4b 471 {
5cd64f97
MW
472 if (alg == integ_prf_map[i].integ)
473 {
474 add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
475 integ_prf_map[i].prf, 0);
476 break;
477 }
7ee16e4b
MW
478 }
479 }
e98414ea
TB
480 e->destroy(e);
481 }
482 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
483 {
484 DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
485 return FALSE;
7ee16e4b 486 }
f5e8bc18
TB
487 /* remove MODP_NONE from IKE proposal */
488 e = array_create_enumerator(this->transforms);
489 while (e->enumerate(e, &entry))
490 {
491 if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
492 {
493 array_remove_at(this->transforms, e);
494 }
495 }
496 e->destroy(e);
e98414ea 497 if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
9b191d59
TB
498 {
499 DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
9b191d59
TB
500 return FALSE;
501 }
e98414ea
TB
502 }
503 else
504 { /* remove PRFs from ESP/AH proposals */
505 remove_transform(this, PSEUDO_RANDOM_FUNCTION);
7ee16e4b 506 }
7daf5226 507
6a5e6579 508 if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
3f730ec1 509 {
f0c59e1c
MW
510 e = create_enumerator(this, ENCRYPTION_ALGORITHM);
511 while (e->enumerate(e, &alg, &ks))
3f730ec1 512 {
6a5e6579
TB
513 any_enc = TRUE;
514 if (encryption_algorithm_is_aead(alg))
f0c59e1c 515 {
6a5e6579
TB
516 any_aead = TRUE;
517 continue;
f0c59e1c 518 }
6a5e6579 519 all_aead = FALSE;
3f730ec1 520 }
f0c59e1c 521 e->destroy(e);
7daf5226 522
6a5e6579
TB
523 if (!any_enc)
524 {
525 DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
526 protocol_id_names, this->protocol);
527 return FALSE;
528 }
529 else if (any_aead && !all_aead)
3f730ec1 530 {
6a5e6579
TB
531 DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
532 "algorithms can't be contained in the same %N proposal",
533 protocol_id_names, this->protocol);
534 return FALSE;
535 }
536 else if (all_aead)
537 { /* if all encryption algorithms in the proposal are AEADs,
f0c59e1c 538 * we MUST NOT propose any integrity algorithms */
6a5e6579 539 remove_transform(this, INTEGRITY_ALGORITHM);
3f730ec1
TB
540 }
541 }
a65a282f
TB
542 else
543 { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
544 * proper integrity algorithm */
545 e = array_create_enumerator(this->transforms);
546 while (e->enumerate(e, &entry))
547 {
548 if (entry->type == ENCRYPTION_ALGORITHM)
549 {
550 if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
551 {
552 entry->type = INTEGRITY_ALGORITHM;
553 ks = entry->key_size;
554 entry->key_size = 0;
555 switch (ks)
556 {
557 case 128:
558 entry->alg = AUTH_AES_128_GMAC;
559 continue;
560 case 192:
561 entry->alg = AUTH_AES_192_GMAC;
562 continue;
563 case 256:
564 entry->alg = AUTH_AES_256_GMAC;
565 continue;
566 default:
567 break;
568 }
569 }
570 /* remove all other encryption algorithms */
571 array_remove_at(this->transforms, e);
572 }
573 }
574 e->destroy(e);
575
576 if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
577 {
578 DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
579 "proposals");
580 return FALSE;
581 }
582 }
390b38b8
MW
583
584 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
585 {
e98414ea 586 if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
390b38b8
MW
587 { /* ESN not specified, assume not supported */
588 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
589 }
390b38b8 590 }
c907b57f
MW
591
592 array_compress(this->transforms);
9b191d59 593 return TRUE;
3f730ec1
TB
594}
595
1fa9bdc4
MW
596/**
597 * add a algorithm identified by a string to the proposal.
1fa9bdc4 598 */
99587521 599static bool add_string_algo(private_proposal_t *this, const char *alg)
c095388f 600{
4c57c630 601 const proposal_token_t *token;
a44bb934 602
4c57c630 603 token = lib->proposal->get_token(lib->proposal, alg);
a44bb934 604 if (token == NULL)
c095388f 605 {
99587521
TB
606 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
607 return FALSE;
c095388f 608 }
15c508c7 609
a44bb934 610 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 611
99587521 612 return TRUE;
c095388f
MW
613}
614
035930fc 615/**
d25ce370 616 * print all algorithms of a kind to buffer
035930fc 617 */
1b40b74d 618static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
d25ce370 619 u_int kind, void *names, bool *first)
035930fc
MW
620{
621 enumerator_t *enumerator;
622 size_t written = 0;
b12c53ce 623 uint16_t alg, size;
7daf5226 624
035930fc
MW
625 enumerator = create_enumerator(this, kind);
626 while (enumerator->enumerate(enumerator, &alg, &size))
627 {
628 if (*first)
629 {
1b40b74d 630 written += print_in_hook(data, "%N", names, alg);
035930fc
MW
631 *first = FALSE;
632 }
633 else
634 {
1b40b74d 635 written += print_in_hook(data, "/%N", names, alg);
035930fc
MW
636 }
637 if (size)
638 {
1b40b74d 639 written += print_in_hook(data, "_%u", size);
035930fc
MW
640 }
641 }
642 enumerator->destroy(enumerator);
643 return written;
644}
645
646/**
d25ce370 647 * Described in header.
035930fc 648 */
1b40b74d 649int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 650 const void *const *args)
035930fc
MW
651{
652 private_proposal_t *this = *((private_proposal_t**)(args[0]));
653 linked_list_t *list = *((linked_list_t**)(args[0]));
654 enumerator_t *enumerator;
655 size_t written = 0;
656 bool first = TRUE;
7daf5226 657
035930fc
MW
658 if (this == NULL)
659 {
1b40b74d 660 return print_in_hook(data, "(null)");
035930fc 661 }
7daf5226 662
d25ce370 663 if (spec->hash)
035930fc
MW
664 {
665 enumerator = list->create_enumerator(list);
666 while (enumerator->enumerate(enumerator, &this))
667 { /* call recursivly */
668 if (first)
669 {
1b40b74d 670 written += print_in_hook(data, "%P", this);
035930fc
MW
671 first = FALSE;
672 }
673 else
674 {
1b40b74d 675 written += print_in_hook(data, ", %P", this);
035930fc
MW
676 }
677 }
678 enumerator->destroy(enumerator);
679 return written;
680 }
7daf5226 681
1b40b74d
MW
682 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
683 written += print_alg(this, data, ENCRYPTION_ALGORITHM,
035930fc 684 encryption_algorithm_names, &first);
1b40b74d 685 written += print_alg(this, data, INTEGRITY_ALGORITHM,
035930fc 686 integrity_algorithm_names, &first);
1b40b74d 687 written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
035930fc 688 pseudo_random_function_names, &first);
1b40b74d 689 written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
035930fc 690 diffie_hellman_group_names, &first);
1b40b74d 691 written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
035930fc
MW
692 extended_sequence_numbers_names, &first);
693 return written;
694}
695
d454c586
MW
696METHOD(proposal_t, destroy, void,
697 private_proposal_t *this)
c06dbbab 698{
c907b57f 699 array_destroy(this->transforms);
5113680f 700 free(this);
c06dbbab
MW
701}
702
703/*
8e52dc27 704 * Described in header
c06dbbab 705 */
bb162175 706proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 707{
d454c586
MW
708 private_proposal_t *this;
709
710 INIT(this,
711 .public = {
712 .add_algorithm = _add_algorithm,
713 .create_enumerator = _create_enumerator,
714 .get_algorithm = _get_algorithm,
715 .has_dh_group = _has_dh_group,
716 .strip_dh = _strip_dh,
717 .select = _select_proposal,
718 .get_protocol = _get_protocol,
719 .set_spi = _set_spi,
720 .get_spi = _get_spi,
bb162175 721 .get_number = _get_number,
d454c586
MW
722 .equals = _equals,
723 .clone = _clone_,
724 .destroy = _destroy,
725 },
726 .protocol = protocol,
bb162175 727 .number = number,
c907b57f 728 .transforms = array_create(sizeof(entry_t), 0),
d454c586 729 );
7daf5226 730
8d77edde 731 return &this->public;
c06dbbab 732}
c095388f 733
e577ad39
MW
734/**
735 * Add supported IKE algorithms to proposal
736 */
2f893f27 737static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
e577ad39
MW
738{
739 enumerator_t *enumerator;
740 encryption_algorithm_t encryption;
741 integrity_algorithm_t integrity;
742 pseudo_random_function_t prf;
743 diffie_hellman_group_t group;
5932f41f 744 const char *plugin_name;
7daf5226 745
0fc4dd42 746 if (aead)
e577ad39 747 {
a78e1c3b 748 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
749 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
750 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39 751 {
0fc4dd42
MW
752 switch (encryption)
753 {
a78e1c3b 754 case ENCR_AES_GCM_ICV16:
0fc4dd42 755 case ENCR_AES_CCM_ICV16:
a78e1c3b
AS
756 case ENCR_CAMELLIA_CCM_ICV16:
757 /* we assume that we support all AES/Camellia sizes */
758 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
759 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
760 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
761 break;
762 case ENCR_CHACHA20_POLY1305:
763 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
764 break;
765 default:
766 break;
767 }
768 }
769 enumerator->destroy(enumerator);
770
771 /* Round 2 adds algorithms with less than 128 bit security strength */
772 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
773 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
774 {
775 switch (encryption)
776 {
0fc4dd42 777 case ENCR_AES_GCM_ICV12:
a78e1c3b
AS
778 case ENCR_AES_GCM_ICV8:
779 case ENCR_AES_CCM_ICV12:
780 case ENCR_AES_CCM_ICV8:
0fc4dd42 781 case ENCR_CAMELLIA_CCM_ICV12:
a78e1c3b 782 case ENCR_CAMELLIA_CCM_ICV8:
0fc4dd42
MW
783 /* we assume that we support all AES/Camellia sizes */
784 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
785 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
786 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
787 break;
788 default:
789 break;
790 }
2fa92ad2 791 }
0fc4dd42 792 enumerator->destroy(enumerator);
2f893f27
MW
793
794 if (!array_count(this->transforms))
795 {
796 return FALSE;
797 }
2fa92ad2 798 }
0fc4dd42 799 else
2fa92ad2 800 {
a78e1c3b 801 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
802 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
803 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
2fa92ad2 804 {
0fc4dd42
MW
805 switch (encryption)
806 {
807 case ENCR_AES_CBC:
808 case ENCR_AES_CTR:
809 case ENCR_CAMELLIA_CBC:
810 case ENCR_CAMELLIA_CTR:
811 /* we assume that we support all AES/Camellia sizes */
812 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
813 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
814 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
815 break;
a78e1c3b
AS
816 default:
817 break;
818 }
819 }
820 enumerator->destroy(enumerator);
821
822 /* Round 2 adds algorithms with less than 128 bit security strength */
823 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
824 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
825 {
826 switch (encryption)
827 {
0fc4dd42
MW
828 case ENCR_3DES:
829 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
830 break;
831 case ENCR_DES:
832 /* no, thanks */
833 break;
834 default:
835 break;
836 }
7daf5226 837 }
0fc4dd42 838 enumerator->destroy(enumerator);
7daf5226 839
2f893f27
MW
840 if (!array_count(this->transforms))
841 {
842 return FALSE;
843 }
844
a78e1c3b 845 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
846 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
847 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39 848 {
0fc4dd42
MW
849 switch (integrity)
850 {
0fc4dd42
MW
851 case AUTH_HMAC_SHA2_256_128:
852 case AUTH_HMAC_SHA2_384_192:
853 case AUTH_HMAC_SHA2_512_256:
a78e1c3b
AS
854 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
855 break;
856 default:
857 break;
858 }
859 }
860 enumerator->destroy(enumerator);
861
862 /* Round 2 adds algorithms with less than 128 bit security strength */
863 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
864 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
865 {
866 switch (integrity)
867 {
0fc4dd42
MW
868 case AUTH_AES_XCBC_96:
869 case AUTH_AES_CMAC_96:
a78e1c3b
AS
870 case AUTH_HMAC_SHA1_96:
871 case AUTH_HMAC_MD5_96:
0fc4dd42
MW
872 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
873 break;
874 default:
875 break;
876 }
7daf5226 877 }
0fc4dd42 878 enumerator->destroy(enumerator);
e577ad39 879 }
7daf5226 880
a78e1c3b 881 /* Round 1 adds algorithms with at least 128 bit security strength */
e577ad39 882 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 883 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
884 {
885 switch (prf)
886 {
e577ad39
MW
887 case PRF_HMAC_SHA2_256:
888 case PRF_HMAC_SHA2_384:
889 case PRF_HMAC_SHA2_512:
e577ad39 890 case PRF_AES128_XCBC:
bad19206 891 case PRF_AES128_CMAC:
e577ad39
MW
892 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
893 break;
894 default:
895 break;
896 }
897 }
898 enumerator->destroy(enumerator);
7daf5226 899
a78e1c3b
AS
900 /* Round 2 adds algorithms with less than 128 bit security strength */
901 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
902 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
903 {
904 switch (prf)
905 {
906 case PRF_HMAC_SHA1:
907 case PRF_HMAC_MD5:
908 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
909 break;
910 default:
911 break;
912 }
913 }
914 enumerator->destroy(enumerator);
915
916 /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
917 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
918 while (enumerator->enumerate(enumerator, &group, &plugin_name))
919 {
920 switch (group)
921 {
922 case ECP_256_BIT:
923 case ECP_384_BIT:
924 case ECP_521_BIT:
925 case ECP_256_BP:
926 case ECP_384_BP:
927 case ECP_512_BP:
549b325d
TB
928 case CURVE_25519:
929 case CURVE_448:
a78e1c3b
AS
930 case NTRU_128_BIT:
931 case NTRU_192_BIT:
932 case NTRU_256_BIT:
393688ae 933 case NH_128_BIT:
a78e1c3b
AS
934 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
935 break;
936 default:
937 break;
938 }
939 }
940 enumerator->destroy(enumerator);
941
942 /* Round 2 adds other algorithms with at least 128 bit security strength */
943 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
944 while (enumerator->enumerate(enumerator, &group, &plugin_name))
945 {
946 switch (group)
947 {
948 case MODP_3072_BIT:
949 case MODP_4096_BIT:
950 case MODP_8192_BIT:
951 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
952 break;
953 default:
954 break;
955 }
956 }
957 enumerator->destroy(enumerator);
958
959 /* Round 3 adds algorithms with less than 128 bit security strength */
e577ad39 960 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 961 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
962 {
963 switch (group)
964 {
a20abb81
MW
965 case MODP_NULL:
966 /* only for testing purposes */
967 break;
e577ad39
MW
968 case MODP_768_BIT:
969 /* weak */
970 break;
649537ee 971 case MODP_1024_160:
a78e1c3b 972 case MODP_2048_224:
649537ee
MW
973 case MODP_2048_256:
974 /* RFC 5114 primes are of questionable source */
975 break;
a78e1c3b 976 case MODP_1536_BIT:
e577ad39 977 case ECP_224_BIT:
73134999 978 case ECP_224_BP:
a78e1c3b 979 case ECP_192_BIT:
798a36dc 980 case NTRU_112_BIT:
fae18fd2
TB
981 /* rarely used */
982 break;
983 case MODP_2048_BIT:
fae18fd2 984 case MODP_1024_BIT:
e577ad39
MW
985 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
986 break;
987 default:
988 break;
989 }
990 }
991 enumerator->destroy(enumerator);
2f893f27
MW
992
993 return TRUE;
e577ad39
MW
994}
995
c095388f 996/*
8e52dc27 997 * Described in header
c095388f
MW
998 */
999proposal_t *proposal_create_default(protocol_id_t protocol)
1000{
bb162175 1001 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1002
c095388f
MW
1003 switch (protocol)
1004 {
1005 case PROTO_IKE:
2f893f27
MW
1006 if (!proposal_add_supported_ike(this, FALSE))
1007 {
1008 destroy(this);
1009 return NULL;
1010 }
c095388f
MW
1011 break;
1012 case PROTO_ESP:
a78e1c3b
AS
1013 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
1014 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
1015 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
1016 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
1017 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
1018 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1019 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1020 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1021 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1022 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
1023 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
1024 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
1025 break;
1026 case PROTO_AH:
a78e1c3b
AS
1027 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1028 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1029 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1030 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1031 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
1032 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
1033 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f 1034 break;
3dd3c5f3
MW
1035 default:
1036 break;
c095388f 1037 }
c095388f
MW
1038 return &this->public;
1039}
1040
8642f8bd 1041/*
8e52dc27 1042 * Described in header
8642f8bd
MW
1043 */
1044proposal_t *proposal_create_default_aead(protocol_id_t protocol)
1045{
1046 private_proposal_t *this;
1047
1048 switch (protocol)
1049 {
1050 case PROTO_IKE:
1051 this = (private_proposal_t*)proposal_create(protocol, 0);
2f893f27
MW
1052 if (!proposal_add_supported_ike(this, TRUE))
1053 {
1054 destroy(this);
1055 return NULL;
1056 }
8642f8bd
MW
1057 return &this->public;
1058 case PROTO_ESP:
1059 /* we currently don't include any AEAD proposal for ESP, as we
1060 * don't know if our kernel backend actually supports it. */
1061 return NULL;
1062 case PROTO_AH:
1063 default:
1064 return NULL;
1065 }
1066}
1067
c095388f 1068/*
8e52dc27 1069 * Described in header
c095388f
MW
1070 */
1071proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
1072{
99587521
TB
1073 private_proposal_t *this;
1074 enumerator_t *enumerator;
1075 bool failed = TRUE;
1076 char *alg;
7daf5226 1077
99587521 1078 this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1079
c095388f 1080 /* get all tokens, separated by '-' */
99587521
TB
1081 enumerator = enumerator_create_token(algs, "-", " ");
1082 while (enumerator->enumerate(enumerator, &alg))
c095388f 1083 {
99587521
TB
1084 if (!add_string_algo(this, alg))
1085 {
1086 failed = TRUE;
1087 break;
1088 }
1089 failed = FALSE;
c095388f 1090 }
99587521
TB
1091 enumerator->destroy(enumerator);
1092
9b191d59 1093 if (failed || !check_proposal(this))
c095388f
MW
1094 {
1095 destroy(this);
1096 return NULL;
1097 }
7daf5226 1098
c095388f
MW
1099 return &this->public;
1100}