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