2 * Copyright (C) 2011 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2011 Martin Willi
6 * Copyright (C) 2011 revosec AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "main_mode.h"
24 #include <sa/keymat_v1.h>
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/id_payload.h>
30 #include <encoding/payloads/hash_payload.h>
32 typedef struct private_main_mode_t private_main_mode_t
;
35 * Private members of a main_mode_t task.
37 struct private_main_mode_t
{
40 * Public methods and task_t interface.
50 * Are we the initiator?
55 * IKE config to establish
65 * Local authentication configuration
70 * Remote authentication configuration
72 auth_cfg_t
*other_auth
;
75 * selected IKE proposal
85 * Keymat derivation (from SA)
90 * Received public DH value from peer
105 * Encoded SA initiator payload used for authentication
109 /** states of main mode */
119 * Get the first authentcation config from peer config
121 static auth_cfg_t
*get_auth_cfg(private_main_mode_t
*this, bool local
)
123 enumerator_t
*enumerator
;
124 auth_cfg_t
*cfg
= NULL
;
126 enumerator
= this->peer_cfg
->create_auth_cfg_enumerator(this->peer_cfg
,
128 enumerator
->enumerate(enumerator
, &cfg
);
129 enumerator
->destroy(enumerator
);
134 * Save the encoded SA payload of a message
136 static bool save_sa_payload(private_main_mode_t
*this, message_t
*message
)
138 enumerator_t
*enumerator
;
139 payload_t
*payload
, *sa
= NULL
;
141 size_t offset
= IKE_HEADER_LENGTH
;
143 enumerator
= message
->create_payload_enumerator(message
);
144 while (enumerator
->enumerate(enumerator
, &payload
))
146 if (payload
->get_type(payload
) == SECURITY_ASSOCIATION_V1
)
153 offset
+= payload
->get_length(payload
);
156 enumerator
->destroy(enumerator
);
158 data
= message
->get_packet_data(message
);
159 if (sa
&& data
.len
>= offset
+ sa
->get_length(sa
))
161 /* Get SA payload without 4 byte fixed header */
162 data
= chunk_skip(data
, offset
);
163 data
.len
= sa
->get_length(sa
);
164 data
= chunk_skip(data
, 4);
165 this->sa_payload
= chunk_clone(data
);
172 * Build main mode hash payloads
174 static void build_hash(private_main_mode_t
*this, bool initiator
,
175 message_t
*message
, identification_t
*id
)
177 hash_payload_t
*hash_payload
;
180 this->dh
->get_my_public_value(this->dh
, &dh
);
181 hash
= this->keymat
->get_hash(this->keymat
, initiator
, dh
, this->dh_value
,
182 this->ike_sa
->get_id(this->ike_sa
), this->sa_payload
, id
);
185 hash_payload
= hash_payload_create();
186 hash_payload
->set_hash(hash_payload
, hash
);
189 message
->add_payload(message
, &hash_payload
->payload_interface
);
193 * Verify main mode hash payload
195 static bool verify_hash(private_main_mode_t
*this, bool initiator
,
196 message_t
*message
, identification_t
*id
)
198 hash_payload_t
*hash_payload
;
202 hash_payload
= (hash_payload_t
*)message
->get_payload(message
,
206 DBG1(DBG_IKE
, "HASH payload missing in message");
209 hash
= hash_payload
->get_hash(hash_payload
);
210 this->dh
->get_my_public_value(this->dh
, &dh
);
211 hash
= this->keymat
->get_hash(this->keymat
, initiator
, this->dh_value
, dh
,
212 this->ike_sa
->get_id(this->ike_sa
), this->sa_payload
, id
);
214 equal
= chunk_equals(hash
, hash_payload
->get_hash(hash_payload
));
218 DBG1(DBG_IKE
, "calculated HASH does not match HASH payload");
224 * Generate and add NONCE, KE payload
226 static bool add_nonce_ke(private_main_mode_t
*this, chunk_t
*nonce
,
229 nonce_payload_t
*nonce_payload
;
230 ke_payload_t
*ke_payload
;
233 ke_payload
= ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1
,
235 message
->add_payload(message
, &ke_payload
->payload_interface
);
237 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
240 DBG1(DBG_IKE
, "no RNG found to create nonce");
243 rng
->allocate_bytes(rng
, NONCE_SIZE
, nonce
);
246 nonce_payload
= nonce_payload_create(NONCE_V1
);
247 nonce_payload
->set_nonce(nonce_payload
, *nonce
);
248 message
->add_payload(message
, &nonce_payload
->payload_interface
);
254 * Extract nonce from NONCE payload, process KE payload
256 static bool get_nonce_ke(private_main_mode_t
*this, chunk_t
*nonce
,
259 nonce_payload_t
*nonce_payload
;
260 ke_payload_t
*ke_payload
;
262 ke_payload
= (ke_payload_t
*)message
->get_payload(message
, KEY_EXCHANGE_V1
);
265 DBG1(DBG_IKE
, "KE payload missing in message");
268 this->dh_value
= chunk_clone(ke_payload
->get_key_exchange_data(ke_payload
));
269 this->dh
->set_other_public_value(this->dh
, this->dh_value
);
271 nonce_payload
= (nonce_payload_t
*)message
->get_payload(message
, NONCE_V1
);
274 DBG1(DBG_IKE
, "NONCE payload missing in message");
277 *nonce
= nonce_payload
->get_nonce(nonce_payload
);
282 METHOD(task_t
, build_i
, status_t
,
283 private_main_mode_t
*this, message_t
*message
)
289 sa_payload_t
*sa_payload
;
290 linked_list_t
*proposals
;
293 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
294 DBG0(DBG_IKE
, "initiating IKE_SA %s[%d] to %H",
295 this->ike_sa
->get_name(this->ike_sa
),
296 this->ike_sa
->get_unique_id(this->ike_sa
),
297 this->ike_sa
->get_other_host(this->ike_sa
));
298 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
300 proposals
= this->ike_cfg
->get_proposals(this->ike_cfg
);
302 sa_payload
= sa_payload_create_from_proposal_list(
303 SECURITY_ASSOCIATION_V1
, proposals
);
304 proposals
->destroy_offset(proposals
, offsetof(proposal_t
, destroy
));
306 message
->add_payload(message
, &sa_payload
->payload_interface
);
308 /* pregenerate message to store SA payload */
309 if (this->ike_sa
->generate_message(this->ike_sa
, message
,
312 DBG1(DBG_IKE
, "pregenerating SA payload failed");
315 packet
->destroy(packet
);
316 if (!save_sa_payload(this, message
))
318 DBG1(DBG_IKE
, "SA payload invalid");
329 if (!this->proposal
->get_algorithm(this->proposal
,
330 DIFFIE_HELLMAN_GROUP
, &group
, NULL
))
332 DBG1(DBG_IKE
, "DH group selection failed");
335 this->dh
= this->keymat
->keymat
.create_dh(&this->keymat
->keymat
,
339 DBG1(DBG_IKE
, "negotiated DH group not supported");
342 if (!add_nonce_ke(this, &this->nonce_i
, message
))
351 id_payload_t
*id_payload
;
352 identification_t
*id
;
354 this->peer_cfg
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
355 this->peer_cfg
->get_ref(this->peer_cfg
);
357 this->my_auth
= get_auth_cfg(this, TRUE
);
358 this->other_auth
= get_auth_cfg(this, FALSE
);
359 if (!this->my_auth
|| !this->other_auth
)
361 DBG1(DBG_CFG
, "no auth config found");
364 id
= this->my_auth
->get(this->my_auth
, AUTH_RULE_IDENTITY
);
367 DBG1(DBG_CFG
, "own identity not known");
371 this->ike_sa
->set_my_id(this->ike_sa
, id
->clone(id
));
373 id_payload
= id_payload_create_from_identification(ID_V1
, id
);
374 message
->add_payload(message
, &id_payload
->payload_interface
);
376 build_hash(this, TRUE
, message
, id
);
378 this->state
= MM_AUTH
;
386 METHOD(task_t
, process_r
, status_t
,
387 private_main_mode_t
*this, message_t
*message
)
394 sa_payload_t
*sa_payload
;
396 this->ike_cfg
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
397 DBG0(DBG_IKE
, "%H is initiating a Main Mode",
398 message
->get_source(message
));
399 this->ike_sa
->set_state(this->ike_sa
, IKE_CONNECTING
);
401 this->ike_sa
->update_hosts(this->ike_sa
,
402 message
->get_destination(message
),
403 message
->get_source(message
), TRUE
);
405 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
406 SECURITY_ASSOCIATION_V1
);
407 if (!sa_payload
|| !save_sa_payload(this, message
))
409 DBG1(DBG_IKE
, "SA payload missing or invalid");
413 list
= sa_payload
->get_proposals(sa_payload
);
414 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
416 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
419 DBG1(DBG_IKE
, "no proposal found");
429 if (!this->proposal
->get_algorithm(this->proposal
,
430 DIFFIE_HELLMAN_GROUP
, &group
, NULL
))
432 DBG1(DBG_IKE
, "DH group selection failed");
435 this->dh
= lib
->crypto
->create_dh(lib
->crypto
, group
);
438 DBG1(DBG_IKE
, "negotiated DH group not supported");
441 if (!get_nonce_ke(this, &this->nonce_i
, message
))
450 enumerator_t
*enumerator
;
451 id_payload_t
*id_payload
;
452 identification_t
*id
, *any
;
454 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_V1
);
457 DBG1(DBG_IKE
, "IDii payload missing");
461 id
= id_payload
->get_identification(id_payload
);
462 any
= identification_create_from_encoding(ID_ANY
, chunk_empty
);
463 enumerator
= charon
->backends
->create_peer_cfg_enumerator(
465 this->ike_sa
->get_my_host(this->ike_sa
),
466 this->ike_sa
->get_other_host(this->ike_sa
),
468 if (!enumerator
->enumerate(enumerator
, &this->peer_cfg
))
470 DBG1(DBG_IKE
, "no peer config found");
473 enumerator
->destroy(enumerator
);
476 this->peer_cfg
->get_ref(this->peer_cfg
);
477 enumerator
->destroy(enumerator
);
480 this->ike_sa
->set_other_id(this->ike_sa
, id
);
482 this->ike_sa
->set_peer_cfg(this->ike_sa
, this->peer_cfg
);
484 this->my_auth
= get_auth_cfg(this, TRUE
);
485 this->other_auth
= get_auth_cfg(this, FALSE
);
486 if (!this->my_auth
|| !this->other_auth
)
488 DBG1(DBG_IKE
, "auth config missing");
492 if (!verify_hash(this, TRUE
, message
, id
))
497 this->state
= MM_AUTH
;
506 * Lookup a shared secret for this IKE_SA
508 static shared_key_t
*lookup_shared_key(private_main_mode_t
*this)
511 identification_t
*my_id
, *other_id
;
512 shared_key_t
*shared_key
;
514 me
= this->ike_sa
->get_my_host(this->ike_sa
);
515 other
= this->ike_sa
->get_other_host(this->ike_sa
);
516 my_id
= identification_create_from_sockaddr(me
->get_sockaddr(me
));
517 other_id
= identification_create_from_sockaddr(other
->get_sockaddr(other
));
518 if (!my_id
|| !other_id
)
521 DESTROY_IF(other_id
);
524 shared_key
= lib
->credmgr
->get_shared(lib
->credmgr
, SHARED_IKE
, my_id
,
528 DBG1(DBG_IKE
, "no shared key found for %H - %H", me
, other
);
530 my_id
->destroy(my_id
);
531 other_id
->destroy(other_id
);
536 * Derive key material for this IKE_SA
538 static bool derive_keys(private_main_mode_t
*this, chunk_t nonce_i
,
541 ike_sa_id_t
*id
= this->ike_sa
->get_id(this->ike_sa
);
542 shared_key_t
*shared_key
= NULL
;
545 /* TODO-IKEv1: support other authentication classes */
546 auth
= AUTH_CLASS_PSK
;
550 shared_key
= lookup_shared_key(this);
555 if (!this->keymat
->derive_ike_keys(this->keymat
, this->proposal
, this->dh
,
556 this->dh_value
, nonce_i
, nonce_r
, id
, auth
, shared_key
))
558 DESTROY_IF(shared_key
);
561 DESTROY_IF(shared_key
);
562 charon
->bus
->ike_keys(charon
->bus
, this->ike_sa
, this->dh
, nonce_i
, nonce_r
,
567 METHOD(task_t
, build_r
, status_t
,
568 private_main_mode_t
*this, message_t
*message
)
574 sa_payload_t
*sa_payload
;
576 sa_payload
= sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1
,
578 message
->add_payload(message
, &sa_payload
->payload_interface
);
584 if (!add_nonce_ke(this, &this->nonce_r
, message
))
588 if (!derive_keys(this, this->nonce_i
, this->nonce_r
))
590 DBG1(DBG_IKE
, "key derivation failed");
597 id_payload_t
*id_payload
;
598 identification_t
*id
;
600 id
= this->my_auth
->get(this->my_auth
, AUTH_RULE_IDENTITY
);
603 DBG1(DBG_CFG
, "own identity not known");
607 this->ike_sa
->set_my_id(this->ike_sa
, id
->clone(id
));
609 id_payload
= id_payload_create_from_identification(ID_V1
, id
);
610 message
->add_payload(message
, &id_payload
->payload_interface
);
612 build_hash(this, FALSE
, message
, id
);
614 DBG0(DBG_IKE
, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
615 this->ike_sa
->get_name(this->ike_sa
),
616 this->ike_sa
->get_unique_id(this->ike_sa
),
617 this->ike_sa
->get_my_host(this->ike_sa
),
618 this->ike_sa
->get_my_id(this->ike_sa
),
619 this->ike_sa
->get_other_host(this->ike_sa
),
620 this->ike_sa
->get_other_id(this->ike_sa
));
621 this->ike_sa
->set_state(this->ike_sa
, IKE_ESTABLISHED
);
622 charon
->bus
->ike_updown(charon
->bus
, this->ike_sa
, TRUE
);
624 /* TODO-IKEv1: Check the proposal for XAuthInit* auth modes */
625 /* TODO-IKEv1: check for XAUTH rounds, queue them */
626 if(0) /* TODO-IKEv1: Change to 1 if XAUTH is desired. */
635 METHOD(task_t
, process_i
, status_t
,
636 private_main_mode_t
*this, message_t
*message
)
643 sa_payload_t
*sa_payload
;
645 sa_payload
= (sa_payload_t
*)message
->get_payload(message
,
646 SECURITY_ASSOCIATION_V1
);
649 DBG1(DBG_IKE
, "SA payload missing");
652 list
= sa_payload
->get_proposals(sa_payload
);
653 this->proposal
= this->ike_cfg
->select_proposal(this->ike_cfg
,
655 list
->destroy_offset(list
, offsetof(proposal_t
, destroy
));
658 DBG1(DBG_IKE
, "no proposal found");
665 if (!get_nonce_ke(this, &this->nonce_r
, message
))
669 if (!derive_keys(this, this->nonce_i
, this->nonce_r
))
671 DBG1(DBG_IKE
, "key derivation failed");
678 id_payload_t
*id_payload
;
679 identification_t
*id
;
681 id_payload
= (id_payload_t
*)message
->get_payload(message
, ID_V1
);
684 DBG1(DBG_IKE
, "IDir payload missing");
687 id
= id_payload
->get_identification(id_payload
);
688 if (!id
->matches(id
, this->other_auth
->get(this->other_auth
,
689 AUTH_RULE_IDENTITY
)))
691 DBG1(DBG_IKE
, "IDir does not match");
695 this->ike_sa
->set_other_id(this->ike_sa
, id
);
697 if (!verify_hash(this, FALSE
, message
, id
))
702 /* TODO-IKEv1: check for XAUTH rounds, queue them */
703 DBG0(DBG_IKE
, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]",
704 this->ike_sa
->get_name(this->ike_sa
),
705 this->ike_sa
->get_unique_id(this->ike_sa
),
706 this->ike_sa
->get_my_host(this->ike_sa
),
707 this->ike_sa
->get_my_id(this->ike_sa
),
708 this->ike_sa
->get_other_host(this->ike_sa
),
709 this->ike_sa
->get_other_id(this->ike_sa
));
710 this->ike_sa
->set_state(this->ike_sa
, IKE_ESTABLISHED
);
711 charon
->bus
->ike_updown(charon
->bus
, this->ike_sa
, TRUE
);
719 METHOD(task_t
, get_type
, task_type_t
,
720 private_main_mode_t
*this)
722 return TASK_MAIN_MODE
;
725 METHOD(task_t
, migrate
, void,
726 private_main_mode_t
*this, ike_sa_t
*ike_sa
)
728 this->ike_sa
= ike_sa
;
731 METHOD(task_t
, destroy
, void,
732 private_main_mode_t
*this)
734 DESTROY_IF(this->peer_cfg
);
735 DESTROY_IF(this->proposal
);
736 DESTROY_IF(this->dh
);
737 free(this->dh_value
.ptr
);
738 free(this->nonce_i
.ptr
);
739 free(this->nonce_r
.ptr
);
740 free(this->sa_payload
.ptr
);
745 * Described in header.
747 main_mode_t
*main_mode_create(ike_sa_t
*ike_sa
, bool initiator
)
749 private_main_mode_t
*this;
754 .get_type
= _get_type
,
760 .keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
),
761 .initiator
= initiator
,
767 this->public.task
.build
= _build_i
;
768 this->public.task
.process
= _process_i
;
772 this->public.task
.build
= _build_r
;
773 this->public.task
.process
= _process_r
;
776 return &this->public;