2 * Copyright (C) 2006-2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "eap_authenticator.h"
19 #include <sa/ikev2/keymat_v2.h>
20 #include <sa/ikev2/authenticators/eap/eap_method.h>
21 #include <encoding/payloads/auth_payload.h>
22 #include <encoding/payloads/eap_payload.h>
24 typedef struct private_eap_authenticator_t private_eap_authenticator_t
;
27 * Private data of an eap_authenticator_t object.
29 struct private_eap_authenticator_t
{
32 * Public authenticator_t interface.
34 eap_authenticator_t
public;
42 * others nonce to include in AUTH calculation
44 chunk_t received_nonce
;
47 * our nonce to include in AUTH calculation
52 * others IKE_SA_INIT message data to include in AUTH calculation
54 chunk_t received_init
;
57 * our IKE_SA_INIT message data to include in AUTH calculation
62 * Reserved bytes of ID payload
67 * Current EAP method processing
72 * MSK used to build and verify auth payload
77 * EAP authentication method completed successfully
82 * Set if we require mutual EAP due EAP-only authentication
87 * authentication payload verified successfully
92 * generated EAP payload
94 eap_payload_t
*eap_payload
;
97 * EAP identity of peer
99 identification_t
*eap_identity
;
105 static eap_method_t
*load_method(private_eap_authenticator_t
*this,
106 eap_type_t type
, u_int32_t vendor
, eap_role_t role
)
108 identification_t
*server
, *peer
, *aaa
;
111 if (role
== EAP_SERVER
)
113 server
= this->ike_sa
->get_my_id(this->ike_sa
);
114 peer
= this->ike_sa
->get_other_id(this->ike_sa
);
115 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
119 server
= this->ike_sa
->get_other_id(this->ike_sa
);
120 peer
= this->ike_sa
->get_my_id(this->ike_sa
);
121 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
123 if (this->eap_identity
)
125 peer
= this->eap_identity
;
127 aaa
= auth
->get(auth
, AUTH_RULE_AAA_IDENTITY
);
132 return charon
->eap
->create_instance(charon
->eap
, type
, vendor
,
137 * Initiate EAP conversation as server
139 static eap_payload_t
* server_initiate_eap(private_eap_authenticator_t
*this,
144 identification_t
*id
;
149 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
151 /* initiate EAP-Identity exchange if required */
152 if (!this->eap_identity
&& do_identity
)
154 id
= auth
->get(auth
, AUTH_RULE_EAP_IDENTITY
);
157 if (id
->get_type(id
) == ID_ANY
)
159 this->method
= load_method(this, EAP_IDENTITY
, 0, EAP_SERVER
);
162 if (this->method
->initiate(this->method
, &out
) == NEED_MORE
)
164 DBG1(DBG_IKE
, "initiating %N method (id 0x%02X)",
165 eap_type_names
, EAP_IDENTITY
,
166 this->method
->get_identifier(this->method
));
169 this->method
->destroy(this->method
);
171 DBG1(DBG_IKE
, "EAP-Identity request configured, "
172 "but not supported");
176 DBG1(DBG_IKE
, "using configured EAP-Identity %Y", id
);
177 this->eap_identity
= id
->clone(id
);
181 /* invoke real EAP method */
182 type
= (uintptr_t)auth
->get(auth
, AUTH_RULE_EAP_TYPE
);
183 vendor
= (uintptr_t)auth
->get(auth
, AUTH_RULE_EAP_VENDOR
);
185 this->method
= load_method(this, type
, vendor
, EAP_SERVER
);
188 action
= "initiating";
189 type
= this->method
->get_type(this->method
, &vendor
);
190 if (this->method
->initiate(this->method
, &out
) == NEED_MORE
)
194 DBG1(DBG_IKE
, "initiating EAP vendor type %d-%d method (id 0x%02X)",
195 type
, vendor
, out
->get_identifier(out
));
199 DBG1(DBG_IKE
, "initiating %N method (id 0x%02X)", eap_type_names
,
200 type
, out
->get_identifier(out
));
207 DBG1(DBG_IKE
, "%s EAP vendor type %d-%d method failed",
208 action
, type
, vendor
);
212 DBG1(DBG_IKE
, "%s %N method failed", action
, eap_type_names
, type
);
214 return eap_payload_create_code(EAP_FAILURE
, 0);
218 * Replace the existing EAP-Identity in other auth config
220 static void replace_eap_identity(private_eap_authenticator_t
*this)
222 enumerator_t
*enumerator
;
227 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
228 enumerator
= cfg
->create_enumerator(cfg
);
229 while (enumerator
->enumerate(enumerator
, &rule
, &ptr
))
231 if (rule
== AUTH_RULE_EAP_IDENTITY
)
233 cfg
->replace(cfg
, enumerator
, AUTH_RULE_EAP_IDENTITY
,
234 this->eap_identity
->clone(this->eap_identity
));
238 enumerator
->destroy(enumerator
);
242 * Handle EAP exchange as server
244 static eap_payload_t
* server_process_eap(private_eap_authenticator_t
*this,
247 eap_type_t type
, received_type
;
248 u_int32_t vendor
, received_vendor
;
251 if (in
->get_code(in
) != EAP_RESPONSE
)
253 DBG1(DBG_IKE
, "received %N, sending %N",
254 eap_code_names
, in
->get_code(in
), eap_code_names
, EAP_FAILURE
);
255 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
258 type
= this->method
->get_type(this->method
, &vendor
);
259 received_type
= in
->get_type(in
, &received_vendor
);
260 if (type
!= received_type
|| vendor
!= received_vendor
)
262 if (received_vendor
== 0 && received_type
== EAP_NAK
)
264 DBG1(DBG_IKE
, "received %N, sending %N",
265 eap_type_names
, EAP_NAK
, eap_code_names
, EAP_FAILURE
);
269 DBG1(DBG_IKE
, "received invalid EAP response, sending %N",
270 eap_code_names
, EAP_FAILURE
);
272 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
275 switch (this->method
->process(this->method
, in
, &out
))
280 if (!vendor
&& type
== EAP_IDENTITY
)
284 if (this->method
->get_msk(this->method
, &data
) == SUCCESS
)
286 this->eap_identity
= identification_create_from_data(data
);
287 DBG1(DBG_IKE
, "received EAP identity '%Y'",
289 replace_eap_identity(this);
291 /* restart EAP exchange, but with real method */
292 this->method
->destroy(this->method
);
293 return server_initiate_eap(this, FALSE
);
295 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
297 this->msk
= chunk_clone(this->msk
);
301 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
302 "%sMSK established", type
, vendor
,
303 this->msk
.ptr ?
"" : "no ");
307 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
308 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
310 this->ike_sa
->set_condition(this->ike_sa
, COND_EAP_AUTHENTICATED
,
312 this->eap_complete
= TRUE
;
313 return eap_payload_create_code(EAP_SUCCESS
, in
->get_identifier(in
));
318 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d failed for "
319 "peer %Y", type
, vendor
,
320 this->ike_sa
->get_other_id(this->ike_sa
));
324 DBG1(DBG_IKE
, "EAP method %N failed for peer %Y",
325 eap_type_names
, type
,
326 this->ike_sa
->get_other_id(this->ike_sa
));
328 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
333 * Processing method for a peer
335 static eap_payload_t
* client_process_eap(private_eap_authenticator_t
*this,
342 identification_t
*id
;
344 type
= in
->get_type(in
, &vendor
);
346 if (!vendor
&& type
== EAP_IDENTITY
)
348 DESTROY_IF(this->eap_identity
);
349 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
350 id
= auth
->get(auth
, AUTH_RULE_EAP_IDENTITY
);
351 if (!id
|| id
->get_type(id
) == ID_ANY
)
353 id
= this->ike_sa
->get_my_id(this->ike_sa
);
355 DBG1(DBG_IKE
, "server requested %N (id 0x%02X), sending '%Y'",
356 eap_type_names
, type
, in
->get_identifier(in
), id
);
357 this->eap_identity
= id
->clone(id
);
359 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
362 if (this->method
->process(this->method
, in
, &out
) == SUCCESS
)
364 this->method
->destroy(this->method
);
368 this->method
->destroy(this->method
);
371 DBG1(DBG_IKE
, "%N not supported, sending EAP_NAK",
372 eap_type_names
, type
);
373 return eap_payload_create_nak(in
->get_identifier(in
));
375 if (this->method
== NULL
)
379 DBG1(DBG_IKE
, "server requested vendor specific EAP method %d-%d ",
380 "(id 0x%02X)", type
, vendor
, in
->get_identifier(in
));
384 DBG1(DBG_IKE
, "server requested %N authentication (id 0x%02X)",
385 eap_type_names
, type
, in
->get_identifier(in
));
387 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
390 DBG1(DBG_IKE
, "EAP method not supported, sending EAP_NAK");
391 return eap_payload_create_nak(in
->get_identifier(in
));
395 type
= this->method
->get_type(this->method
, &vendor
);
397 if (this->method
->process(this->method
, in
, &out
) == NEED_MORE
)
398 { /* client methods should never return SUCCESS */
404 DBG1(DBG_IKE
, "vendor specific EAP method %d-%d failed", type
, vendor
);
408 DBG1(DBG_IKE
, "%N method failed", eap_type_names
, type
);
414 * Verify AUTH payload
416 static bool verify_auth(private_eap_authenticator_t
*this, message_t
*message
,
417 chunk_t nonce
, chunk_t init
)
419 auth_payload_t
*auth_payload
;
420 chunk_t auth_data
, recv_auth_data
;
421 identification_t
*other_id
;
425 auth_payload
= (auth_payload_t
*)message
->get_payload(message
,
429 DBG1(DBG_IKE
, "AUTH payload missing");
432 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
433 keymat
= (keymat_v2_t
*)this->ike_sa
->get_keymat(this->ike_sa
);
434 auth_data
= keymat
->get_psk_sig(keymat
, TRUE
, init
, nonce
,
435 this->msk
, other_id
, this->reserved
);
436 recv_auth_data
= auth_payload
->get_data(auth_payload
);
437 if (!auth_data
.len
|| !chunk_equals(auth_data
, recv_auth_data
))
439 DBG1(DBG_IKE
, "verification of AUTH payload with%s EAP MSK failed",
440 this->msk
.ptr ?
"" : "out");
441 chunk_free(&auth_data
);
444 chunk_free(&auth_data
);
446 DBG1(DBG_IKE
, "authentication of '%Y' with %N successful",
447 other_id
, auth_class_names
, AUTH_CLASS_EAP
);
448 this->auth_complete
= TRUE
;
449 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
450 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
457 static void build_auth(private_eap_authenticator_t
*this, message_t
*message
,
458 chunk_t nonce
, chunk_t init
)
460 auth_payload_t
*auth_payload
;
461 identification_t
*my_id
;
465 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
466 keymat
= (keymat_v2_t
*)this->ike_sa
->get_keymat(this->ike_sa
);
468 DBG1(DBG_IKE
, "authentication of '%Y' (myself) with %N",
469 my_id
, auth_class_names
, AUTH_CLASS_EAP
);
471 auth_data
= keymat
->get_psk_sig(keymat
, FALSE
, init
, nonce
,
472 this->msk
, my_id
, this->reserved
);
473 auth_payload
= auth_payload_create();
474 auth_payload
->set_auth_method(auth_payload
, AUTH_PSK
);
475 auth_payload
->set_data(auth_payload
, auth_data
);
476 message
->add_payload(message
, (payload_t
*)auth_payload
);
477 chunk_free(&auth_data
);
480 METHOD(authenticator_t
, process_server
, status_t
,
481 private_eap_authenticator_t
*this, message_t
*message
)
483 eap_payload_t
*eap_payload
;
485 if (this->eap_complete
)
487 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
496 this->eap_payload
= server_initiate_eap(this, TRUE
);
500 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
501 EXTENSIBLE_AUTHENTICATION
);
506 this->eap_payload
= server_process_eap(this, eap_payload
);
511 METHOD(authenticator_t
, build_server
, status_t
,
512 private_eap_authenticator_t
*this, message_t
*message
)
514 if (this->eap_payload
)
518 code
= this->eap_payload
->get_code(this->eap_payload
);
519 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
520 this->eap_payload
= NULL
;
521 if (code
== EAP_FAILURE
)
527 if (this->eap_complete
&& this->auth_complete
)
529 build_auth(this, message
, this->received_nonce
, this->sent_init
);
535 METHOD(authenticator_t
, process_client
, status_t
,
536 private_eap_authenticator_t
*this, message_t
*message
)
538 eap_payload_t
*eap_payload
;
540 if (this->eap_complete
)
542 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
546 if (this->require_mutual
&& !this->method
->is_mutual(this->method
))
547 { /* we require mutual authentication due to EAP-only */
550 DBG1(DBG_IKE
, "EAP-only authentication requires a mutual and "
551 "MSK deriving EAP method, but %N is not",
552 eap_type_names
, this->method
->get_type(this->method
, &vendor
));
558 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
559 EXTENSIBLE_AUTHENTICATION
);
562 switch (eap_payload
->get_code(eap_payload
))
566 this->eap_payload
= client_process_eap(this, eap_payload
);
567 if (this->eap_payload
)
579 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
581 this->msk
= chunk_clone(this->msk
);
583 type
= this->method
->get_type(this->method
, &vendor
);
586 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
587 "%sMSK established", type
, vendor
,
588 this->msk
.ptr ?
"" : "no ");
592 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
593 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
595 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
596 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
);
599 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, vendor
);
601 this->eap_complete
= TRUE
;
607 DBG1(DBG_IKE
, "received %N, EAP authentication failed",
608 eap_code_names
, eap_payload
->get_code(eap_payload
));
616 METHOD(authenticator_t
, build_client
, status_t
,
617 private_eap_authenticator_t
*this, message_t
*message
)
619 if (this->eap_payload
)
621 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
622 this->eap_payload
= NULL
;
625 if (this->eap_complete
)
627 build_auth(this, message
, this->received_nonce
, this->sent_init
);
633 METHOD(authenticator_t
, is_mutual
, bool,
634 private_eap_authenticator_t
*this)
636 /* we don't know yet, but insist on it after EAP is complete */
637 this->require_mutual
= TRUE
;
641 METHOD(authenticator_t
, destroy
, void,
642 private_eap_authenticator_t
*this)
644 DESTROY_IF(this->method
);
645 DESTROY_IF(this->eap_payload
);
646 DESTROY_IF(this->eap_identity
);
647 chunk_free(&this->msk
);
652 * Described in header.
654 eap_authenticator_t
*eap_authenticator_create_builder(ike_sa_t
*ike_sa
,
655 chunk_t received_nonce
, chunk_t sent_nonce
,
656 chunk_t received_init
, chunk_t sent_init
,
659 private_eap_authenticator_t
*this;
664 .build
= _build_client
,
665 .process
= _process_client
,
666 .is_mutual
= _is_mutual
,
671 .received_init
= received_init
,
672 .received_nonce
= received_nonce
,
673 .sent_init
= sent_init
,
674 .sent_nonce
= sent_nonce
,
676 memcpy(this->reserved
, reserved
, sizeof(this->reserved
));
678 return &this->public;
682 * Described in header.
684 eap_authenticator_t
*eap_authenticator_create_verifier(ike_sa_t
*ike_sa
,
685 chunk_t received_nonce
, chunk_t sent_nonce
,
686 chunk_t received_init
, chunk_t sent_init
,
689 private_eap_authenticator_t
*this;
694 .build
= _build_server
,
695 .process
= _process_server
,
696 .is_mutual
= _is_mutual
,
701 .received_init
= received_init
,
702 .received_nonce
= received_nonce
,
703 .sent_init
= sent_init
,
704 .sent_nonce
= sent_nonce
,
706 memcpy(this->reserved
, reserved
, sizeof(this->reserved
));
708 return &this->public;