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 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");
275 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
276 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
280 this->tsr
= other_ts
;
285 this->tsi
= other_ts
;
288 if (!this->initiator
)
290 /* check if requested mode is acceptable, downgrade if required */
294 if (!ts_list_is_host(this->tsi
, other
) ||
295 !ts_list_is_host(this->tsr
, me
))
297 this->mode
= MODE_TUNNEL
;
298 DBG1(DBG_IKE
, "not using tranport mode, not host-to-host");
300 else if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
302 this->mode
= MODE_TUNNEL
;
303 DBG1(DBG_IKE
, "not using tranport mode, connection NATed");
307 if (!ts_list_is_host(this->tsi
, NULL
) ||
308 !ts_list_is_host(this->tsr
, NULL
))
310 this->mode
= MODE_TUNNEL
;
311 DBG1(DBG_IKE
, "not using BEET mode, not host-to-host");
321 if (this->dh
->get_shared_secret(this->dh
, &secret
) != SUCCESS
)
323 SIG(CHILD_UP_FAILED
, "DH exchange incomplete");
326 DBG3(DBG_IKE
, "DH secret %B", &secret
);
327 seed
= chunk_cata("mcc", secret
, nonce_i
, nonce_r
);
331 seed
= chunk_cata("cc", nonce_i
, nonce_r
);
333 prf_plus
= prf_plus_create(this->ike_sa
->get_child_prf(this->ike_sa
), seed
);
337 status
= this->child_sa
->update(this->child_sa
, this->proposal
,
338 this->mode
, prf_plus
);
342 status
= this->child_sa
->add(this->child_sa
, this->proposal
,
343 this->mode
, prf_plus
);
345 prf_plus
->destroy(prf_plus
);
347 if (status
!= SUCCESS
)
349 SIG(CHILD_UP_FAILED
, "unable to install IPsec SA (SAD) in kernel");
353 status
= this->child_sa
->add_policies(this->child_sa
, my_ts
, other_ts
,
356 if (status
!= SUCCESS
)
358 SIG(CHILD_UP_FAILED
, "unable to install IPsec policies (SPD) in kernel");
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
;
369 * build the payloads for the message
371 static void build_payloads(private_child_create_t
*this, message_t
*message
)
373 sa_payload_t
*sa_payload
;
374 nonce_payload_t
*nonce_payload
;
375 ke_payload_t
*ke_payload
;
376 ts_payload_t
*ts_payload
;
381 sa_payload
= sa_payload_create_from_proposal_list(this->proposals
);
385 sa_payload
= sa_payload_create_from_proposal(this->proposal
);
387 message
->add_payload(message
, (payload_t
*)sa_payload
);
389 /* add nonce payload if not in IKE_AUTH */
390 if (message
->get_exchange_type(message
) == CREATE_CHILD_SA
)
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
);
397 /* diffie hellman exchange, if PFS enabled */
400 ke_payload
= ke_payload_create_from_diffie_hellman(this->dh
);
401 message
->add_payload(message
, (payload_t
*)ke_payload
);
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
);
410 /* add a notify if we are not in tunnel mode */
414 message
->add_notify(message
, FALSE
, USE_TRANSPORT_MODE
, chunk_empty
);
417 message
->add_notify(message
, FALSE
, USE_BEET_MODE
, chunk_empty
);
425 * Read payloads from message
427 static void process_payloads(private_child_create_t
*this, message_t
*message
)
429 iterator_t
*iterator
;
431 sa_payload_t
*sa_payload
;
432 ke_payload_t
*ke_payload
;
433 ts_payload_t
*ts_payload
;
434 notify_payload_t
*notify_payload
;
436 /* defaults to TUNNEL mode */
437 this->mode
= MODE_TUNNEL
;
439 iterator
= message
->get_payload_iterator(message
);
440 while (iterator
->iterate(iterator
, (void**)&payload
))
442 switch (payload
->get_type(payload
))
444 case SECURITY_ASSOCIATION
:
445 sa_payload
= (sa_payload_t
*)payload
;
446 this->proposals
= sa_payload
->get_proposals(sa_payload
);
449 ke_payload
= (ke_payload_t
*)payload
;
450 if (!this->initiator
)
452 this->dh_group
= ke_payload
->get_dh_group_number(ke_payload
);
453 this->dh
= diffie_hellman_create(this->dh_group
);
457 this->dh
->set_other_public_value(this->dh
,
458 ke_payload
->get_key_exchange_data(ke_payload
));
461 case TRAFFIC_SELECTOR_INITIATOR
:
462 ts_payload
= (ts_payload_t
*)payload
;
463 this->tsi
= ts_payload
->get_traffic_selectors(ts_payload
);
465 case TRAFFIC_SELECTOR_RESPONDER
:
466 ts_payload
= (ts_payload_t
*)payload
;
467 this->tsr
= ts_payload
->get_traffic_selectors(ts_payload
);
470 notify_payload
= (notify_payload_t
*)payload
;
471 switch (notify_payload
->get_notify_type(notify_payload
))
473 case USE_TRANSPORT_MODE
:
474 this->mode
= MODE_TRANSPORT
;
477 this->mode
= MODE_BEET
;
487 iterator
->destroy(iterator
);
491 * Implementation of task_t.build for initiator
493 static status_t
build_i(private_child_create_t
*this, message_t
*message
)
495 host_t
*me
, *other
, *vip
;
496 peer_cfg_t
*peer_cfg
;
498 switch (message
->get_exchange_type(message
))
501 return get_nonce(message
, &this->my_nonce
);
502 case CREATE_CHILD_SA
:
503 if (generate_nonce(&this->my_nonce
) != SUCCESS
)
505 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
508 if (this->dh_group
== MODP_NONE
)
510 this->dh_group
= this->config
->get_dh_group(this->config
);
514 if (!message
->get_payload(message
, ID_INITIATOR
))
516 /* send only in the first request, not in subsequent EAP */
524 SIG(CHILD_UP_START
, "establishing CHILD_SA");
526 me
= this->ike_sa
->get_my_host(this->ike_sa
);
527 other
= this->ike_sa
->get_other_host(this->ike_sa
);
528 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
529 vip
= peer_cfg
->get_my_virtual_ip(peer_cfg
);
532 { /* propose a 0.0.0.0/0 subnet when we use virtual ip */
533 this->tsi
= this->config
->get_traffic_selectors(this->config
, TRUE
,
538 { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
539 this->tsi
= this->config
->get_traffic_selectors(this->config
, TRUE
,
542 this->tsr
= this->config
->get_traffic_selectors(this->config
, FALSE
,
544 this->proposals
= this->config
->get_proposals(this->config
,
545 this->dh_group
== MODP_NONE
);
546 this->mode
= this->config
->get_mode(this->config
);
548 this->child_sa
= child_sa_create(me
, other
,
549 this->ike_sa
->get_my_id(this->ike_sa
),
550 this->ike_sa
->get_other_id(this->ike_sa
),
551 this->config
, this->reqid
,
552 this->ike_sa
->is_natt_enabled(this->ike_sa
));
554 if (this->child_sa
->alloc(this->child_sa
, this->proposals
) != SUCCESS
)
556 SIG(CHILD_UP_FAILED
, "unable to allocate SPIs from kernel");
560 if (this->dh_group
!= MODP_NONE
)
562 this->dh
= diffie_hellman_create(this->dh_group
);
565 build_payloads(this, message
);
567 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
568 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
569 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
572 this->proposals
= NULL
;
578 * Implementation of task_t.process for initiator
580 static status_t
process_r(private_child_create_t
*this, message_t
*message
)
582 peer_cfg_t
*peer_cfg
;
584 switch (message
->get_exchange_type(message
))
587 return get_nonce(message
, &this->other_nonce
);
588 case CREATE_CHILD_SA
:
589 get_nonce(message
, &this->other_nonce
);
592 if (message
->get_payload(message
, ID_INITIATOR
) == NULL
)
594 /* wait until extensible authentication completed, if used */
601 process_payloads(this, message
);
603 if (this->tsi
== NULL
|| this->tsr
== NULL
)
605 DBG1(DBG_IKE
, "TS payload missing in message");
609 peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
612 this->config
= peer_cfg
->select_child_cfg(peer_cfg
, this->tsr
, this->tsi
,
613 this->ike_sa
->get_my_host(this->ike_sa
),
614 this->ike_sa
->get_other_host(this->ike_sa
));
620 * Implementation of task_t.build for responder
622 static status_t
build_r(private_child_create_t
*this, message_t
*message
)
626 switch (message
->get_exchange_type(message
))
629 return get_nonce(message
, &this->my_nonce
);
630 case CREATE_CHILD_SA
:
631 if (generate_nonce(&this->my_nonce
) != SUCCESS
)
633 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
639 if (message
->get_payload(message
, EXTENSIBLE_AUTHENTICATION
))
641 /* wait until extensible authentication completed, if used */
648 if (this->ike_sa
->get_state(this->ike_sa
) == IKE_REKEYING
)
650 SIG(CHILD_UP_FAILED
, "unable to create CHILD_SA while rekeying IKE_SA");
651 message
->add_notify(message
, TRUE
, NO_ADDITIONAL_SAS
, chunk_empty
);
655 if (this->config
== NULL
)
657 SIG(CHILD_UP_FAILED
, "traffic selectors %#R=== %#R inacceptable",
658 this->tsr
, this->tsi
);
659 message
->add_notify(message
, FALSE
, TS_UNACCEPTABLE
, chunk_empty
);
663 this->child_sa
= child_sa_create(this->ike_sa
->get_my_host(this->ike_sa
),
664 this->ike_sa
->get_other_host(this->ike_sa
),
665 this->ike_sa
->get_my_id(this->ike_sa
),
666 this->ike_sa
->get_other_id(this->ike_sa
),
667 this->config
, this->reqid
,
668 this->ike_sa
->is_natt_enabled(this->ike_sa
));
670 switch (select_and_install(this, no_dh
))
675 message
->add_notify(message
, FALSE
, TS_UNACCEPTABLE
, chunk_empty
);
679 u_int16_t group
= htons(this->dh_group
);
680 message
->add_notify(message
, FALSE
, INVALID_KE_PAYLOAD
,
681 chunk_from_thing(group
));
686 message
->add_notify(message
, FALSE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
690 build_payloads(this, message
);
692 SIG(CHILD_UP_SUCCESS
, "established CHILD_SA successfully");
698 * Implementation of task_t.process for initiator
700 static status_t
process_i(private_child_create_t
*this, message_t
*message
)
702 iterator_t
*iterator
;
706 switch (message
->get_exchange_type(message
))
709 return get_nonce(message
, &this->other_nonce
);
710 case CREATE_CHILD_SA
:
711 get_nonce(message
, &this->other_nonce
);
715 if (message
->get_payload(message
, EXTENSIBLE_AUTHENTICATION
))
717 /* wait until extensible authentication completed, if used */
724 /* check for erronous notifies */
725 iterator
= message
->get_payload_iterator(message
);
726 while (iterator
->iterate(iterator
, (void**)&payload
))
728 if (payload
->get_type(payload
) == NOTIFY
)
730 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
731 notify_type_t type
= notify
->get_notify_type(notify
);
735 /* handle notify errors related to CHILD_SA only */
736 case NO_PROPOSAL_CHOSEN
:
737 case SINGLE_PAIR_REQUIRED
:
738 case NO_ADDITIONAL_SAS
:
739 case INTERNAL_ADDRESS_FAILURE
:
740 case FAILED_CP_REQUIRED
:
741 case TS_UNACCEPTABLE
:
742 case INVALID_SELECTORS
:
744 SIG(CHILD_UP_FAILED
, "received %N notify, no CHILD_SA built",
745 notify_type_names
, type
);
746 iterator
->destroy(iterator
);
747 /* an error in CHILD_SA creation is not critical */
750 case INVALID_KE_PAYLOAD
:
753 diffie_hellman_group_t bad_group
;
755 bad_group
= this->dh_group
;
756 data
= notify
->get_notification_data(notify
);
757 this->dh_group
= ntohs(*((u_int16_t
*)data
.ptr
));
758 DBG1(DBG_IKE
, "peer didn't accept DH group %N, "
759 "it requested %N", diffie_hellman_group_names
,
760 bad_group
, diffie_hellman_group_names
, this->dh_group
);
762 this->public.task
.migrate(&this->public.task
, this->ike_sa
);
763 iterator
->destroy(iterator
);
771 iterator
->destroy(iterator
);
773 process_payloads(this, message
);
775 if (select_and_install(this, no_dh
) == SUCCESS
)
777 SIG(CHILD_UP_SUCCESS
, "established CHILD_SA successfully");
783 * Implementation of task_t.get_type
785 static task_type_t
get_type(private_child_create_t
*this)
791 * Implementation of child_create_t.use_reqid
793 static void use_reqid(private_child_create_t
*this, u_int32_t reqid
)
799 * Implementation of child_create_t.get_child
801 static child_sa_t
* get_child(private_child_create_t
*this)
803 return this->child_sa
;
807 * Implementation of child_create_t.get_lower_nonce
809 static chunk_t
get_lower_nonce(private_child_create_t
*this)
811 if (memcmp(this->my_nonce
.ptr
, this->other_nonce
.ptr
,
812 min(this->my_nonce
.len
, this->other_nonce
.len
)) < 0)
814 return this->my_nonce
;
818 return this->other_nonce
;
823 * Implementation of task_t.migrate
825 static void migrate(private_child_create_t
*this, ike_sa_t
*ike_sa
)
827 chunk_free(&this->my_nonce
);
828 chunk_free(&this->other_nonce
);
831 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
835 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
837 DESTROY_IF(this->child_sa
);
838 DESTROY_IF(this->proposal
);
839 DESTROY_IF(this->dh
);
842 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
845 this->ike_sa
= ike_sa
;
846 this->proposals
= NULL
;
850 this->child_sa
= NULL
;
851 this->mode
= MODE_TUNNEL
;
853 this->established
= FALSE
;
857 * Implementation of task_t.destroy
859 static void destroy(private_child_create_t
*this)
861 chunk_free(&this->my_nonce
);
862 chunk_free(&this->other_nonce
);
865 this->tsr
->destroy_offset(this->tsr
, offsetof(traffic_selector_t
, destroy
));
869 this->tsi
->destroy_offset(this->tsi
, offsetof(traffic_selector_t
, destroy
));
871 if (!this->established
)
873 DESTROY_IF(this->child_sa
);
875 DESTROY_IF(this->proposal
);
876 DESTROY_IF(this->dh
);
879 this->proposals
->destroy_offset(this->proposals
, offsetof(proposal_t
, destroy
));
882 DESTROY_IF(this->config
);
887 * Described in header.
889 child_create_t
*child_create_create(ike_sa_t
*ike_sa
, child_cfg_t
*config
)
891 private_child_create_t
*this = malloc_thing(private_child_create_t
);
893 this->public.get_child
= (child_sa_t
*(*)(child_create_t
*))get_child
;
894 this->public.get_lower_nonce
= (chunk_t(*)(child_create_t
*))get_lower_nonce
;
895 this->public.use_reqid
= (void(*)(child_create_t
*,u_int32_t
))use_reqid
;
896 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
897 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
898 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
901 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
902 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
903 this->initiator
= TRUE
;
904 config
->get_ref(config
);
908 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
909 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
910 this->initiator
= FALSE
;
913 this->ike_sa
= ike_sa
;
914 this->config
= config
;
915 this->my_nonce
= chunk_empty
;
916 this->other_nonce
= chunk_empty
;
917 this->proposals
= NULL
;
918 this->proposal
= NULL
;
922 this->dh_group
= MODP_NONE
;
923 this->child_sa
= NULL
;
924 this->mode
= MODE_TUNNEL
;
926 this->established
= FALSE
;
928 return &this->public;