a340c04d7074b20eda88988c46269916c64170e3
[strongswan.git] / src / libcharon / sa / ikev2 / authenticators / eap_authenticator.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2006-2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "eap_authenticator.h"
18
19 #include <daemon.h>
20 #include <sa/ikev2/keymat_v2.h>
21 #include <sa/eap/eap_method.h>
22 #include <encoding/payloads/auth_payload.h>
23 #include <encoding/payloads/eap_payload.h>
24
25 typedef struct private_eap_authenticator_t private_eap_authenticator_t;
26
27 /**
28 * Private data of an eap_authenticator_t object.
29 */
30 struct private_eap_authenticator_t {
31
32 /**
33 * Public authenticator_t interface.
34 */
35 eap_authenticator_t public;
36
37 /**
38 * Assigned IKE_SA
39 */
40 ike_sa_t *ike_sa;
41
42 /**
43 * others nonce to include in AUTH calculation
44 */
45 chunk_t received_nonce;
46
47 /**
48 * our nonce to include in AUTH calculation
49 */
50 chunk_t sent_nonce;
51
52 /**
53 * others IKE_SA_INIT message data to include in AUTH calculation
54 */
55 chunk_t received_init;
56
57 /**
58 * our IKE_SA_INIT message data to include in AUTH calculation
59 */
60 chunk_t sent_init;
61
62 /**
63 * Reserved bytes of ID payload
64 */
65 char reserved[3];
66
67 /**
68 * Current EAP method processing
69 */
70 eap_method_t *method;
71
72 /**
73 * MSK used to build and verify auth payload
74 */
75 chunk_t msk;
76
77 /**
78 * EAP authentication method completed successfully
79 */
80 bool eap_complete;
81
82 /**
83 * Set if we require mutual EAP due EAP-only authentication
84 */
85 bool require_mutual;
86
87 /**
88 * authentication payload verified successfully
89 */
90 bool auth_complete;
91
92 /**
93 * generated EAP payload
94 */
95 eap_payload_t *eap_payload;
96
97 /**
98 * EAP identity of peer
99 */
100 identification_t *eap_identity;
101 };
102
103 /**
104 * load an EAP method
105 */
106 static eap_method_t *load_method(private_eap_authenticator_t *this,
107 eap_type_t type, u_int32_t vendor, eap_role_t role)
108 {
109 identification_t *server, *peer, *aaa;
110 auth_cfg_t *auth;
111
112 if (role == EAP_SERVER)
113 {
114 server = this->ike_sa->get_my_id(this->ike_sa);
115 peer = this->ike_sa->get_other_id(this->ike_sa);
116 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
117 }
118 else
119 {
120 server = this->ike_sa->get_other_id(this->ike_sa);
121 peer = this->ike_sa->get_my_id(this->ike_sa);
122 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
123 }
124 if (this->eap_identity)
125 {
126 peer = this->eap_identity;
127 }
128 aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY);
129 if (aaa)
130 {
131 server = aaa;
132 }
133 return charon->eap->create_instance(charon->eap, type, vendor,
134 role, server, peer);
135 }
136
137 /**
138 * Initiate EAP conversation as server
139 */
140 static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
141 bool do_identity)
142 {
143 auth_cfg_t *auth;
144 eap_type_t type;
145 identification_t *id;
146 u_int32_t vendor;
147 eap_payload_t *out;
148 char *action;
149
150 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
151
152 /* initiate EAP-Identity exchange if required */
153 if (!this->eap_identity && do_identity)
154 {
155 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
156 if (id)
157 {
158 if (id->get_type(id) == ID_ANY)
159 {
160 this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
161 if (this->method)
162 {
163 if (this->method->initiate(this->method, &out) == NEED_MORE)
164 {
165 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)",
166 eap_type_names, EAP_IDENTITY,
167 this->method->get_identifier(this->method));
168 return out;
169 }
170 this->method->destroy(this->method);
171 }
172 DBG1(DBG_IKE, "EAP-Identity request configured, "
173 "but not supported");
174 }
175 else
176 {
177 DBG1(DBG_IKE, "using configured EAP-Identity %Y", id);
178 this->eap_identity = id->clone(id);
179 }
180 }
181 }
182 /* invoke real EAP method */
183 type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
184 vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
185 action = "loading";
186 this->method = load_method(this, type, vendor, EAP_SERVER);
187 if (this->method)
188 {
189 action = "initiating";
190 type = this->method->get_type(this->method, &vendor);
191 if (this->method->initiate(this->method, &out) == NEED_MORE)
192 {
193 if (vendor)
194 {
195 DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)",
196 type, vendor, out->get_identifier(out));
197 }
198 else
199 {
200 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names,
201 type, out->get_identifier(out));
202 }
203 return out;
204 }
205 }
206 if (vendor)
207 {
208 DBG1(DBG_IKE, "%s EAP vendor type %d-%d method failed",
209 action, type, vendor);
210 }
211 else
212 {
213 DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type);
214 }
215 return eap_payload_create_code(EAP_FAILURE, 0);
216 }
217
218 /**
219 * Replace the existing EAP-Identity in other auth config
220 */
221 static void replace_eap_identity(private_eap_authenticator_t *this)
222 {
223 identification_t *eap_identity;
224 auth_cfg_t *cfg;
225
226 eap_identity = this->eap_identity->clone(this->eap_identity);
227 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
228 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity);
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, conf_type;
238 u_int32_t vendor, received_vendor, conf_vendor;
239 eap_payload_t *out;
240 auth_cfg_t *auth;
241
242 if (in->get_code(in) != EAP_RESPONSE)
243 {
244 DBG1(DBG_IKE, "received %N, sending %N",
245 eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
246 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
247 }
248
249 type = this->method->get_type(this->method, &vendor);
250 received_type = in->get_type(in, &received_vendor);
251 if (type != received_type || vendor != received_vendor)
252 {
253 if (received_vendor == 0 && received_type == EAP_NAK)
254 {
255 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
256 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
257 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
258 if ((type == EAP_IDENTITY && !vendor) ||
259 (type == conf_type && vendor == conf_vendor))
260 {
261 DBG1(DBG_IKE, "received %N, sending %N",
262 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
263 return eap_payload_create_code(EAP_FAILURE,
264 in->get_identifier(in));
265 }
266 /* virtual methods handle NAKs in process() */
267 }
268 else
269 {
270 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
271 eap_code_names, EAP_FAILURE);
272 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
273 }
274 }
275
276 switch (this->method->process(this->method, in, &out))
277 {
278 case NEED_MORE:
279 return out;
280 case SUCCESS:
281 if (!vendor && type == EAP_IDENTITY)
282 {
283 chunk_t data;
284
285 if (this->method->get_msk(this->method, &data) == SUCCESS)
286 {
287 this->eap_identity = identification_create_from_data(data);
288 DBG1(DBG_IKE, "received EAP identity '%Y'",
289 this->eap_identity);
290 replace_eap_identity(this);
291 }
292 /* restart EAP exchange, but with real method */
293 this->method->destroy(this->method);
294 return server_initiate_eap(this, FALSE);
295 }
296 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
297 {
298 this->msk = chunk_clone(this->msk);
299 }
300 if (vendor)
301 {
302 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
303 "%sMSK established", type, vendor,
304 this->msk.ptr ? "" : "no ");
305 }
306 else
307 {
308 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
309 eap_type_names, type, this->msk.ptr ? "" : "no ");
310 }
311 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
312 TRUE);
313 this->eap_complete = TRUE;
314 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
315 case FAILED:
316 default:
317 if (vendor)
318 {
319 DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
320 "peer %Y", type, vendor,
321 this->ike_sa->get_other_id(this->ike_sa));
322 }
323 else
324 {
325 DBG1(DBG_IKE, "EAP method %N failed for peer %Y",
326 eap_type_names, type,
327 this->ike_sa->get_other_id(this->ike_sa));
328 }
329 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
330 }
331 }
332
333 /**
334 * Processing method for a peer
335 */
336 static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
337 eap_payload_t *in)
338 {
339 eap_type_t type, conf_type;
340 u_int32_t vendor, conf_vendor;
341 auth_cfg_t *auth;
342 eap_payload_t *out;
343 identification_t *id;
344
345 type = in->get_type(in, &vendor);
346
347 if (!vendor && type == EAP_IDENTITY)
348 {
349 DESTROY_IF(this->eap_identity);
350 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
351 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
352 if (!id || id->get_type(id) == ID_ANY)
353 {
354 id = this->ike_sa->get_my_id(this->ike_sa);
355 }
356 DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'",
357 eap_type_names, type, in->get_identifier(in), id);
358 this->eap_identity = id->clone(id);
359
360 this->method = load_method(this, type, vendor, EAP_PEER);
361 if (this->method)
362 {
363 if (this->method->process(this->method, in, &out) == SUCCESS)
364 {
365 this->method->destroy(this->method);
366 this->method = NULL;
367 return out;
368 }
369 this->method->destroy(this->method);
370 this->method = NULL;
371 }
372 /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
373 * EAP method (types 3-253, 255) */
374 DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
375 eap_type_names, type);
376 return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE);
377 }
378 if (this->method == NULL)
379 {
380 if (vendor)
381 {
382 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ",
383 "(id 0x%02X)", type, vendor, in->get_identifier(in));
384 }
385 else
386 {
387 DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
388 eap_type_names, type, in->get_identifier(in));
389 }
390 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
391 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
392 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
393 if (conf_type != EAP_NAK &&
394 (conf_type != type || conf_vendor != vendor))
395 {
396 if (conf_vendor)
397 {
398 DBG1(DBG_IKE, "requesting EAP method %d-%d, sending EAP_NAK",
399 conf_type, conf_vendor);
400 }
401 else
402 {
403 DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK",
404 eap_type_names, conf_type);
405 }
406 return eap_payload_create_nak(in->get_identifier(in), conf_type,
407 conf_vendor, in->is_expanded(in));
408 }
409 this->method = load_method(this, type, vendor, EAP_PEER);
410 if (!this->method)
411 {
412 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
413 return eap_payload_create_nak(in->get_identifier(in), 0, 0,
414 in->is_expanded(in));
415 }
416 }
417
418 type = this->method->get_type(this->method, &vendor);
419
420 if (this->method->process(this->method, in, &out) == NEED_MORE)
421 { /* client methods should never return SUCCESS */
422 return out;
423 }
424
425 if (vendor)
426 {
427 DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
428 }
429 else
430 {
431 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
432 }
433 return NULL;
434 }
435
436 /**
437 * Verify AUTH payload
438 */
439 static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
440 chunk_t nonce, chunk_t init)
441 {
442 auth_payload_t *auth_payload;
443 chunk_t auth_data, recv_auth_data;
444 identification_t *other_id;
445 auth_cfg_t *auth;
446 keymat_v2_t *keymat;
447
448 auth_payload = (auth_payload_t*)message->get_payload(message,
449 AUTHENTICATION);
450 if (!auth_payload)
451 {
452 DBG1(DBG_IKE, "AUTH payload missing");
453 return FALSE;
454 }
455 other_id = this->ike_sa->get_other_id(this->ike_sa);
456 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
457 if (!keymat->get_psk_sig(keymat, TRUE, init, nonce,
458 this->msk, other_id, this->reserved, &auth_data))
459 {
460 return FALSE;
461 }
462 recv_auth_data = auth_payload->get_data(auth_payload);
463 if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
464 {
465 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
466 this->msk.ptr ? "" : "out");
467 chunk_free(&auth_data);
468 return FALSE;
469 }
470 chunk_free(&auth_data);
471
472 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
473 other_id, auth_class_names, AUTH_CLASS_EAP);
474 this->auth_complete = TRUE;
475 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
476 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
477 return TRUE;
478 }
479
480 /**
481 * Build AUTH payload
482 */
483 static bool build_auth(private_eap_authenticator_t *this, message_t *message,
484 chunk_t nonce, chunk_t init)
485 {
486 auth_payload_t *auth_payload;
487 identification_t *my_id;
488 chunk_t auth_data;
489 keymat_v2_t *keymat;
490
491 my_id = this->ike_sa->get_my_id(this->ike_sa);
492 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
493
494 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
495 my_id, auth_class_names, AUTH_CLASS_EAP);
496
497 if (!keymat->get_psk_sig(keymat, FALSE, init, nonce,
498 this->msk, my_id, this->reserved, &auth_data))
499 {
500 return FALSE;
501 }
502 auth_payload = auth_payload_create();
503 auth_payload->set_auth_method(auth_payload, AUTH_PSK);
504 auth_payload->set_data(auth_payload, auth_data);
505 message->add_payload(message, (payload_t*)auth_payload);
506 chunk_free(&auth_data);
507 return TRUE;
508 }
509
510 METHOD(authenticator_t, process_server, status_t,
511 private_eap_authenticator_t *this, message_t *message)
512 {
513 eap_payload_t *eap_payload;
514
515 if (this->eap_complete)
516 {
517 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
518 {
519 return FAILED;
520 }
521 return NEED_MORE;
522 }
523
524 if (!this->method)
525 {
526 this->eap_payload = server_initiate_eap(this, TRUE);
527 }
528 else
529 {
530 eap_payload = (eap_payload_t*)message->get_payload(message,
531 EXTENSIBLE_AUTHENTICATION);
532 if (!eap_payload)
533 {
534 return FAILED;
535 }
536 this->eap_payload = server_process_eap(this, eap_payload);
537 }
538 return NEED_MORE;
539 }
540
541 METHOD(authenticator_t, build_server, status_t,
542 private_eap_authenticator_t *this, message_t *message)
543 {
544 if (this->eap_payload)
545 {
546 eap_code_t code;
547
548 code = this->eap_payload->get_code(this->eap_payload);
549 message->add_payload(message, (payload_t*)this->eap_payload);
550 this->eap_payload = NULL;
551 if (code == EAP_FAILURE)
552 {
553 return FAILED;
554 }
555 return NEED_MORE;
556 }
557 if (this->eap_complete && this->auth_complete &&
558 build_auth(this, message, this->received_nonce, this->sent_init))
559 {
560 return SUCCESS;
561 }
562 return FAILED;
563 }
564
565 METHOD(authenticator_t, process_client, status_t,
566 private_eap_authenticator_t *this, message_t *message)
567 {
568 eap_payload_t *eap_payload;
569
570 if (this->eap_complete)
571 {
572 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
573 {
574 return FAILED;
575 }
576 if (this->require_mutual && !this->method->is_mutual(this->method))
577 { /* we require mutual authentication due to EAP-only */
578 u_int32_t vendor;
579
580 DBG1(DBG_IKE, "EAP-only authentication requires a mutual and "
581 "MSK deriving EAP method, but %N is not",
582 eap_type_names, this->method->get_type(this->method, &vendor));
583 return FAILED;
584 }
585 return SUCCESS;
586 }
587
588 eap_payload = (eap_payload_t*)message->get_payload(message,
589 EXTENSIBLE_AUTHENTICATION);
590 if (eap_payload)
591 {
592 switch (eap_payload->get_code(eap_payload))
593 {
594 case EAP_REQUEST:
595 {
596 this->eap_payload = client_process_eap(this, eap_payload);
597 if (this->eap_payload)
598 {
599 return NEED_MORE;
600 }
601 return FAILED;
602 }
603 case EAP_SUCCESS:
604 {
605 eap_type_t type;
606 u_int32_t vendor;
607 auth_cfg_t *cfg;
608
609 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
610 {
611 this->msk = chunk_clone(this->msk);
612 }
613 type = this->method->get_type(this->method, &vendor);
614 if (vendor)
615 {
616 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
617 "%sMSK established", type, vendor,
618 this->msk.ptr ? "" : "no ");
619 }
620 else
621 {
622 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
623 eap_type_names, type, this->msk.ptr ? "" : "no ");
624 }
625 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
626 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
627 if (vendor)
628 {
629 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
630 }
631 this->eap_complete = TRUE;
632 return NEED_MORE;
633 }
634 case EAP_FAILURE:
635 default:
636 {
637 DBG1(DBG_IKE, "received %N, EAP authentication failed",
638 eap_code_names, eap_payload->get_code(eap_payload));
639 return FAILED;
640 }
641 }
642 }
643 return FAILED;
644 }
645
646 METHOD(authenticator_t, build_client, status_t,
647 private_eap_authenticator_t *this, message_t *message)
648 {
649 if (this->eap_payload)
650 {
651 message->add_payload(message, (payload_t*)this->eap_payload);
652 this->eap_payload = NULL;
653 return NEED_MORE;
654 }
655 if (this->eap_complete &&
656 build_auth(this, message, this->received_nonce, this->sent_init))
657 {
658 return NEED_MORE;
659 }
660 return NEED_MORE;
661 }
662
663 METHOD(authenticator_t, is_mutual, bool,
664 private_eap_authenticator_t *this)
665 {
666 /* we don't know yet, but insist on it after EAP is complete */
667 this->require_mutual = TRUE;
668 return TRUE;
669 }
670
671 METHOD(authenticator_t, destroy, void,
672 private_eap_authenticator_t *this)
673 {
674 DESTROY_IF(this->method);
675 DESTROY_IF(this->eap_payload);
676 DESTROY_IF(this->eap_identity);
677 chunk_free(&this->msk);
678 free(this);
679 }
680
681 /*
682 * Described in header.
683 */
684 eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
685 chunk_t received_nonce, chunk_t sent_nonce,
686 chunk_t received_init, chunk_t sent_init,
687 char reserved[3])
688 {
689 private_eap_authenticator_t *this;
690
691 INIT(this,
692 .public = {
693 .authenticator = {
694 .build = _build_client,
695 .process = _process_client,
696 .is_mutual = _is_mutual,
697 .destroy = _destroy,
698 },
699 },
700 .ike_sa = ike_sa,
701 .received_init = received_init,
702 .received_nonce = received_nonce,
703 .sent_init = sent_init,
704 .sent_nonce = sent_nonce,
705 );
706 memcpy(this->reserved, reserved, sizeof(this->reserved));
707
708 return &this->public;
709 }
710
711 /*
712 * Described in header.
713 */
714 eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
715 chunk_t received_nonce, chunk_t sent_nonce,
716 chunk_t received_init, chunk_t sent_init,
717 char reserved[3])
718 {
719 private_eap_authenticator_t *this;
720
721 INIT(this,
722 .public = {
723 .authenticator = {
724 .build = _build_server,
725 .process = _process_server,
726 .is_mutual = _is_mutual,
727 .destroy = _destroy,
728 },
729 },
730 .ike_sa = ike_sa,
731 .received_init = received_init,
732 .received_nonce = received_nonce,
733 .sent_init = sent_init,
734 .sent_nonce = sent_nonce,
735 );
736 memcpy(this->reserved, reserved, sizeof(this->reserved));
737
738 return &this->public;
739 }