2 * Copyright (C) 2006-2008 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
20 #include "eap_authenticator.h"
23 #include <config/peer_cfg.h>
24 #include <sa/authenticators/eap/eap_method.h>
26 typedef struct private_eap_authenticator_t private_eap_authenticator_t
;
29 * Private data of an eap_authenticator_t object.
31 struct private_eap_authenticator_t
{
34 * Public authenticator_t interface.
36 eap_authenticator_t
public;
44 * Role of this authenticator, PEER or SERVER
49 * Current EAP method processing
54 * MSK used to build and verify auth payload
59 * should we do a EAP-Identity exchange as server?
64 * saved EAP type if we do eap_identity
69 * saved vendor id if we do eap_identity
74 * Implementation of authenticator_t.verify.
76 static status_t
verify(private_eap_authenticator_t
*this, chunk_t ike_sa_init
,
77 chunk_t my_nonce
, auth_payload_t
*auth_payload
)
79 chunk_t auth_data
, recv_auth_data
;
80 identification_t
*other_id
;
83 other_id
= this->ike_sa
->get_other_id(this->ike_sa
);
84 keymat
= this->ike_sa
->get_keymat(this->ike_sa
);
86 auth_data
= keymat
->get_psk_sig(keymat
, TRUE
, ike_sa_init
, my_nonce
,
89 recv_auth_data
= auth_payload
->get_data(auth_payload
);
90 if (!auth_data
.len
|| !chunk_equals(auth_data
, recv_auth_data
))
92 DBG1(DBG_IKE
, "verification of AUTH payload created from EAP MSK failed");
93 chunk_free(&auth_data
);
96 chunk_free(&auth_data
);
98 DBG1(DBG_IKE
, "authentication of '%D' with %N successful",
99 other_id
, auth_class_names
, AUTH_CLASS_EAP
);
104 * Implementation of authenticator_t.build.
106 static status_t
build(private_eap_authenticator_t
*this, chunk_t ike_sa_init
,
107 chunk_t other_nonce
, auth_payload_t
**auth_payload
)
109 identification_t
*my_id
;
113 my_id
= this->ike_sa
->get_my_id(this->ike_sa
);
114 keymat
= this->ike_sa
->get_keymat(this->ike_sa
);
116 DBG1(DBG_IKE
, "authentication of '%D' (myself) with %N",
117 my_id
, auth_class_names
, AUTH_CLASS_EAP
);
119 auth_data
= keymat
->get_psk_sig(keymat
, FALSE
, ike_sa_init
, other_nonce
,
122 *auth_payload
= auth_payload_create();
123 (*auth_payload
)->set_auth_method(*auth_payload
, AUTH_PSK
);
124 (*auth_payload
)->set_data(*auth_payload
, auth_data
);
125 chunk_free(&auth_data
);
131 * get the peers identity to use in the EAP method
133 static identification_t
*get_peer_id(private_eap_authenticator_t
*this)
135 identification_t
*id
;
139 id
= this->ike_sa
->get_eap_identity(this->ike_sa
);
142 config
= this->ike_sa
->get_peer_cfg(this->ike_sa
);
143 auth
= config
->get_auth(config
);
144 if (!auth
->get_item(auth
, AUTHN_EAP_IDENTITY
, (void**)&id
))
146 if (this->role
== EAP_PEER
)
148 id
= this->ike_sa
->get_my_id(this->ike_sa
);
152 id
= this->ike_sa
->get_other_id(this->ike_sa
);
156 if (id
->get_type(id
) == ID_EAP
)
158 return id
->clone(id
);
160 return identification_create_from_encoding(ID_EAP
, id
->get_encoding(id
));
164 * get the servers identity to use in the EAP method
166 static identification_t
*get_server_id(private_eap_authenticator_t
*this)
168 identification_t
*id
;
170 if (this->role
== EAP_SERVER
)
172 id
= this->ike_sa
->get_my_id(this->ike_sa
);
176 id
= this->ike_sa
->get_other_id(this->ike_sa
);
178 if (id
->get_type(id
) == ID_EAP
)
180 return id
->clone(id
);
182 return identification_create_from_encoding(ID_EAP
, id
->get_encoding(id
));
186 * load an EAP method using the correct identities
188 static eap_method_t
*load_method(private_eap_authenticator_t
*this,
189 eap_type_t type
, u_int32_t vendor
, eap_role_t role
)
191 identification_t
*server
, *peer
;
192 eap_method_t
*method
;
194 server
= get_server_id(this);
195 peer
= get_peer_id(this);
196 method
= charon
->eap
->create_instance(charon
->eap
, type
, vendor
, role
,
198 server
->destroy(server
);
204 * Implementation of eap_authenticator_t.initiate
206 static status_t
initiate(private_eap_authenticator_t
*this, eap_type_t type
,
207 u_int32_t vendor
, eap_payload_t
**out
)
209 /* if initiate() is called, role is always server */
210 this->role
= EAP_SERVER
;
212 if (this->do_eap_identity
)
213 { /* do an EAP-Identity request first */
215 this->vendor
= vendor
;
223 "client requested EAP authentication, but configuration forbids it");
224 *out
= eap_payload_create_code(EAP_FAILURE
, 0);
230 DBG1(DBG_IKE
, "requesting vendor specific EAP method %d-%d",
235 DBG1(DBG_IKE
, "requesting EAP method %N", eap_type_names
, type
);
237 this->method
= load_method(this, type
, vendor
, this->role
);
238 if (this->method
== NULL
)
240 if (vendor
== 0 && type
== EAP_IDENTITY
)
242 DBG1(DBG_IKE
, "skipping %N, no implementation found",
243 eap_type_names
, type
);
244 this->do_eap_identity
= FALSE
;
245 return initiate(this, this->type
, this->vendor
, out
);
247 DBG1(DBG_IKE
, "configured EAP server method not supported, sending %N",
248 eap_code_names
, EAP_FAILURE
);
249 *out
= eap_payload_create_code(EAP_FAILURE
, 0);
252 if (this->method
->initiate(this->method
, out
) != NEED_MORE
)
254 DBG1(DBG_IKE
, "failed to initiate EAP exchange, sending %N",
255 eap_type_names
, type
, eap_code_names
, EAP_FAILURE
);
256 *out
= eap_payload_create_code(EAP_FAILURE
, 0);
263 * Processing method for a peer
265 static status_t
process_peer(private_eap_authenticator_t
*this,
266 eap_payload_t
*in
, eap_payload_t
**out
)
271 type
= in
->get_type(in
, &vendor
);
273 if (!vendor
&& type
== EAP_IDENTITY
)
275 eap_method_t
*method
;
277 method
= load_method(this, type
, 0, EAP_PEER
);
278 if (method
== NULL
|| method
->process(method
, in
, out
) != SUCCESS
)
280 DBG1(DBG_IKE
, "EAP server requested %N, but unable to process",
281 eap_type_names
, type
);
285 DBG1(DBG_IKE
, "EAP server requested %N", eap_type_names
, type
);
286 method
->destroy(method
);
290 /* create an eap_method for the first call */
291 if (this->method
== NULL
)
295 DBG1(DBG_IKE
, "EAP server requested vendor specific EAP method %d-%d",
300 DBG1(DBG_IKE
, "EAP server requested %N authentication",
301 eap_type_names
, type
);
303 this->method
= load_method(this, type
, vendor
, EAP_PEER
);
304 if (this->method
== NULL
)
306 DBG1(DBG_IKE
, "EAP server requested unsupported "
307 "EAP method, sending EAP_NAK");
308 *out
= eap_payload_create_nak(in
->get_identifier(in
));
313 type
= this->method
->get_type(this->method
, &vendor
);
315 switch (this->method
->process(this->method
, in
, out
))
322 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeded",
327 DBG1(DBG_IKE
, "EAP method %N succeeded", eap_type_names
, type
);
334 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d failed",
339 DBG1(DBG_IKE
, "EAP method %N failed",
340 eap_type_names
, type
);
347 * handle an EAP-Identity response on the server
349 static status_t
process_eap_identity(private_eap_authenticator_t
*this,
353 identification_t
*id
;
355 if (this->method
->get_msk(this->method
, &data
) == SUCCESS
)
357 id
= identification_create_from_encoding(ID_EAP
, data
);
358 DBG1(DBG_IKE
, "using EAP identity '%D'", id
);
359 this->ike_sa
->set_eap_identity(this->ike_sa
, id
);
361 /* restart EAP exchange, but with real method */
362 this->method
->destroy(this->method
);
363 this->do_eap_identity
= FALSE
;
364 return initiate(this, this->type
, this->vendor
, out
);
368 * Processing method for a server
370 static status_t
process_server(private_eap_authenticator_t
*this,
371 eap_payload_t
*in
, eap_payload_t
**out
)
376 type
= this->method
->get_type(this->method
, &vendor
);
378 switch (this->method
->process(this->method
, in
, out
))
383 if (this->do_eap_identity
)
385 return process_eap_identity(this, out
);
387 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
389 this->msk
= chunk_clone(this->msk
);
393 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d succeded, "
394 "%sMSK established", type
, vendor
,
395 this->msk
.ptr ?
"" : "no ");
399 DBG1(DBG_IKE
, "EAP method %N succeded, %sMSK established",
400 eap_type_names
, type
, this->msk
.ptr ?
"" : "no ");
402 *out
= eap_payload_create_code(EAP_SUCCESS
, in
->get_identifier(in
));
408 DBG1(DBG_IKE
, "EAP vendor specific method %d-%d failed for "
409 "peer %D", type
, vendor
,
410 this->ike_sa
->get_other_id(this->ike_sa
));
414 DBG1(DBG_IKE
, "EAP method %N failed for peer %D",
415 eap_type_names
, type
,
416 this->ike_sa
->get_other_id(this->ike_sa
));
418 *out
= eap_payload_create_code(EAP_FAILURE
, in
->get_identifier(in
));
424 * Implementation of eap_authenticator_t.process
426 static status_t
process(private_eap_authenticator_t
*this, eap_payload_t
*in
,
429 eap_code_t code
= in
->get_code(in
);
439 return process_server(this, in
, out
);
443 DBG1(DBG_IKE
, "received %N, sending %N",
444 eap_code_names
, code
, eap_code_names
, EAP_FAILURE
);
445 *out
= eap_payload_create_code(EAP_FAILURE
,
446 in
->get_identifier(in
));
457 return process_peer(this, in
, out
);
461 if (this->method
->get_msk(this->method
, &this->msk
) == SUCCESS
)
463 this->msk
= chunk_clone(this->msk
);
470 DBG1(DBG_IKE
, "received %N, EAP authentication failed",
471 eap_code_names
, code
);
484 * Implementation of authenticator_t.is_mutual.
486 static bool is_mutual(private_eap_authenticator_t
*this)
490 return this->method
->is_mutual(this->method
);
496 * Implementation of authenticator_t.destroy.
498 static void destroy(private_eap_authenticator_t
*this)
500 DESTROY_IF(this->method
);
501 chunk_free(&this->msk
);
506 * Described in header.
508 eap_authenticator_t
*eap_authenticator_create(ike_sa_t
*ike_sa
)
512 identification_t
*id
;
513 private_eap_authenticator_t
*this = malloc_thing(private_eap_authenticator_t
);
515 /* public functions */
516 this->public.authenticator_interface
.verify
= (status_t(*)(authenticator_t
*,chunk_t
,chunk_t
,auth_payload_t
*))verify
;
517 this->public.authenticator_interface
.build
= (status_t(*)(authenticator_t
*,chunk_t
,chunk_t
,auth_payload_t
**))build
;
518 this->public.authenticator_interface
.destroy
= (void(*)(authenticator_t
*))destroy
;
520 this->public.is_mutual
= (bool(*)(eap_authenticator_t
*))is_mutual
;
521 this->public.initiate
= (status_t(*)(eap_authenticator_t
*,eap_type_t
,u_int32_t
,eap_payload_t
**))initiate
;
522 this->public.process
= (status_t(*)(eap_authenticator_t
*,eap_payload_t
*,eap_payload_t
**))process
;
525 this->ike_sa
= ike_sa
;
526 this->role
= EAP_PEER
;
528 this->msk
= chunk_empty
;
529 this->do_eap_identity
= FALSE
;
533 config
= ike_sa
->get_peer_cfg(ike_sa
);
536 auth
= config
->get_auth(config
);
537 if (auth
->get_item(auth
, AUTHN_EAP_IDENTITY
, (void**)&id
))
539 if (id
->get_type(id
) == ID_ANY
)
540 { /* %any as configured EAP identity runs EAP-Identity first */
541 this->do_eap_identity
= TRUE
;
545 ike_sa
->set_eap_identity(ike_sa
, id
->clone(id
));
549 return &this->public;