922a95f5d5d96f33185a88e027c14158c6d8ab8c
[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 char *action;
129
130 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
131
132 /* initiate EAP-Identity exchange if required */
133 if (!this->eap_identity && do_identity)
134 {
135 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
136 if (id)
137 {
138 this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
139 if (this->method)
140 {
141 if (this->method->initiate(this->method, &out) == NEED_MORE)
142 {
143 DBG1(DBG_IKE, "initiating EAP-Identity request");
144 return out;
145 }
146 this->method->destroy(this->method);
147 }
148 DBG1(DBG_IKE, "EAP-Identity request configured, but not supported");
149 }
150 }
151 /* invoke real EAP method */
152 type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
153 vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
154 action = "loading";
155 this->method = load_method(this, type, vendor, EAP_SERVER);
156 if (this->method)
157 {
158 action = "initiating";
159 if (this->method->initiate(this->method, &out) == NEED_MORE)
160 {
161 if (vendor)
162 {
163 DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method",
164 type, vendor);
165 }
166 else
167 {
168 DBG1(DBG_IKE, "initiating %N method", eap_type_names, type);
169 }
170 return out;
171 }
172 }
173 if (vendor)
174 {
175 DBG1(DBG_IKE, "%s EAP vendor type %d-%d method failed",
176 action, type, vendor);
177 }
178 else
179 {
180 DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type);
181 }
182 return eap_payload_create_code(EAP_FAILURE, 0);
183 }
184
185 /**
186 * Replace the existing EAP-Identity in other auth config
187 */
188 static void replace_eap_identity(private_eap_authenticator_t *this)
189 {
190 enumerator_t *enumerator;
191 auth_rule_t rule;
192 auth_cfg_t *cfg;
193 void *ptr;
194
195 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
196 enumerator = cfg->create_enumerator(cfg);
197 while (enumerator->enumerate(enumerator, &rule, &ptr))
198 {
199 if (rule == AUTH_RULE_EAP_IDENTITY)
200 {
201 cfg->replace(cfg, enumerator, AUTH_RULE_EAP_IDENTITY,
202 this->eap_identity->clone(this->eap_identity));
203 break;
204 }
205 }
206 enumerator->destroy(enumerator);
207 }
208
209 /**
210 * Handle EAP exchange as server
211 */
212 static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
213 eap_payload_t *in)
214 {
215 eap_type_t type, received_type;
216 u_int32_t vendor, received_vendor;
217 eap_payload_t *out;
218 auth_cfg_t *cfg;
219
220 if (in->get_code(in) != EAP_RESPONSE)
221 {
222 DBG1(DBG_IKE, "received %N, sending %N",
223 eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
224 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
225 }
226
227 type = this->method->get_type(this->method, &vendor);
228 received_type = in->get_type(in, &received_vendor);
229 if (type != received_type || vendor != received_vendor)
230 {
231 if (received_vendor == 0 && received_type == EAP_NAK)
232 {
233 DBG1(DBG_IKE, "received %N, sending %N",
234 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
235 }
236 else
237 {
238 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
239 eap_code_names, EAP_FAILURE);
240 }
241 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
242 }
243
244 switch (this->method->process(this->method, in, &out))
245 {
246 case NEED_MORE:
247 return out;
248 case SUCCESS:
249 if (type == EAP_IDENTITY)
250 {
251 chunk_t data;
252
253 if (this->method->get_msk(this->method, &data) == SUCCESS)
254 {
255 this->eap_identity = identification_create_from_data(data);
256 DBG1(DBG_IKE, "received EAP identity '%Y'",
257 this->eap_identity);
258 replace_eap_identity(this);
259 }
260 /* restart EAP exchange, but with real method */
261 this->method->destroy(this->method);
262 return server_initiate_eap(this, FALSE);
263 }
264 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
265 {
266 this->msk = chunk_clone(this->msk);
267 }
268 if (vendor)
269 {
270 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
271 "%sMSK established", type, vendor,
272 this->msk.ptr ? "" : "no ");
273 }
274 else
275 {
276 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
277 eap_type_names, type, this->msk.ptr ? "" : "no ");
278 }
279 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
280 TRUE);
281 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
282 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
283 if (vendor)
284 {
285 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
286 }
287 this->eap_complete = TRUE;
288 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
289 case FAILED:
290 default:
291 if (vendor)
292 {
293 DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
294 "peer %Y", type, vendor,
295 this->ike_sa->get_other_id(this->ike_sa));
296 }
297 else
298 {
299 DBG1(DBG_IKE, "EAP method %N failed for peer %Y",
300 eap_type_names, type,
301 this->ike_sa->get_other_id(this->ike_sa));
302 }
303 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
304 }
305 }
306
307 /**
308 * Processing method for a peer
309 */
310 static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
311 eap_payload_t *in)
312 {
313 eap_type_t type;
314 u_int32_t vendor;
315 auth_cfg_t *auth;
316 eap_payload_t *out;
317 identification_t *id;
318
319 type = in->get_type(in, &vendor);
320
321 if (!vendor && type == EAP_IDENTITY)
322 {
323 DESTROY_IF(this->eap_identity);
324 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
325 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
326 if (!id || id->get_type(id) == ID_ANY)
327 {
328 id = this->ike_sa->get_my_id(this->ike_sa);
329 }
330 DBG1(DBG_IKE, "server requested %N, sending '%Y'",
331 eap_type_names, type, id);
332 this->eap_identity = id->clone(id);
333
334 this->method = load_method(this, type, vendor, EAP_PEER);
335 if (this->method)
336 {
337 if (this->method->process(this->method, in, &out) == SUCCESS)
338 {
339 this->method->destroy(this->method);
340 this->method = NULL;
341 return out;
342 }
343 this->method->destroy(this->method);
344 this->method = NULL;
345 }
346 DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
347 eap_type_names, type);
348 return eap_payload_create_nak(in->get_identifier(in));
349 }
350 if (this->method == NULL)
351 {
352 if (vendor)
353 {
354 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d",
355 type, vendor);
356 }
357 else
358 {
359 DBG1(DBG_IKE, "server requested %N authentication",
360 eap_type_names, type);
361 }
362 this->method = load_method(this, type, vendor, EAP_PEER);
363 if (!this->method)
364 {
365 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
366 return eap_payload_create_nak(in->get_identifier(in));
367 }
368 }
369
370 type = this->method->get_type(this->method, &vendor);
371
372 if (this->method->process(this->method, in, &out) == NEED_MORE)
373 { /* client methods should never return SUCCESS */
374 return out;
375 }
376
377 if (vendor)
378 {
379 DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
380 }
381 else
382 {
383 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
384 }
385 return NULL;
386 }
387
388 /**
389 * Verify AUTH payload
390 */
391 static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
392 chunk_t nonce, chunk_t init)
393 {
394 auth_payload_t *auth_payload;
395 chunk_t auth_data, recv_auth_data;
396 identification_t *other_id;
397 auth_cfg_t *auth;
398 keymat_t *keymat;
399
400 auth_payload = (auth_payload_t*)message->get_payload(message,
401 AUTHENTICATION);
402 if (!auth_payload)
403 {
404 DBG1(DBG_IKE, "AUTH payload missing");
405 return FALSE;
406 }
407 other_id = this->ike_sa->get_other_id(this->ike_sa);
408 keymat = this->ike_sa->get_keymat(this->ike_sa);
409 auth_data = keymat->get_psk_sig(keymat, TRUE, init, nonce,
410 this->msk, other_id);
411 recv_auth_data = auth_payload->get_data(auth_payload);
412 if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
413 {
414 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
415 this->msk.ptr ? "" : "out");
416 chunk_free(&auth_data);
417 return FALSE;
418 }
419 chunk_free(&auth_data);
420
421 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
422 other_id, auth_class_names, AUTH_CLASS_EAP);
423 this->auth_complete = TRUE;
424 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
425 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
426 return TRUE;
427 }
428
429 /**
430 * Build AUTH payload
431 */
432 static void build_auth(private_eap_authenticator_t *this, message_t *message,
433 chunk_t nonce, chunk_t init)
434 {
435 auth_payload_t *auth_payload;
436 identification_t *my_id;
437 chunk_t auth_data;
438 keymat_t *keymat;
439
440 my_id = this->ike_sa->get_my_id(this->ike_sa);
441 keymat = this->ike_sa->get_keymat(this->ike_sa);
442
443 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
444 my_id, auth_class_names, AUTH_CLASS_EAP);
445
446 auth_data = keymat->get_psk_sig(keymat, FALSE, init, nonce, this->msk, my_id);
447 auth_payload = auth_payload_create();
448 auth_payload->set_auth_method(auth_payload, AUTH_PSK);
449 auth_payload->set_data(auth_payload, auth_data);
450 message->add_payload(message, (payload_t*)auth_payload);
451 chunk_free(&auth_data);
452 }
453
454 /**
455 * Implementation of authenticator_t.process for a server
456 */
457 static status_t process_server(private_eap_authenticator_t *this,
458 message_t *message)
459 {
460 eap_payload_t *eap_payload;
461
462 if (this->eap_complete)
463 {
464 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
465 {
466 return FAILED;
467 }
468 return NEED_MORE;
469 }
470
471 if (!this->method)
472 {
473 this->eap_payload = server_initiate_eap(this, TRUE);
474 }
475 else
476 {
477 eap_payload = (eap_payload_t*)message->get_payload(message,
478 EXTENSIBLE_AUTHENTICATION);
479 if (!eap_payload)
480 {
481 return FAILED;
482 }
483 this->eap_payload = server_process_eap(this, eap_payload);
484 }
485 return NEED_MORE;
486 }
487
488 /**
489 * Implementation of authenticator_t.build for a server
490 */
491 static status_t build_server(private_eap_authenticator_t *this,
492 message_t *message)
493 {
494 if (this->eap_payload)
495 {
496 eap_code_t code;
497
498 code = this->eap_payload->get_code(this->eap_payload);
499 message->add_payload(message, (payload_t*)this->eap_payload);
500 this->eap_payload = NULL;
501 if (code == EAP_FAILURE)
502 {
503 return FAILED;
504 }
505 return NEED_MORE;
506 }
507 if (this->eap_complete && this->auth_complete)
508 {
509 build_auth(this, message, this->received_nonce, this->sent_init);
510 return SUCCESS;
511 }
512 return FAILED;
513 }
514
515 /**
516 * Implementation of authenticator_t.process for a client
517 */
518 static status_t process_client(private_eap_authenticator_t *this,
519 message_t *message)
520 {
521 eap_payload_t *eap_payload;
522
523 if (this->eap_complete)
524 {
525 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
526 {
527 return FAILED;
528 }
529 return SUCCESS;
530 }
531
532 eap_payload = (eap_payload_t*)message->get_payload(message,
533 EXTENSIBLE_AUTHENTICATION);
534 if (eap_payload)
535 {
536 switch (eap_payload->get_code(eap_payload))
537 {
538 case EAP_REQUEST:
539 {
540 this->eap_payload = client_process_eap(this, eap_payload);
541 if (this->eap_payload)
542 {
543 return NEED_MORE;
544 }
545 return FAILED;
546 }
547 case EAP_SUCCESS:
548 {
549 eap_type_t type;
550 u_int32_t vendor;
551 auth_cfg_t *cfg;
552
553 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
554 {
555 this->msk = chunk_clone(this->msk);
556 }
557 type = this->method->get_type(this->method, &vendor);
558 if (vendor)
559 {
560 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
561 "%sMSK established", type, vendor,
562 this->msk.ptr ? "" : "no ");
563 }
564 else
565 {
566 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
567 eap_type_names, type, this->msk.ptr ? "" : "no ");
568 }
569 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
570 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
571 if (vendor)
572 {
573 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
574 }
575 this->eap_complete = TRUE;
576 return NEED_MORE;
577 }
578 case EAP_FAILURE:
579 default:
580 {
581 DBG1(DBG_IKE, "received %N, EAP authentication failed",
582 eap_code_names, eap_payload->get_code(eap_payload));
583 return FAILED;
584 }
585 }
586 }
587 return FAILED;
588 }
589
590 /**
591 * Implementation of authenticator_t.build for a client
592 */
593 static status_t build_client(private_eap_authenticator_t *this,
594 message_t *message)
595 {
596 if (this->eap_payload)
597 {
598 message->add_payload(message, (payload_t*)this->eap_payload);
599 this->eap_payload = NULL;
600 return NEED_MORE;
601 }
602 if (this->eap_complete)
603 {
604 build_auth(this, message, this->received_nonce, this->sent_init);
605 return NEED_MORE;
606 }
607 return NEED_MORE;
608 }
609
610 /**
611 * Implementation of authenticator_t.destroy.
612 */
613 static void destroy(private_eap_authenticator_t *this)
614 {
615 DESTROY_IF(this->method);
616 DESTROY_IF(this->eap_payload);
617 DESTROY_IF(this->eap_identity);
618 chunk_free(&this->msk);
619 free(this);
620 }
621
622 /*
623 * Described in header.
624 */
625 eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
626 chunk_t received_nonce, chunk_t sent_nonce,
627 chunk_t received_init, chunk_t sent_init)
628 {
629 private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
630
631 this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build_client;
632 this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_client;
633 this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
634
635 this->ike_sa = ike_sa;
636 this->received_init = received_init;
637 this->received_nonce = received_nonce;
638 this->sent_init = sent_init;
639 this->sent_nonce = sent_nonce;
640 this->msk = chunk_empty;
641 this->method = NULL;
642 this->eap_payload = NULL;
643 this->eap_complete = FALSE;
644 this->auth_complete = FALSE;
645 this->eap_identity = NULL;
646
647 return &this->public;
648 }
649
650 /*
651 * Described in header.
652 */
653 eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
654 chunk_t received_nonce, chunk_t sent_nonce,
655 chunk_t received_init, chunk_t sent_init)
656 {
657 private_eap_authenticator_t *this = malloc_thing(private_eap_authenticator_t);
658
659 this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))build_server;
660 this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_server;
661 this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
662
663 this->ike_sa = ike_sa;
664 this->received_init = received_init;
665 this->received_nonce = received_nonce;
666 this->sent_init = sent_init;
667 this->sent_nonce = sent_nonce;
668 this->msk = chunk_empty;
669 this->method = NULL;
670 this->eap_payload = NULL;
671 this->eap_complete = FALSE;
672 this->auth_complete = FALSE;
673 this->eap_identity = NULL;
674
675 return &this->public;
676 }
677