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