not detaching from bus when IKE_SA_INIT is retried
[strongswan.git] / src / charon / sa / tasks / ike_init.c
1 /**
2 * @file ike_init.c
3 *
4 * @brief Implementation of the ike_init task.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005-2007 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
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>.
17 *
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
21 * for more details.
22 */
23
24 #include "ike_init.h"
25
26 #include <string.h>
27
28 #include <daemon.h>
29 #include <crypto/diffie_hellman.h>
30 #include <encoding/payloads/sa_payload.h>
31 #include <encoding/payloads/ke_payload.h>
32 #include <encoding/payloads/nonce_payload.h>
33
34
35 typedef struct private_ike_init_t private_ike_init_t;
36
37 /**
38 * Private members of a ike_init_t task.
39 */
40 struct private_ike_init_t {
41
42 /**
43 * Public methods and task_t interface.
44 */
45 ike_init_t public;
46
47 /**
48 * Assigned IKE_SA.
49 */
50 ike_sa_t *ike_sa;
51
52 /**
53 * Are we the initiator?
54 */
55 bool initiator;
56
57 /**
58 * Connection established by this IKE_SA
59 */
60 connection_t *connection;
61
62 /**
63 * diffie hellman group to use
64 */
65 diffie_hellman_group_t dh_group;
66
67 /**
68 * Diffie hellman object used to generate public DH value.
69 */
70 diffie_hellman_t *diffie_hellman;
71
72 /**
73 * nonce chosen by us
74 */
75 chunk_t my_nonce;
76
77 /**
78 * nonce chosen by peer
79 */
80 chunk_t other_nonce;
81
82 /**
83 * Negotiated proposal used for IKE_SA
84 */
85 proposal_t *proposal;
86
87 /**
88 * Old IKE_SA which gets rekeyed
89 */
90 ike_sa_t *old_sa;
91
92 /**
93 * cookie received from responder
94 */
95 chunk_t cookie;
96 };
97
98 /**
99 * build the payloads for the message
100 */
101 static void build_payloads(private_ike_init_t *this, message_t *message)
102 {
103 sa_payload_t *sa_payload;
104 ke_payload_t *ke_payload;
105 nonce_payload_t *nonce_payload;
106 linked_list_t *proposal_list;
107 ike_sa_id_t *id;
108 proposal_t *proposal;
109 iterator_t *iterator;
110
111 id = this->ike_sa->get_id(this->ike_sa);
112
113 this->connection = this->ike_sa->get_connection(this->ike_sa);
114
115 if (this->initiator)
116 {
117 proposal_list = this->connection->get_proposals(this->connection);
118 if (this->old_sa)
119 {
120 /* include SPI of new IKE_SA when we are rekeying */
121 iterator = proposal_list->create_iterator(proposal_list, TRUE);
122 while (iterator->iterate(iterator, (void**)&proposal))
123 {
124 proposal->set_spi(proposal, id->get_initiator_spi(id));
125 }
126 iterator->destroy(iterator);
127 }
128
129 sa_payload = sa_payload_create_from_proposal_list(proposal_list);
130 proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
131 }
132 else
133 {
134 if (this->old_sa)
135 {
136 /* include SPI of new IKE_SA when we are rekeying */
137 this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
138 }
139 sa_payload = sa_payload_create_from_proposal(this->proposal);
140 }
141 message->add_payload(message, (payload_t*)sa_payload);
142
143 nonce_payload = nonce_payload_create();
144 nonce_payload->set_nonce(nonce_payload, this->my_nonce);
145 message->add_payload(message, (payload_t*)nonce_payload);
146
147 ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
148 message->add_payload(message, (payload_t*)ke_payload);
149 }
150
151 /**
152 * Read payloads from message
153 */
154 static void process_payloads(private_ike_init_t *this, message_t *message)
155 {
156 iterator_t *iterator;
157 payload_t *payload;
158
159 iterator = message->get_payload_iterator(message);
160 while (iterator->iterate(iterator, (void**)&payload))
161 {
162 switch (payload->get_type(payload))
163 {
164 case SECURITY_ASSOCIATION:
165 {
166 sa_payload_t *sa_payload = (sa_payload_t*)payload;
167 linked_list_t *proposal_list;
168
169 proposal_list = sa_payload->get_proposals(sa_payload);
170 this->proposal = this->connection->select_proposal(
171 this->connection, proposal_list);
172 proposal_list->destroy_offset(proposal_list,
173 offsetof(proposal_t, destroy));
174 break;
175 }
176 case KEY_EXCHANGE:
177 {
178 ke_payload_t *ke_payload = (ke_payload_t*)payload;
179 diffie_hellman_group_t dh_group;
180 chunk_t key_data;
181
182 dh_group = ke_payload->get_dh_group_number(ke_payload);
183
184 if (this->initiator)
185 {
186 if (dh_group != this->dh_group)
187 {
188 DBG1(DBG_IKE, "received a DH group not requested (%N)",
189 diffie_hellman_group_names, dh_group);
190 break;
191 }
192 }
193 else
194 {
195 this->dh_group = dh_group;
196 if (!this->connection->check_dh_group(this->connection,
197 dh_group))
198 {
199 break;
200 }
201 this->diffie_hellman = diffie_hellman_create(dh_group);
202 }
203 if (this->diffie_hellman)
204 {
205 key_data = ke_payload->get_key_exchange_data(ke_payload);
206 this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
207 }
208 break;
209 }
210 case NONCE:
211 {
212 nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
213 this->other_nonce = nonce_payload->get_nonce(nonce_payload);
214 break;
215 }
216 default:
217 break;
218 }
219 }
220 iterator->destroy(iterator);
221 }
222
223 /**
224 * Implementation of task_t.process for initiator
225 */
226 static status_t build_i(private_ike_init_t *this, message_t *message)
227 {
228 randomizer_t *randomizer;
229 status_t status;
230
231 this->connection = this->ike_sa->get_connection(this->ike_sa);
232 SIG(IKE_UP_START, "initiating IKE_SA to %H",
233 this->connection->get_other_host(this->connection));
234 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
235
236 /* if the DH group is set via use_dh_group(), we already have a DH object */
237 if (!this->diffie_hellman)
238 {
239 this->dh_group = this->connection->get_dh_group(this->connection);
240 this->diffie_hellman = diffie_hellman_create(this->dh_group);
241 if (this->diffie_hellman == NULL)
242 {
243 SIG(IKE_UP_FAILED, "configured DH group %N not supported",
244 diffie_hellman_group_names, this->dh_group);
245 return FAILED;
246 }
247 }
248
249 /* generate nonce only when we are trying the first time */
250 if (this->my_nonce.ptr == NULL)
251 {
252 randomizer = randomizer_create();
253 status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
254 &this->my_nonce);
255 randomizer->destroy(randomizer);
256 if (status != SUCCESS)
257 {
258 SIG(IKE_UP_FAILED, "error generating random nonce value");
259 return FAILED;
260 }
261 }
262
263 if (this->cookie.ptr)
264 {
265 message->add_notify(message, FALSE, COOKIE, this->cookie);
266 }
267
268 build_payloads(this, message);
269
270
271 return NEED_MORE;
272 }
273
274 /**
275 * Implementation of task_t.process for initiator
276 */
277 static status_t process_r(private_ike_init_t *this, message_t *message)
278 {
279 randomizer_t *randomizer;
280
281 this->connection = this->ike_sa->get_connection(this->ike_sa);
282 SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
283 message->get_source(message));
284 this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
285
286 randomizer = randomizer_create();
287 if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
288 &this->my_nonce) != SUCCESS)
289 {
290 DBG1(DBG_IKE, "error generating random nonce value");
291 }
292 randomizer->destroy(randomizer);
293
294 process_payloads(this, message);
295
296 return NEED_MORE;
297 }
298
299 /**
300 * Implementation of task_t.build for responder
301 */
302 static status_t build_r(private_ike_init_t *this, message_t *message)
303 {
304 chunk_t secret;
305 status_t status;
306
307 /* check if we have everything we need */
308 if (this->proposal == NULL ||
309 this->other_nonce.len == 0 || this->my_nonce.len == 0)
310 {
311 SIG(IKE_UP_FAILED, "received proposals inacceptable");
312 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
313 return FAILED;
314 }
315
316 if (this->diffie_hellman == NULL ||
317 this->diffie_hellman->get_shared_secret(this->diffie_hellman,
318 &secret) != SUCCESS)
319 {
320 chunk_t chunk;
321 u_int16_t dh_enc;
322
323 SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
324 diffie_hellman_group_names, this->dh_group);
325 this->dh_group = this->connection->get_dh_group(this->connection);
326 dh_enc = htons(this->dh_group);
327 chunk.ptr = (u_int8_t*)&dh_enc;
328 chunk.len = sizeof(dh_enc);
329 message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
330 DBG1(DBG_IKE, "requesting DH group %N",
331 diffie_hellman_group_names, this->dh_group);
332 return FAILED;
333 }
334
335
336 if (this->old_sa)
337 {
338 ike_sa_id_t *id;
339 prf_t *prf, *child_prf;
340
341 /* Apply SPI if we are rekeying */
342 id = this->ike_sa->get_id(this->ike_sa);
343 id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
344
345 /* setup crypto keys for the rekeyed SA */
346 prf = this->old_sa->get_prf(this->old_sa);
347 child_prf = this->old_sa->get_child_prf(this->old_sa);
348 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
349 this->other_nonce, this->my_nonce,
350 FALSE, child_prf, prf);
351 }
352 else
353 {
354 /* setup crypto keys */
355 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
356 this->other_nonce, this->my_nonce,
357 FALSE, NULL, NULL);
358 }
359 if (status != SUCCESS)
360 {
361 SIG(IKE_UP_FAILED, "key derivation failed");
362 message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
363 return FAILED;
364 }
365
366 build_payloads(this, message);
367
368 return SUCCESS;
369 }
370
371 /**
372 * Implementation of task_t.process for initiator
373 */
374 static status_t process_i(private_ike_init_t *this, message_t *message)
375 {
376 chunk_t secret;
377 status_t status;
378 iterator_t *iterator;
379 payload_t *payload;
380
381 /* check for erronous notifies */
382 iterator = message->get_payload_iterator(message);
383 while (iterator->iterate(iterator, (void**)&payload))
384 {
385 if (payload->get_type(payload) == NOTIFY)
386 {
387 notify_payload_t *notify = (notify_payload_t*)payload;
388 notify_type_t type = notify->get_notify_type(notify);
389
390 switch (type)
391 {
392 case INVALID_KE_PAYLOAD:
393 {
394 chunk_t data;
395 diffie_hellman_group_t old_dh_group;
396
397 old_dh_group = this->dh_group;
398 data = notify->get_notification_data(notify);
399 this->dh_group = ntohs(*((u_int16_t*)data.ptr));
400
401 DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
402 " %N", diffie_hellman_group_names, old_dh_group,
403 diffie_hellman_group_names, this->dh_group);
404 if (!this->connection->check_dh_group(this->connection,
405 this->dh_group))
406 {
407 DBG1(DBG_IKE, "requested DH group %N not acceptable, "
408 "giving up", diffie_hellman_group_names,
409 this->dh_group);
410 iterator->destroy(iterator);
411 return FAILED;
412 }
413
414 this->ike_sa->reset(this->ike_sa);
415
416 iterator->destroy(iterator);
417 return NEED_MORE;
418 }
419 case NAT_DETECTION_SOURCE_IP:
420 case NAT_DETECTION_DESTINATION_IP:
421 /* skip, handled in ike_natd_t */
422 break;
423 case COOKIE:
424 {
425 this->cookie = chunk_clone(notify->get_notification_data(notify));
426 this->ike_sa->reset(this->ike_sa);
427 iterator->destroy(iterator);
428 DBG1(DBG_IKE, "received %N notify", notify_type_names, type);
429 return NEED_MORE;
430 }
431 default:
432 {
433 if (type < 16383)
434 {
435 SIG(IKE_UP_FAILED, "received %N notify error",
436 notify_type_names, type);
437 iterator->destroy(iterator);
438 return FAILED;
439 }
440 DBG1(DBG_IKE, "received %N notify",
441 notify_type_names, type);
442 break;
443 }
444 }
445 }
446 }
447 iterator->destroy(iterator);
448
449 process_payloads(this, message);
450
451 /* check if we have everything */
452 if (this->proposal == NULL ||
453 this->other_nonce.len == 0 || this->my_nonce.len == 0)
454 {
455 SIG(IKE_UP_FAILED, "peers proposal selection invalid");
456 return FAILED;
457 }
458
459 if (this->diffie_hellman == NULL ||
460 this->diffie_hellman->get_shared_secret(this->diffie_hellman,
461 &secret) != SUCCESS)
462 {
463 SIG(IKE_UP_FAILED, "peers DH group selection invalid");
464 return FAILED;
465 }
466
467 /* Apply SPI if we are rekeying */
468 if (this->old_sa)
469 {
470 ike_sa_id_t *id;
471 prf_t *prf, *child_prf;
472
473 id = this->ike_sa->get_id(this->ike_sa);
474 id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
475
476 /* setup crypto keys for the rekeyed SA */
477 prf = this->old_sa->get_prf(this->old_sa);
478 child_prf = this->old_sa->get_child_prf(this->old_sa);
479 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
480 this->my_nonce, this->other_nonce,
481 TRUE, child_prf, prf);
482 }
483 else
484 {
485 /* setup crypto keys for a new SA */
486 status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret,
487 this->my_nonce, this->other_nonce,
488 TRUE, NULL, NULL);
489 }
490 if (status != SUCCESS)
491 {
492 SIG(IKE_UP_FAILED, "key derivation failed");
493 return FAILED;
494 }
495 return SUCCESS;
496 }
497
498 /**
499 * Implementation of task_t.get_type
500 */
501 static task_type_t get_type(private_ike_init_t *this)
502 {
503 return IKE_INIT;
504 }
505
506 /**
507 * Implementation of task_t.migrate
508 */
509 static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
510 {
511 DESTROY_IF(this->proposal);
512 DESTROY_IF(this->diffie_hellman);
513 chunk_free(&this->other_nonce);
514
515 this->ike_sa = ike_sa;
516 this->proposal = NULL;
517 this->diffie_hellman = diffie_hellman_create(this->dh_group);
518 }
519
520 /**
521 * Implementation of task_t.destroy
522 */
523 static void destroy(private_ike_init_t *this)
524 {
525 DESTROY_IF(this->proposal);
526 DESTROY_IF(this->diffie_hellman);
527 chunk_free(&this->my_nonce);
528 chunk_free(&this->other_nonce);
529 chunk_free(&this->cookie);
530 free(this);
531 }
532
533 /*
534 * Described in header.
535 */
536 ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
537 {
538 private_ike_init_t *this = malloc_thing(private_ike_init_t);
539
540 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
541 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
542 this->public.task.destroy = (void(*)(task_t*))destroy;
543 if (initiator)
544 {
545 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
546 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
547 }
548 else
549 {
550 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
551 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
552 }
553
554 this->ike_sa = ike_sa;
555 this->initiator = initiator;
556 this->dh_group = MODP_NONE;
557 this->diffie_hellman = NULL;
558 this->my_nonce = chunk_empty;
559 this->other_nonce = chunk_empty;
560 this->cookie = chunk_empty;
561 this->proposal = NULL;
562 this->connection = NULL;
563 this->old_sa = old_sa;
564
565 return &this->public;
566 }