Fixed EAP authentication regression
[strongswan.git] / src / charon / sa / authenticators / eap_authenticator.c
1 /*
2 * Copyright (C) 2006-2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "eap_authenticator.h"
17
18 #include <daemon.h>
19 #include <sa/authenticators/eap/eap_method.h>
20 #include <encoding/payloads/auth_payload.h>
21 #include <encoding/payloads/eap_payload.h>
22
23 typedef struct private_eap_authenticator_t private_eap_authenticator_t;
24
25 /**
26 * Private data of an eap_authenticator_t object.
27 */
28 struct private_eap_authenticator_t {
29
30 /**
31 * Public authenticator_t interface.
32 */
33 eap_authenticator_t public;
34
35 /**
36 * Assigned IKE_SA
37 */
38 ike_sa_t *ike_sa;
39
40 /**
41 * others nonce to include in AUTH calculation
42 */
43 chunk_t received_nonce;
44
45 /**
46 * our nonce to include in AUTH calculation
47 */
48 chunk_t sent_nonce;
49
50 /**
51 * others IKE_SA_INIT message data to include in AUTH calculation
52 */
53 chunk_t received_init;
54
55 /**
56 * our IKE_SA_INIT message data to include in AUTH calculation
57 */
58 chunk_t sent_init;
59
60 /**
61 * Current EAP method processing
62 */
63 eap_method_t *method;
64
65 /**
66 * MSK used to build and verify auth payload
67 */
68 chunk_t msk;
69
70 /**
71 * EAP authentication method completed successfully
72 */
73 bool eap_complete;
74
75 /**
76 * authentication payload verified successfully
77 */
78 bool auth_complete;
79
80 /**
81 * generated EAP payload
82 */
83 eap_payload_t *eap_payload;
84
85 /**
86 * EAP identity of peer
87 */
88 identification_t *eap_identity;
89 };
90
91 /**
92 * load an EAP method
93 */
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)
96 {
97 identification_t *server, *peer;
98
99 if (role == EAP_SERVER)
100 {
101 server = this->ike_sa->get_my_id(this->ike_sa);
102 peer = this->ike_sa->get_other_id(this->ike_sa);
103 }
104 else
105 {
106 server = this->ike_sa->get_other_id(this->ike_sa);
107 peer = this->ike_sa->get_my_id(this->ike_sa);
108 }
109 if (this->eap_identity)
110 {
111 peer = this->eap_identity;
112 }
113 return charon->eap->create_instance(charon->eap, type, vendor,
114 role, server, peer);
115 }
116
117 /**
118 * Initiate EAP conversation as server
119 */
120 static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
121 bool do_identity)
122 {
123 auth_cfg_t *auth;
124 eap_type_t type;
125 identification_t *id;
126 u_int32_t vendor;
127 eap_payload_t *out;
128
129 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
130
131 /* initiate EAP-Identity exchange if required */
132 if (!this->eap_identity && do_identity)
133 {
134 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
135 if (id)
136 {
137 this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
138 if (this->method)
139 {
140 if (this->method->initiate(this->method, &out) == NEED_MORE)
141 {
142 DBG1(DBG_IKE, "initiating EAP-Identity request");
143 return out;
144 }
145 this->method->destroy(this->method);
146 }
147 DBG1(DBG_IKE, "EAP-Identity request configured, but not supported");
148 }
149 }
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);
154 if (this->method &&
155 this->method->initiate(this->method, &out) == NEED_MORE)
156 {
157 if (vendor)
158 {
159 DBG1(DBG_IKE, "initiating EAP vendor type %d-%d", type, vendor);
160
161 }
162 else
163 {
164 DBG1(DBG_IKE, "initiating %N", eap_type_names, type);
165 }
166 return out;
167 }
168 if (vendor)
169 {
170 DBG1(DBG_IKE, "initiating EAP vendor type %d-%d failed", type, vendor);
171 }
172 else
173 {
174 DBG1(DBG_IKE, "initiating %N failed", eap_type_names, type);
175 }
176 return eap_payload_create_code(EAP_FAILURE, 0);
177 }
178
179 /**
180 * Handle EAP exchange as server
181 */
182 static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
183 eap_payload_t *in)
184 {
185 eap_type_t type, received_type;
186 u_int32_t vendor, received_vendor;
187 eap_payload_t *out;
188 auth_cfg_t *cfg;
189
190 if (in->get_code(in) != EAP_RESPONSE)
191 {
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));
195 }
196
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)
200 {
201 if (received_vendor == 0 && received_type == EAP_NAK)
202 {
203 DBG1(DBG_IKE, "received %N, sending %N",
204 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
205 }
206 else
207 {
208 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
209 eap_code_names, EAP_FAILURE);
210 }
211 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
212 }
213
214 switch (this->method->process(this->method, in, &out))
215 {
216 case NEED_MORE:
217 return out;
218 case SUCCESS:
219 if (type == EAP_IDENTITY)
220 {
221 chunk_t data;
222 char buf[256];
223
224 if (this->method->get_msk(this->method, &data) == SUCCESS)
225 {
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'",
229 this->eap_identity);
230 }
231 /* restart EAP exchange, but with real method */
232 this->method->destroy(this->method);
233 return server_initiate_eap(this, FALSE);
234 }
235 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
236 {
237 this->msk = chunk_clone(this->msk);
238 }
239 if (vendor)
240 {
241 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
242 "%sMSK established", type, vendor,
243 this->msk.ptr ? "" : "no ");
244 }
245 else
246 {
247 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
248 eap_type_names, type, this->msk.ptr ? "" : "no ");
249 }
250 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
251 TRUE);
252 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
253 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
254 if (vendor)
255 {
256 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
257 }
258 this->eap_complete = TRUE;
259 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
260 case FAILED:
261 default:
262 if (vendor)
263 {
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));
267 }
268 else
269 {
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));
273 }
274 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
275 }
276 }
277
278 /**
279 * Processing method for a peer
280 */
281 static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
282 eap_payload_t *in)
283 {
284 eap_type_t type;
285 u_int32_t vendor;
286 auth_cfg_t *auth;
287 eap_payload_t *out;
288 identification_t *id;
289
290 type = in->get_type(in, &vendor);
291
292 if (!vendor && type == EAP_IDENTITY)
293 {
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)
298 {
299 id = this->ike_sa->get_my_id(this->ike_sa);
300 }
301 DBG1(DBG_IKE, "server requested %N, sending '%Y'",
302 eap_type_names, type, id);
303 this->eap_identity = id->clone(id);
304
305 this->method = load_method(this, type, vendor, EAP_PEER);
306 if (this->method)
307 {
308 if (this->method->process(this->method, in, &out) == SUCCESS)
309 {
310 this->method->destroy(this->method);
311 this->method = NULL;
312 return out;
313 }
314 this->method->destroy(this->method);
315 this->method = NULL;
316 }
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));
320 }
321 if (this->method == NULL)
322 {
323 if (vendor)
324 {
325 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d",
326 type, vendor);
327 }
328 else
329 {
330 DBG1(DBG_IKE, "server requested %N authentication",
331 eap_type_names, type);
332 }
333 this->method = load_method(this, type, vendor, EAP_PEER);
334 if (!this->method)
335 {
336 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
337 return eap_payload_create_nak(in->get_identifier(in));
338 }
339 }
340
341 type = this->method->get_type(this->method, &vendor);
342
343 if (this->method->process(this->method, in, &out) == NEED_MORE)
344 { /* client methods should never return SUCCESS */
345 return out;
346 }
347
348 if (vendor)
349 {
350 DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
351 }
352 else
353 {
354 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
355 }
356 return NULL;
357 }
358
359 /**
360 * Verify AUTH payload
361 */
362 static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
363 chunk_t nonce, chunk_t init)
364 {
365 auth_payload_t *auth_payload;
366 chunk_t auth_data, recv_auth_data;
367 identification_t *other_id;
368 auth_cfg_t *auth;
369 keymat_t *keymat;
370
371 auth_payload = (auth_payload_t*)message->get_payload(message,
372 AUTHENTICATION);
373 if (!auth_payload)
374 {
375 DBG1(DBG_IKE, "AUTH payload missing");
376 return FALSE;
377 }
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))
384 {
385 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
386 this->msk.ptr ? "" : "out");
387 chunk_free(&auth_data);
388 return FALSE;
389 }
390 chunk_free(&auth_data);
391
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);
397 return TRUE;
398 }
399
400 /**
401 * Build AUTH payload
402 */
403 static void build_auth(private_eap_authenticator_t *this, message_t *message,
404 chunk_t nonce, chunk_t init)
405 {
406 auth_payload_t *auth_payload;
407 identification_t *my_id;
408 chunk_t auth_data;
409 keymat_t *keymat;
410
411 my_id = this->ike_sa->get_my_id(this->ike_sa);
412 keymat = this->ike_sa->get_keymat(this->ike_sa);
413
414 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
415 my_id, auth_class_names, AUTH_CLASS_EAP);
416
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);
423 }
424
425 /**
426 * Implementation of authenticator_t.process for a server
427 */
428 static status_t process_server(private_eap_authenticator_t *this,
429 message_t *message)
430 {
431 eap_payload_t *eap_payload;
432
433 if (this->eap_complete)
434 {
435 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
436 {
437 return FAILED;
438 }
439 return NEED_MORE;
440 }
441
442 if (!this->method)
443 {
444 this->eap_payload = server_initiate_eap(this, TRUE);
445 }
446 else
447 {
448 eap_payload = (eap_payload_t*)message->get_payload(message,
449 EXTENSIBLE_AUTHENTICATION);
450 if (!eap_payload)
451 {
452 return FAILED;
453 }
454 this->eap_payload = server_process_eap(this, eap_payload);
455 }
456 return NEED_MORE;
457 }
458
459 /**
460 * Implementation of authenticator_t.build for a server
461 */
462 static status_t build_server(private_eap_authenticator_t *this,
463 message_t *message)
464 {
465 if (this->eap_payload)
466 {
467 eap_code_t code;
468
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)
473 {
474 return FAILED;
475 }
476 return NEED_MORE;
477 }
478 if (this->eap_complete && this->auth_complete)
479 {
480 build_auth(this, message, this->received_nonce, this->sent_init);
481 return SUCCESS;
482 }
483 return FAILED;
484 }
485
486 /**
487 * Implementation of authenticator_t.process for a client
488 */
489 static status_t process_client(private_eap_authenticator_t *this,
490 message_t *message)
491 {
492 eap_payload_t *eap_payload;
493
494 if (this->eap_complete)
495 {
496 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
497 {
498 return FAILED;
499 }
500 return SUCCESS;
501 }
502
503 eap_payload = (eap_payload_t*)message->get_payload(message,
504 EXTENSIBLE_AUTHENTICATION);
505 if (eap_payload)
506 {
507 switch (eap_payload->get_code(eap_payload))
508 {
509 case EAP_REQUEST:
510 {
511 this->eap_payload = client_process_eap(this, eap_payload);
512 return NEED_MORE;
513 }
514 case EAP_SUCCESS:
515 {
516 eap_type_t type;
517 u_int32_t vendor;
518 auth_cfg_t *cfg;
519
520 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
521 {
522 this->msk = chunk_clone(this->msk);
523 }
524 type = this->method->get_type(this->method, &vendor);
525 if (vendor)
526 {
527 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
528 "%sMSK established", type, vendor,
529 this->msk.ptr ? "" : "no ");
530 }
531 else
532 {
533 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
534 eap_type_names, type, this->msk.ptr ? "" : "no ");
535 }
536 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
537 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
538 if (vendor)
539 {
540 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
541 }
542 this->eap_complete = TRUE;
543 return NEED_MORE;
544 }
545 case EAP_FAILURE:
546 default:
547 {
548 DBG1(DBG_IKE, "received %N, EAP authentication failed",
549 eap_code_names, eap_payload->get_code(eap_payload));
550 return FAILED;
551 }
552 }
553 }
554 return FAILED;
555 }
556
557 /**
558 * Implementation of authenticator_t.build for a client
559 */
560 static status_t build_client(private_eap_authenticator_t *this,
561 message_t *message)
562 {
563 if (this->eap_payload)
564 {
565 message->add_payload(message, (payload_t*)this->eap_payload);
566 this->eap_payload = NULL;
567 return NEED_MORE;
568 }
569 if (this->eap_complete)
570 {
571 build_auth(this, message, this->received_nonce, this->sent_init);
572 return NEED_MORE;
573 }
574 return NEED_MORE;
575 }
576
577 /**
578 * Implementation of authenticator_t.destroy.
579 */
580 static void destroy(private_eap_authenticator_t *this)
581 {
582 DESTROY_IF(this->method);
583 DESTROY_IF(this->eap_payload);
584 DESTROY_IF(this->eap_identity);
585 chunk_free(&this->msk);
586 free(this);
587 }
588
589 /*
590 * Described in header.
591 */
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)
595 {
596 private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
597
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;
601
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;
608 this->method = NULL;
609 this->eap_payload = NULL;
610 this->eap_complete = FALSE;
611 this->auth_complete = FALSE;
612 this->eap_identity = NULL;
613
614 return &this->public;
615 }
616
617 /*
618 * Described in header.
619 */
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)
623 {
624 private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
625
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;
629
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;
636 this->method = NULL;
637 this->eap_payload = NULL;
638 this->eap_complete = FALSE;
639 this->auth_complete = FALSE;
640 this->eap_identity = NULL;
641
642 return &this->public;
643 }
644