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/authenticators/eap/eap_method.h>
20 #include <encoding/payloads/auth_payload.h>
21 #include <encoding/payloads/eap_payload.h>
23 typedef struct private_eap_authenticator_t private_eap_authenticator_t
;
26 * Private data of an eap_authenticator_t object.
28 struct private_eap_authenticator_t
{
31 * Public authenticator_t interface.
33 eap_authenticator_t
public;
41 * others nonce to include in AUTH calculation
43 chunk_t received_nonce
;
46 * our nonce to include in AUTH calculation
51 * others IKE_SA_INIT message data to include in AUTH calculation
53 chunk_t received_init
;
56 * our IKE_SA_INIT message data to include in AUTH calculation
61 * Current EAP method processing
66 * MSK used to build and verify auth payload
71 * EAP authentication method completed successfully
76 * authentication payload verified successfully
81 * generated EAP payload
83 eap_payload_t
*eap_payload
;
86 * EAP identity of peer
88 identification_t
*eap_identity
;
94 static eap_method_t
*load_method(private_eap_authenticator_t
*this,
95 eap_type_t type
, u_int32_t vendor
, eap_role_t role
)
97 identification_t
*server
, *peer
;
99 if (role
== EAP_SERVER
)
101 server
= this->ike_sa
->get_my_id(this->ike_sa
);
102 peer
= this->ike_sa
->get_other_id(this->ike_sa
);
106 server
= this->ike_sa
->get_other_id(this->ike_sa
);
107 peer
= this->ike_sa
->get_my_id(this->ike_sa
);
109 if (this->eap_identity
)
111 peer
= this->eap_identity
;
113 return charon
->eap
->create_instance(charon
->eap
, type
, vendor
,
118 * Initiate EAP conversation as server
120 static eap_payload_t
* server_initiate_eap(private_eap_authenticator_t
*this,
125 identification_t
*id
;
129 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
131 /* initiate EAP-Identity exchange if required */
132 if (!this->eap_identity
&& do_identity
)
134 id
= auth
->get(auth
, AUTH_RULE_EAP_IDENTITY
);
137 this->method
= load_method(this, EAP_IDENTITY
, 0, EAP_SERVER
);
140 if (this->method
->initiate(this->method
, &out
) == NEED_MORE
)
142 DBG1(DBG_IKE
, "initiating EAP-Identity request");
145 this->method
->destroy(this->method
);
147 DBG1(DBG_IKE
, "EAP-Identity request configured, but not supported");
150 /* invoke real EAP method */
151 type
= (uintptr_t)auth
->get(auth
, AUTH_RULE_EAP_TYPE
);
152 vendor
= (uintptr_t)auth
->get(auth
, AUTH_RULE_EAP_VENDOR
);
153 this->method
= load_method(this, type
, vendor
, EAP_SERVER
);
155 this->method
->initiate(this->method
, &out
) == NEED_MORE
)
159 DBG1(DBG_IKE
, "initiating EAP vendor type %d-%d", type
, vendor
);
164 DBG1(DBG_IKE
, "initiating %N", eap_type_names
, type
);
170 DBG1(DBG_IKE
, "initiating EAP vendor type %d-%d failed", type
, vendor
);
174 DBG1(DBG_IKE
, "initiating %N failed", eap_type_names
, type
);
176 return eap_payload_create_code(EAP_FAILURE
, 0);
180 * Handle EAP exchange as server
182 static eap_payload_t
* server_process_eap(private_eap_authenticator_t
*this,
185 eap_type_t type
, received_type
;
186 u_int32_t vendor
, received_vendor
;
190 if (in
->get_code(in
) != EAP_RESPONSE
)
192 DBG1(DBG_IKE
, "received %N, sending %N",
193 eap_code_names
, in
->get_code(in
), eap_code_names
, EAP_FAILURE
);
194 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
197 type
= this->method
->get_type(this->method
, &vendor
);
198 received_type
= in
->get_type(in
, &received_vendor
);
199 if (type
!= received_type
|| vendor
!= received_vendor
)
201 if (received_vendor
== 0 && received_type
== EAP_NAK
)
203 DBG1(DBG_IKE
, "received %N, sending %N",
204 eap_type_names
, EAP_NAK
, eap_code_names
, EAP_FAILURE
);
208 DBG1(DBG_IKE
, "received invalid EAP response, sending %N",
209 eap_code_names
, EAP_FAILURE
);
211 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
214 switch (this->method
->process(this->method
, in
, &out
))
219 if (type
== EAP_IDENTITY
)
224 if (this->method
->get_msk(this->method
, &data
) == SUCCESS
)
226 snprintf(buf
, sizeof(buf
), "%.*s", data
.len
, data
.ptr
);
227 this->eap_identity
= identification_create_from_string(buf
);
228 DBG1(DBG_IKE
, "received EAP identity '%Y'",
231 /* restart EAP exchange, but with real method */
232 this->method
->destroy(this->method
);
233 return server_initiate_eap(this, FALSE
);
235 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
237 this->msk
= chunk_clone(this->msk
);
241 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
242 "%sMSK established", type
, vendor
,
243 this->msk
.ptr ?
"" : "no ");
247 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
248 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
250 this->ike_sa
->set_condition(this->ike_sa
, COND_EAP_AUTHENTICATED
,
252 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
253 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
);
256 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, vendor
);
258 this->eap_complete
= TRUE
;
259 return eap_payload_create_code(EAP_SUCCESS
, in
->get_identifier(in
));
264 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d failed for "
265 "peer %Y", type
, vendor
,
266 this->ike_sa
->get_other_id(this->ike_sa
));
270 DBG1(DBG_IKE
, "EAP method %N failed for peer %Y",
271 eap_type_names
, type
,
272 this->ike_sa
->get_other_id(this->ike_sa
));
274 return eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
279 * Processing method for a peer
281 static eap_payload_t
* client_process_eap(private_eap_authenticator_t
*this,
288 identification_t
*id
;
290 type
= in
->get_type(in
, &vendor
);
292 if (!vendor
&& type
== EAP_IDENTITY
)
294 DESTROY_IF(this->eap_identity
);
295 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
296 id
= auth
->get(auth
, AUTH_RULE_EAP_IDENTITY
);
297 if (!id
|| id
->get_type(id
) == ID_ANY
)
299 id
= this->ike_sa
->get_my_id(this->ike_sa
);
301 DBG1(DBG_IKE
, "server requested %N, sending '%Y'",
302 eap_type_names
, type
, id
);
303 this->eap_identity
= id
->clone(id
);
305 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
308 if (this->method
->process(this->method
, in
, &out
) == SUCCESS
)
310 this->method
->destroy(this->method
);
314 this->method
->destroy(this->method
);
317 DBG1(DBG_IKE
, "%N not supported, sending EAP_NAK",
318 eap_type_names
, type
);
319 return eap_payload_create_nak(in
->get_identifier(in
));
321 if (this->method
== NULL
)
325 DBG1(DBG_IKE
, "server requested vendor specific EAP method %d-%d",
330 DBG1(DBG_IKE
, "server requested %N authentication",
331 eap_type_names
, type
);
333 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
336 DBG1(DBG_IKE
, "EAP method not supported, sending EAP_NAK");
337 return eap_payload_create_nak(in
->get_identifier(in
));
341 type
= this->method
->get_type(this->method
, &vendor
);
343 if (this->method
->process(this->method
, in
, &out
) == NEED_MORE
)
344 { /* client methods should never return SUCCESS */
350 DBG1(DBG_IKE
, "vendor specific EAP method %d-%d failed", type
, vendor
);
354 DBG1(DBG_IKE
, "%N method failed", eap_type_names
, type
);
360 * Verify AUTH payload
362 static bool verify_auth(private_eap_authenticator_t
*this, message_t
*message
,
363 chunk_t nonce
, chunk_t init
)
365 auth_payload_t
*auth_payload
;
366 chunk_t auth_data
, recv_auth_data
;
367 identification_t
*other_id
;
371 auth_payload
= (auth_payload_t
*)message
->get_payload(message
,
375 DBG1(DBG_IKE
, "AUTH payload missing");
378 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
379 keymat
= this->ike_sa
->get_keymat(this->ike_sa
);
380 auth_data
= keymat
->get_psk_sig(keymat
, TRUE
, init
, nonce
,
381 this->msk
, other_id
);
382 recv_auth_data
= auth_payload
->get_data(auth_payload
);
383 if (!auth_data
.len
|| !chunk_equals(auth_data
, recv_auth_data
))
385 DBG1(DBG_IKE
, "verification of AUTH payload with%s EAP MSK failed",
386 this->msk
.ptr ?
"" : "out");
387 chunk_free(&auth_data
);
390 chunk_free(&auth_data
);
392 DBG1(DBG_IKE
, "authentication of '%Y' with %N successful",
393 other_id
, auth_class_names
, AUTH_CLASS_EAP
);
394 this->auth_complete
= TRUE
;
395 auth
= this->ike_sa
->get_auth_cfg(this->ike_sa
, FALSE
);
396 auth
->add(auth
, AUTH_RULE_AUTH_CLASS
, AUTH_CLASS_EAP
);
403 static void build_auth(private_eap_authenticator_t
*this, message_t
*message
,
404 chunk_t nonce
, chunk_t init
)
406 auth_payload_t
*auth_payload
;
407 identification_t
*my_id
;
411 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
412 keymat
= this->ike_sa
->get_keymat(this->ike_sa
);
414 DBG1(DBG_IKE
, "authentication of '%Y' (myself) with %N",
415 my_id
, auth_class_names
, AUTH_CLASS_EAP
);
417 auth_data
= keymat
->get_psk_sig(keymat
, FALSE
, init
, nonce
, this->msk
, my_id
);
418 auth_payload
= auth_payload_create();
419 auth_payload
->set_auth_method(auth_payload
, AUTH_PSK
);
420 auth_payload
->set_data(auth_payload
, auth_data
);
421 message
->add_payload(message
, (payload_t
*)auth_payload
);
422 chunk_free(&auth_data
);
426 * Implementation of authenticator_t.process for a server
428 static status_t
process_server(private_eap_authenticator_t
*this,
431 eap_payload_t
*eap_payload
;
433 if (this->eap_complete
)
435 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
444 this->eap_payload
= server_initiate_eap(this, TRUE
);
448 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
449 EXTENSIBLE_AUTHENTICATION
);
454 this->eap_payload
= server_process_eap(this, eap_payload
);
460 * Implementation of authenticator_t.build for a server
462 static status_t
build_server(private_eap_authenticator_t
*this,
465 if (this->eap_payload
)
469 code
= this->eap_payload
->get_code(this->eap_payload
);
470 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
471 this->eap_payload
= NULL
;
472 if (code
== EAP_FAILURE
)
478 if (this->eap_complete
&& this->auth_complete
)
480 build_auth(this, message
, this->received_nonce
, this->sent_init
);
487 * Implementation of authenticator_t.process for a client
489 static status_t
process_client(private_eap_authenticator_t
*this,
492 eap_payload_t
*eap_payload
;
494 if (this->eap_complete
)
496 if (!verify_auth(this, message
, this->sent_nonce
, this->received_init
))
503 eap_payload
= (eap_payload_t
*)message
->get_payload(message
,
504 EXTENSIBLE_AUTHENTICATION
);
507 switch (eap_payload
->get_code(eap_payload
))
511 this->eap_payload
= client_process_eap(this, eap_payload
);
520 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
522 this->msk
= chunk_clone(this->msk
);
524 type
= this->method
->get_type(this->method
, &vendor
);
527 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeeded, "
528 "%sMSK established", type
, vendor
,
529 this->msk
.ptr ?
"" : "no ");
533 DBG1(DBG_IKE
, "EAP method %N succeeded, %sMSK established",
534 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
536 cfg
= this->ike_sa
->get_auth_cfg(this->ike_sa
, TRUE
);
537 cfg
->add(cfg
, AUTH_RULE_EAP_TYPE
, type
);
540 cfg
->add(cfg
, AUTH_RULE_EAP_VENDOR
, vendor
);
542 this->eap_complete
= TRUE
;
548 DBG1(DBG_IKE
, "received %N, EAP authentication failed",
549 eap_code_names
, eap_payload
->get_code(eap_payload
));
558 * Implementation of authenticator_t.build for a client
560 static status_t
build_client(private_eap_authenticator_t
*this,
563 if (this->eap_payload
)
565 message
->add_payload(message
, (payload_t
*)this->eap_payload
);
566 this->eap_payload
= NULL
;
569 if (this->eap_complete
)
571 build_auth(this, message
, this->received_nonce
, this->sent_init
);
578 * Implementation of authenticator_t.destroy.
580 static void destroy(private_eap_authenticator_t
*this)
582 DESTROY_IF(this->method
);
583 DESTROY_IF(this->eap_payload
);
584 DESTROY_IF(this->eap_identity
);
585 chunk_free(&this->msk
);
590 * Described in header.
592 eap_authenticator_t
*eap_authenticator_create_builder(ike_sa_t
*ike_sa
,
593 chunk_t received_nonce
, chunk_t sent_nonce
,
594 chunk_t received_init
, chunk_t sent_init
)
596 private_eap_authenticator_t
*this = malloc_thing(private_eap_authenticator_t
);
598 this->public.authenticator
.build
= (status_t(*)(authenticator_t
*, message_t
*message
))build_client
;
599 this->public.authenticator
.process
= (status_t(*)(authenticator_t
*, message_t
*message
))process_client
;
600 this->public.authenticator
.destroy
= (void(*)(authenticator_t
*))destroy
;
602 this->ike_sa
= ike_sa
;
603 this->received_init
= received_init
;
604 this->received_nonce
= received_nonce
;
605 this->sent_init
= sent_init
;
606 this->sent_nonce
= sent_nonce
;
607 this->msk
= chunk_empty
;
609 this->eap_payload
= NULL
;
610 this->eap_complete
= FALSE
;
611 this->auth_complete
= FALSE
;
612 this->eap_identity
= NULL
;
614 return &this->public;
618 * Described in header.
620 eap_authenticator_t
*eap_authenticator_create_verifier(ike_sa_t
*ike_sa
,
621 chunk_t received_nonce
, chunk_t sent_nonce
,
622 chunk_t received_init
, chunk_t sent_init
)
624 private_eap_authenticator_t
*this = malloc_thing(private_eap_authenticator_t
);
626 this->public.authenticator
.build
= (status_t(*)(authenticator_t
*, message_t
*messageh
))build_server
;
627 this->public.authenticator
.process
= (status_t(*)(authenticator_t
*, message_t
*message
))process_server
;
628 this->public.authenticator
.destroy
= (void(*)(authenticator_t
*))destroy
;
630 this->ike_sa
= ike_sa
;
631 this->received_init
= received_init
;
632 this->received_nonce
= received_nonce
;
633 this->sent_init
= sent_init
;
634 this->sent_nonce
= sent_nonce
;
635 this->msk
= chunk_empty
;
637 this->eap_payload
= NULL
;
638 this->eap_complete
= FALSE
;
639 this->auth_complete
= FALSE
;
640 this->eap_identity
= NULL
;
642 return &this->public;