stopping connectivity checks on the responders side after receiving an IKE_SA_INIT...
[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 randomizer_t *randomizer;
222 status_t status;
223
224 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
225 SIG(IKE_UP_START, "initiating IKE_SA '%s' to %H",
226 this->ike_sa->get_name(this->ike_sa),
227 this->config->get_other_host(this->config));
228 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
229
230 if (this->retry++ >= MAX_RETRIES)
231 {
232 SIG(IKE_UP_FAILED, "giving up after %d retries", MAX_RETRIES);
233 return FAILED;
234 }
235
236 /* if the DH group is set via use_dh_group(), we already have a DH object */
237 if (!this->dh)
238 {
239 this->dh_group = this->config->get_dh_group(this->config);
240 this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
241 if (this->dh == NULL)
242 {
243 SIG(IKE_UP_FAILED, "configured DH group %N not supported",
244 diffie_hellman_group_names, this->dh_group);
245 return FAILED;
246 }
247 }
248
249 /* generate nonce only when we are trying the first time */
250 if (this->my_nonce.ptr == NULL)
251 {
252 randomizer = randomizer_create();
253 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
254 &this->my_nonce);
255 randomizer->destroy(randomizer);
256 if (status != SUCCESS)
257 {
258 SIG(IKE_UP_FAILED, "error generating random nonce value");
259 return FAILED;
260 }
261 }
262
263 if (this->cookie.ptr)
264 {
265 message->add_notify(message, FALSE, COOKIE, this->cookie);
266 }
267
268 build_payloads(this, message);
269
270 #ifdef ME
271 {
272 chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa);
273 if (connect_id.ptr)
274 {
275 message->add_notify(message, FALSE, ME_CONNECTID, connect_id);
276 }
277 }
278 #endif /* ME */
279
280 return NEED_MORE;
281 }
282
283 /**
284 * Implementation of task_t.process for responder
285 */
286 static status_t process_r(private_ike_init_t *this, message_t *message)
287 {
288 randomizer_t *randomizer;
289
290 this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
291 SIG(IKE_UP_START, "%H is initiating an IKE_SA",
292 message->get_source(message));
293 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
294
295 randomizer = randomizer_create();
296 if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
297 &this->my_nonce) != SUCCESS)
298 {
299 DBG1(DBG_IKE, "error generating random nonce value");
300 }
301 randomizer->destroy(randomizer);
302
303 #ifdef ME
304 {
305 chunk_t connect_id = chunk_empty;
306 iterator_t *iterator;
307 payload_t *payload;
308
309 /* check for a ME_CONNECTID notify */
310 iterator = message->get_payload_iterator(message);
311 while (iterator->iterate(iterator, (void**)&payload))
312 {
313 if (payload->get_type(payload) == NOTIFY)
314 {
315 notify_payload_t *notify = (notify_payload_t*)payload;
316 notify_type_t type = notify->get_notify_type(notify);
317
318 switch (type)
319 {
320 case ME_CONNECTID:
321 {
322 chunk_free(&connect_id);
323 connect_id = chunk_clone(notify->get_notification_data(notify));
324 DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id);
325 break;
326 }
327 default:
328 {
329 if (type < 16383)
330 {
331 DBG1(DBG_IKE, "received %N notify error",
332 notify_type_names, type);
333 break;
334 }
335 DBG1(DBG_IKE, "received %N notify",
336 notify_type_names, type);
337 break;
338 }
339 }
340 }
341 }
342 iterator->destroy(iterator);
343
344 if (connect_id.ptr)
345 {
346 charon->connect_manager->stop_checks(charon->connect_manager,
347 connect_id);
348 chunk_free(&connect_id);
349 }
350 }
351 #endif /* ME */
352
353 process_payloads(this, message);
354
355 return NEED_MORE;
356 }
357
358 /**
359 * Implementation of task_t.build for responder
360 */
361 static status_t build_r(private_ike_init_t *this, message_t *message)
362 {
363 chunk_t secret;
364 status_t status;
365
366 /* check if we have everything we need */
367 if (this->proposal == NULL ||
368 this->other_nonce.len == 0 || this->my_nonce.len == 0)
369 {
370 SIG(IKE_UP_FAILED, "received proposals inacceptable");
371 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
372 return FAILED;
373 }
374
375 if (this->dh == NULL ||
376 !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
377 this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
378 {
379 u_int16_t group;
380
381 if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
382 &group, NULL))
383 {
384 SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
385 diffie_hellman_group_names, this->dh_group,
386 diffie_hellman_group_names, group);
387 this->dh_group = group;
388 group = htons(group);
389 message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
390 chunk_from_thing(group));
391 }
392 else
393 {
394 SIG(IKE_UP_FAILED, "no acceptable proposal found");
395 }
396 return FAILED;
397 }
398
399 if (this->old_sa)
400 {
401 ike_sa_id_t *id;
402 prf_t *prf, *child_prf;
403
404 /* Apply SPI if we are rekeying */
405 id = this->ike_sa->get_id(this->ike_sa);
406 id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
407
408 /* setup crypto keys for the rekeyed SA */
409 prf = this->old_sa->get_prf(this->old_sa);
410 child_prf = this->old_sa->get_child_prf(this->old_sa);
411 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
412 this->other_nonce, this->my_nonce,
413 FALSE, child_prf, prf);
414 }
415 else
416 {
417 /* setup crypto keys */
418 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
419 this->other_nonce, this->my_nonce,
420 FALSE, NULL, NULL);
421 }
422 if (status != SUCCESS)
423 {
424 SIG(IKE_UP_FAILED, "key derivation failed");
425 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
426 return FAILED;
427 }
428
429 build_payloads(this, message);
430
431 return SUCCESS;
432 }
433
434 /**
435 * Implementation of task_t.process for initiator
436 */
437 static status_t process_i(private_ike_init_t *this, message_t *message)
438 {
439 chunk_t secret;
440 status_t status;
441 iterator_t *iterator;
442 payload_t *payload;
443
444 /* check for erronous notifies */
445 iterator = message->get_payload_iterator(message);
446 while (iterator->iterate(iterator, (void**)&payload))
447 {
448 if (payload->get_type(payload) == NOTIFY)
449 {
450 notify_payload_t *notify = (notify_payload_t*)payload;
451 notify_type_t type = notify->get_notify_type(notify);
452
453 switch (type)
454 {
455 case INVALID_KE_PAYLOAD:
456 {
457 chunk_t data;
458 diffie_hellman_group_t bad_group;
459
460 bad_group = this->dh_group;
461 data = notify->get_notification_data(notify);
462 this->dh_group = ntohs(*((u_int16_t*)data.ptr));
463 DBG1(DBG_IKE, "peer didn't accept DH group %N, "
464 "it requested %N", diffie_hellman_group_names,
465 bad_group, diffie_hellman_group_names, this->dh_group);
466
467 if (this->old_sa == NULL)
468 { /* reset the IKE_SA if we are not rekeying */
469 this->ike_sa->reset(this->ike_sa);
470 }
471
472 iterator->destroy(iterator);
473 return NEED_MORE;
474 }
475 case NAT_DETECTION_SOURCE_IP:
476 case NAT_DETECTION_DESTINATION_IP:
477 /* skip, handled in ike_natd_t */
478 break;
479 case COOKIE:
480 {
481 chunk_free(&this->cookie);
482 this->cookie = chunk_clone(notify->get_notification_data(notify));
483 this->ike_sa->reset(this->ike_sa);
484 iterator->destroy(iterator);
485 DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
486 return NEED_MORE;
487 }
488 default:
489 {
490 if (type < 16383)
491 {
492 SIG(IKE_UP_FAILED, "received %N notify error",
493 notify_type_names, type);
494 iterator->destroy(iterator);
495 return FAILED;
496 }
497 DBG1(DBG_IKE, "received %N notify",
498 notify_type_names, type);
499 break;
500 }
501 }
502 }
503 }
504 iterator->destroy(iterator);
505
506 process_payloads(this, message);
507
508 /* check if we have everything */
509 if (this->proposal == NULL ||
510 this->other_nonce.len == 0 || this->my_nonce.len == 0)
511 {
512 SIG(IKE_UP_FAILED, "peers proposal selection invalid");
513 return FAILED;
514 }
515
516 if (this->dh == NULL ||
517 !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
518 this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
519 {
520 SIG(IKE_UP_FAILED, "peers DH group selection invalid");
521 return FAILED;
522 }
523
524 /* Apply SPI if we are rekeying */
525 if (this->old_sa)
526 {
527 ike_sa_id_t *id;
528 prf_t *prf, *child_prf;
529
530 id = this->ike_sa->get_id(this->ike_sa);
531 id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
532
533 /* setup crypto keys for the rekeyed SA */
534 prf = this->old_sa->get_prf(this->old_sa);
535 child_prf = this->old_sa->get_child_prf(this->old_sa);
536 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
537 this->my_nonce, this->other_nonce,
538 TRUE, child_prf, prf);
539 }
540 else
541 {
542 /* setup crypto keys for a new SA */
543 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
544 this->my_nonce, this->other_nonce,
545 TRUE, NULL, NULL);
546 }
547 if (status != SUCCESS)
548 {
549 SIG(IKE_UP_FAILED, "key derivation failed");
550 return FAILED;
551 }
552 return SUCCESS;
553 }
554
555 /**
556 * Implementation of task_t.get_type
557 */
558 static task_type_t get_type(private_ike_init_t *this)
559 {
560 return IKE_INIT;
561 }
562
563 /**
564 * Implementation of task_t.get_type
565 */
566 static chunk_t get_lower_nonce(private_ike_init_t *this)
567 {
568 if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
569 min(this->my_nonce.len, this->other_nonce.len)) < 0)
570 {
571 return this->my_nonce;
572 }
573 else
574 {
575 return this->other_nonce;
576 }
577 }
578
579 /**
580 * Implementation of task_t.migrate
581 */
582 static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
583 {
584 DESTROY_IF(this->proposal);
585 DESTROY_IF(this->dh);
586 chunk_free(&this->other_nonce);
587
588 this->ike_sa = ike_sa;
589 this->proposal = NULL;
590 this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
591 }
592
593 /**
594 * Implementation of task_t.destroy
595 */
596 static void destroy(private_ike_init_t *this)
597 {
598 DESTROY_IF(this->proposal);
599 DESTROY_IF(this->dh);
600 chunk_free(&this->my_nonce);
601 chunk_free(&this->other_nonce);
602 chunk_free(&this->cookie);
603 free(this);
604 }
605
606 /*
607 * Described in header.
608 */
609 ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
610 {
611 private_ike_init_t *this = malloc_thing(private_ike_init_t);
612
613 this->public.get_lower_nonce = (chunk_t(*)(ike_init_t*))get_lower_nonce;
614 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
615 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
616 this->public.task.destroy = (void(*)(task_t*))destroy;
617 if (initiator)
618 {
619 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
620 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
621 }
622 else
623 {
624 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
625 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
626 }
627
628 this->ike_sa = ike_sa;
629 this->initiator = initiator;
630 this->dh_group = MODP_NONE;
631 this->dh = NULL;
632 this->my_nonce = chunk_empty;
633 this->other_nonce = chunk_empty;
634 this->cookie = chunk_empty;
635 this->proposal = NULL;
636 this->config = NULL;
637 this->old_sa = old_sa;
638 this->retry = 0;
639
640 return &this->public;
641 }