fixed SPI when rekeying and deleting CHILD_SAs
[strongswan.git] / src / charon / sa / states / create_child_sa_requested.c
1 /**
2 * @file create_child_sa_requested.c
3 *
4 * @brief State after a CREATE_CHILD_SA request was sent.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include <string.h>
24
25 #include "create_child_sa_requested.h"
26
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>
35
36
37 typedef struct private_create_child_sa_requested_t private_create_child_sa_requested_t;
38
39 /**
40 * Private data of a create_child_sa_requested_t object.
41 */
42 struct private_create_child_sa_requested_t {
43 /**
44 * Public interface of create_child_sa_requested_t.
45 */
46 create_child_sa_requested_t public;
47
48 /**
49 * Assigned IKE_SA.
50 */
51 protected_ike_sa_t *ike_sa;
52
53 /**
54 * nonce chosen by initiator
55 */
56 chunk_t nonce_i;
57
58 /**
59 * nonce chosen by the responder
60 */
61 chunk_t nonce_r;
62
63 /**
64 * Policy to use for new child_sa
65 */
66 policy_t *policy;
67
68 /**
69 * Proposal negotiated
70 */
71 proposal_t *proposal;
72
73 /**
74 * Negotiated list of traffic selectors for local site
75 */
76 linked_list_t *my_ts;
77
78 /**
79 * Negotiated list of traffic selectors for remote site
80 */
81 linked_list_t *other_ts;
82
83 /**
84 * Child SA to create
85 */
86 child_sa_t *child_sa;
87
88 /**
89 * Reqid of the old CHILD_SA, when rekeying
90 */
91 u_int32_t reqid;
92
93 /**
94 * Assigned logger.
95 *
96 * Is logger of ike_sa!
97 */
98 logger_t *logger;
99 };
100
101 /**
102 * Implementation of private_create_child_sa_requested_t.process_sa_payload.
103 */
104 static status_t process_sa_payload(private_create_child_sa_requested_t *this, sa_payload_t *sa_payload)
105 {
106 proposal_t *proposal, *proposal_tmp;
107 linked_list_t *proposal_list;
108
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)
113 {
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);
117 return FAILED;
118 }
119 if (proposal_list->get_count(proposal_list) > 1)
120 {
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)
124 {
125 proposal->destroy(proposal);
126 }
127 proposal_list->destroy(proposal_list);
128 return FAILED;
129 }
130
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)
135 {
136 proposal_tmp->destroy(proposal_tmp);
137 }
138 proposal_list->destroy(proposal_list);
139 /* got a match? */
140 if (proposal == NULL)
141 {
142 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
143 return FAILED;
144 }
145
146 /* apply proposal */
147 this->proposal = proposal;
148
149 return SUCCESS;
150 }
151
152 /**
153 * Implementation of private_create_child_sa_requested_t.process_ts_payload.
154 */
155 static status_t process_ts_payload(private_create_child_sa_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
156 {
157 linked_list_t *ts_received, *ts_selected;
158 traffic_selector_t *ts;
159
160 /* get ts form payload */
161 ts_received = ts_payload->get_traffic_selectors(ts_payload);
162 /* select ts depending on payload type */
163 if (ts_initiator)
164 {
165 ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
166 this->my_ts = ts_selected;
167 }
168 else
169 {
170 ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
171 this->other_ts = ts_selected;
172 }
173 /* check if the responder selected valid proposals */
174 if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
175 {
176 this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
177 }
178
179 /* cleanup */
180 while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
181 {
182 ts->destroy(ts);
183 }
184 ts_received->destroy(ts_received);
185
186 return SUCCESS;
187 }
188
189 /**
190 * Implementation of private_create_child_sa_requested_t.process_nonce_payload.
191 */
192 static status_t process_nonce_payload(private_create_child_sa_requested_t *this, nonce_payload_t *nonce_request)
193 {
194 this->nonce_r = nonce_request->get_nonce(nonce_request);
195 return SUCCESS;
196 }
197
198 /**
199 * Process a CREATE_CHILD_SA response
200 */
201 static status_t process_message(private_create_child_sa_requested_t *this, message_t *response)
202 {
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;
208 crypter_t *crypter;
209 signer_t *signer;
210 status_t status;
211 chunk_t seed;
212 prf_plus_t *prf_plus;
213 child_sa_t *old_child_sa;
214
215 this->policy = this->ike_sa->get_policy(this->ike_sa);
216 if (response->get_exchange_type(response) != CREATE_CHILD_SA)
217 {
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)));
220 return FAILED;
221 }
222
223 if (response->get_request(response))
224 {
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.
230 */
231 state_t *state = (state_t*)ike_sa_established_create(this->ike_sa);
232 state->process_message(state, response);
233 state->destroy(state);
234 return SUCCESS;
235 }
236
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))
240 {
241 crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
242 signer = this->ike_sa->get_signer_initiator(this->ike_sa);
243 }
244 else
245 {
246 crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
247 signer = this->ike_sa->get_signer_responder(this->ike_sa);
248 }
249
250 /* parse incoming message */
251 status = response->parse_body(response, crypter, signer);
252 if (status != SUCCESS)
253 {
254 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA r decryption failed. Ignoring message");
255 return status;
256 }
257
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))
261 {
262 payload_t *payload;
263 payloads->current(payloads, (void**)&payload);
264
265 switch (payload->get_type(payload))
266 {
267 case SECURITY_ASSOCIATION:
268 {
269 sa_request = (sa_payload_t*)payload;
270 break;
271 }
272 case TRAFFIC_SELECTOR_INITIATOR:
273 {
274 tsi_request = (ts_payload_t*)payload;
275 break;
276 }
277 case TRAFFIC_SELECTOR_RESPONDER:
278 {
279 tsr_request = (ts_payload_t*)payload;
280 break;
281 }
282 case NONCE:
283 {
284 nonce_request = (nonce_payload_t*)payload;
285 break;
286 }
287 case NOTIFY:
288 {
289 /* TODO: handle notifys */
290 break;
291 }
292 default:
293 {
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));
296 break;
297 }
298 }
299 }
300 /* iterator can be destroyed */
301 payloads->destroy(payloads);
302
303 /* check if we have all payloads */
304 if (!(sa_request && nonce_request && tsi_request && tsr_request))
305 {
306 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
307 return FAILED;
308 }
309
310 /* add payloads to it */
311 status = process_nonce_payload(this, nonce_request);
312 if (status != SUCCESS)
313 {
314 response->destroy(response);
315 return status;
316 }
317 status = process_sa_payload(this, sa_request);
318 if (status != SUCCESS)
319 {
320 response->destroy(response);
321 return status;
322 }
323 status = process_ts_payload(this, TRUE, tsi_request);
324 if (status != SUCCESS)
325 {
326 response->destroy(response);
327 return status;
328 }
329 status = process_ts_payload(this, FALSE, tsr_request);
330 if (status != SUCCESS)
331 {
332 response->destroy(response);
333 return status;
334 }
335
336 /* install child SAs for AH and esp */
337 if (!this->proposal)
338 {
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;
342 }
343 else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
344 {
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;
348 }
349 else
350 {
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);
355
356 this->logger->log_chunk(this->logger, RAW|LEVEL2, "Rekey seed", seed);
357 chunk_free(&seed);
358
359 status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
360 prf_plus->destroy(prf_plus);
361 if (status != SUCCESS)
362 {
363 this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
364 return DESTROY_ME;
365 }
366 status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
367 if (status != SUCCESS)
368 {
369 this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
370 return DESTROY_ME;
371 }
372 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
373 }
374
375 this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
376
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);
380
381 /* if we are rekeying, inform the old child SA that it has been superseeded and
382 * start its delete */
383 if (this->reqid)
384 {
385 old_child_sa = this->ike_sa->public.get_child_sa(&this->ike_sa->public, this->reqid);
386 if (old_child_sa)
387 {
388 old_child_sa->set_rekeyed(old_child_sa);
389 }
390 this->ike_sa->public.delete_child_sa(&this->ike_sa->public, this->reqid);
391 }
392 return SUCCESS;
393 }
394
395 /**
396 * Implements state_t.get_state
397 */
398 static ike_sa_state_t get_state(private_create_child_sa_requested_t *this)
399 {
400 return CREATE_CHILD_SA_REQUESTED;
401 }
402
403 /**
404 * Implementation of state_t.destroy.
405 */
406 static void destroy(private_create_child_sa_requested_t *this)
407 {
408 chunk_free(&this->nonce_i);
409 chunk_free(&this->nonce_r);
410 free(this);
411 }
412
413 /*
414 * Described in header.
415 */
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)
417 {
418 private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_requested_t);
419
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;
424
425 /* private data */
426 this->ike_sa = ike_sa;
427 this->child_sa = child_sa;
428 this->nonce_i = nonce_i;
429 this->nonce_r = CHUNK_INITIALIZER;
430 this->reqid = reqid;
431 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
432
433 return &(this->public);
434 }