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