DNS resolving of ike_cfg hosts dynamically on demand
[strongswan.git] / src / charon / sa / tasks / ike_init.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * $Id$
18 */
19
20 #include "ike_init.h"
21
22 #include <string.h>
23
24 #include <daemon.h>
25 #include <crypto/diffie_hellman.h>
26 #include <encoding/payloads/sa_payload.h>
27 #include <encoding/payloads/ke_payload.h>
28 #include <encoding/payloads/nonce_payload.h>
29
30 /** maximum retries to do with cookies/other dh groups */
31 #define MAX_RETRIES 5
32
33 typedef struct private_ike_init_t private_ike_init_t;
34
35 /**
36 * Private members of a ike_init_t task.
37 */
38 struct private_ike_init_t {
39
40 /**
41 * Public methods and task_t interface.
42 */
43 ike_init_t public;
44
45 /**
46 * Assigned IKE_SA.
47 */
48 ike_sa_t *ike_sa;
49
50 /**
51 * Are we the initiator?
52 */
53 bool initiator;
54
55 /**
56 * IKE config to establish
57 */
58 ike_cfg_t *config;
59
60 /**
61 * diffie hellman group to use
62 */
63 diffie_hellman_group_t dh_group;
64
65 /**
66 * Diffie hellman object used to generate public DH value.
67 */
68 diffie_hellman_t *dh;
69
70 /**
71 * nonce chosen by us
72 */
73 chunk_t my_nonce;
74
75 /**
76 * nonce chosen by peer
77 */
78 chunk_t other_nonce;
79
80 /**
81 * Negotiated proposal used for IKE_SA
82 */
83 proposal_t *proposal;
84
85 /**
86 * Old IKE_SA which gets rekeyed
87 */
88 ike_sa_t *old_sa;
89
90 /**
91 * cookie received from responder
92 */
93 chunk_t cookie;
94
95 /**
96 * retries done so far after failure (cookie or bad dh group)
97 */
98 u_int retry;
99 };
100
101 /**
102 * build the payloads for the message
103 */
104 static void build_payloads(private_ike_init_t *this, message_t *message)
105 {
106 sa_payload_t *sa_payload;
107 ke_payload_t *ke_payload;
108 nonce_payload_t *nonce_payload;
109 linked_list_t *proposal_list;
110 ike_sa_id_t *id;
111 proposal_t *proposal;
112 iterator_t *iterator;
113
114 id = this->ike_sa->get_id(this->ike_sa);
115
116 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
117
118 if (this->initiator)
119 {
120 proposal_list = this->config->get_proposals(this->config);
121 if (this->old_sa)
122 {
123 /* include SPI of new IKE_SA when we are rekeying */
124 iterator = proposal_list->create_iterator(proposal_list, TRUE);
125 while (iterator->iterate(iterator, (void**)&proposal))
126 {
127 proposal->set_spi(proposal, id->get_initiator_spi(id));
128 }
129 iterator->destroy(iterator);
130 }
131
132 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
133 proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
134 }
135 else
136 {
137 if (this->old_sa)
138 {
139 /* include SPI of new IKE_SA when we are rekeying */
140 this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
141 }
142 sa_payload = sa_payload_create_from_proposal(this->proposal);
143 }
144 message->add_payload(message, (payload_t*)sa_payload);
145
146 nonce_payload = nonce_payload_create();
147 nonce_payload->set_nonce(nonce_payload, this->my_nonce);
148 ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
149
150 if (this->old_sa)
151 { /* payload order differs if we are rekeying */
152 message->add_payload(message, (payload_t*)nonce_payload);
153 message->add_payload(message, (payload_t*)ke_payload);
154 }
155 else
156 {
157 message->add_payload(message, (payload_t*)ke_payload);
158 message->add_payload(message, (payload_t*)nonce_payload);
159 }
160 }
161
162 /**
163 * Read payloads from message
164 */
165 static void process_payloads(private_ike_init_t *this, message_t *message)
166 {
167 iterator_t *iterator;
168 payload_t *payload;
169
170 iterator = message->get_payload_iterator(message);
171 while (iterator->iterate(iterator, (void**)&payload))
172 {
173 switch (payload->get_type(payload))
174 {
175 case SECURITY_ASSOCIATION:
176 {
177 sa_payload_t *sa_payload = (sa_payload_t*)payload;
178 linked_list_t *proposal_list;
179
180 proposal_list = sa_payload->get_proposals(sa_payload);
181 this->proposal = this->config->select_proposal(this->config,
182 proposal_list);
183 proposal_list->destroy_offset(proposal_list,
184 offsetof(proposal_t, destroy));
185 break;
186 }
187 case KEY_EXCHANGE:
188 {
189 ke_payload_t *ke_payload = (ke_payload_t*)payload;
190
191 this->dh_group = ke_payload->get_dh_group_number(ke_payload);
192 if (!this->initiator)
193 {
194 this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
195 }
196 if (this->dh)
197 {
198 this->dh->set_other_public_value(this->dh,
199 ke_payload->get_key_exchange_data(ke_payload));
200 }
201 break;
202 }
203 case NONCE:
204 {
205 nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
206 this->other_nonce = nonce_payload->get_nonce(nonce_payload);
207 break;
208 }
209 default:
210 break;
211 }
212 }
213 iterator->destroy(iterator);
214 }
215
216 /**
217 * Implementation of task_t.process for initiator
218 */
219 static status_t build_i(private_ike_init_t *this, message_t *message)
220 {
221 rng_t *rng;
222
223 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
224 SIG(IKE_UP_START, "initiating IKE_SA '%s' to %H",
225 this->ike_sa->get_name(this->ike_sa),
226 this->ike_sa->get_other_host(this->ike_sa));
227 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
228
229 if (this->retry++ >= MAX_RETRIES)
230 {
231 SIG(IKE_UP_FAILED, "giving up after %d retries", MAX_RETRIES);
232 return FAILED;
233 }
234
235 /* if the DH group is set via use_dh_group(), we already have a DH object */
236 if (!this->dh)
237 {
238 this->dh_group = this->config->get_dh_group(this->config);
239 this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
240 if (this->dh == NULL)
241 {
242 SIG(IKE_UP_FAILED, "configured DH group %N not supported",
243 diffie_hellman_group_names, this->dh_group);
244 return FAILED;
245 }
246 }
247
248 /* generate nonce only when we are trying the first time */
249 if (this->my_nonce.ptr == NULL)
250 {
251 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
252 if (!rng)
253 {
254 SIG(IKE_UP_FAILED, "error generating nonce");
255 return FAILED;
256 }
257 rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce);
258 rng->destroy(rng);
259 }
260
261 if (this->cookie.ptr)
262 {
263 message->add_notify(message, FALSE, COOKIE, this->cookie);
264 }
265
266 build_payloads(this, message);
267
268 #ifdef ME
269 {
270 chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa);
271 if (connect_id.ptr)
272 {
273 message->add_notify(message, FALSE, ME_CONNECTID, connect_id);
274 }
275 }
276 #endif /* ME */
277
278 return NEED_MORE;
279 }
280
281 /**
282 * Implementation of task_t.process for responder
283 */
284 static status_t process_r(private_ike_init_t *this, message_t *message)
285 {
286 rng_t *rng;
287
288 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
289 SIG(IKE_UP_START, "%H is initiating an IKE_SA",
290 message->get_source(message));
291 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
292
293 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
294 if (!rng)
295 {
296 DBG1(DBG_IKE, "error generating nonce");
297 return FAILED;
298 }
299 rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce);
300 rng->destroy(rng);
301
302 #ifdef ME
303 {
304 chunk_t connect_id = chunk_empty;
305 iterator_t *iterator;
306 payload_t *payload;
307
308 /* check for a ME_CONNECTID notify */
309 iterator = message->get_payload_iterator(message);
310 while (iterator->iterate(iterator, (void**)&payload))
311 {
312 if (payload->get_type(payload) == NOTIFY)
313 {
314 notify_payload_t *notify = (notify_payload_t*)payload;
315 notify_type_t type = notify->get_notify_type(notify);
316
317 switch (type)
318 {
319 case ME_CONNECTID:
320 {
321 chunk_free(&connect_id);
322 connect_id = chunk_clone(notify->get_notification_data(notify));
323 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id);
324 break;
325 }
326 default:
327 {
328 if (type < 16383)
329 {
330 DBG1(DBG_IKE, "received %N notify error",
331 notify_type_names, type);
332 break;
333 }
334 DBG2(DBG_IKE, "received %N notify",
335 notify_type_names, type);
336 break;
337 }
338 }
339 }
340 }
341 iterator->destroy(iterator);
342
343 if (connect_id.ptr)
344 {
345 charon->connect_manager->stop_checks(charon->connect_manager,
346 connect_id);
347 chunk_free(&connect_id);
348 }
349 }
350 #endif /* ME */
351
352 process_payloads(this, message);
353
354 return NEED_MORE;
355 }
356
357 /**
358 * Implementation of task_t.build for responder
359 */
360 static status_t build_r(private_ike_init_t *this, message_t *message)
361 {
362 chunk_t secret;
363 status_t status;
364
365 /* check if we have everything we need */
366 if (this->proposal == NULL ||
367 this->other_nonce.len == 0 || this->my_nonce.len == 0)
368 {
369 SIG(IKE_UP_FAILED, "received proposals inacceptable");
370 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
371 return FAILED;
372 }
373
374 if (this->dh == NULL ||
375 !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
376 this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
377 {
378 u_int16_t group;
379
380 if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
381 &group, NULL))
382 {
383 SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
384 diffie_hellman_group_names, this->dh_group,
385 diffie_hellman_group_names, group);
386 this->dh_group = group;
387 group = htons(group);
388 message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
389 chunk_from_thing(group));
390 }
391 else
392 {
393 SIG(IKE_UP_FAILED, "no acceptable proposal found");
394 }
395 return FAILED;
396 }
397
398 if (this->old_sa)
399 {
400 ike_sa_id_t *id;
401 prf_t *prf, *child_prf;
402
403 /* Apply SPI if we are rekeying */
404 id = this->ike_sa->get_id(this->ike_sa);
405 id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
406
407 /* setup crypto keys for the rekeyed SA */
408 prf = this->old_sa->get_prf(this->old_sa);
409 child_prf = this->old_sa->get_child_prf(this->old_sa);
410 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
411 this->other_nonce, this->my_nonce,
412 FALSE, child_prf, prf);
413 }
414 else
415 {
416 /* setup crypto keys */
417 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
418 this->other_nonce, this->my_nonce,
419 FALSE, NULL, NULL);
420 }
421 if (status != SUCCESS)
422 {
423 SIG(IKE_UP_FAILED, "key derivation failed");
424 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
425 return FAILED;
426 }
427
428 build_payloads(this, message);
429
430 return SUCCESS;
431 }
432
433 /**
434 * Implementation of task_t.process for initiator
435 */
436 static status_t process_i(private_ike_init_t *this, message_t *message)
437 {
438 chunk_t secret;
439 status_t status;
440 iterator_t *iterator;
441 payload_t *payload;
442
443 /* check for erronous notifies */
444 iterator = message->get_payload_iterator(message);
445 while (iterator->iterate(iterator, (void**)&payload))
446 {
447 if (payload->get_type(payload) == NOTIFY)
448 {
449 notify_payload_t *notify = (notify_payload_t*)payload;
450 notify_type_t type = notify->get_notify_type(notify);
451
452 switch (type)
453 {
454 case INVALID_KE_PAYLOAD:
455 {
456 chunk_t data;
457 diffie_hellman_group_t bad_group;
458
459 bad_group = this->dh_group;
460 data = notify->get_notification_data(notify);
461 this->dh_group = ntohs(*((u_int16_t*)data.ptr));
462 DBG1(DBG_IKE, "peer didn't accept DH group %N, "
463 "it requested %N", diffie_hellman_group_names,
464 bad_group, diffie_hellman_group_names, this->dh_group);
465
466 if (this->old_sa == NULL)
467 { /* reset the IKE_SA if we are not rekeying */
468 this->ike_sa->reset(this->ike_sa);
469 }
470
471 iterator->destroy(iterator);
472 return NEED_MORE;
473 }
474 case NAT_DETECTION_SOURCE_IP:
475 case NAT_DETECTION_DESTINATION_IP:
476 /* skip, handled in ike_natd_t */
477 break;
478 case COOKIE:
479 {
480 chunk_free(&this->cookie);
481 this->cookie = chunk_clone(notify->get_notification_data(notify));
482 this->ike_sa->reset(this->ike_sa);
483 iterator->destroy(iterator);
484 DBG2(DBG_IKE, "received %N notify", notify_type_names, type);
485 return NEED_MORE;
486 }
487 default:
488 {
489 if (type < 16383)
490 {
491 SIG(IKE_UP_FAILED, "received %N notify error",
492 notify_type_names, type);
493 iterator->destroy(iterator);
494 return FAILED;
495 }
496 DBG2(DBG_IKE, "received %N notify",
497 notify_type_names, type);
498 break;
499 }
500 }
501 }
502 }
503 iterator->destroy(iterator);
504
505 process_payloads(this, message);
506
507 /* check if we have everything */
508 if (this->proposal == NULL ||
509 this->other_nonce.len == 0 || this->my_nonce.len == 0)
510 {
511 SIG(IKE_UP_FAILED, "peers proposal selection invalid");
512 return FAILED;
513 }
514
515 if (this->dh == NULL ||
516 !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
517 this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
518 {
519 SIG(IKE_UP_FAILED, "peers DH group selection invalid");
520 return FAILED;
521 }
522
523 /* Apply SPI if we are rekeying */
524 if (this->old_sa)
525 {
526 ike_sa_id_t *id;
527 prf_t *prf, *child_prf;
528
529 id = this->ike_sa->get_id(this->ike_sa);
530 id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
531
532 /* setup crypto keys for the rekeyed SA */
533 prf = this->old_sa->get_prf(this->old_sa);
534 child_prf = this->old_sa->get_child_prf(this->old_sa);
535 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
536 this->my_nonce, this->other_nonce,
537 TRUE, child_prf, prf);
538 }
539 else
540 {
541 /* setup crypto keys for a new SA */
542 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
543 this->my_nonce, this->other_nonce,
544 TRUE, NULL, NULL);
545 }
546 if (status != SUCCESS)
547 {
548 SIG(IKE_UP_FAILED, "key derivation failed");
549 return FAILED;
550 }
551 return SUCCESS;
552 }
553
554 /**
555 * Implementation of task_t.get_type
556 */
557 static task_type_t get_type(private_ike_init_t *this)
558 {
559 return IKE_INIT;
560 }
561
562 /**
563 * Implementation of task_t.get_type
564 */
565 static chunk_t get_lower_nonce(private_ike_init_t *this)
566 {
567 if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
568 min(this->my_nonce.len, this->other_nonce.len)) < 0)
569 {
570 return this->my_nonce;
571 }
572 else
573 {
574 return this->other_nonce;
575 }
576 }
577
578 /**
579 * Implementation of task_t.migrate
580 */
581 static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
582 {
583 DESTROY_IF(this->proposal);
584 DESTROY_IF(this->dh);
585 chunk_free(&this->other_nonce);
586
587 this->ike_sa = ike_sa;
588 this->proposal = NULL;
589 this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
590 }
591
592 /**
593 * Implementation of task_t.destroy
594 */
595 static void destroy(private_ike_init_t *this)
596 {
597 DESTROY_IF(this->proposal);
598 DESTROY_IF(this->dh);
599 chunk_free(&this->my_nonce);
600 chunk_free(&this->other_nonce);
601 chunk_free(&this->cookie);
602 free(this);
603 }
604
605 /*
606 * Described in header.
607 */
608 ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
609 {
610 private_ike_init_t *this = malloc_thing(private_ike_init_t);
611
612 this->public.get_lower_nonce = (chunk_t(*)(ike_init_t*))get_lower_nonce;
613 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
614 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
615 this->public.task.destroy = (void(*)(task_t*))destroy;
616 if (initiator)
617 {
618 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
619 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
620 }
621 else
622 {
623 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
624 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
625 }
626
627 this->ike_sa = ike_sa;
628 this->initiator = initiator;
629 this->dh_group = MODP_NONE;
630 this->dh = NULL;
631 this->my_nonce = chunk_empty;
632 this->other_nonce = chunk_empty;
633 this->cookie = chunk_empty;
634 this->proposal = NULL;
635 this->config = NULL;
636 this->old_sa = old_sa;
637 this->retry = 0;
638
639 return &this->public;
640 }