]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/sa/ikev2/authenticators/eap_authenticator.c
eap-authenticator: Handle IntAuth data
[thirdparty/strongswan.git] / src / libcharon / sa / ikev2 / authenticators / eap_authenticator.c
CommitLineData
f27f6296 1/*
66277067 2 * Copyright (C) 2012-2018 Tobias Brunner
a44bb934 3 * Copyright (C) 2006-2009 Martin Willi
19ef2aec
TB
4 *
5 * Copyright (C) secunet Security Networks AG
f27f6296
MW
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
f27f6296
MW
18#include "eap_authenticator.h"
19
20#include <daemon.h>
15a682f4 21#include <sa/ikev2/keymat_v2.h>
326a9423 22#include <sa/eap/eap_method.h>
a44bb934
MW
23#include <encoding/payloads/auth_payload.h>
24#include <encoding/payloads/eap_payload.h>
f27f6296
MW
25
26typedef struct private_eap_authenticator_t private_eap_authenticator_t;
27
28/**
29 * Private data of an eap_authenticator_t object.
30 */
31struct private_eap_authenticator_t {
7daf5226 32
f27f6296
MW
33 /**
34 * Public authenticator_t interface.
35 */
36 eap_authenticator_t public;
7daf5226 37
f27f6296
MW
38 /**
39 * Assigned IKE_SA
40 */
41 ike_sa_t *ike_sa;
7daf5226 42
f27f6296 43 /**
25f2d52f 44 * others nonce to include in AUTH calculation
f27f6296 45 */
25f2d52f 46 chunk_t received_nonce;
7daf5226 47
a44bb934 48 /**
25f2d52f 49 * our nonce to include in AUTH calculation
a44bb934 50 */
25f2d52f 51 chunk_t sent_nonce;
7daf5226 52
25f2d52f
MW
53 /**
54 * others IKE_SA_INIT message data to include in AUTH calculation
55 */
56 chunk_t received_init;
7daf5226 57
25f2d52f
MW
58 /**
59 * our IKE_SA_INIT message data to include in AUTH calculation
60 */
61 chunk_t sent_init;
7daf5226 62
f3b02d88
TB
63 /**
64 * IntAuth data to include in AUTH calculation
65 */
66 chunk_t int_auth;
67
5f15faeb
MW
68 /**
69 * Reserved bytes of ID payload
70 */
71 char reserved[3];
72
66277067
TB
73 /**
74 * PPK to use
75 */
76 chunk_t ppk;
77
78 /**
79 * Add a NO_PPK_AUTH notify
80 */
81 bool no_ppk_auth;
82
f27f6296
MW
83 /**
84 * Current EAP method processing
85 */
86 eap_method_t *method;
7daf5226 87
f27f6296
MW
88 /**
89 * MSK used to build and verify auth payload
90 */
91 chunk_t msk;
7daf5226 92
82290106 93 /**
a44bb934 94 * EAP authentication method completed successfully
82290106 95 */
a44bb934 96 bool eap_complete;
7daf5226 97
f34702ff
MW
98 /**
99 * Set if we require mutual EAP due EAP-only authentication
100 */
101 bool require_mutual;
102
82290106 103 /**
a44bb934 104 * authentication payload verified successfully
82290106 105 */
a44bb934 106 bool auth_complete;
7daf5226 107
82290106 108 /**
a44bb934 109 * generated EAP payload
82290106 110 */
a44bb934 111 eap_payload_t *eap_payload;
7daf5226 112
a44bb934
MW
113 /**
114 * EAP identity of peer
115 */
116 identification_t *eap_identity;
f27f6296 117};
a44bb934 118
f27f6296 119/**
a44bb934 120 * load an EAP method
f27f6296 121 */
a44bb934 122static eap_method_t *load_method(private_eap_authenticator_t *this,
f6e6fcd2 123 eap_type_t type, pen_t vendor, eap_role_t role)
f27f6296 124{
36eafea2
MW
125 identification_t *server, *peer, *aaa;
126 auth_cfg_t *auth;
7daf5226 127
a44bb934 128 if (role == EAP_SERVER)
f27f6296 129 {
a44bb934
MW
130 server = this->ike_sa->get_my_id(this->ike_sa);
131 peer = this->ike_sa->get_other_id(this->ike_sa);
36eafea2 132 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
f27f6296 133 }
a44bb934
MW
134 else
135 {
136 server = this->ike_sa->get_other_id(this->ike_sa);
137 peer = this->ike_sa->get_my_id(this->ike_sa);
36eafea2 138 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
a44bb934
MW
139 }
140 if (this->eap_identity)
141 {
142 peer = this->eap_identity;
143 }
36eafea2
MW
144 aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY);
145 if (aaa)
146 {
147 server = aaa;
148 }
a44bb934
MW
149 return charon->eap->create_instance(charon->eap, type, vendor,
150 role, server, peer);
f27f6296
MW
151}
152
82290106 153/**
a44bb934 154 * Initiate EAP conversation as server
82290106 155 */
a44bb934
MW
156static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
157 bool do_identity)
82290106 158{
a44bb934
MW
159 auth_cfg_t *auth;
160 eap_type_t type;
82290106 161 identification_t *id;
f6e6fcd2 162 pen_t vendor;
a44bb934 163 eap_payload_t *out;
83c282eb 164 char *action;
7daf5226 165
a44bb934 166 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
7daf5226 167
a44bb934
MW
168 /* initiate EAP-Identity exchange if required */
169 if (!this->eap_identity && do_identity)
82290106 170 {
a44bb934
MW
171 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
172 if (id)
82290106 173 {
53913d76 174 if (id->get_type(id) == ID_ANY)
82290106 175 {
53913d76
MW
176 this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER);
177 if (this->method)
a44bb934 178 {
53913d76
MW
179 if (this->method->initiate(this->method, &out) == NEED_MORE)
180 {
c76b8a21
AS
181 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)",
182 eap_type_names, EAP_IDENTITY,
183 this->method->get_identifier(this->method));
53913d76
MW
184 return out;
185 }
186 this->method->destroy(this->method);
a44bb934 187 }
53913d76
MW
188 DBG1(DBG_IKE, "EAP-Identity request configured, "
189 "but not supported");
190 }
191 else
192 {
193 DBG1(DBG_IKE, "using configured EAP-Identity %Y", id);
194 this->eap_identity = id->clone(id);
82290106
MW
195 }
196 }
197 }
a44bb934
MW
198 /* invoke real EAP method */
199 type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
200 vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
83c282eb 201 action = "loading";
a44bb934 202 this->method = load_method(this, type, vendor, EAP_SERVER);
83c282eb 203 if (this->method)
82290106 204 {
83c282eb
AS
205 action = "initiating";
206 if (this->method->initiate(this->method, &out) == NEED_MORE)
a44bb934 207 {
7f2e3091 208 type = this->method->get_type(this->method, &vendor);
83c282eb
AS
209 if (vendor)
210 {
9efd7d7e
TB
211 DBG1(DBG_IKE, "initiating EAP vendor type %d-%N method (id 0x%02X)",
212 type, pen_names, vendor, out->get_identifier(out));
83c282eb
AS
213 }
214 else
215 {
c98ed04d 216 DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names,
de931542 217 type, out->get_identifier(out));
83c282eb
AS
218 }
219 return out;
a44bb934 220 }
7f2e3091
TB
221 /* type might have changed for virtual methods */
222 type = this->method->get_type(this->method, &vendor);
82290106 223 }
a44bb934 224 if (vendor)
82290106 225 {
9efd7d7e
TB
226 DBG1(DBG_IKE, "%s EAP vendor type %d-%N method failed",
227 action, type, pen_names, vendor);
82290106
MW
228 }
229 else
230 {
83c282eb 231 DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type);
82290106 232 }
a44bb934 233 return eap_payload_create_code(EAP_FAILURE, 0);
82290106
MW
234}
235
f6116e61
MW
236/**
237 * Replace the existing EAP-Identity in other auth config
238 */
239static void replace_eap_identity(private_eap_authenticator_t *this)
240{
b447af65 241 identification_t *eap_identity;
f6116e61 242 auth_cfg_t *cfg;
f6116e61 243
b447af65 244 eap_identity = this->eap_identity->clone(this->eap_identity);
f6116e61 245 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
7e84c427 246 cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity);
f6116e61
MW
247}
248
82290106 249/**
a44bb934 250 * Handle EAP exchange as server
82290106 251 */
a44bb934
MW
252static eap_payload_t* server_process_eap(private_eap_authenticator_t *this,
253 eap_payload_t *in)
82290106 254{
34742f1b 255 eap_type_t type, received_type, conf_type;
f6e6fcd2 256 pen_t vendor, received_vendor, conf_vendor;
a44bb934 257 eap_payload_t *out;
34742f1b 258 auth_cfg_t *auth;
7daf5226 259
a44bb934 260 if (in->get_code(in) != EAP_RESPONSE)
f27f6296 261 {
a44bb934
MW
262 DBG1(DBG_IKE, "received %N, sending %N",
263 eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE);
264 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
f27f6296 265 }
7daf5226 266
a44bb934
MW
267 type = this->method->get_type(this->method, &vendor);
268 received_type = in->get_type(in, &received_vendor);
269 if (type != received_type || vendor != received_vendor)
f27f6296 270 {
a44bb934 271 if (received_vendor == 0 && received_type == EAP_NAK)
82290106 272 {
34742f1b
TB
273 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
274 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
275 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
276 if ((type == EAP_IDENTITY && !vendor) ||
277 (type == conf_type && vendor == conf_vendor))
278 {
279 DBG1(DBG_IKE, "received %N, sending %N",
280 eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE);
281 return eap_payload_create_code(EAP_FAILURE,
282 in->get_identifier(in));
283 }
284 /* virtual methods handle NAKs in process() */
82290106 285 }
a44bb934
MW
286 else
287 {
288 DBG1(DBG_IKE, "received invalid EAP response, sending %N",
289 eap_code_names, EAP_FAILURE);
34742f1b 290 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
a44bb934 291 }
f27f6296 292 }
7daf5226 293
a44bb934 294 switch (this->method->process(this->method, in, &out))
f27f6296 295 {
a44bb934
MW
296 case NEED_MORE:
297 return out;
298 case SUCCESS:
aa59a7f2 299 if (!vendor && type == EAP_IDENTITY)
a44bb934
MW
300 {
301 chunk_t data;
7daf5226 302
a44bb934
MW
303 if (this->method->get_msk(this->method, &data) == SUCCESS)
304 {
f6116e61 305 this->eap_identity = identification_create_from_data(data);
d24a74c5 306 DBG1(DBG_IKE, "received EAP identity '%Y'",
a44bb934 307 this->eap_identity);
f6116e61 308 replace_eap_identity(this);
a44bb934
MW
309 }
310 /* restart EAP exchange, but with real method */
311 this->method->destroy(this->method);
312 return server_initiate_eap(this, FALSE);
313 }
64cc9acb 314 switch (this->method->get_msk(this->method, &this->msk))
a44bb934 315 {
64cc9acb
TB
316 case SUCCESS:
317 this->msk = chunk_clone(this->msk);
318 break;
319 case NOT_SUPPORTED:
320 break;
321 case FAILED:
322 default:
323 DBG1(DBG_IKE, "failed to establish MSK");
324 goto failure;
a44bb934
MW
325 }
326 if (vendor)
327 {
9efd7d7e
TB
328 DBG1(DBG_IKE, "EAP vendor specific method %d-%N succeeded, "
329 "%sMSK established", type, pen_names, vendor,
a44bb934
MW
330 this->msk.ptr ? "" : "no ");
331 }
332 else
333 {
334 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
335 eap_type_names, type, this->msk.ptr ? "" : "no ");
336 }
337 this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED,
338 TRUE);
a44bb934
MW
339 this->eap_complete = TRUE;
340 return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in));
341 case FAILED:
342 default:
64cc9acb 343failure:
7f2e3091
TB
344 /* type might have changed for virtual methods */
345 type = this->method->get_type(this->method, &vendor);
a44bb934
MW
346 if (vendor)
347 {
9efd7d7e
TB
348 DBG1(DBG_IKE, "EAP vendor specific method %d-%N failed for "
349 "peer %Y", type, pen_names, vendor,
a44bb934
MW
350 this->ike_sa->get_other_id(this->ike_sa));
351 }
352 else
353 {
d24a74c5 354 DBG1(DBG_IKE, "EAP method %N failed for peer %Y",
a44bb934
MW
355 eap_type_names, type,
356 this->ike_sa->get_other_id(this->ike_sa));
357 }
358 return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in));
f27f6296 359 }
f27f6296
MW
360}
361
362/**
363 * Processing method for a peer
364 */
a44bb934
MW
365static eap_payload_t* client_process_eap(private_eap_authenticator_t *this,
366 eap_payload_t *in)
f27f6296 367{
78e8dca9 368 eap_type_t type, conf_type;
f6e6fcd2 369 pen_t vendor, conf_vendor;
a44bb934
MW
370 auth_cfg_t *auth;
371 eap_payload_t *out;
372 identification_t *id;
7daf5226 373
0f806802 374 type = in->get_type(in, &vendor);
7daf5226 375
0f806802 376 if (!vendor && type == EAP_IDENTITY)
3bc0b1a8 377 {
a44bb934
MW
378 DESTROY_IF(this->eap_identity);
379 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
380 id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
381 if (!id || id->get_type(id) == ID_ANY)
382 {
383 id = this->ike_sa->get_my_id(this->ike_sa);
384 }
c76b8a21
AS
385 DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'",
386 eap_type_names, type, in->get_identifier(in), id);
a44bb934 387 this->eap_identity = id->clone(id);
7daf5226 388
a44bb934
MW
389 this->method = load_method(this, type, vendor, EAP_PEER);
390 if (this->method)
3bc0b1a8 391 {
a44bb934
MW
392 if (this->method->process(this->method, in, &out) == SUCCESS)
393 {
394 this->method->destroy(this->method);
395 this->method = NULL;
396 return out;
397 }
398 this->method->destroy(this->method);
399 this->method = NULL;
3bc0b1a8 400 }
af04233e
TB
401 /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no
402 * EAP method (types 3-253, 255) */
a44bb934
MW
403 DBG1(DBG_IKE, "%N not supported, sending EAP_NAK",
404 eap_type_names, type);
78e8dca9 405 return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE);
3bc0b1a8 406 }
f27f6296
MW
407 if (this->method == NULL)
408 {
0f806802
MW
409 if (vendor)
410 {
9efd7d7e
TB
411 DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%N ",
412 "(id 0x%02X)", type, pen_names, vendor, in->get_identifier(in));
0f806802
MW
413 }
414 else
415 {
c98ed04d 416 DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)",
de931542 417 eap_type_names, type, in->get_identifier(in));
0f806802 418 }
78e8dca9
TB
419 auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
420 conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE);
421 conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR);
422 if (conf_type != EAP_NAK &&
423 (conf_type != type || conf_vendor != vendor))
424 {
425 if (conf_vendor)
426 {
9efd7d7e
TB
427 DBG1(DBG_IKE, "requesting EAP method %d-%N, sending EAP_NAK",
428 conf_type, pen_names, conf_vendor);
78e8dca9
TB
429 }
430 else
431 {
432 DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK",
433 eap_type_names, conf_type);
434 }
435 return eap_payload_create_nak(in->get_identifier(in), conf_type,
cc4eec56 436 conf_vendor, in->is_expanded(in));
78e8dca9 437 }
82290106 438 this->method = load_method(this, type, vendor, EAP_PEER);
a44bb934 439 if (!this->method)
f27f6296 440 {
a44bb934 441 DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK");
78e8dca9 442 return eap_payload_create_nak(in->get_identifier(in), 0, 0,
cc4eec56 443 in->is_expanded(in));
f27f6296
MW
444 }
445 }
7daf5226 446
0f806802 447 type = this->method->get_type(this->method, &vendor);
7daf5226 448
a44bb934
MW
449 if (this->method->process(this->method, in, &out) == NEED_MORE)
450 { /* client methods should never return SUCCESS */
451 return out;
452 }
7daf5226 453
a44bb934 454 if (vendor)
f27f6296 455 {
9efd7d7e
TB
456 DBG1(DBG_IKE, "vendor specific EAP method %d-%N failed", type,
457 pen_names, vendor);
a44bb934
MW
458 }
459 else
460 {
461 DBG1(DBG_IKE, "%N method failed", eap_type_names, type);
f27f6296 462 }
a44bb934 463 return NULL;
f27f6296
MW
464}
465
82290106 466/**
a44bb934 467 * Verify AUTH payload
82290106 468 */
25f2d52f
MW
469static bool verify_auth(private_eap_authenticator_t *this, message_t *message,
470 chunk_t nonce, chunk_t init)
82290106 471{
a44bb934 472 auth_payload_t *auth_payload;
66277067 473 notify_payload_t *notify;
a44bb934
MW
474 chunk_t auth_data, recv_auth_data;
475 identification_t *other_id;
476 auth_cfg_t *auth;
a0563846 477 keymat_v2_t *keymat;
49a20ef0 478 eap_type_t type;
f6e6fcd2 479 pen_t vendor;
7daf5226 480
a44bb934 481 auth_payload = (auth_payload_t*)message->get_payload(message,
3ecfc83c 482 PLV2_AUTH);
a44bb934 483 if (!auth_payload)
82290106 484 {
a44bb934
MW
485 DBG1(DBG_IKE, "AUTH payload missing");
486 return FALSE;
82290106 487 }
66277067
TB
488 recv_auth_data = auth_payload->get_data(auth_payload);
489
490 if (this->ike_sa->supports_extension(this->ike_sa, EXT_PPK) &&
491 !this->ppk.ptr)
492 { /* look for a NO_PPK_AUTH notify if we have no PPK */
493 notify = message->get_notify(message, NO_PPK_AUTH);
494 if (notify)
495 {
496 DBG1(DBG_IKE, "no PPK available, using NO_PPK_AUTH notify");
497 recv_auth_data = notify->get_notification_data(notify);
498 }
499 }
500
a44bb934 501 other_id = this->ike_sa->get_other_id(this->ike_sa);
a0563846 502 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
f3b02d88
TB
503 if (!keymat->get_psk_sig(keymat, TRUE, init, nonce, this->int_auth,
504 this->msk, this->ppk, other_id, this->reserved,
505 &auth_data))
2baae8e3
MW
506 {
507 return FALSE;
508 }
161a0157 509 if (!auth_data.len || !chunk_equals_const(auth_data, recv_auth_data))
a44bb934
MW
510 {
511 DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed",
512 this->msk.ptr ? "" : "out");
513 chunk_free(&auth_data);
514 return FALSE;
515 }
516 chunk_free(&auth_data);
7daf5226 517
d24a74c5 518 DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
a44bb934
MW
519 other_id, auth_class_names, AUTH_CLASS_EAP);
520 this->auth_complete = TRUE;
521 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
522 auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
49a20ef0
TB
523
524 type = this->method->get_type(this->method, &vendor);
525 auth->add(auth, AUTH_RULE_EAP_TYPE, type);
526 if (vendor)
527 {
528 auth->add(auth, AUTH_RULE_EAP_VENDOR, vendor);
529 }
a44bb934
MW
530 return TRUE;
531}
532
533/**
534 * Build AUTH payload
535 */
2baae8e3 536static bool build_auth(private_eap_authenticator_t *this, message_t *message,
25f2d52f 537 chunk_t nonce, chunk_t init)
a44bb934
MW
538{
539 auth_payload_t *auth_payload;
540 identification_t *my_id;
541 chunk_t auth_data;
a0563846 542 keymat_v2_t *keymat;
7daf5226 543
a44bb934 544 my_id = this->ike_sa->get_my_id(this->ike_sa);
a0563846 545 keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
7daf5226 546
d24a74c5 547 DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N",
a44bb934 548 my_id, auth_class_names, AUTH_CLASS_EAP);
7daf5226 549
f3b02d88
TB
550 if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->int_auth,
551 this->msk, this->ppk, my_id, this->reserved,
552 &auth_data))
2baae8e3
MW
553 {
554 return FALSE;
555 }
a44bb934
MW
556 auth_payload = auth_payload_create();
557 auth_payload->set_auth_method(auth_payload, AUTH_PSK);
558 auth_payload->set_data(auth_payload, auth_data);
559 message->add_payload(message, (payload_t*)auth_payload);
560 chunk_free(&auth_data);
66277067
TB
561
562 if (this->no_ppk_auth)
563 {
f3b02d88 564 if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, this->int_auth,
d0131f70
TB
565 this->msk, chunk_empty, my_id, this->reserved,
566 &auth_data))
66277067
TB
567 {
568 DBG1(DBG_IKE, "failed adding NO_PPK_AUTH notify");
569 return FALSE;
570 }
571 message->add_notify(message, FALSE, NO_PPK_AUTH, auth_data);
572 chunk_free(&auth_data);
573 }
2baae8e3 574 return TRUE;
82290106
MW
575}
576
45c4021b
AS
577METHOD(authenticator_t, process_server, status_t,
578 private_eap_authenticator_t *this, message_t *message)
f27f6296 579{
a44bb934 580 eap_payload_t *eap_payload;
7daf5226 581
a44bb934
MW
582 if (this->eap_complete)
583 {
25f2d52f 584 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
a44bb934
MW
585 {
586 return FAILED;
587 }
0c608316
MW
588 if (this->method->get_auth)
589 {
590 auth_cfg_t *auth;
591
592 auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
593 auth->merge(auth, this->method->get_auth(this->method), FALSE);
594 }
a44bb934
MW
595 return NEED_MORE;
596 }
7daf5226 597
a44bb934 598 if (!this->method)
f27f6296 599 {
a44bb934
MW
600 this->eap_payload = server_initiate_eap(this, TRUE);
601 }
602 else
603 {
604 eap_payload = (eap_payload_t*)message->get_payload(message,
3ecfc83c 605 PLV2_EAP);
a44bb934
MW
606 if (!eap_payload)
607 {
f27f6296 608 return FAILED;
a44bb934
MW
609 }
610 this->eap_payload = server_process_eap(this, eap_payload);
f27f6296 611 }
a44bb934 612 return NEED_MORE;
f27f6296
MW
613}
614
45c4021b
AS
615METHOD(authenticator_t, build_server, status_t,
616 private_eap_authenticator_t *this, message_t *message)
f27f6296 617{
a44bb934
MW
618 if (this->eap_payload)
619 {
620 eap_code_t code;
7daf5226 621
a44bb934
MW
622 code = this->eap_payload->get_code(this->eap_payload);
623 message->add_payload(message, (payload_t*)this->eap_payload);
624 this->eap_payload = NULL;
625 if (code == EAP_FAILURE)
626 {
627 return FAILED;
628 }
629 return NEED_MORE;
630 }
2baae8e3
MW
631 if (this->eap_complete && this->auth_complete &&
632 build_auth(this, message, this->received_nonce, this->sent_init))
a44bb934 633 {
a44bb934
MW
634 return SUCCESS;
635 }
636 return FAILED;
637}
638
45c4021b
AS
639METHOD(authenticator_t, process_client, status_t,
640 private_eap_authenticator_t *this, message_t *message)
a44bb934
MW
641{
642 eap_payload_t *eap_payload;
7daf5226 643
a44bb934 644 if (this->eap_complete)
f27f6296 645 {
25f2d52f 646 if (!verify_auth(this, message, this->sent_nonce, this->received_init))
f27f6296 647 {
a44bb934 648 return FAILED;
f27f6296 649 }
f34702ff
MW
650 if (this->require_mutual && !this->method->is_mutual(this->method))
651 { /* we require mutual authentication due to EAP-only */
f6e6fcd2 652 pen_t vendor;
f34702ff
MW
653
654 DBG1(DBG_IKE, "EAP-only authentication requires a mutual and "
655 "MSK deriving EAP method, but %N is not",
656 eap_type_names, this->method->get_type(this->method, &vendor));
657 return FAILED;
658 }
a44bb934
MW
659 return SUCCESS;
660 }
7daf5226 661
a44bb934 662 eap_payload = (eap_payload_t*)message->get_payload(message,
3ecfc83c 663 PLV2_EAP);
a44bb934
MW
664 if (eap_payload)
665 {
666 switch (eap_payload->get_code(eap_payload))
f27f6296 667 {
a44bb934
MW
668 case EAP_REQUEST:
669 {
670 this->eap_payload = client_process_eap(this, eap_payload);
cd37e131
MW
671 if (this->eap_payload)
672 {
673 return NEED_MORE;
674 }
675 return FAILED;
a44bb934
MW
676 }
677 case EAP_SUCCESS:
f27f6296 678 {
a44bb934 679 eap_type_t type;
f6e6fcd2 680 pen_t vendor;
a44bb934 681 auth_cfg_t *cfg;
7daf5226 682
64cc9acb 683 if (!this->method)
f27f6296 684 {
64cc9acb
TB
685 DBG1(DBG_IKE, "received unexpected %N",
686 eap_code_names, eap_payload->get_code(eap_payload));
687 return FAILED;
688 }
689 switch (this->method->get_msk(this->method, &this->msk))
690 {
691 case SUCCESS:
692 this->msk = chunk_clone(this->msk);
693 break;
694 case NOT_SUPPORTED:
695 break;
696 case FAILED:
697 default:
698 DBG1(DBG_IKE, "received %N but failed to establish MSK",
699 eap_code_names, eap_payload->get_code(eap_payload));
700 return FAILED;
f27f6296 701 }
a44bb934
MW
702 type = this->method->get_type(this->method, &vendor);
703 if (vendor)
f27f6296 704 {
9efd7d7e
TB
705 DBG1(DBG_IKE, "EAP vendor specific method %d-%N succeeded, "
706 "%sMSK established", type, pen_names, vendor,
a44bb934 707 this->msk.ptr ? "" : "no ");
f27f6296 708 }
a44bb934 709 else
f27f6296 710 {
a44bb934
MW
711 DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established",
712 eap_type_names, type, this->msk.ptr ? "" : "no ");
f27f6296 713 }
a44bb934
MW
714 cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
715 cfg->add(cfg, AUTH_RULE_EAP_TYPE, type);
716 if (vendor)
717 {
718 cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor);
719 }
720 this->eap_complete = TRUE;
721 return NEED_MORE;
722 }
723 case EAP_FAILURE:
724 default:
725 {
726 DBG1(DBG_IKE, "received %N, EAP authentication failed",
727 eap_code_names, eap_payload->get_code(eap_payload));
728 return FAILED;
f27f6296 729 }
f27f6296
MW
730 }
731 }
a44bb934 732 return FAILED;
f27f6296
MW
733}
734
45c4021b
AS
735METHOD(authenticator_t, build_client, status_t,
736 private_eap_authenticator_t *this, message_t *message)
f27f6296 737{
a44bb934 738 if (this->eap_payload)
f27f6296 739 {
a44bb934
MW
740 message->add_payload(message, (payload_t*)this->eap_payload);
741 this->eap_payload = NULL;
742 return NEED_MORE;
f27f6296 743 }
2baae8e3
MW
744 if (this->eap_complete &&
745 build_auth(this, message, this->received_nonce, this->sent_init))
a44bb934 746 {
a44bb934
MW
747 return NEED_MORE;
748 }
749 return NEED_MORE;
f27f6296
MW
750}
751
45c4021b
AS
752METHOD(authenticator_t, is_mutual, bool,
753 private_eap_authenticator_t *this)
f34702ff 754{
d8a94c18
MW
755 if (this->method)
756 {
f6e6fcd2 757 pen_t vendor;
d8a94c18
MW
758
759 if (this->method->get_type(this->method, &vendor) != EAP_IDENTITY ||
760 vendor != 0)
761 {
762 return this->method->is_mutual(this->method);
763 }
764 }
f34702ff
MW
765 /* we don't know yet, but insist on it after EAP is complete */
766 this->require_mutual = TRUE;
767 return TRUE;
768}
769
66277067
TB
770METHOD(authenticator_t, use_ppk, void,
771 private_eap_authenticator_t *this, chunk_t ppk, bool no_ppk_auth)
772{
773 this->ppk = ppk;
774 this->no_ppk_auth = no_ppk_auth;
775}
776
f3b02d88
TB
777METHOD(authenticator_t, set_int_auth, void,
778 private_eap_authenticator_t *this, chunk_t int_auth)
779{
780 this->int_auth = int_auth;
781}
782
45c4021b
AS
783METHOD(authenticator_t, destroy, void,
784 private_eap_authenticator_t *this)
f27f6296
MW
785{
786 DESTROY_IF(this->method);
a44bb934
MW
787 DESTROY_IF(this->eap_payload);
788 DESTROY_IF(this->eap_identity);
f27f6296
MW
789 chunk_free(&this->msk);
790 free(this);
791}
792
793/*
794 * Described in header.
795 */
a44bb934 796eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
25f2d52f 797 chunk_t received_nonce, chunk_t sent_nonce,
5f15faeb
MW
798 chunk_t received_init, chunk_t sent_init,
799 char reserved[3])
f27f6296 800{
45c4021b
AS
801 private_eap_authenticator_t *this;
802
803 INIT(this,
804 .public = {
805 .authenticator = {
806 .build = _build_client,
807 .process = _process_client,
66277067 808 .use_ppk = _use_ppk,
f3b02d88 809 .set_int_auth = _set_int_auth,
45c4021b
AS
810 .is_mutual = _is_mutual,
811 .destroy = _destroy,
812 },
813 },
814 .ike_sa = ike_sa,
815 .received_init = received_init,
816 .received_nonce = received_nonce,
817 .sent_init = sent_init,
818 .sent_nonce = sent_nonce,
45c4021b 819 );
5f15faeb 820 memcpy(this->reserved, reserved, sizeof(this->reserved));
7daf5226 821
a44bb934
MW
822 return &this->public;
823}
824
825/*
826 * Described in header.
827 */
828eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
25f2d52f 829 chunk_t received_nonce, chunk_t sent_nonce,
5f15faeb
MW
830 chunk_t received_init, chunk_t sent_init,
831 char reserved[3])
a44bb934 832{
45c4021b
AS
833 private_eap_authenticator_t *this;
834
835 INIT(this,
ba31fe1f
MW
836 .public = {
837 .authenticator = {
838 .build = _build_server,
839 .process = _process_server,
66277067 840 .use_ppk = _use_ppk,
f3b02d88 841 .set_int_auth = _set_int_auth,
ba31fe1f
MW
842 .is_mutual = _is_mutual,
843 .destroy = _destroy,
844 },
45c4021b
AS
845 },
846 .ike_sa = ike_sa,
847 .received_init = received_init,
848 .received_nonce = received_nonce,
849 .sent_init = sent_init,
850 .sent_nonce = sent_nonce,
45c4021b 851 );
5f15faeb 852 memcpy(this->reserved, reserved, sizeof(this->reserved));
7daf5226 853
f27f6296
MW
854 return &this->public;
855}