fixed compile warnings when using -Wall
[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 * Assigned logger.
90 *
91 * Is logger of ike_sa!
92 */
93 logger_t *logger;
94 };
95
96 /**
97 * Implementation of private_create_child_sa_requested_t.process_sa_payload.
98 */
99 static status_t process_sa_payload(private_create_child_sa_requested_t *this, sa_payload_t *sa_payload)
100 {
101 proposal_t *proposal, *proposal_tmp;
102 linked_list_t *proposal_list;
103
104 /* get his selected proposal */
105 proposal_list = sa_payload->get_proposals(sa_payload);
106 /* check count of proposals */
107 if (proposal_list->get_count(proposal_list) == 0)
108 {
109 /* no proposal? we accept this, but no child sa is built */
110 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained no proposals. CHILD_SA not created");
111 proposal_list->destroy(proposal_list);
112 return FAILED;
113 }
114 if (proposal_list->get_count(proposal_list) > 1)
115 {
116 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained %d proposals. Aborting",
117 proposal_list->get_count(proposal_list));
118 while (proposal_list->remove_last(proposal_list, (void**)&proposal) == SUCCESS)
119 {
120 proposal->destroy(proposal);
121 }
122 proposal_list->destroy(proposal_list);
123 return FAILED;
124 }
125
126 /* we have to re-check here if other's selection is valid */
127 proposal = this->policy->select_proposal(this->policy, proposal_list);
128 /* list not needed anymore */
129 while (proposal_list->remove_last(proposal_list, (void**)&proposal_tmp) == SUCCESS)
130 {
131 proposal_tmp->destroy(proposal_tmp);
132 }
133 proposal_list->destroy(proposal_list);
134 /* got a match? */
135 if (proposal == NULL)
136 {
137 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA reply contained a not offered proposal. Aborting");
138 return FAILED;
139 }
140
141 /* apply proposal */
142 this->proposal = proposal;
143
144 return SUCCESS;
145 }
146
147 /**
148 * Implementation of private_create_child_sa_requested_t.process_ts_payload.
149 */
150 static status_t process_ts_payload(private_create_child_sa_requested_t *this, bool ts_initiator, ts_payload_t *ts_payload)
151 {
152 linked_list_t *ts_received, *ts_selected;
153 traffic_selector_t *ts;
154
155 /* get ts form payload */
156 ts_received = ts_payload->get_traffic_selectors(ts_payload);
157 /* select ts depending on payload type */
158 if (ts_initiator)
159 {
160 ts_selected = this->policy->select_my_traffic_selectors(this->policy, ts_received);
161 this->my_ts = ts_selected;
162 }
163 else
164 {
165 ts_selected = this->policy->select_other_traffic_selectors(this->policy, ts_received);
166 this->other_ts = ts_selected;
167 }
168 /* check if the responder selected valid proposals */
169 if (ts_selected->get_count(ts_selected) != ts_received->get_count(ts_received))
170 {
171 this->logger->log(this->logger, AUDIT, "IKE_AUTH reply contained not offered traffic selectors.");
172 }
173
174 /* cleanup */
175 while (ts_received->remove_last(ts_received, (void**)&ts) == SUCCESS)
176 {
177 ts->destroy(ts);
178 }
179 ts_received->destroy(ts_received);
180
181 return SUCCESS;
182 }
183
184 /**
185 * Implementation of private_create_child_sa_requested_t.process_nonce_payload.
186 */
187 static status_t process_nonce_payload(private_create_child_sa_requested_t *this, nonce_payload_t *nonce_request)
188 {
189 this->nonce_r = nonce_request->get_nonce(nonce_request);
190 return SUCCESS;
191 }
192
193 /**
194 * Process a CREATE_CHILD_SA response
195 */
196 static status_t process_message(private_create_child_sa_requested_t *this, message_t *response)
197 {
198 ts_payload_t *tsi_request = NULL, *tsr_request = NULL;
199 sa_payload_t *sa_request = NULL;
200 nonce_payload_t *nonce_request = NULL;
201 ike_sa_id_t *ike_sa_id;
202 iterator_t *payloads;
203 crypter_t *crypter;
204 signer_t *signer;
205 status_t status;
206 chunk_t seed;
207 prf_plus_t *prf_plus;
208
209 this->policy = this->ike_sa->get_policy(this->ike_sa);
210 if (response->get_exchange_type(response) != CREATE_CHILD_SA)
211 {
212 this->logger->log(this->logger, ERROR | LEVEL1, "Message of type %s not supported in state create_child_sa_requested",
213 mapping_find(exchange_type_m, response->get_exchange_type(response)));
214 return FAILED;
215 }
216
217 if (response->get_request(response))
218 {
219 this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested");
220 return FAILED;
221 }
222
223 /* get signer for verification and crypter for decryption */
224 ike_sa_id = this->ike_sa->public.get_id(&this->ike_sa->public);
225 if (!ike_sa_id->is_initiator(ike_sa_id))
226 {
227 crypter = this->ike_sa->get_crypter_initiator(this->ike_sa);
228 signer = this->ike_sa->get_signer_initiator(this->ike_sa);
229 }
230 else
231 {
232 crypter = this->ike_sa->get_crypter_responder(this->ike_sa);
233 signer = this->ike_sa->get_signer_responder(this->ike_sa);
234 }
235
236 /* parse incoming message */
237 status = response->parse_body(response, crypter, signer);
238 if (status != SUCCESS)
239 {
240 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA r decryption failed. Ignoring message");
241 return status;
242 }
243
244 /* iterate over incoming payloads. Message is verified, we can be sure there are the required payloads */
245 payloads = response->get_payload_iterator(response);
246 while (payloads->has_next(payloads))
247 {
248 payload_t *payload;
249 payloads->current(payloads, (void**)&payload);
250
251 switch (payload->get_type(payload))
252 {
253 case SECURITY_ASSOCIATION:
254 {
255 sa_request = (sa_payload_t*)payload;
256 break;
257 }
258 case TRAFFIC_SELECTOR_INITIATOR:
259 {
260 tsi_request = (ts_payload_t*)payload;
261 break;
262 }
263 case TRAFFIC_SELECTOR_RESPONDER:
264 {
265 tsr_request = (ts_payload_t*)payload;
266 break;
267 }
268 case NONCE:
269 {
270 nonce_request = (nonce_payload_t*)payload;
271 break;
272 }
273 case NOTIFY:
274 {
275 /* TODO: handle notifys */
276 break;
277 }
278 default:
279 {
280 this->logger->log(this->logger, ERROR|LEVEL1, "Ignoring payload %s (%d)",
281 mapping_find(payload_type_m, payload->get_type(payload)), payload->get_type(payload));
282 break;
283 }
284 }
285 }
286 /* iterator can be destroyed */
287 payloads->destroy(payloads);
288
289 /* check if we have all payloads */
290 if (!(sa_request && nonce_request && tsi_request && tsr_request))
291 {
292 this->logger->log(this->logger, AUDIT, "CREATE_CHILD_SA request did not contain all required payloads. Ignored");
293 return FAILED;
294 }
295
296 /* add payloads to it */
297 status = process_nonce_payload(this, nonce_request);
298 if (status != SUCCESS)
299 {
300 response->destroy(response);
301 return status;
302 }
303 status = process_sa_payload(this, sa_request);
304 if (status != SUCCESS)
305 {
306 response->destroy(response);
307 return status;
308 }
309 status = process_ts_payload(this, TRUE, tsi_request);
310 if (status != SUCCESS)
311 {
312 response->destroy(response);
313 return status;
314 }
315 status = process_ts_payload(this, FALSE, tsr_request);
316 if (status != SUCCESS)
317 {
318 response->destroy(response);
319 return status;
320 }
321
322 /* install child SAs for AH and esp */
323 if (!this->proposal)
324 {
325 this->logger->log(this->logger, CONTROL, "Proposal negotiation failed, no CHILD_SA built");
326 this->child_sa->destroy(this->child_sa);
327 this->child_sa = NULL;
328 }
329 else if (this->my_ts->get_count(this->my_ts) == 0 || this->other_ts->get_count(this->other_ts) == 0)
330 {
331 this->logger->log(this->logger, CONTROL, "Traffic selector negotiation failed, no CHILD_SA built");
332 this->child_sa->destroy(this->child_sa);
333 this->child_sa = NULL;
334 }
335 else
336 {
337 seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
338 memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
339 memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
340 prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
341
342 this->logger->log_chunk(this->logger, CONTROL, "Seed", seed);
343 chunk_free(&seed);
344
345 status = this->child_sa->update(this->child_sa, this->proposal, prf_plus);
346 prf_plus->destroy(prf_plus);
347 if (status != SUCCESS)
348 {
349 this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA");
350 return DESTROY_ME;
351 }
352 status = this->child_sa->add_policies(this->child_sa, this->my_ts, this->other_ts);
353 if (status != SUCCESS)
354 {
355 this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA policy! Deleting IKE_SA");
356 return DESTROY_ME;
357 }
358 this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
359 }
360
361 this->ike_sa->set_last_replied_message_id(this->ike_sa, response->get_message_id(response));
362
363 /* create new state */
364 this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa));
365 this->public.state_interface.destroy(&this->public.state_interface);
366
367 return SUCCESS;
368 }
369
370 /**
371 * Implements state_t.get_state
372 */
373 static ike_sa_state_t get_state(private_create_child_sa_requested_t *this)
374 {
375 return CREATE_CHILD_SA_REQUESTED;
376 }
377
378 /**
379 * Implementation of state_t.destroy.
380 */
381 static void destroy(private_create_child_sa_requested_t *this)
382 {
383 chunk_free(&this->nonce_i);
384 chunk_free(&this->nonce_r);
385 free(this);
386 }
387
388 /*
389 * Described in header.
390 */
391 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)
392 {
393 private_create_child_sa_requested_t *this = malloc_thing(private_create_child_sa_requested_t);
394
395 /* interface functions */
396 this->public.state_interface.process_message = (status_t (*) (state_t *,message_t *)) process_message;
397 this->public.state_interface.get_state = (ike_sa_state_t (*) (state_t *)) get_state;
398 this->public.state_interface.destroy = (void (*) (state_t *)) destroy;
399
400 /* private data */
401 this->ike_sa = ike_sa;
402 this->child_sa = child_sa;
403 this->nonce_i = nonce_i;
404 this->nonce_r = CHUNK_INITIALIZER;
405 this->logger = logger_manager->get_logger(logger_manager, IKE_SA);
406
407 return &(this->public);
408 }