added support for 3DES encryption algorithm in IKE
[strongswan.git] / src / charon / config / proposal.c
1 /**
2 * @file proposal.c
3 *
4 * @brief Implementation of proposal_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <string.h>
24
25 #include "proposal.h"
26
27 #include <utils/linked_list.h>
28 #include <utils/identification.h>
29 #include <utils/logger.h>
30 #include <utils/lexparser.h>
31 #include <crypto/prfs/prf.h>
32 #include <crypto/crypters/crypter.h>
33 #include <crypto/signers/signer.h>
34
35
36 /**
37 * String mappings for protocol_id_t.
38 */
39 mapping_t protocol_id_m[] = {
40 {PROTO_NONE, "PROTO_NONE"},
41 {PROTO_IKE, "IKE"},
42 {PROTO_AH, "AH"},
43 {PROTO_ESP, "ESP"},
44 {MAPPING_END, NULL}
45 };
46
47 /**
48 * String mappings for transform_type_t.
49 */
50 mapping_t transform_type_m[] = {
51 {UNDEFINED_TRANSFORM_TYPE, "UNDEFINED_TRANSFORM_TYPE"},
52 {ENCRYPTION_ALGORITHM, "ENCRYPTION_ALGORITHM"},
53 {PSEUDO_RANDOM_FUNCTION, "PSEUDO_RANDOM_FUNCTION"},
54 {INTEGRITY_ALGORITHM, "INTEGRITY_ALGORITHM"},
55 {DIFFIE_HELLMAN_GROUP, "DIFFIE_HELLMAN_GROUP"},
56 {EXTENDED_SEQUENCE_NUMBERS, "EXTENDED_SEQUENCE_NUMBERS"},
57 {MAPPING_END, NULL}
58 };
59
60 /**
61 * String mappings for extended_sequence_numbers_t.
62 */
63 mapping_t extended_sequence_numbers_m[] = {
64 {NO_EXT_SEQ_NUMBERS, "NO_EXT_SEQ_NUMBERS"},
65 {EXT_SEQ_NUMBERS, "EXT_SEQ_NUMBERS"},
66 {MAPPING_END, NULL}
67 };
68
69 typedef struct private_proposal_t private_proposal_t;
70
71 /**
72 * Private data of an proposal_t object
73 */
74 struct private_proposal_t {
75
76 /**
77 * Public part
78 */
79 proposal_t public;
80
81 /**
82 * protocol (ESP or AH)
83 */
84 protocol_id_t protocol;
85
86 /**
87 * priority ordered list of encryption algorithms
88 */
89 linked_list_t *encryption_algos;
90
91 /**
92 * priority ordered list of integrity algorithms
93 */
94 linked_list_t *integrity_algos;
95
96 /**
97 * priority ordered list of pseudo random functions
98 */
99 linked_list_t *prf_algos;
100
101 /**
102 * priority ordered list of dh groups
103 */
104 linked_list_t *dh_groups;
105
106 /**
107 * priority ordered list of extended sequence number flags
108 */
109 linked_list_t *esns;
110
111 /**
112 * senders SPI
113 */
114 u_int64_t spi;
115 };
116
117 /**
118 * Add algorithm/keysize to a algorithm list
119 */
120 static void add_algo(linked_list_t *list, u_int8_t algo, size_t key_size)
121 {
122 algorithm_t *algo_key;
123
124 algo_key = malloc_thing(algorithm_t);
125 algo_key->algorithm = algo;
126 algo_key->key_size = key_size;
127 list->insert_last(list, (void*)algo_key);
128 }
129
130 /**
131 * Implements proposal_t.add_algorithm
132 */
133 static void add_algorithm(private_proposal_t *this, transform_type_t type, u_int16_t algo, size_t key_size)
134 {
135 switch (type)
136 {
137 case ENCRYPTION_ALGORITHM:
138 add_algo(this->encryption_algos, algo, key_size);
139 break;
140 case INTEGRITY_ALGORITHM:
141 add_algo(this->integrity_algos, algo, key_size);
142 break;
143 case PSEUDO_RANDOM_FUNCTION:
144 add_algo(this->prf_algos, algo, key_size);
145 break;
146 case DIFFIE_HELLMAN_GROUP:
147 add_algo(this->dh_groups, algo, 0);
148 break;
149 case EXTENDED_SEQUENCE_NUMBERS:
150 add_algo(this->esns, algo, 0);
151 break;
152 default:
153 break;
154 }
155 }
156
157 /**
158 * Implements proposal_t.get_algorithm.
159 */
160 static bool get_algorithm(private_proposal_t *this, transform_type_t type, algorithm_t** algo)
161 {
162 linked_list_t *list;
163 switch (type)
164 {
165 case ENCRYPTION_ALGORITHM:
166 list = this->encryption_algos;
167 break;
168 case INTEGRITY_ALGORITHM:
169 list = this->integrity_algos;
170 break;
171 case PSEUDO_RANDOM_FUNCTION:
172 list = this->prf_algos;
173 break;
174 case DIFFIE_HELLMAN_GROUP:
175 list = this->dh_groups;
176 break;
177 case EXTENDED_SEQUENCE_NUMBERS:
178 list = this->esns;
179 break;
180 default:
181 return FALSE;
182 }
183 if (list->get_first(list, (void**)algo) != SUCCESS)
184 {
185 return FALSE;
186 }
187 return TRUE;
188 }
189
190 /**
191 * Implements proposal_t.create_algorithm_iterator.
192 */
193 static iterator_t *create_algorithm_iterator(private_proposal_t *this, transform_type_t type)
194 {
195 switch (type)
196 {
197 case ENCRYPTION_ALGORITHM:
198 return this->encryption_algos->create_iterator(this->encryption_algos, TRUE);
199 case INTEGRITY_ALGORITHM:
200 return this->integrity_algos->create_iterator(this->integrity_algos, TRUE);
201 case PSEUDO_RANDOM_FUNCTION:
202 return this->prf_algos->create_iterator(this->prf_algos, TRUE);
203 case DIFFIE_HELLMAN_GROUP:
204 return this->dh_groups->create_iterator(this->dh_groups, TRUE);
205 case EXTENDED_SEQUENCE_NUMBERS:
206 return this->esns->create_iterator(this->esns, TRUE);
207 default:
208 break;
209 }
210 return NULL;
211 }
212
213 /**
214 * Find a matching alg/keysize in two linked lists
215 */
216 static bool select_algo(linked_list_t *first, linked_list_t *second, bool *add, u_int16_t *alg, size_t *key_size)
217 {
218 iterator_t *first_iter, *second_iter;
219 algorithm_t *first_alg, *second_alg;
220
221 /* if in both are zero algorithms specified, we HAVE a match */
222 if (first->get_count(first) == 0 && second->get_count(second) == 0)
223 {
224 *add = FALSE;
225 return TRUE;
226 }
227
228 first_iter = first->create_iterator(first, TRUE);
229 second_iter = second->create_iterator(second, TRUE);
230 /* compare algs, order of algs in "first" is preferred */
231 while (first_iter->has_next(first_iter))
232 {
233 first_iter->current(first_iter, (void**)&first_alg);
234 second_iter->reset(second_iter);
235 while (second_iter->has_next(second_iter))
236 {
237 second_iter->current(second_iter, (void**)&second_alg);
238 if (first_alg->algorithm == second_alg->algorithm &&
239 first_alg->key_size == second_alg->key_size)
240 {
241 /* ok, we have an algorithm */
242 *alg = first_alg->algorithm;
243 *key_size = first_alg->key_size;
244 *add = TRUE;
245 first_iter->destroy(first_iter);
246 second_iter->destroy(second_iter);
247 return TRUE;
248 }
249 }
250 }
251 /* no match in all comparisons */
252 first_iter->destroy(first_iter);
253 second_iter->destroy(second_iter);
254 return FALSE;
255 }
256
257 /**
258 * Implements proposal_t.select.
259 */
260 static proposal_t *select_proposal(private_proposal_t *this, private_proposal_t *other)
261 {
262 proposal_t *selected;
263 u_int16_t algo;
264 size_t key_size;
265 bool add;
266
267 /* check protocol */
268 if (this->protocol != other->protocol)
269 {
270 return NULL;
271 }
272
273 selected = proposal_create(this->protocol);
274
275 /* select encryption algorithm */
276 if (select_algo(this->encryption_algos, other->encryption_algos, &add, &algo, &key_size))
277 {
278 if (add)
279 {
280 selected->add_algorithm(selected, ENCRYPTION_ALGORITHM, algo, key_size);
281 }
282 }
283 else
284 {
285 selected->destroy(selected);
286 return NULL;
287 }
288 /* select integrity algorithm */
289 if (select_algo(this->integrity_algos, other->integrity_algos, &add, &algo, &key_size))
290 {
291 if (add)
292 {
293 selected->add_algorithm(selected, INTEGRITY_ALGORITHM, algo, key_size);
294 }
295 }
296 else
297 {
298 selected->destroy(selected);
299 return NULL;
300 }
301 /* select prf algorithm */
302 if (select_algo(this->prf_algos, other->prf_algos, &add, &algo, &key_size))
303 {
304 if (add)
305 {
306 selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION, algo, key_size);
307 }
308 }
309 else
310 {
311 selected->destroy(selected);
312 return NULL;
313 }
314 /* select a DH-group */
315 if (select_algo(this->dh_groups, other->dh_groups, &add, &algo, &key_size))
316 {
317 if (add)
318 {
319 selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
320 }
321 }
322 else
323 {
324 selected->destroy(selected);
325 return NULL;
326 }
327 /* select if we use ESNs */
328 if (select_algo(this->esns, other->esns, &add, &algo, &key_size))
329 {
330 if (add)
331 {
332 selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
333 }
334 }
335 else
336 {
337 selected->destroy(selected);
338 return NULL;
339 }
340
341 /* apply SPI from "other" */
342 selected->set_spi(selected, other->spi);
343
344 /* everything matched, return new proposal */
345 return selected;
346 }
347
348 /**
349 * Implements proposal_t.get_protocols.
350 */
351 static protocol_id_t get_protocol(private_proposal_t *this)
352 {
353 return this->protocol;
354 }
355
356 /**
357 * Implements proposal_t.set_spi.
358 */
359 static void set_spi(private_proposal_t *this, u_int64_t spi)
360 {
361 this->spi = spi;
362 }
363
364 /**
365 * Implements proposal_t.get_spi.
366 */
367 static u_int64_t get_spi(private_proposal_t *this)
368 {
369 return this->spi;
370 }
371
372 /**
373 * Clone a algorithm list
374 */
375 static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
376 {
377 algorithm_t *algo, *clone_algo;
378 iterator_t *iterator = list->create_iterator(list, TRUE);
379 while (iterator->has_next(iterator))
380 {
381 iterator->current(iterator, (void**)&algo);
382 clone_algo = malloc_thing(algorithm_t);
383 memcpy(clone_algo, algo, sizeof(algorithm_t));
384 clone_list->insert_last(clone_list, (void*)clone_algo);
385 }
386 iterator->destroy(iterator);
387 }
388
389 /**
390 * Implements proposal_t.clone
391 */
392 static proposal_t *clone(private_proposal_t *this)
393 {
394 private_proposal_t *clone = (private_proposal_t*)proposal_create(this->protocol);
395
396 clone_algo_list(this->encryption_algos, clone->encryption_algos);
397 clone_algo_list(this->integrity_algos, clone->integrity_algos);
398 clone_algo_list(this->prf_algos, clone->prf_algos);
399 clone_algo_list(this->dh_groups, clone->dh_groups);
400 clone_algo_list(this->esns, clone->esns);
401
402 clone->spi = this->spi;
403
404 return &clone->public;
405 }
406
407 /**
408 * Frees all list items and destroys the list
409 */
410 static void free_algo_list(linked_list_t *list)
411 {
412 algorithm_t *algo;
413
414 while(list->get_count(list) > 0)
415 {
416 list->remove_last(list, (void**)&algo);
417 free(algo);
418 }
419 list->destroy(list);
420 }
421
422 static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
423 {
424 if (strncmp(alg.ptr, "aes128", alg.len) == 0)
425 {
426 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
427 }
428 else if (strncmp(alg.ptr, "aes192", alg.len) == 0)
429 {
430 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
431 }
432 else if (strncmp(alg.ptr, "aes256", alg.len) == 0)
433 {
434 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
435 }
436 else if (strncmp(alg.ptr, "3des", alg.len) == 0)
437 {
438 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
439 }
440 /* blowfish only uses some predefined key sizes yet */
441 else if (strncmp(alg.ptr, "blowfish128", alg.len) == 0)
442 {
443 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128);
444 }
445 else if (strncmp(alg.ptr, "blowfish192", alg.len) == 0)
446 {
447 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192);
448 }
449 else if (strncmp(alg.ptr, "blowfish256", alg.len) == 0)
450 {
451 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
452 }
453 else if (strncmp(alg.ptr, "sha", alg.len) == 0 ||
454 strncmp(alg.ptr, "sha1", alg.len) == 0)
455 {
456 /* sha means we use SHA for both, PRF and AUTH */
457 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
458 if (this->protocol == PROTO_IKE)
459 {
460 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
461 }
462 }
463 else if (strncmp(alg.ptr, "md5", alg.len) == 0)
464 {
465 /* same for MD5 */
466 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
467 if (this->protocol == PROTO_IKE)
468 {
469 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
470 }
471 }
472 else if (strncmp(alg.ptr, "modp1024", alg.len) == 0)
473 {
474 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
475 }
476 else if (strncmp(alg.ptr, "modp1536", alg.len) == 0)
477 {
478 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
479 }
480 else if (strncmp(alg.ptr, "modp2048", alg.len) == 0)
481 {
482 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
483 }
484 else if (strncmp(alg.ptr, "modp4096", alg.len) == 0)
485 {
486 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
487 }
488 else if (strncmp(alg.ptr, "modp8192", alg.len) == 0)
489 {
490 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
491 }
492 else
493 {
494 return FAILED;
495 }
496 return SUCCESS;
497 }
498
499 /**
500 * Implements proposal_t.destroy.
501 */
502 static void destroy(private_proposal_t *this)
503 {
504 free_algo_list(this->encryption_algos);
505 free_algo_list(this->integrity_algos);
506 free_algo_list(this->prf_algos);
507 free_algo_list(this->dh_groups);
508 free_algo_list(this->esns);
509 free(this);
510 }
511
512 /*
513 * Describtion in header-file
514 */
515 proposal_t *proposal_create(protocol_id_t protocol)
516 {
517 private_proposal_t *this = malloc_thing(private_proposal_t);
518
519 this->public.add_algorithm = (void (*)(proposal_t*,transform_type_t,u_int16_t,size_t))add_algorithm;
520 this->public.create_algorithm_iterator = (iterator_t* (*)(proposal_t*,transform_type_t))create_algorithm_iterator;
521 this->public.get_algorithm = (bool (*)(proposal_t*,transform_type_t,algorithm_t**))get_algorithm;
522 this->public.select = (proposal_t* (*)(proposal_t*,proposal_t*))select_proposal;
523 this->public.get_protocol = (protocol_id_t(*)(proposal_t*))get_protocol;
524 this->public.set_spi = (void(*)(proposal_t*,u_int64_t))set_spi;
525 this->public.get_spi = (u_int64_t(*)(proposal_t*))get_spi;
526 this->public.clone = (proposal_t*(*)(proposal_t*))clone;
527 this->public.destroy = (void(*)(proposal_t*))destroy;
528
529 this->spi = 0;
530 this->protocol = protocol;
531
532 this->encryption_algos = linked_list_create();
533 this->integrity_algos = linked_list_create();
534 this->prf_algos = linked_list_create();
535 this->dh_groups = linked_list_create();
536 this->esns = linked_list_create();
537
538 return &this->public;
539 }
540
541 /*
542 * Describtion in header-file
543 */
544 proposal_t *proposal_create_default(protocol_id_t protocol)
545 {
546 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
547
548 switch (protocol)
549 {
550 case PROTO_IKE:
551 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
552 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
553 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
554 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
555 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_SHA1, 0);
556 add_algorithm(this, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0);
557 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0);
558 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0);
559 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0);
560 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0);
561 add_algorithm(this, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0);
562 break;
563 case PROTO_ESP:
564 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
565 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
566 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
567 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_3DES, 0);
568 add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256);
569 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
570 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
571 break;
572 case PROTO_AH:
573 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
574 add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0);
575 break;
576 default:
577 break;
578 }
579
580 return &this->public;
581 }
582
583 /*
584 * Describtion in header-file
585 */
586 proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
587 {
588 private_proposal_t *this = (private_proposal_t*)proposal_create(protocol);
589 chunk_t string = {(void*)algs, strlen(algs)};
590 chunk_t alg;
591 status_t status = SUCCESS;
592
593 eat_whitespace(&string);
594 if (string.len < 1)
595 {
596 destroy(this);
597 return NULL;
598 }
599
600 /* get all tokens, separated by '-' */
601 while (extract_token(&alg, '-', &string))
602 {
603 status |= add_string_algo(this, alg);
604 }
605 if (string.len)
606 {
607 status |= add_string_algo(this, string);
608 }
609 if (status != SUCCESS)
610 {
611 destroy(this);
612 return NULL;
613 }
614
615 return &this->public;
616 }