0acc425d6e76feabf01631f423dcaf4b51f58caa
[strongswan.git] / src / libcharon / config / proposal.c
1 /*
2 * Copyright (C) 2008-2012 Tobias Brunner
3 * Copyright (C) 2006-2010 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <string.h>
18
19 #include "proposal.h"
20
21 #include <daemon.h>
22 #include <collections/array.h>
23 #include <utils/identification.h>
24
25 #include <crypto/transform.h>
26 #include <crypto/prfs/prf.h>
27 #include <crypto/crypters/crypter.h>
28 #include <crypto/signers/signer.h>
29
30 ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
31 "PROTO_NONE",
32 "IKE",
33 "AH",
34 "ESP",
35 "IPCOMP",
36 );
37
38 typedef struct private_proposal_t private_proposal_t;
39
40 /**
41 * Private data of an proposal_t object
42 */
43 struct private_proposal_t {
44
45 /**
46 * Public part
47 */
48 proposal_t public;
49
50 /**
51 * protocol (ESP or AH)
52 */
53 protocol_id_t protocol;
54
55 /**
56 * Priority ordered list of transforms, as entry_t
57 */
58 array_t *transforms;
59
60 /**
61 * senders SPI
62 */
63 u_int64_t spi;
64
65 /**
66 * Proposal number
67 */
68 u_int number;
69 };
70
71 /**
72 * Struct used to store different kinds of algorithms.
73 */
74 typedef struct {
75 /** Type of the transform */
76 transform_type_t type;
77 /** algorithm identifier */
78 u_int16_t alg;
79 /** key size in bits, or zero if not needed */
80 u_int16_t key_size;
81 } entry_t;
82
83 METHOD(proposal_t, add_algorithm, void,
84 private_proposal_t *this, transform_type_t type,
85 u_int16_t alg, u_int16_t key_size)
86 {
87 entry_t entry = {
88 .type = type,
89 .alg = alg,
90 .key_size = key_size,
91 };
92
93 array_insert(this->transforms, ARRAY_TAIL, &entry);
94 }
95
96 /**
97 * filter function for peer configs
98 */
99 static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg,
100 void **unused, u_int16_t *key_size)
101 {
102 entry_t *entry = *in;
103
104 if (entry->type != type)
105 {
106 return FALSE;
107 }
108 if (alg)
109 {
110 *alg = entry->alg;
111 }
112 if (key_size)
113 {
114 *key_size = entry->key_size;
115 }
116 return TRUE;
117 }
118
119 METHOD(proposal_t, create_enumerator, enumerator_t*,
120 private_proposal_t *this, transform_type_t type)
121 {
122 return enumerator_create_filter(
123 array_create_enumerator(this->transforms),
124 (void*)alg_filter, (void*)(uintptr_t)type, NULL);
125 }
126
127 METHOD(proposal_t, get_algorithm, bool,
128 private_proposal_t *this, transform_type_t type,
129 u_int16_t *alg, u_int16_t *key_size)
130 {
131 enumerator_t *enumerator;
132 bool found = FALSE;
133
134 enumerator = create_enumerator(this, type);
135 if (enumerator->enumerate(enumerator, alg, key_size))
136 {
137 found = TRUE;
138 }
139 enumerator->destroy(enumerator);
140
141 return found;
142 }
143
144 METHOD(proposal_t, has_dh_group, bool,
145 private_proposal_t *this, diffie_hellman_group_t group)
146 {
147 bool found = FALSE, any = FALSE;
148 enumerator_t *enumerator;
149 u_int16_t current;
150
151 enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
152 while (enumerator->enumerate(enumerator, &current, NULL))
153 {
154 any = TRUE;
155 if (current == group)
156 {
157 found = TRUE;
158 break;
159 }
160 }
161 enumerator->destroy(enumerator);
162
163 if (!any && group == MODP_NONE)
164 {
165 found = TRUE;
166 }
167 return found;
168 }
169
170 METHOD(proposal_t, strip_dh, void,
171 private_proposal_t *this, diffie_hellman_group_t keep)
172 {
173 enumerator_t *enumerator;
174 entry_t *entry;
175
176 enumerator = array_create_enumerator(this->transforms);
177 while (enumerator->enumerate(enumerator, &entry))
178 {
179 if (entry->type == DIFFIE_HELLMAN_GROUP &&
180 entry->alg != keep)
181 {
182 array_remove_at(this->transforms, enumerator);
183 }
184 }
185 enumerator->destroy(enumerator);
186 }
187
188 /**
189 * Select a matching proposal from this and other, insert into selected.
190 */
191 static bool select_algo(private_proposal_t *this, proposal_t *other,
192 proposal_t *selected, transform_type_t type, bool priv)
193 {
194 enumerator_t *e1, *e2;
195 u_int16_t alg1, alg2, ks1, ks2;
196 bool found = FALSE;
197
198 if (type == INTEGRITY_ALGORITHM &&
199 selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
200 encryption_algorithm_is_aead(alg1))
201 {
202 /* no integrity algorithm required, we have an AEAD */
203 return TRUE;
204 }
205
206 e1 = create_enumerator(this, type);
207 e2 = other->create_enumerator(other, type);
208 if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL))
209 {
210 found = TRUE;
211 }
212
213 e1->destroy(e1);
214 e1 = create_enumerator(this, type);
215 /* compare algs, order of algs in "first" is preferred */
216 while (!found && e1->enumerate(e1, &alg1, &ks1))
217 {
218 e2->destroy(e2);
219 e2 = other->create_enumerator(other, type);
220 while (e2->enumerate(e2, &alg2, &ks2))
221 {
222 if (alg1 == alg2 && ks1 == ks2)
223 {
224 if (!priv && alg1 >= 1024)
225 {
226 /* accept private use algorithms only if requested */
227 DBG1(DBG_CFG, "an algorithm from private space would match, "
228 "but peer implementation is unknown, skipped");
229 continue;
230 }
231 /* ok, we have an algorithm */
232 selected->add_algorithm(selected, type, alg1, ks1);
233 found = TRUE;
234 break;
235 }
236 }
237 }
238 /* no match in all comparisons */
239 e1->destroy(e1);
240 e2->destroy(e2);
241
242 if (!found)
243 {
244 DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type);
245 }
246 return found;
247 }
248
249 METHOD(proposal_t, select_proposal, proposal_t*,
250 private_proposal_t *this, proposal_t *other, bool private)
251 {
252 proposal_t *selected;
253
254 DBG2(DBG_CFG, "selecting proposal:");
255
256 if (this->protocol != other->get_protocol(other))
257 {
258 DBG2(DBG_CFG, " protocol mismatch, skipping");
259 return NULL;
260 }
261
262 selected = proposal_create(this->protocol, other->get_number(other));
263
264 if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
265 !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
266 !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
267 !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
268 !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
269 {
270 selected->destroy(selected);
271 return NULL;
272 }
273
274 DBG2(DBG_CFG, " proposal matches");
275
276 selected->set_spi(selected, other->get_spi(other));
277
278 return selected;
279 }
280
281 METHOD(proposal_t, get_protocol, protocol_id_t,
282 private_proposal_t *this)
283 {
284 return this->protocol;
285 }
286
287 METHOD(proposal_t, set_spi, void,
288 private_proposal_t *this, u_int64_t spi)
289 {
290 this->spi = spi;
291 }
292
293 METHOD(proposal_t, get_spi, u_int64_t,
294 private_proposal_t *this)
295 {
296 return this->spi;
297 }
298
299 /**
300 * Check if two proposals have the same algorithms for a given transform type
301 */
302 static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
303 transform_type_t type)
304 {
305 enumerator_t *e1, *e2;
306 u_int16_t alg1, alg2, ks1, ks2;
307 bool equals = TRUE;
308
309 e1 = create_enumerator(this, type);
310 e2 = other->create_enumerator(other, type);
311 while (e1->enumerate(e1, &alg1, &ks1))
312 {
313 if (!e2->enumerate(e2, &alg2, &ks2))
314 {
315 /* this has more algs */
316 equals = FALSE;
317 break;
318 }
319 if (alg1 != alg2 || ks1 != ks2)
320 {
321 equals = FALSE;
322 break;
323 }
324 }
325 if (e2->enumerate(e2, &alg2, ks2))
326 {
327 /* other has more algs */
328 equals = FALSE;
329 }
330 e1->destroy(e1);
331 e2->destroy(e2);
332
333 return equals;
334 }
335
336 METHOD(proposal_t, get_number, u_int,
337 private_proposal_t *this)
338 {
339 return this->number;
340 }
341
342 METHOD(proposal_t, equals, bool,
343 private_proposal_t *this, proposal_t *other)
344 {
345 if (&this->public == other)
346 {
347 return TRUE;
348 }
349 return (
350 algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
351 algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
352 algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
353 algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
354 algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
355 }
356
357 METHOD(proposal_t, clone_, proposal_t*,
358 private_proposal_t *this)
359 {
360 private_proposal_t *clone;
361 enumerator_t *enumerator;
362 entry_t *entry;
363
364 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
365
366 enumerator = array_create_enumerator(this->transforms);
367 while (enumerator->enumerate(enumerator, &entry))
368 {
369 array_insert(clone->transforms, ARRAY_TAIL, entry);
370 }
371 enumerator->destroy(enumerator);
372
373 clone->spi = this->spi;
374 clone->number = this->number;
375
376 return &clone->public;
377 }
378
379 /**
380 * Map integrity algorithms to the PRF functions using the same algorithm.
381 */
382 static const struct {
383 integrity_algorithm_t integ;
384 pseudo_random_function_t prf;
385 } integ_prf_map[] = {
386 {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
387 {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
388 {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
389 {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
390 {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
391 {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
392 {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
393 {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
394 };
395
396 /**
397 * Checks the proposal read from a string.
398 */
399 static void check_proposal(private_proposal_t *this)
400 {
401 enumerator_t *e;
402 entry_t *entry;
403 u_int16_t alg, ks;
404 bool all_aead = TRUE;
405 int i;
406
407 if (this->protocol == PROTO_IKE)
408 {
409 e = create_enumerator(this, PSEUDO_RANDOM_FUNCTION);
410 if (!e->enumerate(e, &alg, &ks))
411 {
412 /* No explicit PRF found. We assume the same algorithm as used
413 * for integrity checking */
414 e->destroy(e);
415 e = create_enumerator(this, INTEGRITY_ALGORITHM);
416 while (e->enumerate(e, &alg, &ks))
417 {
418 for (i = 0; i < countof(integ_prf_map); i++)
419 {
420 if (alg == integ_prf_map[i].integ)
421 {
422 add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
423 integ_prf_map[i].prf, 0);
424 break;
425 }
426 }
427 }
428 }
429 e->destroy(e);
430 }
431
432 if (this->protocol == PROTO_ESP)
433 {
434 e = create_enumerator(this, ENCRYPTION_ALGORITHM);
435 while (e->enumerate(e, &alg, &ks))
436 {
437 if (!encryption_algorithm_is_aead(alg))
438 {
439 all_aead = FALSE;
440 break;
441 }
442 }
443 e->destroy(e);
444
445 if (all_aead)
446 {
447 /* if all encryption algorithms in the proposal are AEADs,
448 * we MUST NOT propose any integrity algorithms */
449 e = array_create_enumerator(this->transforms);
450 while (e->enumerate(e, &entry))
451 {
452 if (entry->type == INTEGRITY_ALGORITHM)
453 {
454 array_remove_at(this->transforms, e);
455 }
456 }
457 e->destroy(e);
458 }
459 }
460
461 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
462 {
463 e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS);
464 if (!e->enumerate(e, NULL, NULL))
465 { /* ESN not specified, assume not supported */
466 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
467 }
468 e->destroy(e);
469 }
470
471 array_compress(this->transforms);
472 }
473
474 /**
475 * add a algorithm identified by a string to the proposal.
476 */
477 static bool add_string_algo(private_proposal_t *this, const char *alg)
478 {
479 const proposal_token_t *token;
480
481 token = lib->proposal->get_token(lib->proposal, alg);
482 if (token == NULL)
483 {
484 DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
485 return FALSE;
486 }
487
488 add_algorithm(this, token->type, token->algorithm, token->keysize);
489
490 return TRUE;
491 }
492
493 /**
494 * print all algorithms of a kind to buffer
495 */
496 static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
497 u_int kind, void *names, bool *first)
498 {
499 enumerator_t *enumerator;
500 size_t written = 0;
501 u_int16_t alg, size;
502
503 enumerator = create_enumerator(this, kind);
504 while (enumerator->enumerate(enumerator, &alg, &size))
505 {
506 if (*first)
507 {
508 written += print_in_hook(data, "%N", names, alg);
509 *first = FALSE;
510 }
511 else
512 {
513 written += print_in_hook(data, "/%N", names, alg);
514 }
515 if (size)
516 {
517 written += print_in_hook(data, "_%u", size);
518 }
519 }
520 enumerator->destroy(enumerator);
521 return written;
522 }
523
524 /**
525 * Described in header.
526 */
527 int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
528 const void *const *args)
529 {
530 private_proposal_t *this = *((private_proposal_t**)(args[0]));
531 linked_list_t *list = *((linked_list_t**)(args[0]));
532 enumerator_t *enumerator;
533 size_t written = 0;
534 bool first = TRUE;
535
536 if (this == NULL)
537 {
538 return print_in_hook(data, "(null)");
539 }
540
541 if (spec->hash)
542 {
543 enumerator = list->create_enumerator(list);
544 while (enumerator->enumerate(enumerator, &this))
545 { /* call recursivly */
546 if (first)
547 {
548 written += print_in_hook(data, "%P", this);
549 first = FALSE;
550 }
551 else
552 {
553 written += print_in_hook(data, ", %P", this);
554 }
555 }
556 enumerator->destroy(enumerator);
557 return written;
558 }
559
560 written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
561 written += print_alg(this, data, ENCRYPTION_ALGORITHM,
562 encryption_algorithm_names, &first);
563 written += print_alg(this, data, INTEGRITY_ALGORITHM,
564 integrity_algorithm_names, &first);
565 written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
566 pseudo_random_function_names, &first);
567 written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
568 diffie_hellman_group_names, &first);
569 written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
570 extended_sequence_numbers_names, &first);
571 return written;
572 }
573
574 METHOD(proposal_t, destroy, void,
575 private_proposal_t *this)
576 {
577 array_destroy(this->transforms);
578 free(this);
579 }
580
581 /*
582 * Describtion in header-file
583 */
584 proposal_t *proposal_create(protocol_id_t protocol, u_int number)
585 {
586 private_proposal_t *this;
587
588 INIT(this,
589 .public = {
590 .add_algorithm = _add_algorithm,
591 .create_enumerator = _create_enumerator,
592 .get_algorithm = _get_algorithm,
593 .has_dh_group = _has_dh_group,
594 .strip_dh = _strip_dh,
595 .select = _select_proposal,
596 .get_protocol = _get_protocol,
597 .set_spi = _set_spi,
598 .get_spi = _get_spi,
599 .get_number = _get_number,
600 .equals = _equals,
601 .clone = _clone_,
602 .destroy = _destroy,
603 },
604 .protocol = protocol,
605 .number = number,
606 .transforms = array_create(sizeof(entry_t), 0),
607 );
608
609 return &this->public;
610 }
611
612 /**
613 * Add supported IKE algorithms to proposal
614 */
615 static void proposal_add_supported_ike(private_proposal_t *this)
616 {
617 enumerator_t *enumerator;
618 encryption_algorithm_t encryption;
619 integrity_algorithm_t integrity;
620 pseudo_random_function_t prf;
621 diffie_hellman_group_t group;
622 const char *plugin_name;
623
624 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
625 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
626 {
627 switch (encryption)
628 {
629 case ENCR_AES_CBC:
630 case ENCR_AES_CTR:
631 case ENCR_CAMELLIA_CBC:
632 case ENCR_CAMELLIA_CTR:
633 /* we assume that we support all AES/Camellia sizes */
634 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
635 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
636 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
637 break;
638 case ENCR_3DES:
639 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
640 break;
641 case ENCR_DES:
642 /* no, thanks */
643 break;
644 default:
645 break;
646 }
647 }
648 enumerator->destroy(enumerator);
649
650 enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
651 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
652 {
653 switch (encryption)
654 {
655 case ENCR_AES_CCM_ICV8:
656 case ENCR_AES_CCM_ICV12:
657 case ENCR_AES_CCM_ICV16:
658 case ENCR_AES_GCM_ICV8:
659 case ENCR_AES_GCM_ICV12:
660 case ENCR_AES_GCM_ICV16:
661 case ENCR_CAMELLIA_CCM_ICV8:
662 case ENCR_CAMELLIA_CCM_ICV12:
663 case ENCR_CAMELLIA_CCM_ICV16:
664 /* we assume that we support all AES/Camellia sizes */
665 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
666 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
667 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
668 break;
669 default:
670 break;
671 }
672 }
673 enumerator->destroy(enumerator);
674
675 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
676 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
677 {
678 switch (integrity)
679 {
680 case AUTH_HMAC_SHA1_96:
681 case AUTH_HMAC_SHA2_256_128:
682 case AUTH_HMAC_SHA2_384_192:
683 case AUTH_HMAC_SHA2_512_256:
684 case AUTH_HMAC_MD5_96:
685 case AUTH_AES_XCBC_96:
686 case AUTH_AES_CMAC_96:
687 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
688 break;
689 default:
690 break;
691 }
692 }
693 enumerator->destroy(enumerator);
694
695 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
696 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
697 {
698 switch (prf)
699 {
700 case PRF_HMAC_SHA1:
701 case PRF_HMAC_SHA2_256:
702 case PRF_HMAC_SHA2_384:
703 case PRF_HMAC_SHA2_512:
704 case PRF_HMAC_MD5:
705 case PRF_AES128_XCBC:
706 case PRF_AES128_CMAC:
707 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
708 break;
709 default:
710 break;
711 }
712 }
713 enumerator->destroy(enumerator);
714
715 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
716 while (enumerator->enumerate(enumerator, &group, &plugin_name))
717 {
718 switch (group)
719 {
720 case MODP_NULL:
721 /* only for testing purposes */
722 break;
723 case MODP_768_BIT:
724 /* weak */
725 break;
726 case MODP_1024_BIT:
727 case MODP_1536_BIT:
728 case MODP_2048_BIT:
729 case MODP_3072_BIT:
730 case MODP_4096_BIT:
731 case MODP_8192_BIT:
732 case ECP_256_BIT:
733 case ECP_384_BIT:
734 case ECP_521_BIT:
735 case MODP_1024_160:
736 case MODP_2048_224:
737 case MODP_2048_256:
738 case ECP_192_BIT:
739 case ECP_224_BIT:
740 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
741 break;
742 default:
743 break;
744 }
745 }
746 enumerator->destroy(enumerator);
747 }
748
749 /*
750 * Describtion in header-file
751 */
752 proposal_t *proposal_create_default(protocol_id_t protocol)
753 {
754 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
755
756 switch (protocol)
757 {
758 case PROTO_IKE:
759 proposal_add_supported_ike(this);
760 break;
761 case PROTO_ESP:
762 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
763 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
764 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
765 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
766 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
767 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
768 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
769 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
770 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
771 break;
772 case PROTO_AH:
773 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
774 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
775 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
776 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
777 break;
778 default:
779 break;
780 }
781 return &this->public;
782 }
783
784 /*
785 * Describtion in header-file
786 */
787 proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
788 {
789 private_proposal_t *this;
790 enumerator_t *enumerator;
791 bool failed = TRUE;
792 char *alg;
793
794 this = (private_proposal_t*)proposal_create(protocol, 0);
795
796 /* get all tokens, separated by '-' */
797 enumerator = enumerator_create_token(algs, "-", " ");
798 while (enumerator->enumerate(enumerator, &alg))
799 {
800 if (!add_string_algo(this, alg))
801 {
802 failed = TRUE;
803 break;
804 }
805 failed = FALSE;
806 }
807 enumerator->destroy(enumerator);
808
809 if (failed)
810 {
811 destroy(this);
812 return NULL;
813 }
814
815 check_proposal(this);
816
817 return &this->public;
818 }