Send EAP-Nak with supported types if requested type is unsupported
[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/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 identification_t *eap_identity;
223 auth_cfg_t *cfg;
224
225 eap_identity = this->eap_identity->clone(this->eap_identity);
226 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
227 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity);
228 }
229
230 /**
231 * Handle EAP exchange as server
232 */
233 static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
234 eap_payload_t *in)
235 {
236 eap_type_t type, received_type;
237 u_int32_t vendor, received_vendor;
238 eap_payload_t *out;
239
240 if (in->get_code(in) != EAP_RESPONSE)
241 {
242 DBG1(DBG_IKE, "received %N, sending %N",
243 eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
244 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
245 }
246
247 type = this->method->get_type(this->method, &vendor);
248 received_type = in->get_type(in, &received_vendor);
249 if (type != received_type || vendor != received_vendor)
250 {
251 if (received_vendor == 0 && received_type == EAP_NAK)
252 {
253 DBG1(DBG_IKE, "received %N, sending %N",
254 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
255 }
256 else
257 {
258 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
259 eap_code_names, EAP_FAILURE);
260 }
261 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
262 }
263
264 switch (this->method->process(this->method, in, &out))
265 {
266 case NEED_MORE:
267 return out;
268 case SUCCESS:
269 if (!vendor && type == EAP_IDENTITY)
270 {
271 chunk_t data;
272
273 if (this->method->get_msk(this->method, &data) == SUCCESS)
274 {
275 this->eap_identity = identification_create_from_data(data);
276 DBG1(DBG_IKE, "received EAP identity '%Y'",
277 this->eap_identity);
278 replace_eap_identity(this);
279 }
280 /* restart EAP exchange, but with real method */
281 this->method->destroy(this->method);
282 return server_initiate_eap(this, FALSE);
283 }
284 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
285 {
286 this->msk = chunk_clone(this->msk);
287 }
288 if (vendor)
289 {
290 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
291 "%sMSK established", type, vendor,
292 this->msk.ptr ? "" : "no ");
293 }
294 else
295 {
296 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
297 eap_type_names, type, this->msk.ptr ? "" : "no ");
298 }
299 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
300 TRUE);
301 this->eap_complete = TRUE;
302 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
303 case FAILED:
304 default:
305 if (vendor)
306 {
307 DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for "
308 "peer %Y", type, vendor,
309 this->ike_sa->get_other_id(this->ike_sa));
310 }
311 else
312 {
313 DBG1(DBG_IKE, "EAP method %N failed for peer %Y",
314 eap_type_names, type,
315 this->ike_sa->get_other_id(this->ike_sa));
316 }
317 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
318 }
319 }
320
321 /**
322 * Processing method for a peer
323 */
324 static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
325 eap_payload_t *in)
326 {
327 eap_type_t type;
328 u_int32_t vendor;
329 auth_cfg_t *auth;
330 eap_payload_t *out;
331 identification_t *id;
332
333 type = in->get_type(in, &vendor);
334
335 if (!vendor && type == EAP_IDENTITY)
336 {
337 DESTROY_IF(this->eap_identity);
338 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
339 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
340 if (!id || id->get_type(id) == ID_ANY)
341 {
342 id = this->ike_sa->get_my_id(this->ike_sa);
343 }
344 DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'",
345 eap_type_names, type, in->get_identifier(in), id);
346 this->eap_identity = id->clone(id);
347
348 this->method = load_method(this, type, vendor, EAP_PEER);
349 if (this->method)
350 {
351 if (this->method->process(this->method, in, &out) == SUCCESS)
352 {
353 this->method->destroy(this->method);
354 this->method = NULL;
355 return out;
356 }
357 this->method->destroy(this->method);
358 this->method = NULL;
359 }
360 /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
361 * EAP method (types 3-253, 255) */
362 DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
363 eap_type_names, type);
364 return eap_payload_create_nak(in->get_identifier(in), FALSE);
365 }
366 if (this->method == NULL)
367 {
368 if (vendor)
369 {
370 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ",
371 "(id 0x%02X)", type, vendor, in->get_identifier(in));
372 }
373 else
374 {
375 DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
376 eap_type_names, type, in->get_identifier(in));
377 }
378 this->method = load_method(this, type, vendor, EAP_PEER);
379 if (!this->method)
380 {
381 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
382 return eap_payload_create_nak(in->get_identifier(in), vendor != 0);
383 }
384 }
385
386 type = this->method->get_type(this->method, &vendor);
387
388 if (this->method->process(this->method, in, &out) == NEED_MORE)
389 { /* client methods should never return SUCCESS */
390 return out;
391 }
392
393 if (vendor)
394 {
395 DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor);
396 }
397 else
398 {
399 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
400 }
401 return NULL;
402 }
403
404 /**
405 * Verify AUTH payload
406 */
407 static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
408 chunk_t nonce, chunk_t init)
409 {
410 auth_payload_t *auth_payload;
411 chunk_t auth_data, recv_auth_data;
412 identification_t *other_id;
413 auth_cfg_t *auth;
414 keymat_v2_t *keymat;
415
416 auth_payload = (auth_payload_t*)message->get_payload(message,
417 AUTHENTICATION);
418 if (!auth_payload)
419 {
420 DBG1(DBG_IKE, "AUTH payload missing");
421 return FALSE;
422 }
423 other_id = this->ike_sa->get_other_id(this->ike_sa);
424 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
425 if (!keymat->get_psk_sig(keymat, TRUE, init, nonce,
426 this->msk, other_id, this->reserved, &auth_data))
427 {
428 return FALSE;
429 }
430 recv_auth_data = auth_payload->get_data(auth_payload);
431 if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
432 {
433 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
434 this->msk.ptr ? "" : "out");
435 chunk_free(&auth_data);
436 return FALSE;
437 }
438 chunk_free(&auth_data);
439
440 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
441 other_id, auth_class_names, AUTH_CLASS_EAP);
442 this->auth_complete = TRUE;
443 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
444 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
445 return TRUE;
446 }
447
448 /**
449 * Build AUTH payload
450 */
451 static bool build_auth(private_eap_authenticator_t *this, message_t *message,
452 chunk_t nonce, chunk_t init)
453 {
454 auth_payload_t *auth_payload;
455 identification_t *my_id;
456 chunk_t auth_data;
457 keymat_v2_t *keymat;
458
459 my_id = this->ike_sa->get_my_id(this->ike_sa);
460 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
461
462 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
463 my_id, auth_class_names, AUTH_CLASS_EAP);
464
465 if (!keymat->get_psk_sig(keymat, FALSE, init, nonce,
466 this->msk, my_id, this->reserved, &auth_data))
467 {
468 return FALSE;
469 }
470 auth_payload = auth_payload_create();
471 auth_payload->set_auth_method(auth_payload, AUTH_PSK);
472 auth_payload->set_data(auth_payload, auth_data);
473 message->add_payload(message, (payload_t*)auth_payload);
474 chunk_free(&auth_data);
475 return TRUE;
476 }
477
478 METHOD(authenticator_t, process_server, status_t,
479 private_eap_authenticator_t *this, message_t *message)
480 {
481 eap_payload_t *eap_payload;
482
483 if (this->eap_complete)
484 {
485 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
486 {
487 return FAILED;
488 }
489 return NEED_MORE;
490 }
491
492 if (!this->method)
493 {
494 this->eap_payload = server_initiate_eap(this, TRUE);
495 }
496 else
497 {
498 eap_payload = (eap_payload_t*)message->get_payload(message,
499 EXTENSIBLE_AUTHENTICATION);
500 if (!eap_payload)
501 {
502 return FAILED;
503 }
504 this->eap_payload = server_process_eap(this, eap_payload);
505 }
506 return NEED_MORE;
507 }
508
509 METHOD(authenticator_t, build_server, status_t,
510 private_eap_authenticator_t *this, message_t *message)
511 {
512 if (this->eap_payload)
513 {
514 eap_code_t code;
515
516 code = this->eap_payload->get_code(this->eap_payload);
517 message->add_payload(message, (payload_t*)this->eap_payload);
518 this->eap_payload = NULL;
519 if (code == EAP_FAILURE)
520 {
521 return FAILED;
522 }
523 return NEED_MORE;
524 }
525 if (this->eap_complete && this->auth_complete &&
526 build_auth(this, message, this->received_nonce, this->sent_init))
527 {
528 return SUCCESS;
529 }
530 return FAILED;
531 }
532
533 METHOD(authenticator_t, process_client, status_t,
534 private_eap_authenticator_t *this, message_t *message)
535 {
536 eap_payload_t *eap_payload;
537
538 if (this->eap_complete)
539 {
540 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
541 {
542 return FAILED;
543 }
544 if (this->require_mutual && !this->method->is_mutual(this->method))
545 { /* we require mutual authentication due to EAP-only */
546 u_int32_t vendor;
547
548 DBG1(DBG_IKE, "EAP-only authentication requires a mutual and "
549 "MSK deriving EAP method, but %N is not",
550 eap_type_names, this->method->get_type(this->method, &vendor));
551 return FAILED;
552 }
553 return SUCCESS;
554 }
555
556 eap_payload = (eap_payload_t*)message->get_payload(message,
557 EXTENSIBLE_AUTHENTICATION);
558 if (eap_payload)
559 {
560 switch (eap_payload->get_code(eap_payload))
561 {
562 case EAP_REQUEST:
563 {
564 this->eap_payload = client_process_eap(this, eap_payload);
565 if (this->eap_payload)
566 {
567 return NEED_MORE;
568 }
569 return FAILED;
570 }
571 case EAP_SUCCESS:
572 {
573 eap_type_t type;
574 u_int32_t vendor;
575 auth_cfg_t *cfg;
576
577 if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
578 {
579 this->msk = chunk_clone(this->msk);
580 }
581 type = this->method->get_type(this->method, &vendor);
582 if (vendor)
583 {
584 DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, "
585 "%sMSK established", type, vendor,
586 this->msk.ptr ? "" : "no ");
587 }
588 else
589 {
590 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
591 eap_type_names, type, this->msk.ptr ? "" : "no ");
592 }
593 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
594 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
595 if (vendor)
596 {
597 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
598 }
599 this->eap_complete = TRUE;
600 return NEED_MORE;
601 }
602 case EAP_FAILURE:
603 default:
604 {
605 DBG1(DBG_IKE, "received %N, EAP authentication failed",
606 eap_code_names, eap_payload->get_code(eap_payload));
607 return FAILED;
608 }
609 }
610 }
611 return FAILED;
612 }
613
614 METHOD(authenticator_t, build_client, status_t,
615 private_eap_authenticator_t *this, message_t *message)
616 {
617 if (this->eap_payload)
618 {
619 message->add_payload(message, (payload_t*)this->eap_payload);
620 this->eap_payload = NULL;
621 return NEED_MORE;
622 }
623 if (this->eap_complete &&
624 build_auth(this, message, this->received_nonce, this->sent_init))
625 {
626 return NEED_MORE;
627 }
628 return NEED_MORE;
629 }
630
631 METHOD(authenticator_t, is_mutual, bool,
632 private_eap_authenticator_t *this)
633 {
634 /* we don't know yet, but insist on it after EAP is complete */
635 this->require_mutual = TRUE;
636 return TRUE;
637 }
638
639 METHOD(authenticator_t, destroy, void,
640 private_eap_authenticator_t *this)
641 {
642 DESTROY_IF(this->method);
643 DESTROY_IF(this->eap_payload);
644 DESTROY_IF(this->eap_identity);
645 chunk_free(&this->msk);
646 free(this);
647 }
648
649 /*
650 * Described in header.
651 */
652 eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
653 chunk_t received_nonce, chunk_t sent_nonce,
654 chunk_t received_init, chunk_t sent_init,
655 char reserved[3])
656 {
657 private_eap_authenticator_t *this;
658
659 INIT(this,
660 .public = {
661 .authenticator = {
662 .build = _build_client,
663 .process = _process_client,
664 .is_mutual = _is_mutual,
665 .destroy = _destroy,
666 },
667 },
668 .ike_sa = ike_sa,
669 .received_init = received_init,
670 .received_nonce = received_nonce,
671 .sent_init = sent_init,
672 .sent_nonce = sent_nonce,
673 );
674 memcpy(this->reserved, reserved, sizeof(this->reserved));
675
676 return &this->public;
677 }
678
679 /*
680 * Described in header.
681 */
682 eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
683 chunk_t received_nonce, chunk_t sent_nonce,
684 chunk_t received_init, chunk_t sent_init,
685 char reserved[3])
686 {
687 private_eap_authenticator_t *this;
688
689 INIT(this,
690 .public = {
691 .authenticator = {
692 .build = _build_server,
693 .process = _process_server,
694 .is_mutual = _is_mutual,
695 .destroy = _destroy,
696 },
697 },
698 .ike_sa = ike_sa,
699 .received_init = received_init,
700 .received_nonce = received_nonce,
701 .sent_init = sent_init,
702 .sent_nonce = sent_nonce,
703 );
704 memcpy(this->reserved, reserved, sizeof(this->reserved));
705
706 return &this->public;
707 }