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