]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/config/proposal.c
configure: Enable curve25519 plugin by default
[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*,
5cd64f97 276 private_proposal_t *this, proposal_t *other, bool private)
c06dbbab 277{
ce461bbd 278 proposal_t *selected;
7daf5226 279
02b3101b 280 DBG2(DBG_CFG, "selecting proposal:");
7daf5226 281
5cd64f97 282 if (this->protocol != other->get_protocol(other))
c06dbbab 283 {
02b3101b 284 DBG2(DBG_CFG, " protocol mismatch, skipping");
c06dbbab
MW
285 return NULL;
286 }
7daf5226 287
5cd64f97 288 selected = proposal_create(this->protocol, other->get_number(other));
7daf5226 289
5cd64f97
MW
290 if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
291 !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
292 !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
293 !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
294 !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
8d77edde
MW
295 {
296 selected->destroy(selected);
297 return NULL;
298 }
5cd64f97 299
02b3101b 300 DBG2(DBG_CFG, " proposal matches");
5cd64f97 301 selected->set_spi(selected, other->get_spi(other));
c06dbbab
MW
302 return selected;
303}
304
d454c586
MW
305METHOD(proposal_t, get_protocol, protocol_id_t,
306 private_proposal_t *this)
c06dbbab 307{
8d77edde 308 return this->protocol;
c06dbbab
MW
309}
310
d454c586 311METHOD(proposal_t, set_spi, void,
b12c53ce 312 private_proposal_t *this, uint64_t spi)
c06dbbab 313{
8d77edde 314 this->spi = spi;
c06dbbab
MW
315}
316
b12c53ce 317METHOD(proposal_t, get_spi, uint64_t,
d454c586 318 private_proposal_t *this)
c06dbbab 319{
8d77edde 320 return this->spi;
c06dbbab
MW
321}
322
87a217f9 323/**
5cd64f97 324 * Check if two proposals have the same algorithms for a given transform type
3c7e72f5 325 */
5cd64f97
MW
326static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
327 transform_type_t type)
3c7e72f5
MW
328{
329 enumerator_t *e1, *e2;
b12c53ce 330 uint16_t alg1, alg2, ks1, ks2;
3c7e72f5 331 bool equals = TRUE;
7daf5226 332
5cd64f97
MW
333 e1 = create_enumerator(this, type);
334 e2 = other->create_enumerator(other, type);
335 while (e1->enumerate(e1, &alg1, &ks1))
3c7e72f5 336 {
5cd64f97
MW
337 if (!e2->enumerate(e2, &alg2, &ks2))
338 {
339 /* this has more algs */
340 equals = FALSE;
341 break;
342 }
343 if (alg1 != alg2 || ks1 != ks2)
3c7e72f5
MW
344 {
345 equals = FALSE;
346 break;
347 }
348 }
8e52dc27 349 if (e2->enumerate(e2, &alg2, &ks2))
5cd64f97
MW
350 {
351 /* other has more algs */
352 equals = FALSE;
353 }
3c7e72f5
MW
354 e1->destroy(e1);
355 e2->destroy(e2);
5cd64f97 356
3c7e72f5
MW
357 return equals;
358}
359
bb162175
MW
360METHOD(proposal_t, get_number, u_int,
361 private_proposal_t *this)
362{
363 return this->number;
364}
365
d454c586 366METHOD(proposal_t, equals, bool,
5cd64f97 367 private_proposal_t *this, proposal_t *other)
3c7e72f5 368{
5cd64f97 369 if (&this->public == other)
3c7e72f5
MW
370 {
371 return TRUE;
372 }
3c7e72f5 373 return (
5cd64f97
MW
374 algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
375 algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
376 algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
377 algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
378 algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
87a217f9
MW
379}
380
d454c586
MW
381METHOD(proposal_t, clone_, proposal_t*,
382 private_proposal_t *this)
87a217f9 383{
bb162175 384 private_proposal_t *clone;
5cd64f97 385 enumerator_t *enumerator;
c907b57f 386 entry_t *entry;
7daf5226 387
bb162175 388 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
5cd64f97 389
c907b57f
MW
390 enumerator = array_create_enumerator(this->transforms);
391 while (enumerator->enumerate(enumerator, &entry))
5cd64f97 392 {
c907b57f 393 array_insert(clone->transforms, ARRAY_TAIL, entry);
5cd64f97
MW
394 }
395 enumerator->destroy(enumerator);
7daf5226 396
8d77edde 397 clone->spi = this->spi;
bb162175 398 clone->number = this->number;
7daf5226 399
87a217f9
MW
400 return &clone->public;
401}
402
7ee16e4b
MW
403/**
404 * Map integrity algorithms to the PRF functions using the same algorithm.
405 */
406static const struct {
407 integrity_algorithm_t integ;
408 pseudo_random_function_t prf;
409} integ_prf_map[] = {
410 {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
b1ef481c 411 {AUTH_HMAC_SHA1_160, PRF_HMAC_SHA1 },
7ee16e4b
MW
412 {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
413 {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
414 {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
415 {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
b1ef481c 416 {AUTH_HMAC_MD5_128, PRF_HMAC_MD5 },
7ee16e4b
MW
417 {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
418 {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
419 {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
420};
421
e98414ea
TB
422/**
423 * Remove all entries of the given transform type
424 */
425static void remove_transform(private_proposal_t *this, transform_type_t type)
426{
427 enumerator_t *e;
428 entry_t *entry;
429
430 e = array_create_enumerator(this->transforms);
431 while (e->enumerate(e, &entry))
432 {
433 if (entry->type == type)
434 {
435 array_remove_at(this->transforms, e);
436 }
437 }
438 e->destroy(e);
439}
440
3f730ec1
TB
441/**
442 * Checks the proposal read from a string.
443 */
9b191d59 444static bool check_proposal(private_proposal_t *this)
3f730ec1
TB
445{
446 enumerator_t *e;
5cd64f97 447 entry_t *entry;
b12c53ce 448 uint16_t alg, ks;
6a5e6579 449 bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
7ee16e4b
MW
450 int i;
451
5cd64f97
MW
452 if (this->protocol == PROTO_IKE)
453 {
e98414ea
TB
454 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
455 { /* No explicit PRF found. We assume the same algorithm as used
456 * for integrity checking. */
5cd64f97
MW
457 e = create_enumerator(this, INTEGRITY_ALGORITHM);
458 while (e->enumerate(e, &alg, &ks))
7ee16e4b 459 {
5cd64f97 460 for (i = 0; i < countof(integ_prf_map); i++)
7ee16e4b 461 {
5cd64f97
MW
462 if (alg == integ_prf_map[i].integ)
463 {
464 add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
465 integ_prf_map[i].prf, 0);
466 break;
467 }
7ee16e4b
MW
468 }
469 }
e98414ea
TB
470 e->destroy(e);
471 }
472 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
473 {
474 DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
475 return FALSE;
7ee16e4b 476 }
f5e8bc18
TB
477 /* remove MODP_NONE from IKE proposal */
478 e = array_create_enumerator(this->transforms);
479 while (e->enumerate(e, &entry))
480 {
481 if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
482 {
483 array_remove_at(this->transforms, e);
484 }
485 }
486 e->destroy(e);
e98414ea 487 if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
9b191d59
TB
488 {
489 DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
9b191d59
TB
490 return FALSE;
491 }
e98414ea
TB
492 }
493 else
494 { /* remove PRFs from ESP/AH proposals */
495 remove_transform(this, PSEUDO_RANDOM_FUNCTION);
7ee16e4b 496 }
7daf5226 497
6a5e6579 498 if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
3f730ec1 499 {
f0c59e1c
MW
500 e = create_enumerator(this, ENCRYPTION_ALGORITHM);
501 while (e->enumerate(e, &alg, &ks))
3f730ec1 502 {
6a5e6579
TB
503 any_enc = TRUE;
504 if (encryption_algorithm_is_aead(alg))
f0c59e1c 505 {
6a5e6579
TB
506 any_aead = TRUE;
507 continue;
f0c59e1c 508 }
6a5e6579 509 all_aead = FALSE;
3f730ec1 510 }
f0c59e1c 511 e->destroy(e);
7daf5226 512
6a5e6579
TB
513 if (!any_enc)
514 {
515 DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
516 protocol_id_names, this->protocol);
517 return FALSE;
518 }
519 else if (any_aead && !all_aead)
3f730ec1 520 {
6a5e6579
TB
521 DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
522 "algorithms can't be contained in the same %N proposal",
523 protocol_id_names, this->protocol);
524 return FALSE;
525 }
526 else if (all_aead)
527 { /* if all encryption algorithms in the proposal are AEADs,
f0c59e1c 528 * we MUST NOT propose any integrity algorithms */
6a5e6579 529 remove_transform(this, INTEGRITY_ALGORITHM);
3f730ec1
TB
530 }
531 }
a65a282f
TB
532 else
533 { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
534 * proper integrity algorithm */
535 e = array_create_enumerator(this->transforms);
536 while (e->enumerate(e, &entry))
537 {
538 if (entry->type == ENCRYPTION_ALGORITHM)
539 {
540 if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
541 {
542 entry->type = INTEGRITY_ALGORITHM;
543 ks = entry->key_size;
544 entry->key_size = 0;
545 switch (ks)
546 {
547 case 128:
548 entry->alg = AUTH_AES_128_GMAC;
549 continue;
550 case 192:
551 entry->alg = AUTH_AES_192_GMAC;
552 continue;
553 case 256:
554 entry->alg = AUTH_AES_256_GMAC;
555 continue;
556 default:
557 break;
558 }
559 }
560 /* remove all other encryption algorithms */
561 array_remove_at(this->transforms, e);
562 }
563 }
564 e->destroy(e);
565
566 if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
567 {
568 DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
569 "proposals");
570 return FALSE;
571 }
572 }
390b38b8
MW
573
574 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
575 {
e98414ea 576 if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
390b38b8
MW
577 { /* ESN not specified, assume not supported */
578 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
579 }
390b38b8 580 }
c907b57f
MW
581
582 array_compress(this->transforms);
9b191d59 583 return TRUE;
3f730ec1
TB
584}
585
1fa9bdc4
MW
586/**
587 * add a algorithm identified by a string to the proposal.
1fa9bdc4 588 */
99587521 589static bool add_string_algo(private_proposal_t *this, const char *alg)
c095388f 590{
4c57c630 591 const proposal_token_t *token;
a44bb934 592
4c57c630 593 token = lib->proposal->get_token(lib->proposal, alg);
a44bb934 594 if (token == NULL)
c095388f 595 {
99587521
TB
596 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
597 return FALSE;
c095388f 598 }
15c508c7 599
a44bb934 600 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 601
99587521 602 return TRUE;
c095388f
MW
603}
604
035930fc 605/**
d25ce370 606 * print all algorithms of a kind to buffer
035930fc 607 */
1b40b74d 608static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
d25ce370 609 u_int kind, void *names, bool *first)
035930fc
MW
610{
611 enumerator_t *enumerator;
612 size_t written = 0;
b12c53ce 613 uint16_t alg, size;
7daf5226 614
035930fc
MW
615 enumerator = create_enumerator(this, kind);
616 while (enumerator->enumerate(enumerator, &alg, &size))
617 {
618 if (*first)
619 {
1b40b74d 620 written += print_in_hook(data, "%N", names, alg);
035930fc
MW
621 *first = FALSE;
622 }
623 else
624 {
1b40b74d 625 written += print_in_hook(data, "/%N", names, alg);
035930fc
MW
626 }
627 if (size)
628 {
1b40b74d 629 written += print_in_hook(data, "_%u", size);
035930fc
MW
630 }
631 }
632 enumerator->destroy(enumerator);
633 return written;
634}
635
636/**
d25ce370 637 * Described in header.
035930fc 638 */
1b40b74d 639int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 640 const void *const *args)
035930fc
MW
641{
642 private_proposal_t *this = *((private_proposal_t**)(args[0]));
643 linked_list_t *list = *((linked_list_t**)(args[0]));
644 enumerator_t *enumerator;
645 size_t written = 0;
646 bool first = TRUE;
7daf5226 647
035930fc
MW
648 if (this == NULL)
649 {
1b40b74d 650 return print_in_hook(data, "(null)");
035930fc 651 }
7daf5226 652
d25ce370 653 if (spec->hash)
035930fc
MW
654 {
655 enumerator = list->create_enumerator(list);
656 while (enumerator->enumerate(enumerator, &this))
657 { /* call recursivly */
658 if (first)
659 {
1b40b74d 660 written += print_in_hook(data, "%P", this);
035930fc
MW
661 first = FALSE;
662 }
663 else
664 {
1b40b74d 665 written += print_in_hook(data, ", %P", this);
035930fc
MW
666 }
667 }
668 enumerator->destroy(enumerator);
669 return written;
670 }
7daf5226 671
1b40b74d
MW
672 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
673 written += print_alg(this, data, ENCRYPTION_ALGORITHM,
035930fc 674 encryption_algorithm_names, &first);
1b40b74d 675 written += print_alg(this, data, INTEGRITY_ALGORITHM,
035930fc 676 integrity_algorithm_names, &first);
1b40b74d 677 written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
035930fc 678 pseudo_random_function_names, &first);
1b40b74d 679 written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
035930fc 680 diffie_hellman_group_names, &first);
1b40b74d 681 written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
035930fc
MW
682 extended_sequence_numbers_names, &first);
683 return written;
684}
685
d454c586
MW
686METHOD(proposal_t, destroy, void,
687 private_proposal_t *this)
c06dbbab 688{
c907b57f 689 array_destroy(this->transforms);
5113680f 690 free(this);
c06dbbab
MW
691}
692
693/*
8e52dc27 694 * Described in header
c06dbbab 695 */
bb162175 696proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 697{
d454c586
MW
698 private_proposal_t *this;
699
700 INIT(this,
701 .public = {
702 .add_algorithm = _add_algorithm,
703 .create_enumerator = _create_enumerator,
704 .get_algorithm = _get_algorithm,
705 .has_dh_group = _has_dh_group,
706 .strip_dh = _strip_dh,
707 .select = _select_proposal,
708 .get_protocol = _get_protocol,
709 .set_spi = _set_spi,
710 .get_spi = _get_spi,
bb162175 711 .get_number = _get_number,
d454c586
MW
712 .equals = _equals,
713 .clone = _clone_,
714 .destroy = _destroy,
715 },
716 .protocol = protocol,
bb162175 717 .number = number,
c907b57f 718 .transforms = array_create(sizeof(entry_t), 0),
d454c586 719 );
7daf5226 720
8d77edde 721 return &this->public;
c06dbbab 722}
c095388f 723
e577ad39
MW
724/**
725 * Add supported IKE algorithms to proposal
726 */
2f893f27 727static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
e577ad39
MW
728{
729 enumerator_t *enumerator;
730 encryption_algorithm_t encryption;
731 integrity_algorithm_t integrity;
732 pseudo_random_function_t prf;
733 diffie_hellman_group_t group;
5932f41f 734 const char *plugin_name;
7daf5226 735
0fc4dd42 736 if (aead)
e577ad39 737 {
a78e1c3b 738 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
739 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
740 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39 741 {
0fc4dd42
MW
742 switch (encryption)
743 {
a78e1c3b 744 case ENCR_AES_GCM_ICV16:
0fc4dd42 745 case ENCR_AES_CCM_ICV16:
a78e1c3b
AS
746 case ENCR_CAMELLIA_CCM_ICV16:
747 /* we assume that we support all AES/Camellia sizes */
748 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
749 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
750 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
751 break;
752 case ENCR_CHACHA20_POLY1305:
753 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
754 break;
755 default:
756 break;
757 }
758 }
759 enumerator->destroy(enumerator);
760
761 /* Round 2 adds algorithms with less than 128 bit security strength */
762 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
763 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
764 {
765 switch (encryption)
766 {
0fc4dd42 767 case ENCR_AES_GCM_ICV12:
a78e1c3b
AS
768 case ENCR_AES_GCM_ICV8:
769 case ENCR_AES_CCM_ICV12:
770 case ENCR_AES_CCM_ICV8:
0fc4dd42 771 case ENCR_CAMELLIA_CCM_ICV12:
a78e1c3b 772 case ENCR_CAMELLIA_CCM_ICV8:
0fc4dd42
MW
773 /* we assume that we support all AES/Camellia sizes */
774 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
775 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
776 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
777 break;
778 default:
779 break;
780 }
2fa92ad2 781 }
0fc4dd42 782 enumerator->destroy(enumerator);
2f893f27
MW
783
784 if (!array_count(this->transforms))
785 {
786 return FALSE;
787 }
2fa92ad2 788 }
0fc4dd42 789 else
2fa92ad2 790 {
a78e1c3b 791 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
792 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
793 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
2fa92ad2 794 {
0fc4dd42
MW
795 switch (encryption)
796 {
797 case ENCR_AES_CBC:
798 case ENCR_AES_CTR:
799 case ENCR_CAMELLIA_CBC:
800 case ENCR_CAMELLIA_CTR:
801 /* we assume that we support all AES/Camellia sizes */
802 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
803 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
804 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
805 break;
a78e1c3b
AS
806 default:
807 break;
808 }
809 }
810 enumerator->destroy(enumerator);
811
812 /* Round 2 adds algorithms with less than 128 bit security strength */
813 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
814 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
815 {
816 switch (encryption)
817 {
0fc4dd42
MW
818 case ENCR_3DES:
819 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
820 break;
821 case ENCR_DES:
822 /* no, thanks */
823 break;
824 default:
825 break;
826 }
7daf5226 827 }
0fc4dd42 828 enumerator->destroy(enumerator);
7daf5226 829
2f893f27
MW
830 if (!array_count(this->transforms))
831 {
832 return FALSE;
833 }
834
a78e1c3b 835 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
836 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
837 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39 838 {
0fc4dd42
MW
839 switch (integrity)
840 {
0fc4dd42
MW
841 case AUTH_HMAC_SHA2_256_128:
842 case AUTH_HMAC_SHA2_384_192:
843 case AUTH_HMAC_SHA2_512_256:
a78e1c3b
AS
844 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
845 break;
846 default:
847 break;
848 }
849 }
850 enumerator->destroy(enumerator);
851
852 /* Round 2 adds algorithms with less than 128 bit security strength */
853 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
854 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
855 {
856 switch (integrity)
857 {
0fc4dd42
MW
858 case AUTH_AES_XCBC_96:
859 case AUTH_AES_CMAC_96:
a78e1c3b
AS
860 case AUTH_HMAC_SHA1_96:
861 case AUTH_HMAC_MD5_96:
0fc4dd42
MW
862 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
863 break;
864 default:
865 break;
866 }
7daf5226 867 }
0fc4dd42 868 enumerator->destroy(enumerator);
e577ad39 869 }
7daf5226 870
a78e1c3b 871 /* Round 1 adds algorithms with at least 128 bit security strength */
e577ad39 872 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 873 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
874 {
875 switch (prf)
876 {
e577ad39
MW
877 case PRF_HMAC_SHA2_256:
878 case PRF_HMAC_SHA2_384:
879 case PRF_HMAC_SHA2_512:
e577ad39 880 case PRF_AES128_XCBC:
bad19206 881 case PRF_AES128_CMAC:
e577ad39
MW
882 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
883 break;
884 default:
885 break;
886 }
887 }
888 enumerator->destroy(enumerator);
7daf5226 889
a78e1c3b
AS
890 /* Round 2 adds algorithms with less than 128 bit security strength */
891 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
892 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
893 {
894 switch (prf)
895 {
896 case PRF_HMAC_SHA1:
897 case PRF_HMAC_MD5:
898 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
899 break;
900 default:
901 break;
902 }
903 }
904 enumerator->destroy(enumerator);
905
906 /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
907 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
908 while (enumerator->enumerate(enumerator, &group, &plugin_name))
909 {
910 switch (group)
911 {
912 case ECP_256_BIT:
913 case ECP_384_BIT:
914 case ECP_521_BIT:
915 case ECP_256_BP:
916 case ECP_384_BP:
917 case ECP_512_BP:
918 case NTRU_128_BIT:
919 case NTRU_192_BIT:
920 case NTRU_256_BIT:
393688ae 921 case NH_128_BIT:
a78e1c3b
AS
922 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
923 break;
924 default:
925 break;
926 }
927 }
928 enumerator->destroy(enumerator);
929
930 /* Round 2 adds other algorithms with at least 128 bit security strength */
931 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
932 while (enumerator->enumerate(enumerator, &group, &plugin_name))
933 {
934 switch (group)
935 {
936 case MODP_3072_BIT:
937 case MODP_4096_BIT:
938 case MODP_8192_BIT:
939 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
940 break;
941 default:
942 break;
943 }
944 }
945 enumerator->destroy(enumerator);
946
947 /* Round 3 adds algorithms with less than 128 bit security strength */
e577ad39 948 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 949 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
950 {
951 switch (group)
952 {
a20abb81
MW
953 case MODP_NULL:
954 /* only for testing purposes */
955 break;
e577ad39
MW
956 case MODP_768_BIT:
957 /* weak */
958 break;
a78e1c3b
AS
959 case MODP_2048_224:
960 case MODP_1536_BIT:
a78e1c3b 961 case MODP_1024_160:
e577ad39 962 case ECP_224_BIT:
73134999 963 case ECP_224_BP:
a78e1c3b 964 case ECP_192_BIT:
798a36dc 965 case NTRU_112_BIT:
fae18fd2
TB
966 /* rarely used */
967 break;
968 case MODP_2048_BIT:
969 case MODP_2048_256:
970 case MODP_1024_BIT:
e577ad39
MW
971 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
972 break;
973 default:
974 break;
975 }
976 }
977 enumerator->destroy(enumerator);
2f893f27
MW
978
979 return TRUE;
e577ad39
MW
980}
981
c095388f 982/*
8e52dc27 983 * Described in header
c095388f
MW
984 */
985proposal_t *proposal_create_default(protocol_id_t protocol)
986{
bb162175 987 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 988
c095388f
MW
989 switch (protocol)
990 {
991 case PROTO_IKE:
2f893f27
MW
992 if (!proposal_add_supported_ike(this, FALSE))
993 {
994 destroy(this);
995 return NULL;
996 }
c095388f
MW
997 break;
998 case PROTO_ESP:
a78e1c3b
AS
999 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
1000 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
1001 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
1002 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
1003 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
1004 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1005 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1006 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1007 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1008 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
1009 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
1010 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
1011 break;
1012 case PROTO_AH:
a78e1c3b
AS
1013 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1014 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1015 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1016 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1017 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
1018 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
1019 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f 1020 break;
3dd3c5f3
MW
1021 default:
1022 break;
c095388f 1023 }
c095388f
MW
1024 return &this->public;
1025}
1026
8642f8bd 1027/*
8e52dc27 1028 * Described in header
8642f8bd
MW
1029 */
1030proposal_t *proposal_create_default_aead(protocol_id_t protocol)
1031{
1032 private_proposal_t *this;
1033
1034 switch (protocol)
1035 {
1036 case PROTO_IKE:
1037 this = (private_proposal_t*)proposal_create(protocol, 0);
2f893f27
MW
1038 if (!proposal_add_supported_ike(this, TRUE))
1039 {
1040 destroy(this);
1041 return NULL;
1042 }
8642f8bd
MW
1043 return &this->public;
1044 case PROTO_ESP:
1045 /* we currently don't include any AEAD proposal for ESP, as we
1046 * don't know if our kernel backend actually supports it. */
1047 return NULL;
1048 case PROTO_AH:
1049 default:
1050 return NULL;
1051 }
1052}
1053
c095388f 1054/*
8e52dc27 1055 * Described in header
c095388f
MW
1056 */
1057proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
1058{
99587521
TB
1059 private_proposal_t *this;
1060 enumerator_t *enumerator;
1061 bool failed = TRUE;
1062 char *alg;
7daf5226 1063
99587521 1064 this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1065
c095388f 1066 /* get all tokens, separated by '-' */
99587521
TB
1067 enumerator = enumerator_create_token(algs, "-", " ");
1068 while (enumerator->enumerate(enumerator, &alg))
c095388f 1069 {
99587521
TB
1070 if (!add_string_algo(this, alg))
1071 {
1072 failed = TRUE;
1073 break;
1074 }
1075 failed = FALSE;
c095388f 1076 }
99587521
TB
1077 enumerator->destroy(enumerator);
1078
9b191d59 1079 if (failed || !check_proposal(this))
c095388f
MW
1080 {
1081 destroy(this);
1082 return NULL;
1083 }
7daf5226 1084
c095388f
MW
1085 return &this->public;
1086}