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