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