]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/config/proposal.c
represent 0 as a single byte
[thirdparty/strongswan.git] / src / libcharon / config / proposal.c
CommitLineData
c06dbbab 1/*
d25ce370 2 * Copyright (C) 2008-2009 Tobias Brunner
d454c586 3 * Copyright (C) 2006-2010 Martin Willi
c06dbbab
MW
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
5113680f
MW
17#include <string.h>
18
ce461bbd 19#include "proposal.h"
c06dbbab 20
02b3101b 21#include <daemon.h>
c06dbbab 22#include <utils/linked_list.h>
c06dbbab 23#include <utils/identification.h>
c095388f 24#include <utils/lexparser.h>
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>
433cb51b 29#include <crypto/proposal/proposal_keywords.h>
c06dbbab 30
60356f33
MW
31ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP,
32 "PROTO_NONE",
33 "IKE",
34 "AH",
35 "ESP",
36);
c06dbbab 37
8d77edde 38typedef struct private_proposal_t private_proposal_t;
3c7e72f5 39typedef struct algorithm_t algorithm_t;
c06dbbab
MW
40
41/**
8d77edde 42 * Private data of an proposal_t object
c06dbbab 43 */
8d77edde
MW
44struct private_proposal_t {
45
46 /**
47 * Public part
48 */
49 proposal_t public;
7daf5226 50
c06dbbab
MW
51 /**
52 * protocol (ESP or AH)
53 */
54 protocol_id_t protocol;
7daf5226 55
c06dbbab
MW
56 /**
57 * priority ordered list of encryption algorithms
58 */
59 linked_list_t *encryption_algos;
7daf5226 60
c06dbbab
MW
61 /**
62 * priority ordered list of integrity algorithms
63 */
64 linked_list_t *integrity_algos;
7daf5226 65
c06dbbab
MW
66 /**
67 * priority ordered list of pseudo random functions
68 */
69 linked_list_t *prf_algos;
7daf5226 70
c06dbbab
MW
71 /**
72 * priority ordered list of dh groups
73 */
74 linked_list_t *dh_groups;
7daf5226 75
c06dbbab
MW
76 /**
77 * priority ordered list of extended sequence number flags
8d77edde 78 */
c06dbbab 79 linked_list_t *esns;
7daf5226
MW
80
81 /**
c06dbbab
MW
82 * senders SPI
83 */
8d77edde 84 u_int64_t spi;
bb162175
MW
85
86 /**
87 * Proposal number
88 */
89 u_int number;
c06dbbab
MW
90};
91
3c7e72f5 92/**
7daf5226 93 * Struct used to store different kinds of algorithms.
3c7e72f5
MW
94 */
95struct algorithm_t {
96 /**
97 * Value from an encryption_algorithm_t/integrity_algorithm_t/...
98 */
99 u_int16_t algorithm;
7daf5226 100
3c7e72f5
MW
101 /**
102 * the associated key size in bits, or zero if not needed
103 */
104 u_int16_t key_size;
105};
106
c06dbbab
MW
107/**
108 * Add algorithm/keysize to a algorithm list
109 */
3c7e72f5 110static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size)
c06dbbab 111{
c095388f 112 algorithm_t *algo_key;
7daf5226 113
c095388f 114 algo_key = malloc_thing(algorithm_t);
c06dbbab
MW
115 algo_key->algorithm = algo;
116 algo_key->key_size = key_size;
117 list->insert_last(list, (void*)algo_key);
118}
119
d454c586
MW
120METHOD(proposal_t, add_algorithm, void,
121 private_proposal_t *this, transform_type_t type,
122 u_int16_t algo, u_int16_t key_size)
c06dbbab 123{
c06dbbab
MW
124 switch (type)
125 {
126 case ENCRYPTION_ALGORITHM:
8d77edde 127 add_algo(this->encryption_algos, algo, key_size);
c06dbbab
MW
128 break;
129 case INTEGRITY_ALGORITHM:
8d77edde 130 add_algo(this->integrity_algos, algo, key_size);
c06dbbab
MW
131 break;
132 case PSEUDO_RANDOM_FUNCTION:
8d77edde 133 add_algo(this->prf_algos, algo, key_size);
c06dbbab
MW
134 break;
135 case DIFFIE_HELLMAN_GROUP:
8d77edde 136 add_algo(this->dh_groups, algo, 0);
c06dbbab
MW
137 break;
138 case EXTENDED_SEQUENCE_NUMBERS:
8d77edde 139 add_algo(this->esns, algo, 0);
c06dbbab
MW
140 break;
141 default:
142 break;
143 }
144}
145
146/**
3c7e72f5
MW
147 * filter function for peer configs
148 */
149static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
150 void **unused, u_int16_t *key_size)
151{
152 algorithm_t *algo = *in;
153 *alg = algo->algorithm;
154 if (key_size)
155 {
156 *key_size = algo->key_size;
157 }
158 return TRUE;
159}
160
d454c586
MW
161METHOD(proposal_t, create_enumerator, enumerator_t*,
162 private_proposal_t *this, transform_type_t type)
c06dbbab 163{
3c7e72f5
MW
164 linked_list_t *list;
165
c06dbbab
MW
166 switch (type)
167 {
168 case ENCRYPTION_ALGORITHM:
3c7e72f5
MW
169 list = this->encryption_algos;
170 break;
c06dbbab 171 case INTEGRITY_ALGORITHM:
3c7e72f5
MW
172 list = this->integrity_algos;
173 break;
c06dbbab 174 case PSEUDO_RANDOM_FUNCTION:
3c7e72f5
MW
175 list = this->prf_algos;
176 break;
c06dbbab 177 case DIFFIE_HELLMAN_GROUP:
3c7e72f5
MW
178 list = this->dh_groups;
179 break;
c06dbbab 180 case EXTENDED_SEQUENCE_NUMBERS:
3c7e72f5 181 list = this->esns;
c06dbbab 182 break;
3c7e72f5
MW
183 default:
184 return NULL;
c06dbbab 185 }
3c7e72f5
MW
186 return enumerator_create_filter(list->create_enumerator(list),
187 (void*)alg_filter, NULL, NULL);
c06dbbab
MW
188}
189
d454c586
MW
190METHOD(proposal_t, get_algorithm, bool,
191 private_proposal_t *this, transform_type_t type,
192 u_int16_t *alg, u_int16_t *key_size)
1fd5383e 193{
3c7e72f5 194 enumerator_t *enumerator;
9fa5c75f 195 bool found = FALSE;
7daf5226 196
3c7e72f5
MW
197 enumerator = create_enumerator(this, type);
198 if (enumerator->enumerate(enumerator, alg, key_size))
1fd5383e 199 {
3c7e72f5 200 found = TRUE;
1fd5383e 201 }
3c7e72f5
MW
202 enumerator->destroy(enumerator);
203 return found;
1fd5383e
MW
204}
205
d454c586
MW
206METHOD(proposal_t, has_dh_group, bool,
207 private_proposal_t *this, diffie_hellman_group_t group)
1fd5383e 208{
1fd5383e 209 bool result = FALSE;
7daf5226 210
3c7e72f5 211 if (this->dh_groups->get_count(this->dh_groups))
1fd5383e 212 {
3c7e72f5
MW
213 algorithm_t *current;
214 enumerator_t *enumerator;
7daf5226 215
3c7e72f5
MW
216 enumerator = this->dh_groups->create_enumerator(this->dh_groups);
217 while (enumerator->enumerate(enumerator, (void**)&current))
1fd5383e
MW
218 {
219 if (current->algorithm == group)
220 {
221 result = TRUE;
222 break;
223 }
224 }
3c7e72f5 225 enumerator->destroy(enumerator);
1fd5383e
MW
226 }
227 else if (group == MODP_NONE)
228 {
229 result = TRUE;
230 }
1fd5383e
MW
231 return result;
232}
233
d454c586
MW
234METHOD(proposal_t, strip_dh, void,
235 private_proposal_t *this)
3c7e72f5
MW
236{
237 algorithm_t *alg;
7daf5226 238
3c7e72f5
MW
239 while (this->dh_groups->remove_last(this->dh_groups, (void**)&alg) == SUCCESS)
240 {
241 free(alg);
242 }
243}
244
c06dbbab
MW
245/**
246 * Find a matching alg/keysize in two linked lists
247 */
023fd8f1
MW
248static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
249 bool *add, u_int16_t *alg, size_t *key_size)
c06dbbab 250{
3c7e72f5
MW
251 enumerator_t *e1, *e2;
252 algorithm_t *alg1, *alg2;
7daf5226 253
c06dbbab
MW
254 /* if in both are zero algorithms specified, we HAVE a match */
255 if (first->get_count(first) == 0 && second->get_count(second) == 0)
256 {
93df94ac 257 *add = FALSE;
c06dbbab
MW
258 return TRUE;
259 }
7daf5226 260
3c7e72f5
MW
261 e1 = first->create_enumerator(first);
262 e2 = second->create_enumerator(second);
c06dbbab 263 /* compare algs, order of algs in "first" is preferred */
3c7e72f5 264 while (e1->enumerate(e1, &alg1))
c06dbbab 265 {
3c7e72f5
MW
266 e2->destroy(e2);
267 e2 = second->create_enumerator(second);
268 while (e2->enumerate(e2, &alg2))
c06dbbab 269 {
3c7e72f5
MW
270 if (alg1->algorithm == alg2->algorithm &&
271 alg1->key_size == alg2->key_size)
c06dbbab 272 {
023fd8f1
MW
273 if (!priv && alg1->algorithm >= 1024)
274 {
275 /* accept private use algorithms only if requested */
276 DBG1(DBG_CFG, "an algorithm from private space would match, "
277 "but peer implementation is unknown, skipped");
278 continue;
279 }
c06dbbab 280 /* ok, we have an algorithm */
3c7e72f5
MW
281 *alg = alg1->algorithm;
282 *key_size = alg1->key_size;
93df94ac 283 *add = TRUE;
3c7e72f5
MW
284 e1->destroy(e1);
285 e2->destroy(e2);
c06dbbab
MW
286 return TRUE;
287 }
288 }
289 }
290 /* no match in all comparisons */
3c7e72f5
MW
291 e1->destroy(e1);
292 e2->destroy(e2);
c06dbbab
MW
293 return FALSE;
294}
295
d454c586
MW
296METHOD(proposal_t, select_proposal, proposal_t*,
297 private_proposal_t *this, proposal_t *other_pub, bool private)
c06dbbab 298{
d454c586 299 private_proposal_t *other = (private_proposal_t*)other_pub;
ce461bbd 300 proposal_t *selected;
c06dbbab
MW
301 u_int16_t algo;
302 size_t key_size;
93df94ac 303 bool add;
7daf5226 304
02b3101b 305 DBG2(DBG_CFG, "selecting proposal:");
7daf5226 306
8d77edde
MW
307 /* check protocol */
308 if (this->protocol != other->protocol)
c06dbbab 309 {
02b3101b 310 DBG2(DBG_CFG, " protocol mismatch, skipping");
c06dbbab
MW
311 return NULL;
312 }
7daf5226 313
bb162175 314 selected = proposal_create(this->protocol, other->number);
7daf5226 315
8d77edde 316 /* select encryption algorithm */
023fd8f1 317 if (select_algo(this->encryption_algos, other->encryption_algos, private,
035930fc 318 &add, &algo, &key_size))
c06dbbab 319 {
8d77edde 320 if (add)
c06dbbab 321 {
035930fc
MW
322 selected->add_algorithm(selected, ENCRYPTION_ALGORITHM,
323 algo, key_size);
c06dbbab 324 }
8d77edde
MW
325 }
326 else
327 {
328 selected->destroy(selected);
035930fc
MW
329 DBG2(DBG_CFG, " no acceptable %N found",
330 transform_type_names, ENCRYPTION_ALGORITHM);
8d77edde
MW
331 return NULL;
332 }
333 /* select integrity algorithm */
7fc4b081 334 if (!encryption_algorithm_is_aead(algo))
8d77edde 335 {
023fd8f1 336 if (select_algo(this->integrity_algos, other->integrity_algos, private,
035930fc 337 &add, &algo, &key_size))
c06dbbab 338 {
3f730ec1
TB
339 if (add)
340 {
035930fc
MW
341 selected->add_algorithm(selected, INTEGRITY_ALGORITHM,
342 algo, key_size);
3f730ec1
TB
343 }
344 }
345 else
346 {
347 selected->destroy(selected);
035930fc
MW
348 DBG2(DBG_CFG, " no acceptable %N found",
349 transform_type_names, INTEGRITY_ALGORITHM);
3f730ec1 350 return NULL;
c06dbbab 351 }
8d77edde
MW
352 }
353 /* select prf algorithm */
023fd8f1 354 if (select_algo(this->prf_algos, other->prf_algos, private,
035930fc 355 &add, &algo, &key_size))
8d77edde
MW
356 {
357 if (add)
c06dbbab 358 {
035930fc
MW
359 selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION,
360 algo, key_size);
c06dbbab 361 }
8d77edde
MW
362 }
363 else
364 {
365 selected->destroy(selected);
035930fc
MW
366 DBG2(DBG_CFG, " no acceptable %N found",
367 transform_type_names, PSEUDO_RANDOM_FUNCTION);
8d77edde
MW
368 return NULL;
369 }
370 /* select a DH-group */
023fd8f1
MW
371 if (select_algo(this->dh_groups, other->dh_groups, private,
372 &add, &algo, &key_size))
8d77edde
MW
373 {
374 if (add)
c06dbbab 375 {
8d77edde 376 selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
c06dbbab
MW
377 }
378 }
8d77edde 379 else
30b5b412 380 {
8d77edde 381 selected->destroy(selected);
035930fc
MW
382 DBG2(DBG_CFG, " no acceptable %N found",
383 transform_type_names, DIFFIE_HELLMAN_GROUP);
8d77edde 384 return NULL;
30b5b412 385 }
023fd8f1
MW
386 /* select if we use ESNs (has no private use space) */
387 if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size))
30b5b412 388 {
8d77edde
MW
389 if (add)
390 {
391 selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
392 }
30b5b412 393 }
8d77edde
MW
394 else
395 {
396 selected->destroy(selected);
035930fc
MW
397 DBG2(DBG_CFG, " no acceptable %N found",
398 transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
8d77edde
MW
399 return NULL;
400 }
02b3101b 401 DBG2(DBG_CFG, " proposal matches");
7daf5226 402
8d77edde
MW
403 /* apply SPI from "other" */
404 selected->set_spi(selected, other->spi);
7daf5226 405
c06dbbab
MW
406 /* everything matched, return new proposal */
407 return selected;
408}
409
d454c586
MW
410METHOD(proposal_t, get_protocol, protocol_id_t,
411 private_proposal_t *this)
c06dbbab 412{
8d77edde 413 return this->protocol;
c06dbbab
MW
414}
415
d454c586
MW
416METHOD(proposal_t, set_spi, void,
417 private_proposal_t *this, u_int64_t spi)
c06dbbab 418{
8d77edde 419 this->spi = spi;
c06dbbab
MW
420}
421
d454c586
MW
422METHOD(proposal_t, get_spi, u_int64_t,
423 private_proposal_t *this)
c06dbbab 424{
8d77edde 425 return this->spi;
c06dbbab
MW
426}
427
87a217f9
MW
428/**
429 * Clone a algorithm list
430 */
431static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
432{
433 algorithm_t *algo, *clone_algo;
3c7e72f5 434 enumerator_t *enumerator;
7daf5226 435
3c7e72f5
MW
436 enumerator = list->create_enumerator(list);
437 while (enumerator->enumerate(enumerator, &algo))
87a217f9 438 {
5113680f 439 clone_algo = malloc_thing(algorithm_t);
87a217f9
MW
440 memcpy(clone_algo, algo, sizeof(algorithm_t));
441 clone_list->insert_last(clone_list, (void*)clone_algo);
442 }
3c7e72f5
MW
443 enumerator->destroy(enumerator);
444}
445
446/**
447 * check if an algorithm list equals
448 */
449static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2)
450{
451 enumerator_t *e1, *e2;
452 algorithm_t *alg1, *alg2;
453 bool equals = TRUE;
7daf5226 454
3c7e72f5
MW
455 if (l1->get_count(l1) != l2->get_count(l2))
456 {
457 return FALSE;
458 }
7daf5226 459
3c7e72f5
MW
460 e1 = l1->create_enumerator(l1);
461 e2 = l2->create_enumerator(l2);
462 while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2))
463 {
464 if (alg1->algorithm != alg2->algorithm ||
465 alg1->key_size != alg2->key_size)
466 {
467 equals = FALSE;
468 break;
469 }
470 }
471 e1->destroy(e1);
472 e2->destroy(e2);
473 return equals;
474}
475
bb162175
MW
476METHOD(proposal_t, get_number, u_int,
477 private_proposal_t *this)
478{
479 return this->number;
480}
481
d454c586
MW
482METHOD(proposal_t, equals, bool,
483 private_proposal_t *this, proposal_t *other_pub)
3c7e72f5 484{
d454c586
MW
485 private_proposal_t *other = (private_proposal_t*)other_pub;
486
3c7e72f5
MW
487 if (this == other)
488 {
489 return TRUE;
490 }
3c7e72f5
MW
491 return (
492 algo_list_equals(this->encryption_algos, other->encryption_algos) &&
493 algo_list_equals(this->integrity_algos, other->integrity_algos) &&
494 algo_list_equals(this->prf_algos, other->prf_algos) &&
495 algo_list_equals(this->dh_groups, other->dh_groups) &&
496 algo_list_equals(this->esns, other->esns));
87a217f9
MW
497}
498
d454c586
MW
499METHOD(proposal_t, clone_, proposal_t*,
500 private_proposal_t *this)
87a217f9 501{
bb162175 502 private_proposal_t *clone;
7daf5226 503
bb162175 504 clone = (private_proposal_t*)proposal_create(this->protocol, 0);
8d77edde
MW
505 clone_algo_list(this->encryption_algos, clone->encryption_algos);
506 clone_algo_list(this->integrity_algos, clone->integrity_algos);
507 clone_algo_list(this->prf_algos, clone->prf_algos);
508 clone_algo_list(this->dh_groups, clone->dh_groups);
509 clone_algo_list(this->esns, clone->esns);
7daf5226 510
8d77edde 511 clone->spi = this->spi;
bb162175 512 clone->number = this->number;
7daf5226 513
87a217f9
MW
514 return &clone->public;
515}
516
3f730ec1
TB
517/**
518 * Checks the proposal read from a string.
519 */
520static void check_proposal(private_proposal_t *this)
521{
522 enumerator_t *e;
523 algorithm_t *alg;
524 bool all_aead = TRUE;
7daf5226 525
3f730ec1
TB
526 e = this->encryption_algos->create_enumerator(this->encryption_algos);
527 while (e->enumerate(e, &alg))
528 {
7fc4b081 529 if (!encryption_algorithm_is_aead(alg->algorithm))
3f730ec1
TB
530 {
531 all_aead = FALSE;
532 break;
533 }
534 }
535 e->destroy(e);
7daf5226 536
3f730ec1
TB
537 if (all_aead)
538 {
539 /* if all encryption algorithms in the proposal are authenticated encryption
540 * algorithms we MUST NOT propose any integrity algorithms */
035930fc
MW
541 while (this->integrity_algos->remove_last(this->integrity_algos,
542 (void**)&alg) == SUCCESS)
3f730ec1
TB
543 {
544 free(alg);
545 }
546 }
390b38b8
MW
547
548 if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
549 {
550 e = this->esns->create_enumerator(this->esns);
551 if (!e->enumerate(e, &alg))
552 { /* ESN not specified, assume not supported */
553 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
554 }
555 e->destroy(e);
556 }
3f730ec1
TB
557}
558
1fa9bdc4
MW
559/**
560 * add a algorithm identified by a string to the proposal.
1fa9bdc4 561 */
c095388f
MW
562static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
563{
433cb51b 564 const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len);
a44bb934
MW
565
566 if (token == NULL)
c095388f 567 {
a072c34a 568 DBG1(DBG_CFG, "algorithm '%.*s' not recognized", alg.len, alg.ptr);
a44bb934 569 return FAILED;
c095388f 570 }
15c508c7 571
a44bb934 572 add_algorithm(this, token->type, token->algorithm, token->keysize);
15c508c7 573
a44bb934 574 if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM)
c095388f 575 {
a44bb934
MW
576 pseudo_random_function_t prf;
577
578 switch (token->algorithm)
c095388f 579 {
a44bb934
MW
580 case AUTH_HMAC_SHA1_96:
581 prf = PRF_HMAC_SHA1;
582 break;
583 case AUTH_HMAC_SHA2_256_128:
584 prf = PRF_HMAC_SHA2_256;
585 break;
586 case AUTH_HMAC_SHA2_384_192:
587 prf = PRF_HMAC_SHA2_384;
588 break;
589 case AUTH_HMAC_SHA2_512_256:
590 prf = PRF_HMAC_SHA2_512;
591 break;
592 case AUTH_HMAC_MD5_96:
593 prf = PRF_HMAC_MD5;
594 break;
595 case AUTH_AES_XCBC_96:
596 prf = PRF_AES128_XCBC;
597 break;
c7776e0a
MW
598 case AUTH_CAMELLIA_XCBC_96:
599 prf = PRF_CAMELLIA128_XCBC;
600 break;
7daf5226 601 default:
a44bb934 602 prf = PRF_UNDEFINED;
c095388f 603 }
a44bb934 604 if (prf != PRF_UNDEFINED)
c80e8ba1 605 {
a44bb934 606 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
c80e8ba1
MW
607 }
608 }
c095388f
MW
609 return SUCCESS;
610}
611
035930fc 612/**
d25ce370 613 * print all algorithms of a kind to buffer
035930fc 614 */
090ba945 615static int print_alg(private_proposal_t *this, char **dst, size_t *len,
d25ce370 616 u_int kind, void *names, bool *first)
035930fc
MW
617{
618 enumerator_t *enumerator;
619 size_t written = 0;
620 u_int16_t alg, size;
7daf5226 621
035930fc
MW
622 enumerator = create_enumerator(this, kind);
623 while (enumerator->enumerate(enumerator, &alg, &size))
624 {
625 if (*first)
626 {
d25ce370 627 written += print_in_hook(*dst, *len, "%N", names, alg);
035930fc
MW
628 *first = FALSE;
629 }
630 else
631 {
d25ce370 632 written += print_in_hook(*dst, *len, "/%N", names, alg);
035930fc
MW
633 }
634 if (size)
635 {
e36c67ac 636 written += print_in_hook(*dst, *len, "_%u", size);
035930fc
MW
637 }
638 }
639 enumerator->destroy(enumerator);
640 return written;
641}
642
643/**
d25ce370 644 * Described in header.
035930fc 645 */
d25ce370
TB
646int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
647 const void *const *args)
035930fc
MW
648{
649 private_proposal_t *this = *((private_proposal_t**)(args[0]));
650 linked_list_t *list = *((linked_list_t**)(args[0]));
651 enumerator_t *enumerator;
652 size_t written = 0;
653 bool first = TRUE;
7daf5226 654
035930fc
MW
655 if (this == NULL)
656 {
d25ce370 657 return print_in_hook(dst, len, "(null)");
035930fc 658 }
7daf5226 659
d25ce370 660 if (spec->hash)
035930fc
MW
661 {
662 enumerator = list->create_enumerator(list);
663 while (enumerator->enumerate(enumerator, &this))
664 { /* call recursivly */
665 if (first)
666 {
d25ce370 667 written += print_in_hook(dst, len, "%P", this);
035930fc
MW
668 first = FALSE;
669 }
670 else
671 {
d25ce370 672 written += print_in_hook(dst, len, ", %P", this);
035930fc
MW
673 }
674 }
675 enumerator->destroy(enumerator);
676 return written;
677 }
7daf5226 678
d25ce370
TB
679 written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol);
680 written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM,
035930fc 681 encryption_algorithm_names, &first);
d25ce370 682 written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM,
035930fc 683 integrity_algorithm_names, &first);
d25ce370 684 written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION,
035930fc 685 pseudo_random_function_names, &first);
d25ce370 686 written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP,
035930fc 687 diffie_hellman_group_names, &first);
d25ce370 688 written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS,
035930fc
MW
689 extended_sequence_numbers_names, &first);
690 return written;
691}
692
d454c586
MW
693METHOD(proposal_t, destroy, void,
694 private_proposal_t *this)
c06dbbab 695{
55bbff11
MW
696 this->encryption_algos->destroy_function(this->encryption_algos, free);
697 this->integrity_algos->destroy_function(this->integrity_algos, free);
698 this->prf_algos->destroy_function(this->prf_algos, free);
699 this->dh_groups->destroy_function(this->dh_groups, free);
700 this->esns->destroy_function(this->esns, free);
5113680f 701 free(this);
c06dbbab
MW
702}
703
704/*
705 * Describtion in header-file
706 */
bb162175 707proposal_t *proposal_create(protocol_id_t protocol, u_int number)
c06dbbab 708{
d454c586
MW
709 private_proposal_t *this;
710
711 INIT(this,
712 .public = {
713 .add_algorithm = _add_algorithm,
714 .create_enumerator = _create_enumerator,
715 .get_algorithm = _get_algorithm,
716 .has_dh_group = _has_dh_group,
717 .strip_dh = _strip_dh,
718 .select = _select_proposal,
719 .get_protocol = _get_protocol,
720 .set_spi = _set_spi,
721 .get_spi = _get_spi,
bb162175 722 .get_number = _get_number,
d454c586
MW
723 .equals = _equals,
724 .clone = _clone_,
725 .destroy = _destroy,
726 },
727 .protocol = protocol,
bb162175 728 .number = number,
d454c586
MW
729 .encryption_algos = linked_list_create(),
730 .integrity_algos = linked_list_create(),
731 .prf_algos = linked_list_create(),
732 .dh_groups = linked_list_create(),
733 .esns = linked_list_create(),
734 );
7daf5226 735
8d77edde 736 return &this->public;
c06dbbab 737}
c095388f 738
e577ad39
MW
739/**
740 * Add supported IKE algorithms to proposal
741 */
742static void proposal_add_supported_ike(private_proposal_t *this)
743{
744 enumerator_t *enumerator;
745 encryption_algorithm_t encryption;
746 integrity_algorithm_t integrity;
747 pseudo_random_function_t prf;
748 diffie_hellman_group_t group;
5932f41f 749 const char *plugin_name;
7daf5226 750
e577ad39 751 enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
5932f41f 752 while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
e577ad39
MW
753 {
754 switch (encryption)
755 {
756 case ENCR_AES_CBC:
3b77c27a
MW
757 case ENCR_AES_CTR:
758 case ENCR_CAMELLIA_CBC:
759 case ENCR_CAMELLIA_CTR:
e577ad39
MW
760 case ENCR_AES_CCM_ICV8:
761 case ENCR_AES_CCM_ICV12:
762 case ENCR_AES_CCM_ICV16:
763 case ENCR_AES_GCM_ICV8:
764 case ENCR_AES_GCM_ICV12:
765 case ENCR_AES_GCM_ICV16:
08a5a708
MW
766 case ENCR_CAMELLIA_CCM_ICV8:
767 case ENCR_CAMELLIA_CCM_ICV12:
768 case ENCR_CAMELLIA_CCM_ICV16:
769 /* we assume that we support all AES/Camellia sizes */
770 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
771 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
772 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
773 break;
774 case ENCR_3DES:
775 add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
e577ad39
MW
776 break;
777 case ENCR_DES:
778 /* no, thanks */
779 break;
780 default:
781 break;
7daf5226 782 }
e577ad39
MW
783 }
784 enumerator->destroy(enumerator);
7daf5226 785
e577ad39 786 enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
5932f41f 787 while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
e577ad39
MW
788 {
789 switch (integrity)
790 {
791 case AUTH_HMAC_SHA1_96:
792 case AUTH_HMAC_SHA2_256_128:
793 case AUTH_HMAC_SHA2_384_192:
794 case AUTH_HMAC_SHA2_512_256:
795 case AUTH_HMAC_MD5_96:
796 case AUTH_AES_XCBC_96:
797 add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
798 break;
799 default:
800 break;
7daf5226 801 }
e577ad39
MW
802 }
803 enumerator->destroy(enumerator);
7daf5226 804
e577ad39 805 enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
5932f41f 806 while (enumerator->enumerate(enumerator, &prf, &plugin_name))
e577ad39
MW
807 {
808 switch (prf)
809 {
810 case PRF_HMAC_SHA1:
811 case PRF_HMAC_SHA2_256:
812 case PRF_HMAC_SHA2_384:
813 case PRF_HMAC_SHA2_512:
814 case PRF_HMAC_MD5:
815 case PRF_AES128_XCBC:
816 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
817 break;
818 default:
819 break;
820 }
821 }
822 enumerator->destroy(enumerator);
7daf5226 823
e577ad39 824 enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
5932f41f 825 while (enumerator->enumerate(enumerator, &group, &plugin_name))
e577ad39
MW
826 {
827 switch (group)
828 {
a20abb81
MW
829 case MODP_NULL:
830 /* only for testing purposes */
831 break;
e577ad39
MW
832 case MODP_768_BIT:
833 /* weak */
834 break;
835 case MODP_1024_BIT:
836 case MODP_1536_BIT:
837 case MODP_2048_BIT:
838 case MODP_4096_BIT:
839 case MODP_8192_BIT:
840 case ECP_256_BIT:
841 case ECP_384_BIT:
842 case ECP_521_BIT:
4590260b
MW
843 case MODP_1024_160:
844 case MODP_2048_224:
845 case MODP_2048_256:
e577ad39
MW
846 case ECP_192_BIT:
847 case ECP_224_BIT:
848 add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
849 break;
850 default:
851 break;
852 }
853 }
854 enumerator->destroy(enumerator);
855}
856
c095388f
MW
857/*
858 * Describtion in header-file
859 */
860proposal_t *proposal_create_default(protocol_id_t protocol)
861{
bb162175 862 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
7daf5226 863
c095388f
MW
864 switch (protocol)
865 {
866 case PROTO_IKE:
e577ad39 867 proposal_add_supported_ike(this);
c095388f
MW
868 break;
869 case PROTO_ESP:
9aa20fda
MW
870 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
871 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
872 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
873 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
874 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
9aa20fda 875 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
c80e8ba1 876 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
9aa20fda 877 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
9aa20fda 878 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f
MW
879 break;
880 case PROTO_AH:
9aa20fda 881 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
c80e8ba1 882 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
9aa20fda 883 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
9aa20fda 884 add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
c095388f 885 break;
3dd3c5f3
MW
886 default:
887 break;
c095388f 888 }
c095388f
MW
889 return &this->public;
890}
891
892/*
893 * Describtion in header-file
894 */
895proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
896{
bb162175 897 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
c095388f
MW
898 chunk_t string = {(void*)algs, strlen(algs)};
899 chunk_t alg;
900 status_t status = SUCCESS;
7daf5226 901
c095388f
MW
902 eat_whitespace(&string);
903 if (string.len < 1)
904 {
905 destroy(this);
906 return NULL;
907 }
7daf5226 908
c095388f
MW
909 /* get all tokens, separated by '-' */
910 while (extract_token(&alg, '-', &string))
911 {
912 status |= add_string_algo(this, alg);
913 }
914 if (string.len)
915 {
916 status |= add_string_algo(this, string);
917 }
918 if (status != SUCCESS)
919 {
920 destroy(this);
921 return NULL;
922 }
7daf5226 923
3f730ec1 924 check_proposal(this);
7daf5226 925
c095388f
MW
926 return &this->public;
927}