]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/crypto/proposal/proposal.c
proposal: Compress arrays after removing transforms
[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
TB
712 }
713 }
a65a282f
TB
714 else
715 { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
716 * proper integrity algorithm */
717 e = array_create_enumerator(this->transforms);
718 while (e->enumerate(e, &entry))
719 {
720 if (entry->type == ENCRYPTION_ALGORITHM)
721 {
722 if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
723 {
724 entry->type = INTEGRITY_ALGORITHM;
725 ks = entry->key_size;
726 entry->key_size = 0;
727 switch (ks)
728 {
729 case 128:
730 entry->alg = AUTH_AES_128_GMAC;
731 continue;
732 case 192:
733 entry->alg = AUTH_AES_192_GMAC;
734 continue;
735 case 256:
736 entry->alg = AUTH_AES_256_GMAC;
737 continue;
738 default:
739 break;
740 }
741 }
742 /* remove all other encryption algorithms */
743 array_remove_at(this->transforms, e);
744 }
745 }
746 e->destroy(e);
cc55461c 747 remove_type(this, ENCRYPTION_ALGORITHM);
a65a282f
TB
748
749 if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
750 {
751 DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
752 "proposals");
753 return FALSE;
754 }
755 }
390b38b8
MW
756
757 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
758 {
e98414ea 759 if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
390b38b8
MW
760 { /* ESN not specified, assume not supported */
761 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
762 }
390b38b8 763 }
c907b57f
MW
764
765 array_compress(this->transforms);
42a6b187 766 array_compress(this->types);
9b191d59 767 return TRUE;
3f730ec1
TB
768}
769
1fa9bdc4
MW
770/**
771 * add a algorithm identified by a string to the proposal.
1fa9bdc4 772 */
99587521 773static bool add_string_algo(private_proposal_t *this, const char *alg)
c095388f 774{
4c57c630 775 const proposal_token_t *token;
a44bb934 776
4c57c630 777 token = lib->proposal->get_token(lib->proposal, alg);
a44bb934 778 if (token == NULL)
c095388f 779 {
99587521
TB
780 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
781 return FALSE;
c095388f 782 }
15c508c7 783
a44bb934 784 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 785
99587521 786 return TRUE;
c095388f
MW
787}
788
035930fc 789/**
5eb094df 790 * Print all algorithms of the given type
035930fc 791 */
1b40b74d 792static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
5eb094df 793 transform_type_t type, bool *first)
035930fc
MW
794{
795 enumerator_t *enumerator;
796 size_t written = 0;
5eb094df
TB
797 entry_t *entry;
798 enum_name_t *names;
7daf5226 799
5eb094df
TB
800 names = transform_get_enum_names(type);
801
802 enumerator = array_create_enumerator(this->transforms);
803 while (enumerator->enumerate(enumerator, &entry))
035930fc 804 {
5eb094df
TB
805 char *prefix = "/";
806
807 if (type != entry->type)
808 {
809 continue;
810 }
035930fc
MW
811 if (*first)
812 {
5eb094df 813 prefix = "";
035930fc
MW
814 *first = FALSE;
815 }
5eb094df
TB
816 if (names)
817 {
818 written += print_in_hook(data, "%s%N", prefix, names, entry->alg);
819 }
035930fc
MW
820 else
821 {
5eb094df
TB
822 written += print_in_hook(data, "%sUNKNOWN_%u_%u", prefix,
823 entry->type, entry->alg);
035930fc 824 }
5eb094df 825 if (entry->key_size)
035930fc 826 {
5eb094df 827 written += print_in_hook(data, "_%u", entry->key_size);
035930fc
MW
828 }
829 }
830 enumerator->destroy(enumerator);
831 return written;
832}
833
834/**
d25ce370 835 * Described in header.
035930fc 836 */
1b40b74d 837int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
d25ce370 838 const void *const *args)
035930fc
MW
839{
840 private_proposal_t *this = *((private_proposal_t**)(args[0]));
841 linked_list_t *list = *((linked_list_t**)(args[0]));
842 enumerator_t *enumerator;
5eb094df 843 transform_type_t *type;
035930fc
MW
844 size_t written = 0;
845 bool first = TRUE;
7daf5226 846
035930fc
MW
847 if (this == NULL)
848 {
1b40b74d 849 return print_in_hook(data, "(null)");
035930fc 850 }
7daf5226 851
d25ce370 852 if (spec->hash)
035930fc
MW
853 {
854 enumerator = list->create_enumerator(list);
855 while (enumerator->enumerate(enumerator, &this))
2db6d5b8 856 { /* call recursively */
035930fc
MW
857 if (first)
858 {
1b40b74d 859 written += print_in_hook(data, "%P", this);
035930fc
MW
860 first = FALSE;
861 }
862 else
863 {
1b40b74d 864 written += print_in_hook(data, ", %P", this);
035930fc
MW
865 }
866 }
867 enumerator->destroy(enumerator);
868 return written;
869 }
7daf5226 870
1b40b74d 871 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
5eb094df
TB
872 enumerator = array_create_enumerator(this->types);
873 while (enumerator->enumerate(enumerator, &type))
874 {
875 written += print_alg(this, data, *type, &first);
876 }
877 enumerator->destroy(enumerator);
035930fc
MW
878 return written;
879}
880
d454c586
MW
881METHOD(proposal_t, destroy, void,
882 private_proposal_t *this)
c06dbbab 883{
c907b57f 884 array_destroy(this->transforms);
cc55461c 885 array_destroy(this->types);
5113680f 886 free(this);
c06dbbab
MW
887}
888
889/*
8e52dc27 890 * Described in header
c06dbbab 891 */
bb162175 892proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 893{
d454c586
MW
894 private_proposal_t *this;
895
896 INIT(this,
897 .public = {
898 .add_algorithm = _add_algorithm,
899 .create_enumerator = _create_enumerator,
900 .get_algorithm = _get_algorithm,
901 .has_dh_group = _has_dh_group,
d9c9b7b8 902 .promote_dh_group = _promote_dh_group,
d454c586
MW
903 .strip_dh = _strip_dh,
904 .select = _select_proposal,
905 .get_protocol = _get_protocol,
906 .set_spi = _set_spi,
907 .get_spi = _get_spi,
bb162175 908 .get_number = _get_number,
d454c586
MW
909 .equals = _equals,
910 .clone = _clone_,
911 .destroy = _destroy,
912 },
913 .protocol = protocol,
bb162175 914 .number = number,
c907b57f 915 .transforms = array_create(sizeof(entry_t), 0),
cc55461c 916 .types = array_create(sizeof(transform_type_t), 0),
d454c586 917 );
7daf5226 918
8d77edde 919 return &this->public;
c06dbbab 920}
c095388f 921
e577ad39
MW
922/**
923 * Add supported IKE algorithms to proposal
924 */
2f893f27 925static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
e577ad39
MW
926{
927 enumerator_t *enumerator;
928 encryption_algorithm_t encryption;
929 integrity_algorithm_t integrity;
930 pseudo_random_function_t prf;
931 diffie_hellman_group_t group;
5932f41f 932 const char *plugin_name;
7daf5226 933
0fc4dd42 934 if (aead)
e577ad39 935 {
a78e1c3b 936 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
937 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
938 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39 939 {
0fc4dd42
MW
940 switch (encryption)
941 {
a78e1c3b 942 case ENCR_AES_GCM_ICV16:
0fc4dd42 943 case ENCR_AES_CCM_ICV16:
a78e1c3b
AS
944 case ENCR_CAMELLIA_CCM_ICV16:
945 /* we assume that we support all AES/Camellia sizes */
946 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
947 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
948 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
949 break;
950 case ENCR_CHACHA20_POLY1305:
951 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
952 break;
953 default:
954 break;
955 }
956 }
957 enumerator->destroy(enumerator);
958
959 /* Round 2 adds algorithms with less than 128 bit security strength */
960 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
961 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
962 {
963 switch (encryption)
964 {
0fc4dd42 965 case ENCR_AES_GCM_ICV12:
a78e1c3b
AS
966 case ENCR_AES_GCM_ICV8:
967 case ENCR_AES_CCM_ICV12:
968 case ENCR_AES_CCM_ICV8:
0fc4dd42 969 case ENCR_CAMELLIA_CCM_ICV12:
a78e1c3b 970 case ENCR_CAMELLIA_CCM_ICV8:
0fc4dd42
MW
971 /* we assume that we support all AES/Camellia sizes */
972 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
973 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
974 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
975 break;
976 default:
977 break;
978 }
2fa92ad2 979 }
0fc4dd42 980 enumerator->destroy(enumerator);
2f893f27
MW
981
982 if (!array_count(this->transforms))
983 {
984 return FALSE;
985 }
2fa92ad2 986 }
0fc4dd42 987 else
2fa92ad2 988 {
a78e1c3b 989 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
990 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
991 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
2fa92ad2 992 {
0fc4dd42
MW
993 switch (encryption)
994 {
995 case ENCR_AES_CBC:
996 case ENCR_AES_CTR:
997 case ENCR_CAMELLIA_CBC:
998 case ENCR_CAMELLIA_CTR:
999 /* we assume that we support all AES/Camellia sizes */
1000 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
1001 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
1002 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
1003 break;
a78e1c3b
AS
1004 default:
1005 break;
1006 }
1007 }
1008 enumerator->destroy(enumerator);
1009
1010 /* Round 2 adds algorithms with less than 128 bit security strength */
1011 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
1012 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
1013 {
1014 switch (encryption)
1015 {
0fc4dd42
MW
1016 case ENCR_3DES:
1017 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
1018 break;
1019 case ENCR_DES:
1020 /* no, thanks */
1021 break;
1022 default:
1023 break;
1024 }
7daf5226 1025 }
0fc4dd42 1026 enumerator->destroy(enumerator);
7daf5226 1027
2f893f27
MW
1028 if (!array_count(this->transforms))
1029 {
1030 return FALSE;
1031 }
1032
a78e1c3b 1033 /* Round 1 adds algorithms with at least 128 bit security strength */
0fc4dd42
MW
1034 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1035 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39 1036 {
0fc4dd42
MW
1037 switch (integrity)
1038 {
0fc4dd42
MW
1039 case AUTH_HMAC_SHA2_256_128:
1040 case AUTH_HMAC_SHA2_384_192:
1041 case AUTH_HMAC_SHA2_512_256:
a78e1c3b
AS
1042 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1043 break;
1044 default:
1045 break;
1046 }
1047 }
1048 enumerator->destroy(enumerator);
1049
1050 /* Round 2 adds algorithms with less than 128 bit security strength */
1051 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
1052 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
1053 {
1054 switch (integrity)
1055 {
0fc4dd42
MW
1056 case AUTH_AES_XCBC_96:
1057 case AUTH_AES_CMAC_96:
a78e1c3b 1058 case AUTH_HMAC_SHA1_96:
0fc4dd42
MW
1059 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
1060 break;
10da451f
TB
1061 case AUTH_HMAC_MD5_96:
1062 /* no, thanks */
0fc4dd42
MW
1063 default:
1064 break;
1065 }
7daf5226 1066 }
0fc4dd42 1067 enumerator->destroy(enumerator);
e577ad39 1068 }
7daf5226 1069
a78e1c3b 1070 /* Round 1 adds algorithms with at least 128 bit security strength */
e577ad39 1071 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 1072 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
1073 {
1074 switch (prf)
1075 {
e577ad39
MW
1076 case PRF_HMAC_SHA2_256:
1077 case PRF_HMAC_SHA2_384:
1078 case PRF_HMAC_SHA2_512:
e577ad39 1079 case PRF_AES128_XCBC:
bad19206 1080 case PRF_AES128_CMAC:
e577ad39
MW
1081 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1082 break;
1083 default:
1084 break;
1085 }
1086 }
1087 enumerator->destroy(enumerator);
7daf5226 1088
a78e1c3b
AS
1089 /* Round 2 adds algorithms with less than 128 bit security strength */
1090 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
1091 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
1092 {
1093 switch (prf)
1094 {
1095 case PRF_HMAC_SHA1:
a78e1c3b
AS
1096 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
1097 break;
10da451f
TB
1098 case PRF_HMAC_MD5:
1099 /* no, thanks */
1100 break;
a78e1c3b
AS
1101 default:
1102 break;
1103 }
1104 }
1105 enumerator->destroy(enumerator);
1106
1107 /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
1108 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1109 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1110 {
1111 switch (group)
1112 {
1113 case ECP_256_BIT:
1114 case ECP_384_BIT:
1115 case ECP_521_BIT:
1116 case ECP_256_BP:
1117 case ECP_384_BP:
1118 case ECP_512_BP:
549b325d
TB
1119 case CURVE_25519:
1120 case CURVE_448:
a78e1c3b
AS
1121 case NTRU_128_BIT:
1122 case NTRU_192_BIT:
1123 case NTRU_256_BIT:
393688ae 1124 case NH_128_BIT:
a78e1c3b
AS
1125 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1126 break;
1127 default:
1128 break;
1129 }
1130 }
1131 enumerator->destroy(enumerator);
1132
1133 /* Round 2 adds other algorithms with at least 128 bit security strength */
1134 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
1135 while (enumerator->enumerate(enumerator, &group, &plugin_name))
1136 {
1137 switch (group)
1138 {
1139 case MODP_3072_BIT:
1140 case MODP_4096_BIT:
ac140220 1141 case MODP_6144_BIT:
a78e1c3b
AS
1142 case MODP_8192_BIT:
1143 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1144 break;
1145 default:
1146 break;
1147 }
1148 }
1149 enumerator->destroy(enumerator);
1150
1151 /* Round 3 adds algorithms with less than 128 bit security strength */
e577ad39 1152 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 1153 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
1154 {
1155 switch (group)
1156 {
a20abb81
MW
1157 case MODP_NULL:
1158 /* only for testing purposes */
1159 break;
e577ad39 1160 case MODP_768_BIT:
76c58498
TB
1161 case MODP_1024_BIT:
1162 case MODP_1536_BIT:
e577ad39
MW
1163 /* weak */
1164 break;
649537ee 1165 case MODP_1024_160:
a78e1c3b 1166 case MODP_2048_224:
649537ee
MW
1167 case MODP_2048_256:
1168 /* RFC 5114 primes are of questionable source */
1169 break;
e577ad39 1170 case ECP_224_BIT:
73134999 1171 case ECP_224_BP:
a78e1c3b 1172 case ECP_192_BIT:
798a36dc 1173 case NTRU_112_BIT:
fae18fd2
TB
1174 /* rarely used */
1175 break;
1176 case MODP_2048_BIT:
e577ad39
MW
1177 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
1178 break;
1179 default:
1180 break;
1181 }
1182 }
1183 enumerator->destroy(enumerator);
2f893f27
MW
1184
1185 return TRUE;
e577ad39
MW
1186}
1187
c095388f 1188/*
8e52dc27 1189 * Described in header
c095388f
MW
1190 */
1191proposal_t *proposal_create_default(protocol_id_t protocol)
1192{
bb162175 1193 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1194
c095388f
MW
1195 switch (protocol)
1196 {
1197 case PROTO_IKE:
2f893f27
MW
1198 if (!proposal_add_supported_ike(this, FALSE))
1199 {
1200 destroy(this);
1201 return NULL;
1202 }
c095388f
MW
1203 break;
1204 case PROTO_ESP:
a78e1c3b
AS
1205 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
1206 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
1207 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
a78e1c3b
AS
1208 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
1209 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
1210 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
1211 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
1212 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
a78e1c3b 1213 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
1214 break;
1215 case PROTO_AH:
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 1222 break;
3dd3c5f3
MW
1223 default:
1224 break;
c095388f 1225 }
c095388f
MW
1226 return &this->public;
1227}
1228
8642f8bd 1229/*
8e52dc27 1230 * Described in header
8642f8bd
MW
1231 */
1232proposal_t *proposal_create_default_aead(protocol_id_t protocol)
1233{
1234 private_proposal_t *this;
1235
1236 switch (protocol)
1237 {
1238 case PROTO_IKE:
1239 this = (private_proposal_t*)proposal_create(protocol, 0);
2f893f27
MW
1240 if (!proposal_add_supported_ike(this, TRUE))
1241 {
1242 destroy(this);
1243 return NULL;
1244 }
8642f8bd
MW
1245 return &this->public;
1246 case PROTO_ESP:
1247 /* we currently don't include any AEAD proposal for ESP, as we
1248 * don't know if our kernel backend actually supports it. */
1249 return NULL;
1250 case PROTO_AH:
1251 default:
1252 return NULL;
1253 }
1254}
1255
c095388f 1256/*
8e52dc27 1257 * Described in header
c095388f
MW
1258 */
1259proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
1260{
99587521
TB
1261 private_proposal_t *this;
1262 enumerator_t *enumerator;
1263 bool failed = TRUE;
1264 char *alg;
7daf5226 1265
99587521 1266 this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 1267
c095388f 1268 /* get all tokens, separated by '-' */
99587521
TB
1269 enumerator = enumerator_create_token(algs, "-", " ");
1270 while (enumerator->enumerate(enumerator, &alg))
c095388f 1271 {
99587521
TB
1272 if (!add_string_algo(this, alg))
1273 {
1274 failed = TRUE;
1275 break;
1276 }
1277 failed = FALSE;
c095388f 1278 }
99587521
TB
1279 enumerator->destroy(enumerator);
1280
9b191d59 1281 if (failed || !check_proposal(this))
c095388f
MW
1282 {
1283 destroy(this);
1284 return NULL;
1285 }
7daf5226 1286
c095388f
MW
1287 return &this->public;
1288}