]>
Commit | Line | Data |
---|---|---|
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 |
31 | ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP, |
32 | "PROTO_NONE", | |
33 | "IKE", | |
34 | "AH", | |
35 | "ESP", | |
36 | ); | |
c06dbbab | 37 | |
8d77edde | 38 | typedef struct private_proposal_t private_proposal_t; |
3c7e72f5 | 39 | typedef struct algorithm_t algorithm_t; |
c06dbbab MW |
40 | |
41 | /** | |
8d77edde | 42 | * Private data of an proposal_t object |
c06dbbab | 43 | */ |
8d77edde MW |
44 | struct 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 | */ |
95 | struct 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 | 110 | static 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 |
120 | METHOD(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 | */ | |
149 | static 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 |
161 | METHOD(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 |
190 | METHOD(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 |
206 | METHOD(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**)¤t)) | |
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 |
234 | METHOD(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 |
248 | static 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 |
296 | METHOD(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 |
410 | METHOD(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 |
416 | METHOD(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 |
422 | METHOD(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 | */ | |
431 | static 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 | */ | |
449 | static 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 |
476 | METHOD(proposal_t, get_number, u_int, |
477 | private_proposal_t *this) | |
478 | { | |
479 | return this->number; | |
480 | } | |
481 | ||
d454c586 MW |
482 | METHOD(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 |
499 | METHOD(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 | */ | |
520 | static 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 |
562 | static 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 | 615 | static 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 |
646 | int 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 |
693 | METHOD(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 | 707 | proposal_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 | */ | |
742 | static 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 | */ | |
860 | proposal_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 | */ | |
895 | proposal_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 | } |