2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2005-2008 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 #include <crypto/diffie_hellman.h>
26 #include <encoding/payloads/sa_payload.h>
27 #include <encoding/payloads/ke_payload.h>
28 #include <encoding/payloads/nonce_payload.h>
29 #include <encoding/payloads/vendor_id_payload.h>
31 /** maximum retries to do with cookies/other dh groups */
34 typedef struct private_ike_init_t private_ike_init_t
;
37 * Private members of a ike_init_t task.
39 struct private_ike_init_t
{
42 * Public methods and task_t interface.
52 * Are we the initiator?
57 * IKE config to establish
62 * diffie hellman group to use
64 diffie_hellman_group_t dh_group
;
67 * diffie hellman key exchange
72 * Keymat derivation (from IKE_SA)
82 * nonce chosen by peer
87 * Negotiated proposal used for IKE_SA
92 * Old IKE_SA which gets rekeyed
97 * cookie received from responder
102 * retries done so far after failure (cookie or bad dh group)
108 * build the payloads for the message
110 static void build_payloads(private_ike_init_t
*this, message_t
*message
)
112 sa_payload_t
*sa_payload
;
113 ke_payload_t
*ke_payload
;
114 nonce_payload_t
*nonce_payload
;
115 linked_list_t
*proposal_list
;
117 proposal_t
*proposal
;
118 iterator_t
*iterator
;
120 id
= this->ike_sa
->get_id(this->ike_sa
);
122 this->config
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
126 proposal_list
= this->config
->get_proposals(this->config
);
129 /* include SPI of new IKE_SA when we are rekeying */
130 iterator
= proposal_list
->create_iterator(proposal_list
, TRUE
);
131 while (iterator
->iterate(iterator
, (void**)&proposal
))
133 proposal
->set_spi(proposal
, id
->get_initiator_spi(id
));
135 iterator
->destroy(iterator
);
138 sa_payload
= sa_payload_create_from_proposal_list(proposal_list
);
139 proposal_list
->destroy_offset(proposal_list
, offsetof(proposal_t
, destroy
));
145 /* include SPI of new IKE_SA when we are rekeying */
146 this->proposal
->set_spi(this->proposal
, id
->get_responder_spi(id
));
148 sa_payload
= sa_payload_create_from_proposal(this->proposal
);
150 message
->add_payload(message
, (payload_t
*)sa_payload
);
152 nonce_payload
= nonce_payload_create();
153 nonce_payload
->set_nonce(nonce_payload
, this->my_nonce
);
154 ke_payload
= ke_payload_create_from_diffie_hellman(this->dh
);
157 { /* payload order differs if we are rekeying */
158 message
->add_payload(message
, (payload_t
*)nonce_payload
);
159 message
->add_payload(message
, (payload_t
*)ke_payload
);
163 message
->add_payload(message
, (payload_t
*)ke_payload
);
164 message
->add_payload(message
, (payload_t
*)nonce_payload
);
169 * Read payloads from message
171 static void process_payloads(private_ike_init_t
*this, message_t
*message
)
173 iterator_t
*iterator
;
176 iterator
= message
->get_payload_iterator(message
);
177 while (iterator
->iterate(iterator
, (void**)&payload
))
179 switch (payload
->get_type(payload
))
181 case SECURITY_ASSOCIATION
:
183 sa_payload_t
*sa_payload
= (sa_payload_t
*)payload
;
184 linked_list_t
*proposal_list
;
186 proposal_list
= sa_payload
->get_proposals(sa_payload
);
187 this->proposal
= this->config
->select_proposal(this->config
,
189 proposal_list
->destroy_offset(proposal_list
,
190 offsetof(proposal_t
, destroy
));
195 ke_payload_t
*ke_payload
= (ke_payload_t
*)payload
;
197 this->dh_group
= ke_payload
->get_dh_group_number(ke_payload
);
198 if (!this->initiator
)
200 if (this->keymat
->set_dh_group(this->keymat
, this->dh_group
))
202 this->dh
= this->keymat
->get_dh(this->keymat
);
207 this->dh
->set_other_public_value(this->dh
,
208 ke_payload
->get_key_exchange_data(ke_payload
));
214 nonce_payload_t
*nonce_payload
= (nonce_payload_t
*)payload
;
216 this->other_nonce
= nonce_payload
->get_nonce(nonce_payload
);
221 vendor_id_payload_t
*vendor_id
= (vendor_id_payload_t
*)payload
;
222 chunk_t vid
= vendor_id
->get_data(vendor_id
);
224 DBG1(DBG_ENC
, "received vendor id: %#B", &vid
);
230 iterator
->destroy(iterator
);
234 * Implementation of task_t.process for initiator
236 static status_t
build_i(private_ike_init_t
*this, message_t
*message
)
240 this->config
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
241 DBG0(DBG_IKE
, "initiating IKE_SA %s[%d] to %H",
242 this->ike_sa
->get_name(this->ike_sa
),
243 this->ike_sa
->get_unique_id(this->ike_sa
),
244 this->ike_sa
->get_other_host(this->ike_sa
));
245 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
247 if (this->retry
++ >= MAX_RETRIES
)
249 DBG1(DBG_IKE
, "giving up after %d retries", MAX_RETRIES
);
253 /* if the DH group is set via use_dh_group(), we already have a DH object */
256 this->dh_group
= this->config
->get_dh_group(this->config
);
257 if (!this->keymat
->set_dh_group(this->keymat
, this->dh_group
))
259 DBG1(DBG_IKE
, "configured DH group %N not supported",
260 diffie_hellman_group_names
, this->dh_group
);
263 this->dh
= this->keymat
->get_dh(this->keymat
);
266 /* generate nonce only when we are trying the first time */
267 if (this->my_nonce
.ptr
== NULL
)
269 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
272 DBG1(DBG_IKE
, "error generating nonce");
275 rng
->allocate_bytes(rng
, NONCE_SIZE
, &this->my_nonce
);
279 if (this->cookie
.ptr
)
281 message
->add_notify(message
, FALSE
, COOKIE
, this->cookie
);
284 build_payloads(this, message
);
288 chunk_t connect_id
= this->ike_sa
->get_connect_id(this->ike_sa
);
291 message
->add_notify(message
, FALSE
, ME_CONNECTID
, connect_id
);
300 * Implementation of task_t.process for responder
302 static status_t
process_r(private_ike_init_t
*this, message_t
*message
)
306 this->config
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
307 DBG0(DBG_IKE
, "%H is initiating an IKE_SA", message
->get_source(message
));
308 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
310 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
313 DBG1(DBG_IKE
, "error generating nonce");
316 rng
->allocate_bytes(rng
, NONCE_SIZE
, &this->my_nonce
);
321 chunk_t connect_id
= chunk_empty
;
322 iterator_t
*iterator
;
325 /* check for a ME_CONNECTID notify */
326 iterator
= message
->get_payload_iterator(message
);
327 while (iterator
->iterate(iterator
, (void**)&payload
))
329 if (payload
->get_type(payload
) == NOTIFY
)
331 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
332 notify_type_t type
= notify
->get_notify_type(notify
);
338 chunk_free(&connect_id
);
339 connect_id
= chunk_clone(notify
->get_notification_data(notify
));
340 DBG2(DBG_IKE
, "received ME_CONNECTID %#B", &connect_id
);
347 DBG1(DBG_IKE
, "received %N notify error",
348 notify_type_names
, type
);
351 DBG2(DBG_IKE
, "received %N notify",
352 notify_type_names
, type
);
358 iterator
->destroy(iterator
);
362 charon
->connect_manager
->stop_checks(charon
->connect_manager
,
364 chunk_free(&connect_id
);
369 process_payloads(this, message
);
375 * Implementation of task_t.build for responder
377 static status_t
build_r(private_ike_init_t
*this, message_t
*message
)
379 keymat_t
*old_keymat
= NULL
;
382 /* check if we have everything we need */
383 if (this->proposal
== NULL
||
384 this->other_nonce
.len
== 0 || this->my_nonce
.len
== 0)
386 DBG1(DBG_IKE
, "received proposals inacceptable");
387 message
->add_notify(message
, TRUE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
391 if (this->dh
== NULL
||
392 !this->proposal
->has_dh_group(this->proposal
, this->dh_group
))
396 if (this->proposal
->get_algorithm(this->proposal
, DIFFIE_HELLMAN_GROUP
,
399 DBG1(DBG_IKE
, "DH group %N inacceptable, requesting %N",
400 diffie_hellman_group_names
, this->dh_group
,
401 diffie_hellman_group_names
, group
);
402 this->dh_group
= group
;
403 group
= htons(group
);
404 message
->add_notify(message
, FALSE
, INVALID_KE_PAYLOAD
,
405 chunk_from_thing(group
));
409 DBG1(DBG_IKE
, "no acceptable proposal found");
414 id
= this->ike_sa
->get_id(this->ike_sa
);
416 { /* rekeying: Apply SPI, include keymat from old SA in key derivation */
417 id
->set_initiator_spi(id
, this->proposal
->get_spi(this->proposal
));
418 old_keymat
= this->old_sa
->get_keymat(this->old_sa
);
420 if (!this->keymat
->derive_keys(this->keymat
, this->proposal
, this->other_nonce
,
421 this->my_nonce
, id
, old_keymat
))
423 DBG1(DBG_IKE
, "key derivation failed");
424 message
->add_notify(message
, TRUE
, NO_PROPOSAL_CHOSEN
, chunk_empty
);
428 build_payloads(this, message
);
433 * Implementation of task_t.process for initiator
435 static status_t
process_i(private_ike_init_t
*this, message_t
*message
)
437 keymat_t
*old_keymat
= NULL
;
439 iterator_t
*iterator
;
442 /* check for erronous notifies */
443 iterator
= message
->get_payload_iterator(message
);
444 while (iterator
->iterate(iterator
, (void**)&payload
))
446 if (payload
->get_type(payload
) == NOTIFY
)
448 notify_payload_t
*notify
= (notify_payload_t
*)payload
;
449 notify_type_t type
= notify
->get_notify_type(notify
);
453 case INVALID_KE_PAYLOAD
:
456 diffie_hellman_group_t bad_group
;
458 bad_group
= this->dh_group
;
459 data
= notify
->get_notification_data(notify
);
460 this->dh_group
= ntohs(*((u_int16_t
*)data
.ptr
));
461 DBG1(DBG_IKE
, "peer didn't accept DH group %N, "
462 "it requested %N", diffie_hellman_group_names
,
463 bad_group
, diffie_hellman_group_names
, this->dh_group
);
465 if (this->old_sa
== NULL
)
466 { /* reset the IKE_SA if we are not rekeying */
467 this->ike_sa
->reset(this->ike_sa
);
470 iterator
->destroy(iterator
);
473 case NAT_DETECTION_SOURCE_IP
:
474 case NAT_DETECTION_DESTINATION_IP
:
475 /* skip, handled in ike_natd_t */
479 chunk_free(&this->cookie
);
480 this->cookie
= chunk_clone(notify
->get_notification_data(notify
));
481 this->ike_sa
->reset(this->ike_sa
);
482 iterator
->destroy(iterator
);
483 DBG2(DBG_IKE
, "received %N notify", notify_type_names
, type
);
490 DBG1(DBG_IKE
, "received %N notify error",
491 notify_type_names
, type
);
492 iterator
->destroy(iterator
);
495 DBG2(DBG_IKE
, "received %N notify",
496 notify_type_names
, type
);
502 iterator
->destroy(iterator
);
504 process_payloads(this, message
);
506 /* check if we have everything */
507 if (this->proposal
== NULL
||
508 this->other_nonce
.len
== 0 || this->my_nonce
.len
== 0)
510 DBG1(DBG_IKE
, "peers proposal selection invalid");
514 if (this->dh
== NULL
||
515 !this->proposal
->has_dh_group(this->proposal
, this->dh_group
))
517 DBG1(DBG_IKE
, "peer DH group selection invalid");
521 id
= this->ike_sa
->get_id(this->ike_sa
);
523 { /* rekeying: Apply SPI, include keymat from old SA in key derivation */
524 id
->set_responder_spi(id
, this->proposal
->get_spi(this->proposal
));
525 old_keymat
= this->old_sa
->get_keymat(this->old_sa
);
527 if (!this->keymat
->derive_keys(this->keymat
, this->proposal
, this->my_nonce
,
528 this->other_nonce
, id
, old_keymat
))
530 DBG1(DBG_IKE
, "key derivation failed");
538 * Implementation of task_t.get_type
540 static task_type_t
get_type(private_ike_init_t
*this)
546 * Implementation of task_t.get_type
548 static chunk_t
get_lower_nonce(private_ike_init_t
*this)
550 if (memcmp(this->my_nonce
.ptr
, this->other_nonce
.ptr
,
551 min(this->my_nonce
.len
, this->other_nonce
.len
)) < 0)
553 return this->my_nonce
;
557 return this->other_nonce
;
562 * Implementation of task_t.migrate
564 static void migrate(private_ike_init_t
*this, ike_sa_t
*ike_sa
)
566 DESTROY_IF(this->proposal
);
567 chunk_free(&this->other_nonce
);
569 this->ike_sa
= ike_sa
;
570 this->proposal
= NULL
;
571 this->keymat
->set_dh_group(this->keymat
, this->dh_group
);
572 this->dh
= this->keymat
->get_dh(this->keymat
);
576 * Implementation of task_t.destroy
578 static void destroy(private_ike_init_t
*this)
580 DESTROY_IF(this->proposal
);
581 chunk_free(&this->my_nonce
);
582 chunk_free(&this->other_nonce
);
583 chunk_free(&this->cookie
);
588 * Described in header.
590 ike_init_t
*ike_init_create(ike_sa_t
*ike_sa
, bool initiator
, ike_sa_t
*old_sa
)
592 private_ike_init_t
*this = malloc_thing(private_ike_init_t
);
594 this->public.get_lower_nonce
= (chunk_t(*)(ike_init_t
*))get_lower_nonce
;
595 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
596 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
597 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
600 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
601 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
605 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
606 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
609 this->ike_sa
= ike_sa
;
610 this->initiator
= initiator
;
611 this->dh_group
= MODP_NONE
;
613 this->keymat
= ike_sa
->get_keymat(ike_sa
);
614 this->my_nonce
= chunk_empty
;
615 this->other_nonce
= chunk_empty
;
616 this->cookie
= chunk_empty
;
617 this->proposal
= NULL
;
619 this->old_sa
= old_sa
;
622 return &this->public;