4 * @brief Implementation of the child_create task.
9 * Copyright (C) 2005-2007 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
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>.
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
24 #include "child_create.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>
35 typedef struct private_child_create_t private_child_create_t
;
38 * Private members of a child_create_t task.
40 struct private_child_create_t
{
43 * Public methods and task_t interface.
45 child_create_t
public;
53 * Are we the initiator?
63 * nonce chosen by peer
68 * config to create the CHILD_SA from
73 * list of proposal candidates
75 linked_list_t
*proposals
;
78 * selected proposal to use for CHILD_SA
83 * traffic selectors for initiators side
88 * traffic selectors for responders side
93 * optional diffie hellman exchange
98 * group used for DH exchange
100 diffie_hellman_group_t dh_group
;
103 * mode the new CHILD_SA uses (transport/tunnel/beet)
108 * reqid to use if we are rekeying
113 * CHILD_SA which gets established
115 child_sa_t
*child_sa
;
118 * successfully established the CHILD?
124 * get the nonce from a message
126 static status_t
get_nonce(message_t
*message
, chunk_t
*nonce
)
128 nonce_payload_t
*payload
;
130 payload
= (nonce_payload_t
*)message
->get_payload(message
, NONCE
);
135 *nonce
= payload
->get_nonce(payload
);
140 * generate a new nonce to include in a CREATE_CHILD_SA message
142 static status_t
generate_nonce(chunk_t
*nonce
)
145 randomizer_t
*randomizer
= randomizer_create();
147 status
= randomizer
->allocate_pseudo_random_bytes(randomizer
, NONCE_SIZE
,
149 randomizer
->destroy(randomizer
);
150 if (status
!= SUCCESS
)
152 DBG1(DBG_IKE
, "error generating random nonce value");
159 * Check a list of traffic selectors if any selector belongs to host
161 static bool ts_list_is_host(linked_list_t
*list
, host_t
*host
)
163 traffic_selector_t
*ts
;
165 iterator_t
*iterator
= list
->create_iterator(list
, TRUE
);
167 while (is_host
&& iterator
->iterate(iterator
, (void**)&ts
))
169 is_host
= is_host
&& ts
->is_host(ts
, host
);
171 iterator
->destroy(iterator
);
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
181 static status_t
select_and_install(private_child_create_t
*this, bool no_dh
)
183 prf_plus_t
*prf_plus
;
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
;
189 if (this->proposals
== NULL
)
191 SIG(CHILD_UP_FAILED
, "SA payload missing in message");
194 if (this->tsi
== NULL
|| this->tsr
== NULL
)
196 SIG(CHILD_UP_FAILED
, "TS payloads missing in message");
202 nonce_i
= this->my_nonce
;
203 nonce_r
= this->other_nonce
;
205 other_ts
= this->tsr
;
209 nonce_r
= this->my_nonce
;
210 nonce_i
= this->other_nonce
;
212 other_ts
= this->tsi
;
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
);
220 this->proposal
= this->config
->select_proposal(this->config
, this->proposals
,
222 if (this->proposal
== NULL
)
224 SIG(CHILD_UP_FAILED
, "no acceptable proposal found");
228 if (!this->proposal
->has_dh_group(this->proposal
, this->dh_group
))
231 if (this->proposal
->get_algorithm(this->proposal
, DIFFIE_HELLMAN_GROUP
,
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
;
243 SIG(CHILD_UP_FAILED
, "no acceptable proposal found");
252 else if (this->initiator
)
254 /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */
255 this->child_sa
->set_virtual_ip(this->child_sa
, my_vip
);
257 if (other_vip
== NULL
)
262 my_ts
= this->config
->get_traffic_selectors(this->config
, TRUE
, my_ts
,
264 other_ts
= this->config
->get_traffic_selectors(this->config
, FALSE
, other_ts
,
267 if (my_ts
->get_count(my_ts
) == 0 || other_ts
->get_count(other_ts
) == 0)
269 SIG(CHILD_UP_FAILED
, "no acceptable traffic selectors found");
273 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
274 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
278 this->tsr
= other_ts
;
283 this->tsi
= other_ts
;
286 if (!this->initiator
)
288 /* check if requested mode is acceptable, downgrade if required */
292 if (!ts_list_is_host(this->tsi
, other
) ||
293 !ts_list_is_host(this->tsr
, me
))
295 this->mode
= MODE_TUNNEL
;
296 DBG1(DBG_IKE
, "not using tranport mode, not host-to-host");
298 else if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
300 this->mode
= MODE_TUNNEL
;
301 DBG1(DBG_IKE
, "not using tranport mode, connection NATed");
305 if (!ts_list_is_host(this->tsi
, NULL
) ||
306 !ts_list_is_host(this->tsr
, NULL
))
308 this->mode
= MODE_TUNNEL
;
309 DBG1(DBG_IKE
, "not using BEET mode, not host-to-host");
319 if (this->dh
->get_shared_secret(this->dh
, &secret
) != SUCCESS
)
321 SIG(CHILD_UP_FAILED
, "DH exchange incomplete");
324 DBG3(DBG_IKE
, "DH secret %B", &secret
);
325 seed
= chunk_cata("mcc", secret
, nonce_i
, nonce_r
);
329 seed
= chunk_cata("cc", nonce_i
, nonce_r
);
331 prf_plus
= prf_plus_create(this->ike_sa
->get_child_prf(this->ike_sa
), seed
);
335 status
= this->child_sa
->update(this->child_sa
, this->proposal
,
336 this->mode
, prf_plus
);
340 status
= this->child_sa
->add(this->child_sa
, this->proposal
,
341 this->mode
, prf_plus
);
343 prf_plus
->destroy(prf_plus
);
345 if (status
!= SUCCESS
)
347 SIG(CHILD_UP_FAILED
, "unable to install IPsec SA (SAD) in kernel");
351 status
= this->child_sa
->add_policies(this->child_sa
, my_ts
, other_ts
,
354 if (status
!= SUCCESS
)
356 SIG(CHILD_UP_FAILED
, "unable to install IPsec policies (SPD) in kernel");
359 /* add to IKE_SA, and remove from task */
360 this->child_sa
->set_state(this->child_sa
, CHILD_INSTALLED
);
361 this->ike_sa
->add_child_sa(this->ike_sa
, this->child_sa
);
362 this->established
= TRUE
;
367 * build the payloads for the message
369 static void build_payloads(private_child_create_t
*this, message_t
*message
)
371 sa_payload_t
*sa_payload
;
372 nonce_payload_t
*nonce_payload
;
373 ke_payload_t
*ke_payload
;
374 ts_payload_t
*ts_payload
;
379 sa_payload
= sa_payload_create_from_proposal_list(this->proposals
);
383 sa_payload
= sa_payload_create_from_proposal(this->proposal
);
385 message
->add_payload(message
, (payload_t
*)sa_payload
);
387 /* add nonce payload if not in IKE_AUTH */
388 if (message
->get_exchange_type(message
) == CREATE_CHILD_SA
)
390 nonce_payload
= nonce_payload_create();
391 nonce_payload
->set_nonce(nonce_payload
, this->my_nonce
);
392 message
->add_payload(message
, (payload_t
*)nonce_payload
);
395 /* diffie hellman exchange, if PFS enabled */
398 ke_payload
= ke_payload_create_from_diffie_hellman(this->dh
);
399 message
->add_payload(message
, (payload_t
*)ke_payload
);
402 /* add TSi/TSr payloads */
403 ts_payload
= ts_payload_create_from_traffic_selectors(TRUE
, this->tsi
);
404 message
->add_payload(message
, (payload_t
*)ts_payload
);
405 ts_payload
= ts_payload_create_from_traffic_selectors(FALSE
, this->tsr
);
406 message
->add_payload(message
, (payload_t
*)ts_payload
);
408 /* add a notify if we are not in tunnel mode */
412 message
->add_notify(message
, FALSE
, USE_TRANSPORT_MODE
, chunk_empty
);
415 message
->add_notify(message
, FALSE
, USE_BEET_MODE
, chunk_empty
);
423 * Read payloads from message
425 static void process_payloads(private_child_create_t
*this, message_t
*message
)
427 iterator_t
*iterator
;
429 sa_payload_t
*sa_payload
;
430 ke_payload_t
*ke_payload
;
431 ts_payload_t
*ts_payload
;
432 notify_payload_t
*notify_payload
;
434 /* defaults to TUNNEL mode */
435 this->mode
= MODE_TUNNEL
;
437 iterator
= message
->get_payload_iterator(message
);
438 while (iterator
->iterate(iterator
, (void**)&payload
))
440 switch (payload
->get_type(payload
))
442 case SECURITY_ASSOCIATION
:
443 sa_payload
= (sa_payload_t
*)payload
;
444 this->proposals
= sa_payload
->get_proposals(sa_payload
);
447 ke_payload
= (ke_payload_t
*)payload
;
448 if (!this->initiator
)
450 this->dh_group
= ke_payload
->get_dh_group_number(ke_payload
);
451 this->dh
= diffie_hellman_create(this->dh_group
);
455 this->dh
->set_other_public_value(this->dh
,
456 ke_payload
->get_key_exchange_data(ke_payload
));
459 case TRAFFIC_SELECTOR_INITIATOR
:
460 ts_payload
= (ts_payload_t
*)payload
;
461 this->tsi
= ts_payload
->get_traffic_selectors(ts_payload
);
463 case TRAFFIC_SELECTOR_RESPONDER
:
464 ts_payload
= (ts_payload_t
*)payload
;
465 this->tsr
= ts_payload
->get_traffic_selectors(ts_payload
);
468 notify_payload
= (notify_payload_t
*)payload
;
469 switch (notify_payload
->get_notify_type(notify_payload
))
471 case USE_TRANSPORT_MODE
:
472 this->mode
= MODE_TRANSPORT
;
475 this->mode
= MODE_BEET
;
485 iterator
->destroy(iterator
);
489 * Implementation of task_t.build for initiator
491 static status_t
build_i(private_child_create_t
*this, message_t
*message
)
493 host_t
*me
, *other
, *vip
;
494 peer_cfg_t
*peer_cfg
;
496 switch (message
->get_exchange_type(message
))
499 return get_nonce(message
, &this->my_nonce
);
500 case CREATE_CHILD_SA
:
501 if (generate_nonce(&this->my_nonce
) != SUCCESS
)
503 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
506 if (this->dh_group
== MODP_NONE
)
508 this->dh_group
= this->config
->get_dh_group(this->config
);
512 if (!message
->get_payload(message
, ID_INITIATOR
))
514 /* send only in the first request, not in subsequent EAP */
522 SIG(CHILD_UP_START
, "establishing CHILD_SA");
524 me
= this->ike_sa
->get_my_host(this->ike_sa
);
525 other
= this->ike_sa
->get_other_host(this->ike_sa
);
526 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
527 vip
= peer_cfg
->get_virtual_ip(peer_cfg
, NULL
);
530 { /* propose a 0.0.0.0/0 subnet when we use virtual ip */
531 this->tsi
= this->config
->get_traffic_selectors(this->config
, TRUE
,
536 { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
537 this->tsi
= this->config
->get_traffic_selectors(this->config
, TRUE
,
540 this->tsr
= this->config
->get_traffic_selectors(this->config
, FALSE
,
542 this->proposals
= this->config
->get_proposals(this->config
,
543 this->dh_group
== MODP_NONE
);
544 this->mode
= this->config
->get_mode(this->config
);
546 this->child_sa
= child_sa_create(me
, other
,
547 this->ike_sa
->get_my_id(this->ike_sa
),
548 this->ike_sa
->get_other_id(this->ike_sa
),
549 this->config
, this->reqid
,
550 this->ike_sa
->is_natt_enabled(this->ike_sa
));
552 if (this->child_sa
->alloc(this->child_sa
, this->proposals
) != SUCCESS
)
554 SIG(CHILD_UP_FAILED
, "unable to allocate SPIs from kernel");
558 if (this->dh_group
!= MODP_NONE
)
560 this->dh
= diffie_hellman_create(this->dh_group
);
563 build_payloads(this, message
);
565 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
566 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
567 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
570 this->proposals
= NULL
;
576 * Implementation of task_t.process for initiator
578 static status_t
process_r(private_child_create_t
*this, message_t
*message
)
580 peer_cfg_t
*peer_cfg
;
582 switch (message
->get_exchange_type(message
))
585 return get_nonce(message
, &this->other_nonce
);
586 case CREATE_CHILD_SA
:
587 get_nonce(message
, &this->other_nonce
);
590 if (message
->get_payload(message
, ID_INITIATOR
) == NULL
)
592 /* wait until extensible authentication completed, if used */
599 process_payloads(this, message
);
601 if (this->tsi
== NULL
|| this->tsr
== NULL
)
603 DBG1(DBG_IKE
, "TS payload missing in message");
607 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
610 this->config
= peer_cfg
->select_child_cfg(peer_cfg
, this->tsr
, this->tsi
,
611 this->ike_sa
->get_my_host(this->ike_sa
),
612 this->ike_sa
->get_other_host(this->ike_sa
));
618 * Implementation of task_t.build for responder
620 static status_t
build_r(private_child_create_t
*this, message_t
*message
)
624 switch (message
->get_exchange_type(message
))
627 return get_nonce(message
, &this->my_nonce
);
628 case CREATE_CHILD_SA
:
629 if (generate_nonce(&this->my_nonce
) != SUCCESS
)
631 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
637 if (message
->get_payload(message
, EXTENSIBLE_AUTHENTICATION
))
639 /* wait until extensible authentication completed, if used */
646 if (this->ike_sa
->get_state(this->ike_sa
) == IKE_REKEYING
)
648 SIG(CHILD_UP_FAILED
, "unable to create CHILD_SA while rekeying IKE_SA");
649 message
->add_notify(message
, TRUE
, NO_ADDITIONAL_SAS
, chunk_empty
);
653 if (this->config
== NULL
)
655 SIG(CHILD_UP_FAILED
, "traffic selectors %#R=== %#R inacceptable",
656 this->tsr
, this->tsi
);
657 message
->add_notify(message
, FALSE
, TS_UNACCEPTABLE
, chunk_empty
);
661 this->child_sa
= child_sa_create(this->ike_sa
->get_my_host(this->ike_sa
),
662 this->ike_sa
->get_other_host(this->ike_sa
),
663 this->ike_sa
->get_my_id(this->ike_sa
),
664 this->ike_sa
->get_other_id(this->ike_sa
),
665 this->config
, this->reqid
,
666 this->ike_sa
->is_natt_enabled(this->ike_sa
));
668 switch (select_and_install(this, no_dh
))
673 message
->add_notify(message
, FALSE
, TS_UNACCEPTABLE
, chunk_empty
);
677 u_int16_t group
= htons(this->dh_group
);
678 message
->add_notify(message
, FALSE
, INVALID_KE_PAYLOAD
,
679 chunk_from_thing(group
));
684 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
688 build_payloads(this, message
);
690 SIG(CHILD_UP_SUCCESS
, "established CHILD_SA successfully");
696 * Implementation of task_t.process for initiator
698 static status_t
process_i(private_child_create_t
*this, message_t
*message
)
700 iterator_t
*iterator
;
704 switch (message
->get_exchange_type(message
))
707 return get_nonce(message
, &this->other_nonce
);
708 case CREATE_CHILD_SA
:
709 get_nonce(message
, &this->other_nonce
);
713 if (message
->get_payload(message
, EXTENSIBLE_AUTHENTICATION
))
715 /* wait until extensible authentication completed, if used */
722 /* check for erronous notifies */
723 iterator
= message
->get_payload_iterator(message
);
724 while (iterator
->iterate(iterator
, (void**)&payload
))
726 if (payload
->get_type(payload
) == NOTIFY
)
728 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
729 notify_type_t type
= notify
->get_notify_type(notify
);
733 /* handle notify errors related to CHILD_SA only */
734 case NO_PROPOSAL_CHOSEN
:
735 case SINGLE_PAIR_REQUIRED
:
736 case NO_ADDITIONAL_SAS
:
737 case INTERNAL_ADDRESS_FAILURE
:
738 case FAILED_CP_REQUIRED
:
739 case TS_UNACCEPTABLE
:
740 case INVALID_SELECTORS
:
742 SIG(CHILD_UP_FAILED
, "received %N notify, no CHILD_SA built",
743 notify_type_names
, type
);
744 iterator
->destroy(iterator
);
745 /* an error in CHILD_SA creation is not critical */
748 case INVALID_KE_PAYLOAD
:
751 diffie_hellman_group_t bad_group
;
753 bad_group
= this->dh_group
;
754 data
= notify
->get_notification_data(notify
);
755 this->dh_group
= ntohs(*((u_int16_t
*)data
.ptr
));
756 DBG1(DBG_IKE
, "peer didn't accept DH group %N, "
757 "it requested %N", diffie_hellman_group_names
,
758 bad_group
, diffie_hellman_group_names
, this->dh_group
);
760 this->public.task
.migrate(&this->public.task
, this->ike_sa
);
761 iterator
->destroy(iterator
);
769 iterator
->destroy(iterator
);
771 process_payloads(this, message
);
773 if (select_and_install(this, no_dh
) == SUCCESS
)
775 SIG(CHILD_UP_SUCCESS
, "established CHILD_SA successfully");
781 * Implementation of task_t.get_type
783 static task_type_t
get_type(private_child_create_t
*this)
789 * Implementation of child_create_t.use_reqid
791 static void use_reqid(private_child_create_t
*this, u_int32_t reqid
)
797 * Implementation of child_create_t.get_child
799 static child_sa_t
* get_child(private_child_create_t
*this)
801 return this->child_sa
;
805 * Implementation of child_create_t.get_lower_nonce
807 static chunk_t
get_lower_nonce(private_child_create_t
*this)
809 if (memcmp(this->my_nonce
.ptr
, this->other_nonce
.ptr
,
810 min(this->my_nonce
.len
, this->other_nonce
.len
)) < 0)
812 return this->my_nonce
;
816 return this->other_nonce
;
821 * Implementation of task_t.migrate
823 static void migrate(private_child_create_t
*this, ike_sa_t
*ike_sa
)
825 chunk_free(&this->my_nonce
);
826 chunk_free(&this->other_nonce
);
829 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
833 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
835 DESTROY_IF(this->child_sa
);
836 DESTROY_IF(this->proposal
);
837 DESTROY_IF(this->dh
);
840 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
843 this->ike_sa
= ike_sa
;
844 this->proposals
= NULL
;
848 this->child_sa
= NULL
;
849 this->mode
= MODE_TUNNEL
;
851 this->established
= FALSE
;
855 * Implementation of task_t.destroy
857 static void destroy(private_child_create_t
*this)
859 chunk_free(&this->my_nonce
);
860 chunk_free(&this->other_nonce
);
863 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
867 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
869 if (!this->established
)
871 DESTROY_IF(this->child_sa
);
873 DESTROY_IF(this->proposal
);
874 DESTROY_IF(this->dh
);
877 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
880 DESTROY_IF(this->config
);
885 * Described in header.
887 child_create_t
*child_create_create(ike_sa_t
*ike_sa
, child_cfg_t
*config
)
889 private_child_create_t
*this = malloc_thing(private_child_create_t
);
891 this->public.get_child
= (child_sa_t
*(*)(child_create_t
*))get_child
;
892 this->public.get_lower_nonce
= (chunk_t(*)(child_create_t
*))get_lower_nonce
;
893 this->public.use_reqid
= (void(*)(child_create_t
*,u_int32_t
))use_reqid
;
894 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
895 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
896 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
899 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
900 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
901 this->initiator
= TRUE
;
902 config
->get_ref(config
);
906 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
907 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
908 this->initiator
= FALSE
;
911 this->ike_sa
= ike_sa
;
912 this->config
= config
;
913 this->my_nonce
= chunk_empty
;
914 this->other_nonce
= chunk_empty
;
915 this->proposals
= NULL
;
916 this->proposal
= NULL
;
920 this->dh_group
= MODP_NONE
;
921 this->child_sa
= NULL
;
922 this->mode
= MODE_TUNNEL
;
924 this->established
= FALSE
;
926 return &this->public;