]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/crypto/proposal/proposal.c
proposal: Don't specify key length for ChaCha20/Poly1305
[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
d454c586 305METHOD(proposal_t, strip_dh, void,
4eba7269 306 private_proposal_t *this, diffie_hellman_group_t keep)
3c7e72f5 307{
4eba7269 308 enumerator_t *enumerator;
5cd64f97 309 entry_t *entry;
cc55461c 310 bool found = FALSE;
7daf5226 311
c907b57f 312 enumerator = array_create_enumerator(this->transforms);
5cd64f97 313 while (enumerator->enumerate(enumerator, &entry))
3c7e72f5 314 {
cc55461c 315 if (entry->type == DIFFIE_HELLMAN_GROUP)
4eba7269 316 {
cc55461c
TB
317 if (entry->alg != keep)
318 {
319 array_remove_at(this->transforms, enumerator);
320 }
321 else
322 {
323 found = TRUE;
324 }
4eba7269 325 }
3c7e72f5 326 }
4eba7269 327 enumerator->destroy(enumerator);
42a6b187 328 array_compress(this->transforms);
cc55461c
TB
329
330 if (keep == MODP_NONE || !found)
331 {
332 remove_type(this, DIFFIE_HELLMAN_GROUP);
42a6b187 333 array_compress(this->types);
cc55461c 334 }
3c7e72f5
MW
335}
336
c06dbbab 337/**
5cd64f97 338 * Select a matching proposal from this and other, insert into selected.
c06dbbab 339 */
5cd64f97
MW
340static bool select_algo(private_proposal_t *this, proposal_t *other,
341 proposal_t *selected, transform_type_t type, bool priv)
c06dbbab 342{
3c7e72f5 343 enumerator_t *e1, *e2;
b12c53ce 344 uint16_t alg1, alg2, ks1, ks2;
a213944d 345 bool found = FALSE, optional = FALSE;
7daf5226 346
5cd64f97
MW
347 if (type == INTEGRITY_ALGORITHM &&
348 selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
349 encryption_algorithm_is_aead(alg1))
c06dbbab 350 {
5cd64f97 351 /* no integrity algorithm required, we have an AEAD */
c06dbbab
MW
352 return TRUE;
353 }
a213944d
TB
354 if (type == DIFFIE_HELLMAN_GROUP)
355 {
356 optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
357 }
7daf5226 358
5cd64f97
MW
359 e1 = create_enumerator(this, type);
360 e2 = other->create_enumerator(other, type);
aae95101 361 if (!e1->enumerate(e1, &alg1, NULL))
5cd64f97 362 {
a213944d
TB
363 if (!e2->enumerate(e2, &alg2, NULL))
364 {
365 found = TRUE;
366 }
367 else if (optional)
368 {
369 do
aae95101 370 { /* if NONE is proposed, we accept the proposal */
a213944d
TB
371 found = !alg2;
372 }
373 while (!found && e2->enumerate(e2, &alg2, NULL));
374 }
5cd64f97 375 }
aae95101
TB
376 else if (!e2->enumerate(e2, NULL, NULL))
377 {
378 if (optional)
379 {
380 do
381 { /* if NONE is proposed, we accept the proposal */
382 found = !alg1;
383 }
384 while (!found && e1->enumerate(e1, &alg1, NULL));
385 }
386 }
5cd64f97
MW
387
388 e1->destroy(e1);
389 e1 = create_enumerator(this, type);
c06dbbab 390 /* compare algs, order of algs in "first" is preferred */
5cd64f97 391 while (!found && e1->enumerate(e1, &alg1, &ks1))
c06dbbab 392 {
3c7e72f5 393 e2->destroy(e2);
5cd64f97
MW
394 e2 = other->create_enumerator(other, type);
395 while (e2->enumerate(e2, &alg2, &ks2))
c06dbbab 396 {
5cd64f97 397 if (alg1 == alg2 && ks1 == ks2)
c06dbbab 398 {
5cd64f97 399 if (!priv && alg1 >= 1024)
023fd8f1
MW
400 {
401 /* accept private use algorithms only if requested */
402 DBG1(DBG_CFG, "an algorithm from private space would match, "
403 "but peer implementation is unknown, skipped");
404 continue;
405 }
5cd64f97
MW
406 selected->add_algorithm(selected, type, alg1, ks1);
407 found = TRUE;
408 break;
c06dbbab
MW
409 }
410 }
411 }
412 /* no match in all comparisons */
3c7e72f5
MW
413 e1->destroy(e1);
414 e2->destroy(e2);
5cd64f97
MW
415
416 if (!found)
417 {
418 DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type);
419 }
420 return found;
c06dbbab
MW
421}
422
d454c586 423METHOD(proposal_t, select_proposal, proposal_t*,
22f13dce
TB
424 private_proposal_t *this, proposal_t *other, bool other_remote,
425 bool private)
c06dbbab 426{
ce461bbd 427 proposal_t *selected;
76c7c951
TB
428 transform_type_t type;
429 array_t *types;
430 int i;
7daf5226 431
02b3101b 432 DBG2(DBG_CFG, "selecting proposal:");
7daf5226 433
5cd64f97 434 if (this->protocol != other->get_protocol(other))
c06dbbab 435 {
02b3101b 436 DBG2(DBG_CFG, " protocol mismatch, skipping");
c06dbbab
MW
437 return NULL;
438 }
7daf5226 439
22f13dce
TB
440 if (other_remote)
441 {
442 selected = proposal_create(this->protocol, other->get_number(other));
443 selected->set_spi(selected, other->get_spi(other));
444 }
445 else
446 {
447 selected = proposal_create(this->protocol, this->number);
448 selected->set_spi(selected, this->spi);
22f13dce 449 }
7daf5226 450
76c7c951
TB
451 types = merge_types(this, (private_proposal_t*)other);
452 for (i = 0; i < array_count(types); i++)
8d77edde 453 {
76c7c951
TB
454 array_get(types, i, &type);
455 if (!select_algo(this, other, selected, type, private))
456 {
457 selected->destroy(selected);
458 array_destroy(types);
459 return NULL;
460 }
8d77edde 461 }
76c7c951 462 array_destroy(types);
5cd64f97 463
02b3101b 464 DBG2(DBG_CFG, " proposal matches");
c06dbbab
MW
465 return selected;
466}
467
d454c586
MW
468METHOD(proposal_t, get_protocol, protocol_id_t,
469 private_proposal_t *this)
c06dbbab 470{
8d77edde 471 return this->protocol;
c06dbbab
MW
472}
473
d454c586 474METHOD(proposal_t, set_spi, void,
b12c53ce 475 private_proposal_t *this, uint64_t spi)
c06dbbab 476{
8d77edde 477 this->spi = spi;
c06dbbab
MW
478}
479
b12c53ce 480METHOD(proposal_t, get_spi, uint64_t,
d454c586 481 private_proposal_t *this)
c06dbbab 482{
8d77edde 483 return this->spi;
c06dbbab
MW
484}
485
87a217f9 486/**
5cd64f97 487 * Check if two proposals have the same algorithms for a given transform type
3c7e72f5 488 */
5cd64f97
MW
489static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
490 transform_type_t type)
3c7e72f5
MW
491{
492 enumerator_t *e1, *e2;
b12c53ce 493 uint16_t alg1, alg2, ks1, ks2;
3c7e72f5 494 bool equals = TRUE;
7daf5226 495
5cd64f97
MW
496 e1 = create_enumerator(this, type);
497 e2 = other->create_enumerator(other, type);
498 while (e1->enumerate(e1, &alg1, &ks1))
3c7e72f5 499 {
5cd64f97
MW
500 if (!e2->enumerate(e2, &alg2, &ks2))
501 {
502 /* this has more algs */
503 equals = FALSE;
504 break;
505 }
506 if (alg1 != alg2 || ks1 != ks2)
3c7e72f5
MW
507 {
508 equals = FALSE;
509 break;
510 }
511 }
8e52dc27 512 if (e2->enumerate(e2, &alg2, &ks2))
5cd64f97
MW
513 {
514 /* other has more algs */
515 equals = FALSE;
516 }
3c7e72f5
MW
517 e1->destroy(e1);
518 e2->destroy(e2);
5cd64f97 519
3c7e72f5
MW
520 return equals;
521}
522
bb162175
MW
523METHOD(proposal_t, get_number, u_int,
524 private_proposal_t *this)
525{
526 return this->number;
527}
528
d454c586 529METHOD(proposal_t, equals, bool,
5cd64f97 530 private_proposal_t *this, proposal_t *other)
3c7e72f5 531{
6b8749ab
TB
532 transform_type_t type;
533 array_t *types;
534 int i;
535
5cd64f97 536 if (&this->public == other)
3c7e72f5
MW
537 {
538 return TRUE;
539 }
6b8749ab
TB
540
541 types = merge_types(this, (private_proposal_t*)other);
542 for (i = 0; i < array_count(types); i++)
543 {
544 array_get(types, i, &type);
545 if (!algo_list_equals(this, other, type))
546 {
547 array_destroy(types);
548 return FALSE;
549 }
550 }
551 array_destroy(types);
552 return TRUE;
87a217f9
MW
553}
554
d454c586
MW
555METHOD(proposal_t, clone_, proposal_t*,
556 private_proposal_t *this)
87a217f9 557{
bb162175 558 private_proposal_t *clone;
5cd64f97 559 enumerator_t *enumerator;
c907b57f 560 entry_t *entry;
cc55461c 561 transform_type_t *type;
7daf5226 562
bb162175 563 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
5cd64f97 564
c907b57f
MW
565 enumerator = array_create_enumerator(this->transforms);
566 while (enumerator->enumerate(enumerator, &entry))
5cd64f97 567 {
c907b57f 568 array_insert(clone->transforms, ARRAY_TAIL, entry);
5cd64f97
MW
569 }
570 enumerator->destroy(enumerator);
cc55461c
TB
571 enumerator = array_create_enumerator(this->types);
572 while (enumerator->enumerate(enumerator, &type))
573 {
574 array_insert(clone->types, ARRAY_TAIL, type);
575 }
576 enumerator->destroy(enumerator);
7daf5226 577
8d77edde 578 clone->spi = this->spi;
bb162175 579 clone->number = this->number;
7daf5226 580
87a217f9
MW
581 return &clone->public;
582}
583
7ee16e4b
MW
584/**
585 * Map integrity algorithms to the PRF functions using the same algorithm.
586 */
587static const struct {
588 integrity_algorithm_t integ;
589 pseudo_random_function_t prf;
590} integ_prf_map[] = {
591 {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
b1ef481c 592 {AUTH_HMAC_SHA1_160, PRF_HMAC_SHA1 },
7ee16e4b
MW
593 {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
594 {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
595 {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
596 {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
b1ef481c 597 {AUTH_HMAC_MD5_128, PRF_HMAC_MD5 },
7ee16e4b
MW
598 {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
599 {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
600 {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
601};
602
e98414ea
TB
603/**
604 * Remove all entries of the given transform type
605 */
606static void remove_transform(private_proposal_t *this, transform_type_t type)
607{
608 enumerator_t *e;
609 entry_t *entry;
610
611 e = array_create_enumerator(this->transforms);
612 while (e->enumerate(e, &entry))
613 {
614 if (entry->type == type)
615 {
616 array_remove_at(this->transforms, e);
617 }
618 }
619 e->destroy(e);
cc55461c 620 remove_type(this, type);
e98414ea
TB
621}
622
3f730ec1
TB
623/**
624 * Checks the proposal read from a string.
625 */
9b191d59 626static bool check_proposal(private_proposal_t *this)
3f730ec1
TB
627{
628 enumerator_t *e;
5cd64f97 629 entry_t *entry;
b12c53ce 630 uint16_t alg, ks;
6a5e6579 631 bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
7ee16e4b
MW
632 int i;
633
5cd64f97
MW
634 if (this->protocol == PROTO_IKE)
635 {
e98414ea
TB
636 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
637 { /* No explicit PRF found. We assume the same algorithm as used
638 * for integrity checking. */
5cd64f97
MW
639 e = create_enumerator(this, INTEGRITY_ALGORITHM);
640 while (e->enumerate(e, &alg, &ks))
7ee16e4b 641 {
5cd64f97 642 for (i = 0; i < countof(integ_prf_map); i++)
7ee16e4b 643 {
5cd64f97
MW
644 if (alg == integ_prf_map[i].integ)
645 {
646 add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
647 integ_prf_map[i].prf, 0);
648 break;
649 }
7ee16e4b
MW
650 }
651 }
e98414ea
TB
652 e->destroy(e);
653 }
654 if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
655 {
656 DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
657 return FALSE;
7ee16e4b 658 }
f5e8bc18
TB
659 /* remove MODP_NONE from IKE proposal */
660 e = array_create_enumerator(this->transforms);
661 while (e->enumerate(e, &entry))
662 {
663 if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
664 {
665 array_remove_at(this->transforms, e);
666 }
667 }
668 e->destroy(e);
e98414ea 669 if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
9b191d59
TB
670 {
671 DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
9b191d59
TB
672 return FALSE;
673 }
e98414ea
TB
674 }
675 else
676 { /* remove PRFs from ESP/AH proposals */
677 remove_transform(this, PSEUDO_RANDOM_FUNCTION);
7ee16e4b 678 }
7daf5226 679
6a5e6579 680 if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
3f730ec1 681 {
f0c59e1c
MW
682 e = create_enumerator(this, ENCRYPTION_ALGORITHM);
683 while (e->enumerate(e, &alg, &ks))
3f730ec1 684 {
6a5e6579
TB
685 any_enc = TRUE;
686 if (encryption_algorithm_is_aead(alg))
f0c59e1c 687 {
6a5e6579
TB
688 any_aead = TRUE;
689 continue;
f0c59e1c 690 }
6a5e6579 691 all_aead = FALSE;
3f730ec1 692 }
f0c59e1c 693 e->destroy(e);
7daf5226 694
6a5e6579
TB
695 if (!any_enc)
696 {
697 DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
698 protocol_id_names, this->protocol);
699 return FALSE;
700 }
701 else if (any_aead && !all_aead)
3f730ec1 702 {
6a5e6579
TB
703 DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
704 "algorithms can't be contained in the same %N proposal",
705 protocol_id_names, this->protocol);
706 return FALSE;
707 }
708 else if (all_aead)
709 { /* if all encryption algorithms in the proposal are AEADs,
f0c59e1c 710 * we MUST NOT propose any integrity algorithms */
6a5e6579 711 remove_transform(this, INTEGRITY_ALGORITHM);
3f730ec1 712 }
ee019ab3
TB
713 else if (this->protocol == PROTO_IKE &&
714 !get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
715 {
716 DBG1(DBG_CFG, "an integrity algorithm is mandatory in %N proposals "
717 "with classic (non-AEAD) encryption algorithms",
718 protocol_id_names, this->protocol);
719 return FALSE;
720 }
3f730ec1 721 }
a65a282f
TB
722 else
723 { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
724 * proper integrity algorithm */
725 e = array_create_enumerator(this->transforms);
726 while (e->enumerate(e, &entry))
727 {
728 if (entry->type == ENCRYPTION_ALGORITHM)
729 {
730 if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
731 {
732 entry->type = INTEGRITY_ALGORITHM;
733 ks = entry->key_size;
734 entry->key_size = 0;
735 switch (ks)
736 {
737 case 128:
738 entry->alg = AUTH_AES_128_GMAC;
739 continue;
740 case 192:
741 entry->alg = AUTH_AES_192_GMAC;
742 continue;
743 case 256:
744 entry->alg = AUTH_AES_256_GMAC;
745 continue;
746 default:
747 break;
748 }
749 }
750 /* remove all other encryption algorithms */
751 array_remove_at(this->transforms, e);
752 }
753 }
754 e->destroy(e);
cc55461c 755 remove_type(this, ENCRYPTION_ALGORITHM);
a65a282f
TB
756
757 if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
758 {
759 DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
760 "proposals");
761 return FALSE;
762 }
763 }
390b38b8
MW
764
765 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
766 {
e98414ea 767 if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
390b38b8
MW
768 { /* ESN not specified, assume not supported */
769 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
770 }
390b38b8 771 }
c907b57f
MW
772
773 array_compress(this->transforms);
42a6b187 774 array_compress(this->types);
9b191d59 775 return TRUE;
3f730ec1
TB
776}
777
1fa9bdc4
MW
778/**
779 * add a algorithm identified by a string to the proposal.
1fa9bdc4 780 */
99587521 781static bool add_string_algo(private_proposal_t *this, const char *alg)
c095388f 782{
4c57c630 783 const proposal_token_t *token;
a44bb934 784
4c57c630 785 token = lib->proposal->get_token(lib->proposal, alg);
a44bb934 786 if (token == NULL)
c095388f 787 {
99587521
TB
788 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
789 return FALSE;
c095388f 790 }
15c508c7 791
a44bb934 792 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 793
99587521 794 return TRUE;
c095388f
MW
795}
796
035930fc 797/**
5eb094df 798 * Print all algorithms of the given type
035930fc 799 */
1b40b74d 800static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
5eb094df 801 transform_type_t type, bool *first)
035930fc
MW
802{
803 enumerator_t *enumerator;
804 size_t written = 0;
5eb094df
TB
805 entry_t *entry;
806 enum_name_t *names;
7daf5226 807
5eb094df
TB
808 names = transform_get_enum_names(type);
809
810 enumerator = array_create_enumerator(this->transforms);
811 while (enumerator->enumerate(enumerator, &entry))
035930fc 812 {
5eb094df
TB
813 char *prefix = "/";
814
815 if (type != entry->type)
816 {
817 continue;
818 }
035930fc
MW
819 if (*first)
820 {
5eb094df 821 prefix = "";
035930fc
MW
822 *first = FALSE;
823 }
5eb094df
TB
824 if (names)
825 {
826 written += print_in_hook(data, "%s%N", prefix, names, entry->alg);
827 }
035930fc
MW
828 else
829 {
5eb094df
TB
830 written += print_in_hook(data, "%sUNKNOWN_%u_%u", prefix,
831 entry->type, entry->alg);
035930fc 832 }
5eb094df 833 if (entry->key_size)
035930fc 834 {
5eb094df 835 written += print_in_hook(data, "_%u", entry->key_size);
035930fc
MW
836 }
837 }
838 enumerator->destroy(enumerator);
839 return written;
840}
841
842/**
d25ce370 843 * Described in header.
035930fc 844 */
1b40b74d 845int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 846 const void *const *args)
035930fc
MW
847{
848 private_proposal_t *this = *((private_proposal_t**)(args[0]));
849 linked_list_t *list = *((linked_list_t**)(args[0]));
850 enumerator_t *enumerator;
5eb094df 851 transform_type_t *type;
035930fc
MW
852 size_t written = 0;
853 bool first = TRUE;
7daf5226 854
035930fc
MW
855 if (this == NULL)
856 {
1b40b74d 857 return print_in_hook(data, "(null)");
035930fc 858 }
7daf5226 859
d25ce370 860 if (spec->hash)
035930fc
MW
861 {
862 enumerator = list->create_enumerator(list);
863 while (enumerator->enumerate(enumerator, &this))
2db6d5b8 864 { /* call recursively */
035930fc
MW
865 if (first)
866 {
1b40b74d 867 written += print_in_hook(data, "%P", this);
035930fc
MW
868 first = FALSE;
869 }
870 else
871 {
1b40b74d 872 written += print_in_hook(data, ", %P", this);
035930fc
MW
873 }
874 }
875 enumerator->destroy(enumerator);
876 return written;
877 }
7daf5226 878
1b40b74d 879 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
5eb094df
TB
880 enumerator = array_create_enumerator(this->types);
881 while (enumerator->enumerate(enumerator, &type))
882 {
883 written += print_alg(this, data, *type, &first);
884 }
885 enumerator->destroy(enumerator);
035930fc
MW
886 return written;
887}
888
d454c586
MW
889METHOD(proposal_t, destroy, void,
890 private_proposal_t *this)
c06dbbab 891{
c907b57f 892 array_destroy(this->transforms);
cc55461c 893 array_destroy(this->types);
5113680f 894 free(this);
c06dbbab
MW
895}
896
897/*
8e52dc27 898 * Described in header
c06dbbab 899 */
bb162175 900proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 901{
d454c586
MW
902 private_proposal_t *this;
903
904 INIT(this,
905 .public = {
906 .add_algorithm = _add_algorithm,
907 .create_enumerator = _create_enumerator,
908 .get_algorithm = _get_algorithm,
909 .has_dh_group = _has_dh_group,
d9c9b7b8 910 .promote_dh_group = _promote_dh_group,
d454c586
MW
911 .strip_dh = _strip_dh,
912 .select = _select_proposal,
913 .get_protocol = _get_protocol,
914 .set_spi = _set_spi,
915 .get_spi = _get_spi,
bb162175 916 .get_number = _get_number,
d454c586
MW
917 .equals = _equals,
918 .clone = _clone_,
919 .destroy = _destroy,
920 },
921 .protocol = protocol,
bb162175 922 .number = number,
c907b57f 923 .transforms = array_create(sizeof(entry_t), 0),
cc55461c 924 .types = array_create(sizeof(transform_type_t), 0),
d454c586 925 );
7daf5226 926
8d77edde 927 return &this->public;
c06dbbab 928}
c095388f 929
e577ad39
MW
930/**
931 * Add supported IKE algorithms to proposal
932 */
2f893f27 933static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
e577ad39
MW
934{
935 enumerator_t *enumerator;
936 encryption_algorithm_t encryption;
937 integrity_algorithm_t integrity;
938 pseudo_random_function_t prf;
939 diffie_hellman_group_t group;
5932f41f 940 const char *plugin_name;
7daf5226 941
0fc4dd42 942 if (aead)
e577ad39 943 {
a78e1c3b 944 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
945 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
946 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39 947 {
0fc4dd42
MW
948 switch (encryption)
949 {
a78e1c3b 950 case ENCR_AES_GCM_ICV16:
0fc4dd42 951 case ENCR_AES_CCM_ICV16:
a78e1c3b
AS
952 case ENCR_CAMELLIA_CCM_ICV16:
953 /* we assume that we support all AES/Camellia sizes */
954 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
955 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
956 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
957 break;
958 case ENCR_CHACHA20_POLY1305:
5a7b0be2 959 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
a78e1c3b
AS
960 break;
961 default:
962 break;
963 }
964 }
965 enumerator->destroy(enumerator);
966
967 /* Round 2 adds algorithms with less than 128 bit security strength */
968 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
969 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
970 {
971 switch (encryption)
972 {
0fc4dd42 973 case ENCR_AES_GCM_ICV12:
a78e1c3b
AS
974 case ENCR_AES_GCM_ICV8:
975 case ENCR_AES_CCM_ICV12:
976 case ENCR_AES_CCM_ICV8:
0fc4dd42 977 case ENCR_CAMELLIA_CCM_ICV12:
a78e1c3b 978 case ENCR_CAMELLIA_CCM_ICV8:
0fc4dd42
MW
979 /* we assume that we support all AES/Camellia sizes */
980 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
981 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
982 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
983 break;
984 default:
985 break;
986 }
2fa92ad2 987 }
0fc4dd42 988 enumerator->destroy(enumerator);
2f893f27
MW
989
990 if (!array_count(this->transforms))
991 {
992 return FALSE;
993 }
2fa92ad2 994 }
0fc4dd42 995 else
2fa92ad2 996 {
a78e1c3b 997 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
998 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
999 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
2fa92ad2 1000 {
0fc4dd42
MW
1001 switch (encryption)
1002 {
1003 case ENCR_AES_CBC:
1004 case ENCR_AES_CTR:
1005 case ENCR_CAMELLIA_CBC:
1006 case ENCR_CAMELLIA_CTR:
1007 /* we assume that we support all AES/Camellia sizes */
1008 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
1009 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
1010 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
1011 break;
a78e1c3b
AS
1012 default:
1013 break;
1014 }
1015 }
1016 enumerator->destroy(enumerator);
1017
1018 /* Round 2 adds algorithms with less than 128 bit security strength */
1019 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1020 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1021 {
1022 switch (encryption)
1023 {
0fc4dd42
MW
1024 case ENCR_3DES:
1025 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
1026 break;
1027 case ENCR_DES:
1028 /* no, thanks */
1029 break;
1030 default:
1031 break;
1032 }
7daf5226 1033 }
0fc4dd42 1034 enumerator->destroy(enumerator);
7daf5226 1035
2f893f27
MW
1036 if (!array_count(this->transforms))
1037 {
1038 return FALSE;
1039 }
1040
a78e1c3b 1041 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
1042 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1043 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39 1044 {
0fc4dd42
MW
1045 switch (integrity)
1046 {
0fc4dd42
MW
1047 case AUTH_HMAC_SHA2_256_128:
1048 case AUTH_HMAC_SHA2_384_192:
1049 case AUTH_HMAC_SHA2_512_256:
a78e1c3b
AS
1050 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1051 break;
1052 default:
1053 break;
1054 }
1055 }
1056 enumerator->destroy(enumerator);
1057
1058 /* Round 2 adds algorithms with less than 128 bit security strength */
1059 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1060 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1061 {
1062 switch (integrity)
1063 {
0fc4dd42
MW
1064 case AUTH_AES_XCBC_96:
1065 case AUTH_AES_CMAC_96:
a78e1c3b 1066 case AUTH_HMAC_SHA1_96:
0fc4dd42
MW
1067 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1068 break;
10da451f
TB
1069 case AUTH_HMAC_MD5_96:
1070 /* no, thanks */
0fc4dd42
MW
1071 default:
1072 break;
1073 }
7daf5226 1074 }
0fc4dd42 1075 enumerator->destroy(enumerator);
e577ad39 1076 }
7daf5226 1077
a78e1c3b 1078 /* Round 1 adds algorithms with at least 128 bit security strength */
e577ad39 1079 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 1080 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
1081 {
1082 switch (prf)
1083 {
e577ad39
MW
1084 case PRF_HMAC_SHA2_256:
1085 case PRF_HMAC_SHA2_384:
1086 case PRF_HMAC_SHA2_512:
e577ad39 1087 case PRF_AES128_XCBC:
bad19206 1088 case PRF_AES128_CMAC:
e577ad39
MW
1089 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1090 break;
1091 default:
1092 break;
1093 }
1094 }
1095 enumerator->destroy(enumerator);
7daf5226 1096
a78e1c3b
AS
1097 /* Round 2 adds algorithms with less than 128 bit security strength */
1098 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1099 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1100 {
1101 switch (prf)
1102 {
1103 case PRF_HMAC_SHA1:
a78e1c3b
AS
1104 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1105 break;
10da451f
TB
1106 case PRF_HMAC_MD5:
1107 /* no, thanks */
1108 break;
a78e1c3b
AS
1109 default:
1110 break;
1111 }
1112 }
1113 enumerator->destroy(enumerator);
1114
1115 /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
1116 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1117 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1118 {
1119 switch (group)
1120 {
1121 case ECP_256_BIT:
1122 case ECP_384_BIT:
1123 case ECP_521_BIT:
1124 case ECP_256_BP:
1125 case ECP_384_BP:
1126 case ECP_512_BP:
549b325d
TB
1127 case CURVE_25519:
1128 case CURVE_448:
a78e1c3b
AS
1129 case NTRU_128_BIT:
1130 case NTRU_192_BIT:
1131 case NTRU_256_BIT:
393688ae 1132 case NH_128_BIT:
a78e1c3b
AS
1133 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1134 break;
1135 default:
1136 break;
1137 }
1138 }
1139 enumerator->destroy(enumerator);
1140
1141 /* Round 2 adds other algorithms with at least 128 bit security strength */
1142 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1143 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1144 {
1145 switch (group)
1146 {
1147 case MODP_3072_BIT:
1148 case MODP_4096_BIT:
ac140220 1149 case MODP_6144_BIT:
a78e1c3b
AS
1150 case MODP_8192_BIT:
1151 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1152 break;
1153 default:
1154 break;
1155 }
1156 }
1157 enumerator->destroy(enumerator);
1158
1159 /* Round 3 adds algorithms with less than 128 bit security strength */
e577ad39 1160 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 1161 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
1162 {
1163 switch (group)
1164 {
a20abb81
MW
1165 case MODP_NULL:
1166 /* only for testing purposes */
1167 break;
e577ad39 1168 case MODP_768_BIT:
76c58498
TB
1169 case MODP_1024_BIT:
1170 case MODP_1536_BIT:
e577ad39
MW
1171 /* weak */
1172 break;
649537ee 1173 case MODP_1024_160:
a78e1c3b 1174 case MODP_2048_224:
649537ee
MW
1175 case MODP_2048_256:
1176 /* RFC 5114 primes are of questionable source */
1177 break;
e577ad39 1178 case ECP_224_BIT:
73134999 1179 case ECP_224_BP:
a78e1c3b 1180 case ECP_192_BIT:
798a36dc 1181 case NTRU_112_BIT:
fae18fd2
TB
1182 /* rarely used */
1183 break;
1184 case MODP_2048_BIT:
e577ad39
MW
1185 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1186 break;
1187 default:
1188 break;
1189 }
1190 }
1191 enumerator->destroy(enumerator);
2f893f27
MW
1192
1193 return TRUE;
e577ad39
MW
1194}
1195
c095388f 1196/*
8e52dc27 1197 * Described in header
c095388f
MW
1198 */
1199proposal_t *proposal_create_default(protocol_id_t protocol)
1200{
bb162175 1201 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1202
c095388f
MW
1203 switch (protocol)
1204 {
1205 case PROTO_IKE:
2f893f27
MW
1206 if (!proposal_add_supported_ike(this, FALSE))
1207 {
1208 destroy(this);
1209 return NULL;
1210 }
c095388f
MW
1211 break;
1212 case PROTO_ESP:
a78e1c3b
AS
1213 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
1214 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
1215 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
a78e1c3b
AS
1216 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1217 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1218 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1219 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1220 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
a78e1c3b 1221 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
1222 break;
1223 case PROTO_AH:
a78e1c3b
AS
1224 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1225 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1226 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1227 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1228 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
a78e1c3b 1229 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f 1230 break;
3dd3c5f3
MW
1231 default:
1232 break;
c095388f 1233 }
c095388f
MW
1234 return &this->public;
1235}
1236
8642f8bd 1237/*
8e52dc27 1238 * Described in header
8642f8bd
MW
1239 */
1240proposal_t *proposal_create_default_aead(protocol_id_t protocol)
1241{
1242 private_proposal_t *this;
1243
1244 switch (protocol)
1245 {
1246 case PROTO_IKE:
1247 this = (private_proposal_t*)proposal_create(protocol, 0);
2f893f27
MW
1248 if (!proposal_add_supported_ike(this, TRUE))
1249 {
1250 destroy(this);
1251 return NULL;
1252 }
8642f8bd
MW
1253 return &this->public;
1254 case PROTO_ESP:
1255 /* we currently don't include any AEAD proposal for ESP, as we
1256 * don't know if our kernel backend actually supports it. */
1257 return NULL;
1258 case PROTO_AH:
1259 default:
1260 return NULL;
1261 }
1262}
1263
c095388f 1264/*
8e52dc27 1265 * Described in header
c095388f
MW
1266 */
1267proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
1268{
99587521
TB
1269 private_proposal_t *this;
1270 enumerator_t *enumerator;
1271 bool failed = TRUE;
1272 char *alg;
7daf5226 1273
99587521 1274 this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1275
c095388f 1276 /* get all tokens, separated by '-' */
99587521
TB
1277 enumerator = enumerator_create_token(algs, "-", " ");
1278 while (enumerator->enumerate(enumerator, &alg))
c095388f 1279 {
99587521
TB
1280 if (!add_string_algo(this, alg))
1281 {
1282 failed = TRUE;
1283 break;
1284 }
1285 failed = FALSE;
c095388f 1286 }
99587521
TB
1287 enumerator->destroy(enumerator);
1288
9b191d59 1289 if (failed || !check_proposal(this))
c095388f
MW
1290 {
1291 destroy(this);
1292 return NULL;
1293 }
7daf5226 1294
c095388f
MW
1295 return &this->public;
1296}