2 * @file create_child_sa_requested.c
4 * @brief State after a CREATE_CHILD_SA request was sent.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 #include "create_child_sa_requested.h"
27 #include <sa/child_sa.h>
28 #include <sa/states/delete_ike_sa_requested.h>
29 #include <sa/states/ike_sa_established.h>
30 #include <encoding/payloads/ts_payload.h>
31 #include <encoding/payloads/sa_payload.h>
32 #include <encoding/payloads/nonce_payload.h>
33 #include <encoding/payloads/notify_payload.h>
34 #include <utils/logger_manager.h>
37 typedef struct private_create_child_sa_requested_t private_create_child_sa_requested_t
;
40 * Private data of a create_child_sa_requested_t object.
42 struct private_create_child_sa_requested_t
{
44 * Public interface of create_child_sa_requested_t.
46 create_child_sa_requested_t
public;
51 protected_ike_sa_t
*ike_sa
;
54 * nonce chosen by initiator
59 * nonce chosen by the responder
64 * Policy to use for new child_sa
74 * Negotiated list of traffic selectors for local site
79 * Negotiated list of traffic selectors for remote site
81 linked_list_t
*other_ts
;
89 * Reqid of the old CHILD_SA, when rekeying
96 * Is logger of ike_sa!
102 * Implementation of private_create_child_sa_requested_t.process_sa_payload.
104 static status_t
process_sa_payload(private_create_child_sa_requested_t
*this, sa_payload_t
*sa_payload
)
106 proposal_t
*proposal
, *proposal_tmp
;
107 linked_list_t
*proposal_list
;
109 /* get his selected proposal */
110 proposal_list
= sa_payload
->get_proposals(sa_payload
);
111 /* check count of proposals */
112 if (proposal_list
->get_count(proposal_list
) == 0)
114 /* no proposal? we accept this, but no child sa is built */
115 this->logger
->log(this->logger
, AUDIT
, "CREATE_CHILD_SA reply contained no proposals. CHILD_SA not created");
116 proposal_list
->destroy(proposal_list
);
119 if (proposal_list
->get_count(proposal_list
) > 1)
121 this->logger
->log(this->logger
, AUDIT
, "CREATE_CHILD_SA reply contained %d proposals. Aborting",
122 proposal_list
->get_count(proposal_list
));
123 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal
) == SUCCESS
)
125 proposal
->destroy(proposal
);
127 proposal_list
->destroy(proposal_list
);
131 /* we have to re-check here if other's selection is valid */
132 proposal
= this->policy
->select_proposal(this->policy
, proposal_list
);
133 /* list not needed anymore */
134 while (proposal_list
->remove_last(proposal_list
, (void**)&proposal_tmp
) == SUCCESS
)
136 proposal_tmp
->destroy(proposal_tmp
);
138 proposal_list
->destroy(proposal_list
);
140 if (proposal
== NULL
)
142 this->logger
->log(this->logger
, AUDIT
, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
147 this->proposal
= proposal
;
153 * Implementation of private_create_child_sa_requested_t.process_ts_payload.
155 static status_t
process_ts_payload(private_create_child_sa_requested_t
*this, bool ts_initiator
, ts_payload_t
*ts_payload
)
157 linked_list_t
*ts_received
, *ts_selected
;
158 traffic_selector_t
*ts
;
160 /* get ts form payload */
161 ts_received
= ts_payload
->get_traffic_selectors(ts_payload
);
162 /* select ts depending on payload type */
165 ts_selected
= this->policy
->select_my_traffic_selectors(this->policy
, ts_received
);
166 this->my_ts
= ts_selected
;
170 ts_selected
= this->policy
->select_other_traffic_selectors(this->policy
, ts_received
);
171 this->other_ts
= ts_selected
;
173 /* check if the responder selected valid proposals */
174 if (ts_selected
->get_count(ts_selected
) != ts_received
->get_count(ts_received
))
176 this->logger
->log(this->logger
, AUDIT
, "IKE_AUTH reply contained not offered traffic selectors.");
180 while (ts_received
->remove_last(ts_received
, (void**)&ts
) == SUCCESS
)
184 ts_received
->destroy(ts_received
);
190 * Implementation of private_create_child_sa_requested_t.process_nonce_payload.
192 static status_t
process_nonce_payload(private_create_child_sa_requested_t
*this, nonce_payload_t
*nonce_request
)
194 this->nonce_r
= nonce_request
->get_nonce(nonce_request
);
199 * Process a CREATE_CHILD_SA response
201 static status_t
process_message(private_create_child_sa_requested_t
*this, message_t
*response
)
203 ts_payload_t
*tsi_request
= NULL
, *tsr_request
= NULL
;
204 sa_payload_t
*sa_request
= NULL
;
205 nonce_payload_t
*nonce_request
= NULL
;
206 ike_sa_id_t
*ike_sa_id
;
207 iterator_t
*payloads
;
212 prf_plus_t
*prf_plus
;
213 child_sa_t
*old_child_sa
;
215 this->policy
= this->ike_sa
->get_policy(this->ike_sa
);
216 if (response
->get_exchange_type(response
) != CREATE_CHILD_SA
)
218 this->logger
->log(this->logger
, ERROR
| LEVEL1
, "Message of type %s not supported in state create_child_sa_requested",
219 mapping_find(exchange_type_m
, response
->get_exchange_type(response
)));
223 if (response
->get_request(response
))
225 this->logger
->log(this->logger
, ERROR
| LEVEL1
, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
226 /* TODO: our state implementation currently can not handle incoming requests cleanly here.
227 * If a request comes in before an outstanding reply, we can not handle it the correct way.
228 * Currently, we create a ESTABLISHED state and let it process the message... But we
229 * need changes in the whole state mechanism.
231 state_t
*state
= (state_t
*)ike_sa_established_create(this->ike_sa
);
232 state
->process_message(state
, response
);
233 state
->destroy(state
);
237 /* get signer for verification and crypter for decryption */
238 ike_sa_id
= this->ike_sa
->public.get_id(&this->ike_sa
->public);
239 if (!ike_sa_id
->is_initiator(ike_sa_id
))
241 crypter
= this->ike_sa
->get_crypter_initiator(this->ike_sa
);
242 signer
= this->ike_sa
->get_signer_initiator(this->ike_sa
);
246 crypter
= this->ike_sa
->get_crypter_responder(this->ike_sa
);
247 signer
= this->ike_sa
->get_signer_responder(this->ike_sa
);
250 /* parse incoming message */
251 status
= response
->parse_body(response
, crypter
, signer
);
252 if (status
!= SUCCESS
)
254 this->logger
->log(this->logger
, AUDIT
, "CREATE_CHILD_SA r decryption failed. Ignoring message");
258 /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
259 payloads
= response
->get_payload_iterator(response
);
260 while (payloads
->has_next(payloads
))
263 payloads
->current(payloads
, (void**)&payload
);
265 switch (payload
->get_type(payload
))
267 case SECURITY_ASSOCIATION
:
269 sa_request
= (sa_payload_t
*)payload
;
272 case TRAFFIC_SELECTOR_INITIATOR
:
274 tsi_request
= (ts_payload_t
*)payload
;
277 case TRAFFIC_SELECTOR_RESPONDER
:
279 tsr_request
= (ts_payload_t
*)payload
;
284 nonce_request
= (nonce_payload_t
*)payload
;
289 /* TODO: handle notifys */
294 this->logger
->log(this->logger
, ERROR
|LEVEL1
, "Ignoring payload %s (%d)",
295 mapping_find(payload_type_m
, payload
->get_type(payload
)), payload
->get_type(payload
));
300 /* iterator can be destroyed */
301 payloads
->destroy(payloads
);
303 /* check if we have all payloads */
304 if (!(sa_request
&& nonce_request
&& tsi_request
&& tsr_request
))
306 this->logger
->log(this->logger
, AUDIT
, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
310 /* add payloads to it */
311 status
= process_nonce_payload(this, nonce_request
);
312 if (status
!= SUCCESS
)
314 response
->destroy(response
);
317 status
= process_sa_payload(this, sa_request
);
318 if (status
!= SUCCESS
)
320 response
->destroy(response
);
323 status
= process_ts_payload(this, TRUE
, tsi_request
);
324 if (status
!= SUCCESS
)
326 response
->destroy(response
);
329 status
= process_ts_payload(this, FALSE
, tsr_request
);
330 if (status
!= SUCCESS
)
332 response
->destroy(response
);
336 /* install child SAs for AH and esp */
339 this->logger
->log(this->logger
, CONTROL
, "Proposal negotiation failed, no CHILD_SA built");
340 this->child_sa
->destroy(this->child_sa
);
341 this->child_sa
= NULL
;
343 else if (this->my_ts
->get_count(this->my_ts
) == 0 || this->other_ts
->get_count(this->other_ts
) == 0)
345 this->logger
->log(this->logger
, CONTROL
, "Traffic selector negotiation failed, no CHILD_SA built");
346 this->child_sa
->destroy(this->child_sa
);
347 this->child_sa
= NULL
;
351 seed
= chunk_alloc(this->nonce_i
.len
+ this->nonce_r
.len
);
352 memcpy(seed
.ptr
, this->nonce_i
.ptr
, this->nonce_i
.len
);
353 memcpy(seed
.ptr
+ this->nonce_i
.len
, this->nonce_r
.ptr
, this->nonce_r
.len
);
354 prf_plus
= prf_plus_create(this->ike_sa
->get_child_prf(this->ike_sa
), seed
);
356 this->logger
->log_chunk(this->logger
, RAW
|LEVEL2
, "Rekey seed", seed
);
359 status
= this->child_sa
->update(this->child_sa
, this->proposal
, prf_plus
);
360 prf_plus
->destroy(prf_plus
);
361 if (status
!= SUCCESS
)
363 this->logger
->log(this->logger
, AUDIT
, "Could not install CHILD_SA! Deleting IKE_SA");
366 status
= this->child_sa
->add_policies(this->child_sa
, this->my_ts
, this->other_ts
);
367 if (status
!= SUCCESS
)
369 this->logger
->log(this->logger
, AUDIT
, "Could not install CHILD_SA policy! Deleting IKE_SA");
372 this->ike_sa
->add_child_sa(this->ike_sa
, this->child_sa
);
375 this->ike_sa
->set_last_replied_message_id(this->ike_sa
, response
->get_message_id(response
));
377 /* create new state */
378 this->ike_sa
->set_new_state(this->ike_sa
, (state_t
*)ike_sa_established_create(this->ike_sa
));
379 this->public.state_interface
.destroy(&this->public.state_interface
);
381 /* if we are rekeying, inform the old child SA that it has been superseeded and
382 * start its delete */
385 old_child_sa
= this->ike_sa
->public.get_child_sa(&this->ike_sa
->public, this->reqid
);
388 old_child_sa
->set_rekeyed(old_child_sa
);
390 this->ike_sa
->public.delete_child_sa(&this->ike_sa
->public, this->reqid
);
396 * Implements state_t.get_state
398 static ike_sa_state_t
get_state(private_create_child_sa_requested_t
*this)
400 return CREATE_CHILD_SA_REQUESTED
;
404 * Implementation of state_t.destroy.
406 static void destroy(private_create_child_sa_requested_t
*this)
408 chunk_free(&this->nonce_i
);
409 chunk_free(&this->nonce_r
);
414 * Described in header.
416 create_child_sa_requested_t
*create_child_sa_requested_create(protected_ike_sa_t
*ike_sa
, child_sa_t
*child_sa
, chunk_t nonce_i
, u_int32_t reqid
)
418 private_create_child_sa_requested_t
*this = malloc_thing(private_create_child_sa_requested_t
);
420 /* interface functions */
421 this->public.state_interface
.process_message
= (status_t (*) (state_t
*,message_t
*)) process_message
;
422 this->public.state_interface
.get_state
= (ike_sa_state_t (*) (state_t
*)) get_state
;
423 this->public.state_interface
.destroy
= (void (*) (state_t
*)) destroy
;
426 this->ike_sa
= ike_sa
;
427 this->child_sa
= child_sa
;
428 this->nonce_i
= nonce_i
;
429 this->nonce_r
= CHUNK_INITIALIZER
;
431 this->logger
= logger_manager
->get_logger(logger_manager
, IKE_SA
);
433 return &(this->public);