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/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 identification_t
*eap_identity
;
225 eap_identity
= this->eap_identity
->clone(this->eap_identity
);
226 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
227 cfg
->add(cfg
, AUTH_RULE_EAP_IDENTITY
, eap_identity
);
231 * Handle EAP exchange as server
233 static eap_payload_t
* server_process_eap(private_eap_authenticator_t
*this,
236 eap_type_t type
, received_type
;
237 u_int32_t vendor
, received_vendor
;
240 if (in
->get_code(in
) != EAP_RESPONSE
)
242 DBG1(DBG_IKE
, "received %N, sending %N",
243 eap_code_names
, in
->get_code(in
), eap_code_names
, EAP_FAILURE
);
244 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
247 type
= this->method
->get_type(this->method
, &vendor
);
248 received_type
= in
->get_type(in
, &received_vendor
);
249 if (type
!= received_type
|| vendor
!= received_vendor
)
251 if (received_vendor
== 0 && received_type
== EAP_NAK
)
253 DBG1(DBG_IKE
, "received %N, sending %N",
254 eap_type_names
, EAP_NAK
, eap_code_names
, EAP_FAILURE
);
258 DBG1(DBG_IKE
, "received invalid EAP response, sending %N",
259 eap_code_names
, EAP_FAILURE
);
261 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
264 switch (this->method
->process(this->method
, in
, &out
))
269 if (!vendor
&& type
== EAP_IDENTITY
)
273 if (this->method
->get_msk(this->method
, &data
) == SUCCESS
)
275 this->eap_identity
= identification_create_from_data(data
);
276 DBG1(DBG_IKE
, "received EAP identity '%Y'",
278 replace_eap_identity(this);
280 /* restart EAP exchange, but with real method */
281 this->method
->destroy(this->method
);
282 return server_initiate_eap(this, FALSE
);
284 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
286 this->msk
= chunk_clone(this->msk
);
290 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
291 "%sMSK established", type
, vendor
,
292 this->msk
.ptr ?
"" : "no ");
296 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
297 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
299 this->ike_sa
->set_condition(this->ike_sa
, COND_EAP_AUTHENTICATED
,
301 this->eap_complete
= TRUE
;
302 return eap_payload_create_code(EAP_SUCCESS
, in
->get_identifier(in
));
307 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d failed for "
308 "peer %Y", type
, vendor
,
309 this->ike_sa
->get_other_id(this->ike_sa
));
313 DBG1(DBG_IKE
, "EAP method %N failed for peer %Y",
314 eap_type_names
, type
,
315 this->ike_sa
->get_other_id(this->ike_sa
));
317 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
322 * Processing method for a peer
324 static eap_payload_t
* client_process_eap(private_eap_authenticator_t
*this,
331 identification_t
*id
;
333 type
= in
->get_type(in
, &vendor
);
335 if (!vendor
&& type
== EAP_IDENTITY
)
337 DESTROY_IF(this->eap_identity
);
338 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
339 id
= auth
->get(auth
, AUTH_RULE_EAP_IDENTITY
);
340 if (!id
|| id
->get_type(id
) == ID_ANY
)
342 id
= this->ike_sa
->get_my_id(this->ike_sa
);
344 DBG1(DBG_IKE
, "server requested %N (id 0x%02X), sending '%Y'",
345 eap_type_names
, type
, in
->get_identifier(in
), id
);
346 this->eap_identity
= id
->clone(id
);
348 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
351 if (this->method
->process(this->method
, in
, &out
) == SUCCESS
)
353 this->method
->destroy(this->method
);
357 this->method
->destroy(this->method
);
360 /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
361 * EAP method (types 3-253, 255) */
362 DBG1(DBG_IKE
, "%N not supported, sending EAP_NAK",
363 eap_type_names
, type
);
364 return eap_payload_create_nak(in
->get_identifier(in
), FALSE
);
366 if (this->method
== NULL
)
370 DBG1(DBG_IKE
, "server requested vendor specific EAP method %d-%d ",
371 "(id 0x%02X)", type
, vendor
, in
->get_identifier(in
));
375 DBG1(DBG_IKE
, "server requested %N authentication (id 0x%02X)",
376 eap_type_names
, type
, in
->get_identifier(in
));
378 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
381 DBG1(DBG_IKE
, "EAP method not supported, sending EAP_NAK");
382 return eap_payload_create_nak(in
->get_identifier(in
), vendor
!= 0);
386 type
= this->method
->get_type(this->method
, &vendor
);
388 if (this->method
->process(this->method
, in
, &out
) == NEED_MORE
)
389 { /* client methods should never return SUCCESS */
395 DBG1(DBG_IKE
, "vendor specific EAP method %d-%d failed", type
, vendor
);
399 DBG1(DBG_IKE
, "%N method failed", eap_type_names
, type
);
405 * Verify AUTH payload
407 static bool verify_auth(private_eap_authenticator_t
*this, message_t
*message
,
408 chunk_t nonce
, chunk_t init
)
410 auth_payload_t
*auth_payload
;
411 chunk_t auth_data
, recv_auth_data
;
412 identification_t
*other_id
;
416 auth_payload
= (auth_payload_t
*)message
->get_payload(message
,
420 DBG1(DBG_IKE
, "AUTH payload missing");
423 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
424 keymat
= (keymat_v2_t
*)this->ike_sa
->get_keymat(this->ike_sa
);
425 if (!keymat
->get_psk_sig(keymat
, TRUE
, init
, nonce
,
426 this->msk
, other_id
, this->reserved
, &auth_data
))
430 recv_auth_data
= auth_payload
->get_data(auth_payload
);
431 if (!auth_data
.len
|| !chunk_equals(auth_data
, recv_auth_data
))
433 DBG1(DBG_IKE
, "verification of AUTH payload with%s EAP MSK failed",
434 this->msk
.ptr ?
"" : "out");
435 chunk_free(&auth_data
);
438 chunk_free(&auth_data
);
440 DBG1(DBG_IKE
, "authentication of '%Y' with %N successful",
441 other_id
, auth_class_names
, AUTH_CLASS_EAP
);
442 this->auth_complete
= TRUE
;
443 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
444 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
451 static bool build_auth(private_eap_authenticator_t
*this, message_t
*message
,
452 chunk_t nonce
, chunk_t init
)
454 auth_payload_t
*auth_payload
;
455 identification_t
*my_id
;
459 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
460 keymat
= (keymat_v2_t
*)this->ike_sa
->get_keymat(this->ike_sa
);
462 DBG1(DBG_IKE
, "authentication of '%Y' (myself) with %N",
463 my_id
, auth_class_names
, AUTH_CLASS_EAP
);
465 if (!keymat
->get_psk_sig(keymat
, FALSE
, init
, nonce
,
466 this->msk
, my_id
, this->reserved
, &auth_data
))
470 auth_payload
= auth_payload_create();
471 auth_payload
->set_auth_method(auth_payload
, AUTH_PSK
);
472 auth_payload
->set_data(auth_payload
, auth_data
);
473 message
->add_payload(message
, (payload_t
*)auth_payload
);
474 chunk_free(&auth_data
);
478 METHOD(authenticator_t
, process_server
, status_t
,
479 private_eap_authenticator_t
*this, message_t
*message
)
481 eap_payload_t
*eap_payload
;
483 if (this->eap_complete
)
485 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
494 this->eap_payload
= server_initiate_eap(this, TRUE
);
498 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
499 EXTENSIBLE_AUTHENTICATION
);
504 this->eap_payload
= server_process_eap(this, eap_payload
);
509 METHOD(authenticator_t
, build_server
, status_t
,
510 private_eap_authenticator_t
*this, message_t
*message
)
512 if (this->eap_payload
)
516 code
= this->eap_payload
->get_code(this->eap_payload
);
517 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
518 this->eap_payload
= NULL
;
519 if (code
== EAP_FAILURE
)
525 if (this->eap_complete
&& this->auth_complete
&&
526 build_auth(this, message
, this->received_nonce
, this->sent_init
))
533 METHOD(authenticator_t
, process_client
, status_t
,
534 private_eap_authenticator_t
*this, message_t
*message
)
536 eap_payload_t
*eap_payload
;
538 if (this->eap_complete
)
540 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
544 if (this->require_mutual
&& !this->method
->is_mutual(this->method
))
545 { /* we require mutual authentication due to EAP-only */
548 DBG1(DBG_IKE
, "EAP-only authentication requires a mutual and "
549 "MSK deriving EAP method, but %N is not",
550 eap_type_names
, this->method
->get_type(this->method
, &vendor
));
556 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
557 EXTENSIBLE_AUTHENTICATION
);
560 switch (eap_payload
->get_code(eap_payload
))
564 this->eap_payload
= client_process_eap(this, eap_payload
);
565 if (this->eap_payload
)
577 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
579 this->msk
= chunk_clone(this->msk
);
581 type
= this->method
->get_type(this->method
, &vendor
);
584 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
585 "%sMSK established", type
, vendor
,
586 this->msk
.ptr ?
"" : "no ");
590 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
591 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
593 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
594 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
);
597 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, vendor
);
599 this->eap_complete
= TRUE
;
605 DBG1(DBG_IKE
, "received %N, EAP authentication failed",
606 eap_code_names
, eap_payload
->get_code(eap_payload
));
614 METHOD(authenticator_t
, build_client
, status_t
,
615 private_eap_authenticator_t
*this, message_t
*message
)
617 if (this->eap_payload
)
619 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
620 this->eap_payload
= NULL
;
623 if (this->eap_complete
&&
624 build_auth(this, message
, this->received_nonce
, this->sent_init
))
631 METHOD(authenticator_t
, is_mutual
, bool,
632 private_eap_authenticator_t
*this)
634 /* we don't know yet, but insist on it after EAP is complete */
635 this->require_mutual
= TRUE
;
639 METHOD(authenticator_t
, destroy
, void,
640 private_eap_authenticator_t
*this)
642 DESTROY_IF(this->method
);
643 DESTROY_IF(this->eap_payload
);
644 DESTROY_IF(this->eap_identity
);
645 chunk_free(&this->msk
);
650 * Described in header.
652 eap_authenticator_t
*eap_authenticator_create_builder(ike_sa_t
*ike_sa
,
653 chunk_t received_nonce
, chunk_t sent_nonce
,
654 chunk_t received_init
, chunk_t sent_init
,
657 private_eap_authenticator_t
*this;
662 .build
= _build_client
,
663 .process
= _process_client
,
664 .is_mutual
= _is_mutual
,
669 .received_init
= received_init
,
670 .received_nonce
= received_nonce
,
671 .sent_init
= sent_init
,
672 .sent_nonce
= sent_nonce
,
674 memcpy(this->reserved
, reserved
, sizeof(this->reserved
));
676 return &this->public;
680 * Described in header.
682 eap_authenticator_t
*eap_authenticator_create_verifier(ike_sa_t
*ike_sa
,
683 chunk_t received_nonce
, chunk_t sent_nonce
,
684 chunk_t received_init
, chunk_t sent_init
,
687 private_eap_authenticator_t
*this;
692 .build
= _build_server
,
693 .process
= _process_server
,
694 .is_mutual
= _is_mutual
,
699 .received_init
= received_init
,
700 .received_nonce
= received_nonce
,
701 .sent_init
= sent_init
,
702 .sent_nonce
= sent_nonce
,
704 memcpy(this->reserved
, reserved
, sizeof(this->reserved
));
706 return &this->public;