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