]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/crypto/proposal/proposal.c
proposal: Remove unused strip_dh() method
[thirdparty/strongswan.git] / src / libstrongswan / crypto / proposal / proposal.c
CommitLineData
c06dbbab 1/*
d9c9b7b8 2 * Copyright (C) 2008-2018 Tobias Brunner
d454c586 3 * Copyright (C) 2006-2010 Martin Willi
a78e1c3b 4 * Copyright (C) 2013-2015 Andreas Steffen
d9c9b7b8 5 * HSR Hochschule fuer Technik Rapperswil
c06dbbab
MW
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
c907b57f 22#include <collections/array.h>
c06dbbab 23#include <utils/identification.h>
99587521 24
433cb51b 25#include <crypto/transform.h>
c095388f
MW
26#include <crypto/prfs/prf.h>
27#include <crypto/crypters/crypter.h>
28#include <crypto/signers/signer.h>
c06dbbab 29
7a75cae8 30ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
60356f33
MW
31 "PROTO_NONE",
32 "IKE",
33 "AH",
34 "ESP",
7a75cae8 35 "IPCOMP",
60356f33 36);
c06dbbab 37
8d77edde 38typedef struct private_proposal_t private_proposal_t;
c06dbbab
MW
39
40/**
8d77edde 41 * Private data of an proposal_t object
c06dbbab 42 */
8d77edde
MW
43struct private_proposal_t {
44
45 /**
46 * Public part
47 */
48 proposal_t public;
7daf5226 49
c06dbbab
MW
50 /**
51 * protocol (ESP or AH)
52 */
53 protocol_id_t protocol;
7daf5226 54
c06dbbab 55 /**
5cd64f97 56 * Priority ordered list of transforms, as entry_t
c06dbbab 57 */
c907b57f 58 array_t *transforms;
7daf5226 59
cc55461c
TB
60 /**
61 * Types of transforms contained, as transform_type_t
62 */
63 array_t *types;
64
7daf5226 65 /**
c06dbbab
MW
66 * senders SPI
67 */
b12c53ce 68 uint64_t spi;
bb162175
MW
69
70 /**
71 * Proposal number
72 */
73 u_int number;
c06dbbab
MW
74};
75
5eb094df
TB
76/**
77 * This is a hack to not change the previous order when printing proposals
78 */
79static transform_type_t type_for_sort(const void *type)
80{
81 const transform_type_t *t = type;
82
83 switch (*t)
84 {
85 case PSEUDO_RANDOM_FUNCTION:
86 return INTEGRITY_ALGORITHM;
87 case INTEGRITY_ALGORITHM:
88 return PSEUDO_RANDOM_FUNCTION;
89 default:
90 return *t;
91 }
92}
93
cc55461c
TB
94/**
95 * Sort transform types
96 */
97static int type_sort(const void *a, const void *b, void *user)
98{
5eb094df
TB
99 transform_type_t ta = type_for_sort(a), tb = type_for_sort(b);
100 return ta - tb;
cc55461c
TB
101}
102
103/**
104 * Find a transform type
105 */
106static int type_find(const void *a, const void *b)
107{
108 return type_sort(a, b, NULL);
109}
110
111/**
112 * Check if the given transform type is already in the set
113 */
76c7c951 114static bool contains_type(array_t *types, transform_type_t type)
cc55461c 115{
76c7c951 116 return array_bsearch(types, &type, type_find, NULL) != -1;
cc55461c
TB
117}
118
119/**
120 * Add the given transform type to the set
121 */
76c7c951 122static void add_type(array_t *types, transform_type_t type)
cc55461c 123{
76c7c951 124 if (!contains_type(types, type))
cc55461c 125 {
76c7c951
TB
126 array_insert(types, ARRAY_TAIL, &type);
127 array_sort(types, type_sort, NULL);
cc55461c
TB
128 }
129}
130
76c7c951
TB
131/**
132 * Merge two sets of transform types into a new array
133 */
134static array_t *merge_types(private_proposal_t *this, private_proposal_t *other)
135{
136 array_t *types;
137 transform_type_t type;
138 int i, count;
139
140 count = max(array_count(this->types), array_count(other->types));
141 types = array_create(sizeof(transform_type_t), count);
142
143 for (i = 0; i < count; i++)
144 {
145 if (array_get(this->types, i, &type))
146 {
147 add_type(types, type);
148 }
149 if (array_get(other->types, i, &type))
150 {
151 add_type(types, type);
152 }
153 }
154 return types;
155}
156
cc55461c
TB
157/**
158 * Remove the given transform type from the set
159 */
160static void remove_type(private_proposal_t *this, transform_type_t type)
161{
162 int i;
163
164 i = array_bsearch(this->types, &type, type_find, NULL);
165 if (i >= 0)
166 {
167 array_remove(this->types, i, NULL);
168 }
169}
170
3c7e72f5 171/**
7daf5226 172 * Struct used to store different kinds of algorithms.
3c7e72f5 173 */
5cd64f97
MW
174typedef struct {
175 /** Type of the transform */
176 transform_type_t type;
177 /** algorithm identifier */
b12c53ce 178 uint16_t alg;
5cd64f97 179 /** key size in bits, or zero if not needed */
b12c53ce 180 uint16_t key_size;
5cd64f97 181} entry_t;
c06dbbab 182
d454c586
MW
183METHOD(proposal_t, add_algorithm, void,
184 private_proposal_t *this, transform_type_t type,
b12c53ce 185 uint16_t alg, uint16_t key_size)
c06dbbab 186{
c907b57f 187 entry_t entry = {
5cd64f97
MW
188 .type = type,
189 .alg = alg,
190 .key_size = key_size,
c907b57f 191 };
5cd64f97 192
c907b57f 193 array_insert(this->transforms, ARRAY_TAIL, &entry);
76c7c951 194 add_type(this->types, type);
c06dbbab
MW
195}
196
525cc46c
TB
197CALLBACK(alg_filter, bool,
198 uintptr_t type, enumerator_t *orig, va_list args)
3c7e72f5 199{
525cc46c
TB
200 entry_t *entry;
201 uint16_t *alg, *key_size;
5cd64f97 202
525cc46c
TB
203 VA_ARGS_VGET(args, alg, key_size);
204
205 while (orig->enumerate(orig, &entry))
3c7e72f5 206 {
525cc46c
TB
207 if (entry->type != type)
208 {
209 continue;
210 }
211 if (alg)
212 {
213 *alg = entry->alg;
214 }
215 if (key_size)
216 {
217 *key_size = entry->key_size;
218 }
219 return TRUE;
3c7e72f5 220 }
525cc46c 221 return FALSE;
3c7e72f5
MW
222}
223
d454c586
MW
224METHOD(proposal_t, create_enumerator, enumerator_t*,
225 private_proposal_t *this, transform_type_t type)
c06dbbab 226{
5cd64f97 227 return enumerator_create_filter(
c907b57f 228 array_create_enumerator(this->transforms),
525cc46c 229 alg_filter, (void*)(uintptr_t)type, NULL);
c06dbbab
MW
230}
231
d454c586
MW
232METHOD(proposal_t, get_algorithm, bool,
233 private_proposal_t *this, transform_type_t type,
b12c53ce 234 uint16_t *alg, uint16_t *key_size)
1fd5383e 235{
3c7e72f5 236 enumerator_t *enumerator;
9fa5c75f 237 bool found = FALSE;
7daf5226 238
3c7e72f5
MW
239 enumerator = create_enumerator(this, type);
240 if (enumerator->enumerate(enumerator, alg, key_size))
1fd5383e 241 {
3c7e72f5 242 found = TRUE;
1fd5383e 243 }
3c7e72f5 244 enumerator->destroy(enumerator);
5cd64f97 245
3c7e72f5 246 return found;
1fd5383e
MW
247}
248
d454c586
MW
249METHOD(proposal_t, has_dh_group, bool,
250 private_proposal_t *this, diffie_hellman_group_t group)
1fd5383e 251{
5cd64f97
MW
252 bool found = FALSE, any = FALSE;
253 enumerator_t *enumerator;
b12c53ce 254 uint16_t current;
7daf5226 255
5cd64f97
MW
256 enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
257 while (enumerator->enumerate(enumerator, &current, NULL))
1fd5383e 258 {
5cd64f97
MW
259 any = TRUE;
260 if (current == group)
1fd5383e 261 {
5cd64f97
MW
262 found = TRUE;
263 break;
1fd5383e
MW
264 }
265 }
5cd64f97
MW
266 enumerator->destroy(enumerator);
267
268 if (!any && group == MODP_NONE)
1fd5383e 269 {
5cd64f97 270 found = TRUE;
1fd5383e 271 }
5cd64f97 272 return found;
1fd5383e
MW
273}
274
d9c9b7b8
TB
275METHOD(proposal_t, promote_dh_group, bool,
276 private_proposal_t *this, diffie_hellman_group_t group)
277{
278 enumerator_t *enumerator;
279 entry_t *entry;
280 bool found = FALSE;
281
282 enumerator = array_create_enumerator(this->transforms);
283 while (enumerator->enumerate(enumerator, &entry))
284 {
285 if (entry->type == DIFFIE_HELLMAN_GROUP &&
286 entry->alg == group)
287 {
288 array_remove_at(this->transforms, enumerator);
289 found = TRUE;
290 }
291 }
292 enumerator->destroy(enumerator);
293
294 if (found)
295 {
296 entry_t entry = {
297 .type = DIFFIE_HELLMAN_GROUP,
298 .alg = group,
299 };
300 array_insert(this->transforms, ARRAY_HEAD, &entry);
301 }
302 return found;
303}
304
c06dbbab 305/**
f72aa13a 306 * Select a matching proposal from this and other.
c06dbbab 307 */
5cd64f97 308static bool select_algo(private_proposal_t *this, proposal_t *other,
f930b732
TE
309 transform_type_t type, proposal_selection_flag_t flags,
310 bool log, uint16_t *alg, uint16_t *ks)
c06dbbab 311{
3c7e72f5 312 enumerator_t *e1, *e2;
b12c53ce 313 uint16_t alg1, alg2, ks1, ks2;
a213944d 314 bool found = FALSE, optional = FALSE;
7daf5226 315
a213944d
TB
316 if (type == DIFFIE_HELLMAN_GROUP)
317 {
318 optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
319 }
7daf5226 320
5cd64f97
MW
321 e1 = create_enumerator(this, type);
322 e2 = other->create_enumerator(other, type);
aae95101 323 if (!e1->enumerate(e1, &alg1, NULL))
5cd64f97 324 {
a213944d
TB
325 if (!e2->enumerate(e2, &alg2, NULL))
326 {
327 found = TRUE;
328 }
329 else if (optional)
330 {
331 do
aae95101 332 { /* if NONE is proposed, we accept the proposal */
a213944d
TB
333 found = !alg2;
334 }
335 while (!found && e2->enumerate(e2, &alg2, NULL));
336 }
5cd64f97 337 }
aae95101
TB
338 else if (!e2->enumerate(e2, NULL, NULL))
339 {
340 if (optional)
341 {
342 do
343 { /* if NONE is proposed, we accept the proposal */
344 found = !alg1;
345 }
346 while (!found && e1->enumerate(e1, &alg1, NULL));
347 }
348 }
5cd64f97
MW
349
350 e1->destroy(e1);
351 e1 = create_enumerator(this, type);
c06dbbab 352 /* compare algs, order of algs in "first" is preferred */
5cd64f97 353 while (!found && e1->enumerate(e1, &alg1, &ks1))
c06dbbab 354 {
3c7e72f5 355 e2->destroy(e2);
5cd64f97
MW
356 e2 = other->create_enumerator(other, type);
357 while (e2->enumerate(e2, &alg2, &ks2))
c06dbbab 358 {
5cd64f97 359 if (alg1 == alg2 && ks1 == ks2)
c06dbbab 360 {
a2cb2c9c 361 if ((flags & PROPOSAL_SKIP_PRIVATE) && alg1 >= 1024)
023fd8f1 362 {
f72aa13a
TB
363 if (log)
364 {
365 DBG1(DBG_CFG, "an algorithm from private space would "
366 "match, but peer implementation is unknown, "
367 "skipped");
368 }
023fd8f1
MW
369 continue;
370 }
f72aa13a
TB
371 *alg = alg1;
372 *ks = ks1;
5cd64f97
MW
373 found = TRUE;
374 break;
c06dbbab
MW
375 }
376 }
377 }
3c7e72f5
MW
378 e1->destroy(e1);
379 e2->destroy(e2);
f72aa13a
TB
380 return found;
381}
5cd64f97 382
f72aa13a
TB
383/**
384 * Select algorithms from the given proposals, if selected is given, the result
385 * is stored there and errors are logged.
386 */
387static bool select_algos(private_proposal_t *this, proposal_t *other,
f930b732 388 proposal_t *selected, proposal_selection_flag_t flags)
f72aa13a
TB
389{
390 transform_type_t type;
391 array_t *types;
392 bool skip_integrity = FALSE;
393 int i;
394
395 types = merge_types(this, (private_proposal_t*)other);
396 for (i = 0; i < array_count(types); i++)
5cd64f97 397 {
f72aa13a
TB
398 uint16_t alg = 0, ks = 0;
399
400 array_get(types, i, &type);
401 if (type == INTEGRITY_ALGORITHM && skip_integrity)
402 {
403 continue;
404 }
a406bc60
TB
405 if (type == DIFFIE_HELLMAN_GROUP && (flags & PROPOSAL_SKIP_DH))
406 {
407 continue;
408 }
f930b732 409 if (select_algo(this, other, type, flags, selected != NULL, &alg, &ks))
f72aa13a
TB
410 {
411 if (alg == 0 && type != EXTENDED_SEQUENCE_NUMBERS)
412 { /* 0 is "valid" for extended sequence numbers, for other
413 * transforms it either means NONE or is reserved */
414 continue;
415 }
416 if (selected)
417 {
418 selected->add_algorithm(selected, type, alg, ks);
419 }
420 if (type == ENCRYPTION_ALGORITHM &&
421 encryption_algorithm_is_aead(alg))
422 {
423 /* no integrity algorithm required, we have an AEAD */
424 skip_integrity = TRUE;
425 }
426 }
427 else
428 {
429 if (selected)
430 {
431 DBG2(DBG_CFG, " no acceptable %N found", transform_type_names,
432 type);
433 }
434 array_destroy(types);
435 return FALSE;
436 }
5cd64f97 437 }
f72aa13a
TB
438 array_destroy(types);
439 return TRUE;
c06dbbab
MW
440}
441
d454c586 442METHOD(proposal_t, select_proposal, proposal_t*,
f930b732
TE
443 private_proposal_t *this, proposal_t *other,
444 proposal_selection_flag_t flags)
c06dbbab 445{
ce461bbd 446 proposal_t *selected;
7daf5226 447
02b3101b 448 DBG2(DBG_CFG, "selecting proposal:");
7daf5226 449
5cd64f97 450 if (this->protocol != other->get_protocol(other))
c06dbbab 451 {
02b3101b 452 DBG2(DBG_CFG, " protocol mismatch, skipping");
c06dbbab
MW
453 return NULL;
454 }
7daf5226 455
c9599d41 456 if (flags & PROPOSAL_PREFER_SUPPLIED)
22f13dce 457 {
c9599d41
TB
458 selected = proposal_create(this->protocol, this->number);
459 selected->set_spi(selected, this->spi);
22f13dce
TB
460 }
461 else
462 {
c9599d41
TB
463 selected = proposal_create(this->protocol, other->get_number(other));
464 selected->set_spi(selected, other->get_spi(other));
22f13dce 465 }
7daf5226 466
f930b732 467 if (!select_algos(this, other, selected, flags))
8d77edde 468 {
f72aa13a
TB
469 selected->destroy(selected);
470 return NULL;
8d77edde 471 }
02b3101b 472 DBG2(DBG_CFG, " proposal matches");
c06dbbab
MW
473 return selected;
474}
475
f72aa13a 476METHOD(proposal_t, matches, bool,
f930b732
TE
477 private_proposal_t *this, proposal_t *other,
478 proposal_selection_flag_t flags)
f72aa13a
TB
479{
480 if (this->protocol != other->get_protocol(other))
481 {
482 return FALSE;
483 }
f930b732 484 return select_algos(this, other, NULL, flags);
f72aa13a
TB
485}
486
d454c586
MW
487METHOD(proposal_t, get_protocol, protocol_id_t,
488 private_proposal_t *this)
c06dbbab 489{
8d77edde 490 return this->protocol;
c06dbbab
MW
491}
492
d454c586 493METHOD(proposal_t, set_spi, void,
b12c53ce 494 private_proposal_t *this, uint64_t spi)
c06dbbab 495{
8d77edde 496 this->spi = spi;
c06dbbab
MW
497}
498
b12c53ce 499METHOD(proposal_t, get_spi, uint64_t,
d454c586 500 private_proposal_t *this)
c06dbbab 501{
8d77edde 502 return this->spi;
c06dbbab
MW
503}
504
87a217f9 505/**
5cd64f97 506 * Check if two proposals have the same algorithms for a given transform type
3c7e72f5 507 */
5cd64f97
MW
508static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
509 transform_type_t type)
3c7e72f5
MW
510{
511 enumerator_t *e1, *e2;
b12c53ce 512 uint16_t alg1, alg2, ks1, ks2;
3c7e72f5 513 bool equals = TRUE;
7daf5226 514
5cd64f97
MW
515 e1 = create_enumerator(this, type);
516 e2 = other->create_enumerator(other, type);
517 while (e1->enumerate(e1, &alg1, &ks1))
3c7e72f5 518 {
5cd64f97
MW
519 if (!e2->enumerate(e2, &alg2, &ks2))
520 {
521 /* this has more algs */
522 equals = FALSE;
523 break;
524 }
525 if (alg1 != alg2 || ks1 != ks2)
3c7e72f5
MW
526 {
527 equals = FALSE;
528 break;
529 }
530 }
8e52dc27 531 if (e2->enumerate(e2, &alg2, &ks2))
5cd64f97
MW
532 {
533 /* other has more algs */
534 equals = FALSE;
535 }
3c7e72f5
MW
536 e1->destroy(e1);
537 e2->destroy(e2);
5cd64f97 538
3c7e72f5
MW
539 return equals;
540}
541
bb162175
MW
542METHOD(proposal_t, get_number, u_int,
543 private_proposal_t *this)
544{
545 return this->number;
546}
547
d454c586 548METHOD(proposal_t, equals, bool,
5cd64f97 549 private_proposal_t *this, proposal_t *other)
3c7e72f5 550{
6b8749ab
TB
551 transform_type_t type;
552 array_t *types;
553 int i;
554
5cd64f97 555 if (&this->public == other)
3c7e72f5
MW
556 {
557 return TRUE;
558 }
6b8749ab
TB
559
560 types = merge_types(this, (private_proposal_t*)other);
561 for (i = 0; i < array_count(types); i++)
562 {
563 array_get(types, i, &type);
564 if (!algo_list_equals(this, other, type))
565 {
566 array_destroy(types);
567 return FALSE;
568 }
569 }
570 array_destroy(types);
571 return TRUE;
87a217f9
MW
572}
573
d454c586 574METHOD(proposal_t, clone_, proposal_t*,
a2cb2c9c 575 private_proposal_t *this, proposal_selection_flag_t flags)
87a217f9 576{
bb162175 577 private_proposal_t *clone;
5cd64f97 578 enumerator_t *enumerator;
c907b57f 579 entry_t *entry;
7daf5226 580
bb162175 581 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
5cd64f97 582
c907b57f
MW
583 enumerator = array_create_enumerator(this->transforms);
584 while (enumerator->enumerate(enumerator, &entry))
5cd64f97 585 {
a2cb2c9c
TB
586 if (entry->alg >= 1024 && (flags & PROPOSAL_SKIP_PRIVATE))
587 {
588 continue;
589 }
590 if (entry->type == DIFFIE_HELLMAN_GROUP && (flags & PROPOSAL_SKIP_DH))
591 {
592 continue;
593 }
c907b57f 594 array_insert(clone->transforms, ARRAY_TAIL, entry);
a2cb2c9c 595 add_type(clone->types, entry->type);
cc55461c
TB
596 }
597 enumerator->destroy(enumerator);
7daf5226 598
8d77edde 599 clone->spi = this->spi;
bb162175 600 clone->number = this->number;
7daf5226 601
87a217f9
MW
602 return &clone->public;
603}
604
7ee16e4b
MW
605/**
606 * Map integrity algorithms to the PRF functions using the same algorithm.
607 */
608static const struct {
609 integrity_algorithm_t integ;
610 pseudo_random_function_t prf;
611} integ_prf_map[] = {
612 {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
b1ef481c 613 {AUTH_HMAC_SHA1_160, PRF_HMAC_SHA1 },
7ee16e4b
MW
614 {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
615 {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
616 {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
617 {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
b1ef481c 618 {AUTH_HMAC_MD5_128, PRF_HMAC_MD5 },
7ee16e4b
MW
619 {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
620 {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
621 {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
622};
623
e98414ea
TB
624/**
625 * Remove all entries of the given transform type
626 */
627static void remove_transform(private_proposal_t *this, transform_type_t type)
628{
629 enumerator_t *e;
630 entry_t *entry;
631
632 e = array_create_enumerator(this->transforms);
633 while (e->enumerate(e, &entry))
634 {
635 if (entry->type == type)
636 {
637 array_remove_at(this->transforms, e);
638 }
639 }
640 e->destroy(e);
cc55461c 641 remove_type(this, type);
e98414ea
TB
642}
643
3f730ec1
TB
644/**
645 * Checks the proposal read from a string.
646 */
9b191d59 647static bool check_proposal(private_proposal_t *this)
3f730ec1
TB
648{
649 enumerator_t *e;
5cd64f97 650 entry_t *entry;
b12c53ce 651 uint16_t alg, ks;
6a5e6579 652 bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
7ee16e4b
MW
653 int i;
654
5cd64f97
MW
655 if (this->protocol == PROTO_IKE)
656 {
e98414ea
TB
657 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
658 { /* No explicit PRF found. We assume the same algorithm as used
659 * for integrity checking. */
5cd64f97
MW
660 e = create_enumerator(this, INTEGRITY_ALGORITHM);
661 while (e->enumerate(e, &alg, &ks))
7ee16e4b 662 {
5cd64f97 663 for (i = 0; i < countof(integ_prf_map); i++)
7ee16e4b 664 {
5cd64f97
MW
665 if (alg == integ_prf_map[i].integ)
666 {
667 add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
668 integ_prf_map[i].prf, 0);
669 break;
670 }
7ee16e4b
MW
671 }
672 }
e98414ea
TB
673 e->destroy(e);
674 }
675 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
676 {
677 DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
678 return FALSE;
7ee16e4b 679 }
f5e8bc18
TB
680 /* remove MODP_NONE from IKE proposal */
681 e = array_create_enumerator(this->transforms);
682 while (e->enumerate(e, &entry))
683 {
684 if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
685 {
686 array_remove_at(this->transforms, e);
687 }
688 }
689 e->destroy(e);
e98414ea 690 if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
9b191d59
TB
691 {
692 DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
9b191d59
TB
693 return FALSE;
694 }
e98414ea
TB
695 }
696 else
697 { /* remove PRFs from ESP/AH proposals */
698 remove_transform(this, PSEUDO_RANDOM_FUNCTION);
7ee16e4b 699 }
7daf5226 700
6a5e6579 701 if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
3f730ec1 702 {
f0c59e1c
MW
703 e = create_enumerator(this, ENCRYPTION_ALGORITHM);
704 while (e->enumerate(e, &alg, &ks))
3f730ec1 705 {
6a5e6579
TB
706 any_enc = TRUE;
707 if (encryption_algorithm_is_aead(alg))
f0c59e1c 708 {
6a5e6579
TB
709 any_aead = TRUE;
710 continue;
f0c59e1c 711 }
6a5e6579 712 all_aead = FALSE;
3f730ec1 713 }
f0c59e1c 714 e->destroy(e);
7daf5226 715
6a5e6579
TB
716 if (!any_enc)
717 {
718 DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
719 protocol_id_names, this->protocol);
720 return FALSE;
721 }
722 else if (any_aead && !all_aead)
3f730ec1 723 {
6a5e6579
TB
724 DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
725 "algorithms can't be contained in the same %N proposal",
726 protocol_id_names, this->protocol);
727 return FALSE;
728 }
729 else if (all_aead)
730 { /* if all encryption algorithms in the proposal are AEADs,
f0c59e1c 731 * we MUST NOT propose any integrity algorithms */
6a5e6579 732 remove_transform(this, INTEGRITY_ALGORITHM);
3f730ec1 733 }
ee019ab3
TB
734 else if (this->protocol == PROTO_IKE &&
735 !get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
736 {
737 DBG1(DBG_CFG, "an integrity algorithm is mandatory in %N proposals "
738 "with classic (non-AEAD) encryption algorithms",
739 protocol_id_names, this->protocol);
740 return FALSE;
741 }
3f730ec1 742 }
a65a282f
TB
743 else
744 { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
745 * proper integrity algorithm */
746 e = array_create_enumerator(this->transforms);
747 while (e->enumerate(e, &entry))
748 {
749 if (entry->type == ENCRYPTION_ALGORITHM)
750 {
751 if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
752 {
753 entry->type = INTEGRITY_ALGORITHM;
754 ks = entry->key_size;
755 entry->key_size = 0;
756 switch (ks)
757 {
758 case 128:
759 entry->alg = AUTH_AES_128_GMAC;
760 continue;
761 case 192:
762 entry->alg = AUTH_AES_192_GMAC;
763 continue;
764 case 256:
765 entry->alg = AUTH_AES_256_GMAC;
766 continue;
767 default:
768 break;
769 }
770 }
771 /* remove all other encryption algorithms */
772 array_remove_at(this->transforms, e);
773 }
774 }
775 e->destroy(e);
cc55461c 776 remove_type(this, ENCRYPTION_ALGORITHM);
a65a282f
TB
777
778 if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
779 {
780 DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
781 "proposals");
782 return FALSE;
783 }
784 }
390b38b8
MW
785
786 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
787 {
e98414ea 788 if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
390b38b8
MW
789 { /* ESN not specified, assume not supported */
790 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
791 }
390b38b8 792 }
c907b57f
MW
793
794 array_compress(this->transforms);
42a6b187 795 array_compress(this->types);
9b191d59 796 return TRUE;
3f730ec1
TB
797}
798
1fa9bdc4
MW
799/**
800 * add a algorithm identified by a string to the proposal.
1fa9bdc4 801 */
99587521 802static bool add_string_algo(private_proposal_t *this, const char *alg)
c095388f 803{
4c57c630 804 const proposal_token_t *token;
a44bb934 805
4c57c630 806 token = lib->proposal->get_token(lib->proposal, alg);
a44bb934 807 if (token == NULL)
c095388f 808 {
99587521
TB
809 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
810 return FALSE;
c095388f 811 }
15c508c7 812
a44bb934 813 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 814
99587521 815 return TRUE;
c095388f
MW
816}
817
035930fc 818/**
5eb094df 819 * Print all algorithms of the given type
035930fc 820 */
1b40b74d 821static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
5eb094df 822 transform_type_t type, bool *first)
035930fc
MW
823{
824 enumerator_t *enumerator;
825 size_t written = 0;
5eb094df
TB
826 entry_t *entry;
827 enum_name_t *names;
7daf5226 828
5eb094df
TB
829 names = transform_get_enum_names(type);
830
831 enumerator = array_create_enumerator(this->transforms);
832 while (enumerator->enumerate(enumerator, &entry))
035930fc 833 {
5eb094df
TB
834 char *prefix = "/";
835
836 if (type != entry->type)
837 {
838 continue;
839 }
035930fc
MW
840 if (*first)
841 {
5eb094df 842 prefix = "";
035930fc
MW
843 *first = FALSE;
844 }
5eb094df
TB
845 if (names)
846 {
847 written += print_in_hook(data, "%s%N", prefix, names, entry->alg);
848 }
035930fc
MW
849 else
850 {
5eb094df
TB
851 written += print_in_hook(data, "%sUNKNOWN_%u_%u", prefix,
852 entry->type, entry->alg);
035930fc 853 }
5eb094df 854 if (entry->key_size)
035930fc 855 {
5eb094df 856 written += print_in_hook(data, "_%u", entry->key_size);
035930fc
MW
857 }
858 }
859 enumerator->destroy(enumerator);
860 return written;
861}
862
863/**
d25ce370 864 * Described in header.
035930fc 865 */
1b40b74d 866int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 867 const void *const *args)
035930fc
MW
868{
869 private_proposal_t *this = *((private_proposal_t**)(args[0]));
870 linked_list_t *list = *((linked_list_t**)(args[0]));
871 enumerator_t *enumerator;
5eb094df 872 transform_type_t *type;
035930fc
MW
873 size_t written = 0;
874 bool first = TRUE;
7daf5226 875
035930fc
MW
876 if (this == NULL)
877 {
1b40b74d 878 return print_in_hook(data, "(null)");
035930fc 879 }
7daf5226 880
d25ce370 881 if (spec->hash)
035930fc
MW
882 {
883 enumerator = list->create_enumerator(list);
884 while (enumerator->enumerate(enumerator, &this))
2db6d5b8 885 { /* call recursively */
035930fc
MW
886 if (first)
887 {
1b40b74d 888 written += print_in_hook(data, "%P", this);
035930fc
MW
889 first = FALSE;
890 }
891 else
892 {
1b40b74d 893 written += print_in_hook(data, ", %P", this);
035930fc
MW
894 }
895 }
896 enumerator->destroy(enumerator);
897 return written;
898 }
7daf5226 899
1b40b74d 900 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
5eb094df
TB
901 enumerator = array_create_enumerator(this->types);
902 while (enumerator->enumerate(enumerator, &type))
903 {
904 written += print_alg(this, data, *type, &first);
905 }
906 enumerator->destroy(enumerator);
035930fc
MW
907 return written;
908}
909
d454c586
MW
910METHOD(proposal_t, destroy, void,
911 private_proposal_t *this)
c06dbbab 912{
c907b57f 913 array_destroy(this->transforms);
cc55461c 914 array_destroy(this->types);
5113680f 915 free(this);
c06dbbab
MW
916}
917
918/*
8e52dc27 919 * Described in header
c06dbbab 920 */
bb162175 921proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 922{
d454c586
MW
923 private_proposal_t *this;
924
925 INIT(this,
926 .public = {
927 .add_algorithm = _add_algorithm,
928 .create_enumerator = _create_enumerator,
929 .get_algorithm = _get_algorithm,
930 .has_dh_group = _has_dh_group,
d9c9b7b8 931 .promote_dh_group = _promote_dh_group,
d454c586 932 .select = _select_proposal,
f72aa13a 933 .matches = _matches,
d454c586
MW
934 .get_protocol = _get_protocol,
935 .set_spi = _set_spi,
936 .get_spi = _get_spi,
bb162175 937 .get_number = _get_number,
d454c586
MW
938 .equals = _equals,
939 .clone = _clone_,
940 .destroy = _destroy,
941 },
942 .protocol = protocol,
bb162175 943 .number = number,
c907b57f 944 .transforms = array_create(sizeof(entry_t), 0),
cc55461c 945 .types = array_create(sizeof(transform_type_t), 0),
d454c586 946 );
7daf5226 947
8d77edde 948 return &this->public;
c06dbbab 949}
c095388f 950
e577ad39
MW
951/**
952 * Add supported IKE algorithms to proposal
953 */
2f893f27 954static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
e577ad39
MW
955{
956 enumerator_t *enumerator;
957 encryption_algorithm_t encryption;
958 integrity_algorithm_t integrity;
959 pseudo_random_function_t prf;
960 diffie_hellman_group_t group;
5932f41f 961 const char *plugin_name;
7daf5226 962
0fc4dd42 963 if (aead)
e577ad39 964 {
a78e1c3b 965 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
966 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
967 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39 968 {
0fc4dd42
MW
969 switch (encryption)
970 {
a78e1c3b 971 case ENCR_AES_GCM_ICV16:
0fc4dd42 972 case ENCR_AES_CCM_ICV16:
a78e1c3b
AS
973 case ENCR_CAMELLIA_CCM_ICV16:
974 /* we assume that we support all AES/Camellia sizes */
975 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
976 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
977 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
978 break;
979 case ENCR_CHACHA20_POLY1305:
5a7b0be2 980 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
a78e1c3b
AS
981 break;
982 default:
983 break;
984 }
985 }
986 enumerator->destroy(enumerator);
987
988 /* Round 2 adds algorithms with less than 128 bit security strength */
989 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
990 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
991 {
992 switch (encryption)
993 {
0fc4dd42 994 case ENCR_AES_GCM_ICV12:
a78e1c3b
AS
995 case ENCR_AES_GCM_ICV8:
996 case ENCR_AES_CCM_ICV12:
997 case ENCR_AES_CCM_ICV8:
0fc4dd42 998 case ENCR_CAMELLIA_CCM_ICV12:
a78e1c3b 999 case ENCR_CAMELLIA_CCM_ICV8:
0fc4dd42
MW
1000 /* we assume that we support all AES/Camellia sizes */
1001 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
1002 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
1003 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
1004 break;
1005 default:
1006 break;
1007 }
2fa92ad2 1008 }
0fc4dd42 1009 enumerator->destroy(enumerator);
2f893f27
MW
1010
1011 if (!array_count(this->transforms))
1012 {
1013 return FALSE;
1014 }
2fa92ad2 1015 }
0fc4dd42 1016 else
2fa92ad2 1017 {
a78e1c3b 1018 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
1019 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1020 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
2fa92ad2 1021 {
0fc4dd42
MW
1022 switch (encryption)
1023 {
1024 case ENCR_AES_CBC:
1025 case ENCR_AES_CTR:
1026 case ENCR_CAMELLIA_CBC:
1027 case ENCR_CAMELLIA_CTR:
1028 /* we assume that we support all AES/Camellia sizes */
1029 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
1030 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
1031 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
1032 break;
a78e1c3b
AS
1033 default:
1034 break;
1035 }
1036 }
1037 enumerator->destroy(enumerator);
1038
1039 /* Round 2 adds algorithms with less than 128 bit security strength */
1040 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1041 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1042 {
1043 switch (encryption)
1044 {
0fc4dd42
MW
1045 case ENCR_3DES:
1046 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
1047 break;
1048 case ENCR_DES:
1049 /* no, thanks */
1050 break;
1051 default:
1052 break;
1053 }
7daf5226 1054 }
0fc4dd42 1055 enumerator->destroy(enumerator);
7daf5226 1056
2f893f27
MW
1057 if (!array_count(this->transforms))
1058 {
1059 return FALSE;
1060 }
1061
a78e1c3b 1062 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
1063 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1064 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39 1065 {
0fc4dd42
MW
1066 switch (integrity)
1067 {
0fc4dd42
MW
1068 case AUTH_HMAC_SHA2_256_128:
1069 case AUTH_HMAC_SHA2_384_192:
1070 case AUTH_HMAC_SHA2_512_256:
a78e1c3b
AS
1071 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1072 break;
1073 default:
1074 break;
1075 }
1076 }
1077 enumerator->destroy(enumerator);
1078
1079 /* Round 2 adds algorithms with less than 128 bit security strength */
1080 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1081 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1082 {
1083 switch (integrity)
1084 {
0fc4dd42
MW
1085 case AUTH_AES_XCBC_96:
1086 case AUTH_AES_CMAC_96:
a78e1c3b 1087 case AUTH_HMAC_SHA1_96:
0fc4dd42
MW
1088 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1089 break;
10da451f
TB
1090 case AUTH_HMAC_MD5_96:
1091 /* no, thanks */
0fc4dd42
MW
1092 default:
1093 break;
1094 }
7daf5226 1095 }
0fc4dd42 1096 enumerator->destroy(enumerator);
e577ad39 1097 }
7daf5226 1098
a78e1c3b 1099 /* Round 1 adds algorithms with at least 128 bit security strength */
e577ad39 1100 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 1101 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
1102 {
1103 switch (prf)
1104 {
e577ad39
MW
1105 case PRF_HMAC_SHA2_256:
1106 case PRF_HMAC_SHA2_384:
1107 case PRF_HMAC_SHA2_512:
e577ad39 1108 case PRF_AES128_XCBC:
bad19206 1109 case PRF_AES128_CMAC:
e577ad39
MW
1110 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1111 break;
1112 default:
1113 break;
1114 }
1115 }
1116 enumerator->destroy(enumerator);
7daf5226 1117
a78e1c3b
AS
1118 /* Round 2 adds algorithms with less than 128 bit security strength */
1119 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1120 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1121 {
1122 switch (prf)
1123 {
1124 case PRF_HMAC_SHA1:
a78e1c3b
AS
1125 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1126 break;
10da451f
TB
1127 case PRF_HMAC_MD5:
1128 /* no, thanks */
1129 break;
a78e1c3b
AS
1130 default:
1131 break;
1132 }
1133 }
1134 enumerator->destroy(enumerator);
1135
1136 /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
1137 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1138 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1139 {
1140 switch (group)
1141 {
1142 case ECP_256_BIT:
1143 case ECP_384_BIT:
1144 case ECP_521_BIT:
1145 case ECP_256_BP:
1146 case ECP_384_BP:
1147 case ECP_512_BP:
549b325d
TB
1148 case CURVE_25519:
1149 case CURVE_448:
a78e1c3b
AS
1150 case NTRU_128_BIT:
1151 case NTRU_192_BIT:
1152 case NTRU_256_BIT:
393688ae 1153 case NH_128_BIT:
a78e1c3b
AS
1154 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1155 break;
1156 default:
1157 break;
1158 }
1159 }
1160 enumerator->destroy(enumerator);
1161
1162 /* Round 2 adds other algorithms with at least 128 bit security strength */
1163 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1164 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1165 {
1166 switch (group)
1167 {
1168 case MODP_3072_BIT:
1169 case MODP_4096_BIT:
ac140220 1170 case MODP_6144_BIT:
a78e1c3b
AS
1171 case MODP_8192_BIT:
1172 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1173 break;
1174 default:
1175 break;
1176 }
1177 }
1178 enumerator->destroy(enumerator);
1179
1180 /* Round 3 adds algorithms with less than 128 bit security strength */
e577ad39 1181 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 1182 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
1183 {
1184 switch (group)
1185 {
a20abb81
MW
1186 case MODP_NULL:
1187 /* only for testing purposes */
1188 break;
e577ad39 1189 case MODP_768_BIT:
76c58498
TB
1190 case MODP_1024_BIT:
1191 case MODP_1536_BIT:
e577ad39
MW
1192 /* weak */
1193 break;
649537ee 1194 case MODP_1024_160:
a78e1c3b 1195 case MODP_2048_224:
649537ee
MW
1196 case MODP_2048_256:
1197 /* RFC 5114 primes are of questionable source */
1198 break;
e577ad39 1199 case ECP_224_BIT:
73134999 1200 case ECP_224_BP:
a78e1c3b 1201 case ECP_192_BIT:
798a36dc 1202 case NTRU_112_BIT:
fae18fd2
TB
1203 /* rarely used */
1204 break;
1205 case MODP_2048_BIT:
e577ad39
MW
1206 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1207 break;
1208 default:
1209 break;
1210 }
1211 }
1212 enumerator->destroy(enumerator);
2f893f27
MW
1213
1214 return TRUE;
e577ad39
MW
1215}
1216
c095388f 1217/*
8e52dc27 1218 * Described in header
c095388f
MW
1219 */
1220proposal_t *proposal_create_default(protocol_id_t protocol)
1221{
bb162175 1222 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1223
c095388f
MW
1224 switch (protocol)
1225 {
1226 case PROTO_IKE:
2f893f27
MW
1227 if (!proposal_add_supported_ike(this, FALSE))
1228 {
1229 destroy(this);
1230 return NULL;
1231 }
c095388f
MW
1232 break;
1233 case PROTO_ESP:
a78e1c3b
AS
1234 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
1235 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
1236 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
a78e1c3b
AS
1237 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1238 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1239 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1240 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1241 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
a78e1c3b 1242 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
1243 break;
1244 case PROTO_AH:
a78e1c3b
AS
1245 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1246 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1247 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1248 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1249 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
a78e1c3b 1250 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f 1251 break;
3dd3c5f3
MW
1252 default:
1253 break;
c095388f 1254 }
c095388f
MW
1255 return &this->public;
1256}
1257
8642f8bd 1258/*
8e52dc27 1259 * Described in header
8642f8bd
MW
1260 */
1261proposal_t *proposal_create_default_aead(protocol_id_t protocol)
1262{
1263 private_proposal_t *this;
1264
1265 switch (protocol)
1266 {
1267 case PROTO_IKE:
1268 this = (private_proposal_t*)proposal_create(protocol, 0);
2f893f27
MW
1269 if (!proposal_add_supported_ike(this, TRUE))
1270 {
1271 destroy(this);
1272 return NULL;
1273 }
8642f8bd
MW
1274 return &this->public;
1275 case PROTO_ESP:
1276 /* we currently don't include any AEAD proposal for ESP, as we
1277 * don't know if our kernel backend actually supports it. */
1278 return NULL;
1279 case PROTO_AH:
1280 default:
1281 return NULL;
1282 }
1283}
1284
c095388f 1285/*
8e52dc27 1286 * Described in header
c095388f
MW
1287 */
1288proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
1289{
99587521
TB
1290 private_proposal_t *this;
1291 enumerator_t *enumerator;
1292 bool failed = TRUE;
1293 char *alg;
7daf5226 1294
99587521 1295 this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1296
c095388f 1297 /* get all tokens, separated by '-' */
99587521
TB
1298 enumerator = enumerator_create_token(algs, "-", " ");
1299 while (enumerator->enumerate(enumerator, &alg))
c095388f 1300 {
99587521
TB
1301 if (!add_string_algo(this, alg))
1302 {
1303 failed = TRUE;
1304 break;
1305 }
1306 failed = FALSE;
c095388f 1307 }
99587521
TB
1308 enumerator->destroy(enumerator);
1309
9b191d59 1310 if (failed || !check_proposal(this))
c095388f
MW
1311 {
1312 destroy(this);
1313 return NULL;
1314 }
7daf5226 1315
c095388f
MW
1316 return &this->public;
1317}
c9599d41
TB
1318
1319/*
1320 * Described in header
1321 */
1322proposal_t *proposal_select(linked_list_t *configured, linked_list_t *supplied,
1323 proposal_selection_flag_t flags)
1324{
1325 enumerator_t *prefer_enum, *match_enum;
1326 proposal_t *proposal, *match, *selected = NULL;
1327
1328 if (flags & PROPOSAL_PREFER_SUPPLIED)
1329 {
1330 prefer_enum = supplied->create_enumerator(supplied);
1331 match_enum = configured->create_enumerator(configured);
1332 }
1333 else
1334 {
1335 prefer_enum = configured->create_enumerator(configured);
1336 match_enum = supplied->create_enumerator(supplied);
1337 }
1338
1339 while (prefer_enum->enumerate(prefer_enum, &proposal))
1340 {
1341 if (flags & PROPOSAL_PREFER_SUPPLIED)
1342 {
1343 configured->reset_enumerator(configured, match_enum);
1344 }
1345 else
1346 {
1347 supplied->reset_enumerator(supplied, match_enum);
1348 }
1349 while (match_enum->enumerate(match_enum, &match))
1350 {
1351 selected = proposal->select(proposal, match, flags);
1352 if (selected)
1353 {
1354 DBG2(DBG_CFG, "received proposals: %#P", supplied);
1355 DBG2(DBG_CFG, "configured proposals: %#P", configured);
1356 DBG1(DBG_CFG, "selected proposal: %P", selected);
1357 break;
1358 }
1359 }
1360 if (selected)
1361 {
1362 break;
1363 }
1364 }
1365 prefer_enum->destroy(prefer_enum);
1366 match_enum->destroy(match_enum);
1367 if (!selected)
1368 {
1369 DBG1(DBG_CFG, "received proposals: %#P", supplied);
1370 DBG1(DBG_CFG, "configured proposals: %#P", configured);
1371 }
1372 return selected;
1373}