fixed responder initiated CHILD_SA rekeying when using virtual IPs
[strongswan.git] / src / charon / sa / tasks / child_create.c
1 /**
2 * @file child_create.c
3 *
4 * @brief Implementation of the child_create task.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2007 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include "child_create.h"
25
26 #include <daemon.h>
27 #include <crypto/diffie_hellman.h>
28 #include <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/ke_payload.h>
30 #include <encoding/payloads/ts_payload.h>
31 #include <encoding/payloads/nonce_payload.h>
32 #include <encoding/payloads/notify_payload.h>
33
34
35 typedef struct private_child_create_t private_child_create_t;
36
37 /**
38 * Private members of a child_create_t task.
39 */
40 struct private_child_create_t {
41
42 /**
43 * Public methods and task_t interface.
44 */
45 child_create_t public;
46
47 /**
48 * Assigned IKE_SA.
49 */
50 ike_sa_t *ike_sa;
51
52 /**
53 * Are we the initiator?
54 */
55 bool initiator;
56
57 /**
58 * nonce chosen by us
59 */
60 chunk_t my_nonce;
61
62 /**
63 * nonce chosen by peer
64 */
65 chunk_t other_nonce;
66
67 /**
68 * config to create the CHILD_SA from
69 */
70 child_cfg_t *config;
71
72 /**
73 * list of proposal candidates
74 */
75 linked_list_t *proposals;
76
77 /**
78 * selected proposal to use for CHILD_SA
79 */
80 proposal_t *proposal;
81
82 /**
83 * traffic selectors for initiators side
84 */
85 linked_list_t *tsi;
86
87 /**
88 * traffic selectors for responders side
89 */
90 linked_list_t *tsr;
91
92 /**
93 * optional diffie hellman exchange
94 */
95 diffie_hellman_t *dh;
96
97 /**
98 * group used for DH exchange
99 */
100 diffie_hellman_group_t dh_group;
101
102 /**
103 * mode the new CHILD_SA uses (transport/tunnel/beet)
104 */
105 mode_t mode;
106
107 /**
108 * reqid to use if we are rekeying
109 */
110 u_int32_t reqid;
111
112 /**
113 * CHILD_SA which gets established
114 */
115 child_sa_t *child_sa;
116
117 /**
118 * successfully established the CHILD?
119 */
120 bool established;
121 };
122
123 /**
124 * get the nonce from a message
125 */
126 static status_t get_nonce(message_t *message, chunk_t *nonce)
127 {
128 nonce_payload_t *payload;
129
130 payload = (nonce_payload_t*)message->get_payload(message, NONCE);
131 if (payload == NULL)
132 {
133 return FAILED;
134 }
135 *nonce = payload->get_nonce(payload);
136 return NEED_MORE;
137 }
138
139 /**
140 * generate a new nonce to include in a CREATE_CHILD_SA message
141 */
142 static status_t generate_nonce(chunk_t *nonce)
143 {
144 status_t status;
145 randomizer_t *randomizer = randomizer_create();
146
147 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
148 nonce);
149 randomizer->destroy(randomizer);
150 if (status != SUCCESS)
151 {
152 DBG1(DBG_IKE, "error generating random nonce value");
153 return FAILED;
154 }
155 return SUCCESS;
156 }
157
158 /**
159 * Check a list of traffic selectors if any selector belongs to host
160 */
161 static bool ts_list_is_host(linked_list_t *list, host_t *host)
162 {
163 traffic_selector_t *ts;
164 bool is_host = TRUE;
165 iterator_t *iterator = list->create_iterator(list, TRUE);
166
167 while (is_host && iterator->iterate(iterator, (void**)&ts))
168 {
169 is_host = is_host && ts->is_host(ts, host);
170 }
171 iterator->destroy(iterator);
172 return is_host;
173 }
174
175 /**
176 * Install a CHILD_SA for usage, return value:
177 * - FAILED: no acceptable proposal
178 * - INVALID_ARG: diffie hellman group inacceptable
179 * - NOT_FOUND: TS inacceptable
180 */
181 static status_t select_and_install(private_child_create_t *this, bool no_dh)
182 {
183 prf_plus_t *prf_plus;
184 status_t status;
185 chunk_t nonce_i, nonce_r, secret, seed;
186 linked_list_t *my_ts, *other_ts;
187 host_t *me, *other, *other_vip, *my_vip;
188
189 if (this->proposals == NULL)
190 {
191 SIG(CHILD_UP_FAILED, "SA payload missing in message");
192 return FAILED;
193 }
194 if (this->tsi == NULL || this->tsr == NULL)
195 {
196 SIG(CHILD_UP_FAILED, "TS payloads missing in message");
197 return NOT_FOUND;
198 }
199
200 if (this->initiator)
201 {
202 nonce_i = this->my_nonce;
203 nonce_r = this->other_nonce;
204 my_ts = this->tsi;
205 other_ts = this->tsr;
206 }
207 else
208 {
209 nonce_r = this->my_nonce;
210 nonce_i = this->other_nonce;
211 my_ts = this->tsr;
212 other_ts = this->tsi;
213 }
214
215 me = this->ike_sa->get_my_host(this->ike_sa);
216 other = this->ike_sa->get_other_host(this->ike_sa);
217 my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
218 other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
219
220 this->proposal = this->config->select_proposal(this->config, this->proposals,
221 no_dh);
222 if (this->proposal == NULL)
223 {
224 SIG(CHILD_UP_FAILED, "no acceptable proposal found");
225 return FAILED;
226 }
227
228 if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
229 {
230 algorithm_t *algo;
231 if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
232 &algo))
233 {
234 u_int16_t group = algo->algorithm;
235 SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
236 diffie_hellman_group_names, this->dh_group,
237 diffie_hellman_group_names, group);
238 this->dh_group = group;
239 return INVALID_ARG;
240 }
241 else
242 {
243 SIG(CHILD_UP_FAILED, "no acceptable proposal found");
244 return FAILED;
245 }
246 }
247
248 if (my_vip == NULL)
249 {
250 my_vip = me;
251 }
252 else if (this->initiator)
253 {
254 /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */
255 this->child_sa->set_virtual_ip(this->child_sa, my_vip);
256 }
257 if (other_vip == NULL)
258 {
259 other_vip = other;
260 }
261
262 my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts,
263 my_vip);
264 other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
265 other_vip);
266
267 if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
268 {
269 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
270 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
271 SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
272 return NOT_FOUND;
273 }
274
275 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
276 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
277 if (this->initiator)
278 {
279 this->tsi = my_ts;
280 this->tsr = other_ts;
281 }
282 else
283 {
284 this->tsr = my_ts;
285 this->tsi = other_ts;
286 }
287
288 if (!this->initiator)
289 {
290 /* check if requested mode is acceptable, downgrade if required */
291 switch (this->mode)
292 {
293 case MODE_TRANSPORT:
294 if (!ts_list_is_host(this->tsi, other) ||
295 !ts_list_is_host(this->tsr, me))
296 {
297 this->mode = MODE_TUNNEL;
298 DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
299 }
300 else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
301 {
302 this->mode = MODE_TUNNEL;
303 DBG1(DBG_IKE, "not using tranport mode, connection NATed");
304 }
305 break;
306 case MODE_BEET:
307 if (!ts_list_is_host(this->tsi, NULL) ||
308 !ts_list_is_host(this->tsr, NULL))
309 {
310 this->mode = MODE_TUNNEL;
311 DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
312 }
313 break;
314 default:
315 break;
316 }
317 }
318
319 if (this->dh)
320 {
321 if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
322 {
323 SIG(CHILD_UP_FAILED, "DH exchange incomplete");
324 return FAILED;
325 }
326 DBG3(DBG_IKE, "DH secret %B", &secret);
327 seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
328 }
329 else
330 {
331 seed = chunk_cata("cc", nonce_i, nonce_r);
332 }
333 prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
334
335 if (this->initiator)
336 {
337 status = this->child_sa->update(this->child_sa, this->proposal,
338 this->mode, prf_plus);
339 }
340 else
341 {
342 status = this->child_sa->add(this->child_sa, this->proposal,
343 this->mode, prf_plus);
344 }
345 prf_plus->destroy(prf_plus);
346
347 if (status != SUCCESS)
348 {
349 SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
350 return FAILED;
351 }
352
353 status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
354 this->mode);
355
356 if (status != SUCCESS)
357 {
358 SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
359 return NOT_FOUND;
360 }
361 /* add to IKE_SA, and remove from task */
362 this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
363 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
364 this->established = TRUE;
365 return SUCCESS;
366 }
367
368 /**
369 * build the payloads for the message
370 */
371 static void build_payloads(private_child_create_t *this, message_t *message)
372 {
373 sa_payload_t *sa_payload;
374 nonce_payload_t *nonce_payload;
375 ke_payload_t *ke_payload;
376 ts_payload_t *ts_payload;
377
378 /* add SA payload */
379 if (this->initiator)
380 {
381 sa_payload = sa_payload_create_from_proposal_list(this->proposals);
382 }
383 else
384 {
385 sa_payload = sa_payload_create_from_proposal(this->proposal);
386 }
387 message->add_payload(message, (payload_t*)sa_payload);
388
389 /* add nonce payload if not in IKE_AUTH */
390 if (message->get_exchange_type(message) == CREATE_CHILD_SA)
391 {
392 nonce_payload = nonce_payload_create();
393 nonce_payload->set_nonce(nonce_payload, this->my_nonce);
394 message->add_payload(message, (payload_t*)nonce_payload);
395 }
396
397 /* diffie hellman exchange, if PFS enabled */
398 if (this->dh)
399 {
400 ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
401 message->add_payload(message, (payload_t*)ke_payload);
402 }
403
404 /* add TSi/TSr payloads */
405 ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
406 message->add_payload(message, (payload_t*)ts_payload);
407 ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
408 message->add_payload(message, (payload_t*)ts_payload);
409
410 /* add a notify if we are not in tunnel mode */
411 switch (this->mode)
412 {
413 case MODE_TRANSPORT:
414 message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
415 break;
416 case MODE_BEET:
417 message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
418 break;
419 default:
420 break;
421 }
422 }
423
424 /**
425 * Read payloads from message
426 */
427 static void process_payloads(private_child_create_t *this, message_t *message)
428 {
429 iterator_t *iterator;
430 payload_t *payload;
431 sa_payload_t *sa_payload;
432 ke_payload_t *ke_payload;
433 ts_payload_t *ts_payload;
434 notify_payload_t *notify_payload;
435
436 /* defaults to TUNNEL mode */
437 this->mode = MODE_TUNNEL;
438
439 iterator = message->get_payload_iterator(message);
440 while (iterator->iterate(iterator, (void**)&payload))
441 {
442 switch (payload->get_type(payload))
443 {
444 case SECURITY_ASSOCIATION:
445 sa_payload = (sa_payload_t*)payload;
446 this->proposals = sa_payload->get_proposals(sa_payload);
447 break;
448 case KEY_EXCHANGE:
449 ke_payload = (ke_payload_t*)payload;
450 if (!this->initiator)
451 {
452 this->dh_group = ke_payload->get_dh_group_number(ke_payload);
453 this->dh = diffie_hellman_create(this->dh_group);
454 }
455 if (this->dh)
456 {
457 this->dh->set_other_public_value(this->dh,
458 ke_payload->get_key_exchange_data(ke_payload));
459 }
460 break;
461 case TRAFFIC_SELECTOR_INITIATOR:
462 ts_payload = (ts_payload_t*)payload;
463 this->tsi = ts_payload->get_traffic_selectors(ts_payload);
464 break;
465 case TRAFFIC_SELECTOR_RESPONDER:
466 ts_payload = (ts_payload_t*)payload;
467 this->tsr = ts_payload->get_traffic_selectors(ts_payload);
468 break;
469 case NOTIFY:
470 notify_payload = (notify_payload_t*)payload;
471 switch (notify_payload ->get_notify_type(notify_payload ))
472 {
473 case USE_TRANSPORT_MODE:
474 this->mode = MODE_TRANSPORT;
475 break;
476 case USE_BEET_MODE:
477 this->mode = MODE_BEET;
478 break;
479 default:
480 break;
481 }
482 break;
483 default:
484 break;
485 }
486 }
487 iterator->destroy(iterator);
488 }
489
490 /**
491 * Implementation of task_t.build for initiator
492 */
493 static status_t build_i(private_child_create_t *this, message_t *message)
494 {
495 host_t *me, *other, *vip;
496 bool propose_all = FALSE;
497 peer_cfg_t *peer_cfg;
498
499 switch (message->get_exchange_type(message))
500 {
501 case IKE_SA_INIT:
502 return get_nonce(message, &this->my_nonce);
503 case CREATE_CHILD_SA:
504 if (generate_nonce(&this->my_nonce) != SUCCESS)
505 {
506 message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
507 return SUCCESS;
508 }
509 if (this->dh_group == MODP_NONE)
510 {
511 this->dh_group = this->config->get_dh_group(this->config);
512 }
513 break;
514 case IKE_AUTH:
515 if (!message->get_payload(message, ID_INITIATOR))
516 {
517 /* send only in the first request, not in subsequent EAP */
518 return NEED_MORE;
519 }
520 break;
521 default:
522 break;
523 }
524
525 SIG(CHILD_UP_START, "establishing CHILD_SA");
526
527 /* reuse virtual IP if we already have one */
528 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
529 if (me == NULL)
530 {
531 me = this->ike_sa->get_my_host(this->ike_sa);
532 }
533 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
534 if (other == NULL)
535 {
536 other = this->ike_sa->get_other_host(this->ike_sa);
537 }
538
539 /* check if we want a virtual IP, but don't have one */
540 if (!this->reqid)
541 {
542 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
543 vip = peer_cfg->get_my_virtual_ip(peer_cfg);
544 if (vip)
545 {
546 propose_all = TRUE;
547 vip->destroy(vip);
548 }
549 }
550
551 if (propose_all)
552 { /* propose a 0.0.0.0/0 subnet when we use virtual ip */
553 this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
554 NULL, NULL);
555 }
556 else
557 { /* but shorten a 0.0.0.0/0 subnet for host2host/we already have a vip */
558 this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
559 NULL, me);
560 }
561 this->tsr = this->config->get_traffic_selectors(this->config, FALSE,
562 NULL, other);
563
564 this->proposals = this->config->get_proposals(this->config,
565 this->dh_group == MODP_NONE);
566 this->mode = this->config->get_mode(this->config);
567
568 this->child_sa = child_sa_create(
569 this->ike_sa->get_my_host(this->ike_sa),
570 this->ike_sa->get_other_host(this->ike_sa),
571 this->ike_sa->get_my_id(this->ike_sa),
572 this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
573 this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
574
575 if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
576 {
577 SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
578 return FAILED;
579 }
580
581 if (this->dh_group != MODP_NONE)
582 {
583 this->dh = diffie_hellman_create(this->dh_group);
584 }
585
586 build_payloads(this, message);
587
588 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
589 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
590 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
591 this->tsi = NULL;
592 this->tsr = NULL;
593 this->proposals = NULL;
594
595 return NEED_MORE;
596 }
597
598 /**
599 * Implementation of task_t.process for initiator
600 */
601 static status_t process_r(private_child_create_t *this, message_t *message)
602 {
603 peer_cfg_t *peer_cfg;
604
605 switch (message->get_exchange_type(message))
606 {
607 case IKE_SA_INIT:
608 return get_nonce(message, &this->other_nonce);
609 case CREATE_CHILD_SA:
610 get_nonce(message, &this->other_nonce);
611 break;
612 case IKE_AUTH:
613 if (message->get_payload(message, ID_INITIATOR) == NULL)
614 {
615 /* wait until extensible authentication completed, if used */
616 return NEED_MORE;
617 }
618 default:
619 break;
620 }
621
622 process_payloads(this, message);
623
624 if (this->tsi == NULL || this->tsr == NULL)
625 {
626 DBG1(DBG_IKE, "TS payload missing in message");
627 return NEED_MORE;
628 }
629
630 peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
631 if (peer_cfg)
632 {
633 host_t *me, *other;
634
635 me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
636 if (me == NULL)
637 {
638 me = this->ike_sa->get_my_host(this->ike_sa);
639 }
640 other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
641 if (other == NULL)
642 {
643 other = this->ike_sa->get_other_host(this->ike_sa);
644 }
645
646 this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr,
647 this->tsi, me, other);
648 }
649 return NEED_MORE;
650 }
651
652 /**
653 * Implementation of task_t.build for responder
654 */
655 static status_t build_r(private_child_create_t *this, message_t *message)
656 {
657 bool no_dh = TRUE;
658
659 switch (message->get_exchange_type(message))
660 {
661 case IKE_SA_INIT:
662 return get_nonce(message, &this->my_nonce);
663 case CREATE_CHILD_SA:
664 if (generate_nonce(&this->my_nonce) != SUCCESS)
665 {
666 message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
667 return SUCCESS;
668 }
669 no_dh = FALSE;
670 break;
671 case IKE_AUTH:
672 if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
673 {
674 /* wait until extensible authentication completed, if used */
675 return NEED_MORE;
676 }
677 default:
678 break;
679 }
680
681 if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
682 {
683 SIG(CHILD_UP_FAILED, "unable to create CHILD_SA while rekeying IKE_SA");
684 message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty);
685 return SUCCESS;
686 }
687
688 if (this->config == NULL)
689 {
690 SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable",
691 this->tsr, this->tsi);
692 message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
693 return SUCCESS;
694 }
695
696 this->child_sa = child_sa_create(
697 this->ike_sa->get_my_host(this->ike_sa),
698 this->ike_sa->get_other_host(this->ike_sa),
699 this->ike_sa->get_my_id(this->ike_sa),
700 this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
701 this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
702
703 switch (select_and_install(this, no_dh))
704 {
705 case SUCCESS:
706 break;
707 case NOT_FOUND:
708 message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
709 return SUCCESS;
710 case INVALID_ARG:
711 {
712 u_int16_t group = htons(this->dh_group);
713 message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
714 chunk_from_thing(group));
715 return SUCCESS;
716 }
717 case FAILED:
718 default:
719 message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
720 return SUCCESS;
721 }
722
723 build_payloads(this, message);
724
725 SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
726
727 return SUCCESS;
728 }
729
730 /**
731 * Implementation of task_t.process for initiator
732 */
733 static status_t process_i(private_child_create_t *this, message_t *message)
734 {
735 iterator_t *iterator;
736 payload_t *payload;
737 bool no_dh = TRUE;
738
739 switch (message->get_exchange_type(message))
740 {
741 case IKE_SA_INIT:
742 return get_nonce(message, &this->other_nonce);
743 case CREATE_CHILD_SA:
744 get_nonce(message, &this->other_nonce);
745 no_dh = FALSE;
746 break;
747 case IKE_AUTH:
748 if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
749 {
750 /* wait until extensible authentication completed, if used */
751 return NEED_MORE;
752 }
753 default:
754 break;
755 }
756
757 /* check for erronous notifies */
758 iterator = message->get_payload_iterator(message);
759 while (iterator->iterate(iterator, (void**)&payload))
760 {
761 if (payload->get_type(payload) == NOTIFY)
762 {
763 notify_payload_t *notify = (notify_payload_t*)payload;
764 notify_type_t type = notify->get_notify_type(notify);
765
766 switch (type)
767 {
768 /* handle notify errors related to CHILD_SA only */
769 case NO_PROPOSAL_CHOSEN:
770 case SINGLE_PAIR_REQUIRED:
771 case NO_ADDITIONAL_SAS:
772 case INTERNAL_ADDRESS_FAILURE:
773 case FAILED_CP_REQUIRED:
774 case TS_UNACCEPTABLE:
775 case INVALID_SELECTORS:
776 {
777 SIG(CHILD_UP_FAILED, "received %N notify, no CHILD_SA built",
778 notify_type_names, type);
779 iterator->destroy(iterator);
780 /* an error in CHILD_SA creation is not critical */
781 return SUCCESS;
782 }
783 case INVALID_KE_PAYLOAD:
784 {
785 chunk_t data;
786 diffie_hellman_group_t bad_group;
787
788 bad_group = this->dh_group;
789 data = notify->get_notification_data(notify);
790 this->dh_group = ntohs(*((u_int16_t*)data.ptr));
791 DBG1(DBG_IKE, "peer didn't accept DH group %N, "
792 "it requested %N", diffie_hellman_group_names,
793 bad_group, diffie_hellman_group_names, this->dh_group);
794
795 this->public.task.migrate(&this->public.task, this->ike_sa);
796 iterator->destroy(iterator);
797 return NEED_MORE;
798 }
799 default:
800 break;
801 }
802 }
803 }
804 iterator->destroy(iterator);
805
806 process_payloads(this, message);
807
808 if (select_and_install(this, no_dh) == SUCCESS)
809 {
810 SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
811 }
812 return SUCCESS;
813 }
814
815 /**
816 * Implementation of task_t.get_type
817 */
818 static task_type_t get_type(private_child_create_t *this)
819 {
820 return CHILD_CREATE;
821 }
822
823 /**
824 * Implementation of child_create_t.use_reqid
825 */
826 static void use_reqid(private_child_create_t *this, u_int32_t reqid)
827 {
828 this->reqid = reqid;
829 }
830
831 /**
832 * Implementation of child_create_t.get_child
833 */
834 static child_sa_t* get_child(private_child_create_t *this)
835 {
836 return this->child_sa;
837 }
838
839 /**
840 * Implementation of child_create_t.get_lower_nonce
841 */
842 static chunk_t get_lower_nonce(private_child_create_t *this)
843 {
844 if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
845 min(this->my_nonce.len, this->other_nonce.len)) < 0)
846 {
847 return this->my_nonce;
848 }
849 else
850 {
851 return this->other_nonce;
852 }
853 }
854
855 /**
856 * Implementation of task_t.migrate
857 */
858 static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
859 {
860 chunk_free(&this->my_nonce);
861 chunk_free(&this->other_nonce);
862 if (this->tsi)
863 {
864 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
865 }
866 if (this->tsr)
867 {
868 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
869 }
870 DESTROY_IF(this->child_sa);
871 DESTROY_IF(this->proposal);
872 DESTROY_IF(this->dh);
873 if (this->proposals)
874 {
875 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
876 }
877
878 this->ike_sa = ike_sa;
879 this->proposals = NULL;
880 this->tsi = NULL;
881 this->tsr = NULL;
882 this->dh = NULL;
883 this->child_sa = NULL;
884 this->mode = MODE_TUNNEL;
885 this->reqid = 0;
886 this->established = FALSE;
887 }
888
889 /**
890 * Implementation of task_t.destroy
891 */
892 static void destroy(private_child_create_t *this)
893 {
894 chunk_free(&this->my_nonce);
895 chunk_free(&this->other_nonce);
896 if (this->tsi)
897 {
898 this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
899 }
900 if (this->tsr)
901 {
902 this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
903 }
904 if (!this->established)
905 {
906 DESTROY_IF(this->child_sa);
907 }
908 DESTROY_IF(this->proposal);
909 DESTROY_IF(this->dh);
910 if (this->proposals)
911 {
912 this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
913 }
914
915 DESTROY_IF(this->config);
916 free(this);
917 }
918
919 /*
920 * Described in header.
921 */
922 child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config)
923 {
924 private_child_create_t *this = malloc_thing(private_child_create_t);
925
926 this->public.get_child = (child_sa_t*(*)(child_create_t*))get_child;
927 this->public.get_lower_nonce = (chunk_t(*)(child_create_t*))get_lower_nonce;
928 this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
929 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
930 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
931 this->public.task.destroy = (void(*)(task_t*))destroy;
932 if (config)
933 {
934 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
935 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
936 this->initiator = TRUE;
937 config->get_ref(config);
938 }
939 else
940 {
941 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
942 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
943 this->initiator = FALSE;
944 }
945
946 this->ike_sa = ike_sa;
947 this->config = config;
948 this->my_nonce = chunk_empty;
949 this->other_nonce = chunk_empty;
950 this->proposals = NULL;
951 this->proposal = NULL;
952 this->tsi = NULL;
953 this->tsr = NULL;
954 this->dh = NULL;
955 this->dh_group = MODP_NONE;
956 this->child_sa = NULL;
957 this->mode = MODE_TUNNEL;
958 this->reqid = 0;
959 this->established = FALSE;
960
961 return &this->public;
962 }