blob: e55e2d5230dd33ca56ce45f6f826944b11728c7e [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * EAP peer state machines (RFC 4137)
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08003 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 *
8 * This file implements the Peer State Machine as defined in RFC 4137. The used
9 * states and state transitions match mostly with the RFC. However, there are
10 * couple of additional transitions for working around small issues noticed
11 * during testing. These exceptions are explained in comments within the
12 * functions in this file. The method functions, m.func(), are similar to the
13 * ones used in RFC 4137, but some small changes have used here to optimize
14 * operations and to add functionality needed for fast re-authentication
15 * (session resumption).
16 */
17
18#include "includes.h"
19
20#include "common.h"
21#include "pcsc_funcs.h"
22#include "state_machine.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070023#include "ext_password.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024#include "crypto/crypto.h"
25#include "crypto/tls.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080026#include "crypto/sha256.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include "common/wpa_ctrl.h"
28#include "eap_common/eap_wsc_common.h"
29#include "eap_i.h"
30#include "eap_config.h"
31
32#define STATE_MACHINE_DATA struct eap_sm
33#define STATE_MACHINE_DEBUG_PREFIX "EAP"
34
35#define EAP_MAX_AUTH_ROUNDS 50
36#define EAP_CLIENT_TIMEOUT_DEFAULT 60
37
38
39static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
40 EapType method);
41static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
42static void eap_sm_processIdentity(struct eap_sm *sm,
43 const struct wpabuf *req);
44static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
45static struct wpabuf * eap_sm_buildNotify(int id);
46static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
47#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
48static const char * eap_sm_method_state_txt(EapMethodState state);
49static const char * eap_sm_decision_txt(EapDecision decision);
50#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt55840ad2015-12-14 12:45:46 -080051static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
52 const char *msg, size_t msglen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070053
54
55
56static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
57{
58 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
59}
60
61
62static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
63 Boolean value)
64{
65 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
66}
67
68
69static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
70{
71 return sm->eapol_cb->get_int(sm->eapol_ctx, var);
72}
73
74
75static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
76 unsigned int value)
77{
78 sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
79}
80
81
82static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
83{
84 return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
85}
86
87
Dmitry Shmidt04949592012-07-19 12:16:46 -070088static void eap_notify_status(struct eap_sm *sm, const char *status,
89 const char *parameter)
90{
91 wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
92 status, parameter);
93 if (sm->eapol_cb->notify_status)
94 sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
95}
96
Roshan Pius3a1667e2018-07-03 15:17:14 -070097
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -070098static void eap_report_error(struct eap_sm *sm, int error_code)
99{
100 wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
101 if (sm->eapol_cb->notify_eap_error)
102 sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
103}
Dmitry Shmidt04949592012-07-19 12:16:46 -0700104
Roshan Pius3a1667e2018-07-03 15:17:14 -0700105
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700106static void eap_sm_free_key(struct eap_sm *sm)
107{
108 if (sm->eapKeyData) {
109 bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen);
110 sm->eapKeyData = NULL;
111 }
112}
113
114
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700115static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
116{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700117 ext_password_free(sm->ext_pw_buf);
118 sm->ext_pw_buf = NULL;
119
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700120 if (sm->m == NULL || sm->eap_method_priv == NULL)
121 return;
122
123 wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
124 "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
125 sm->m->deinit(sm, sm->eap_method_priv);
126 sm->eap_method_priv = NULL;
127 sm->m = NULL;
128}
129
130
131/**
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700132 * eap_config_allowed_method - Check whether EAP method is allowed
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700133 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700134 * @config: EAP configuration
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700135 * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
136 * @method: EAP type
137 * Returns: 1 = allowed EAP method, 0 = not allowed
138 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700139static int eap_config_allowed_method(struct eap_sm *sm,
140 struct eap_peer_config *config,
141 int vendor, u32 method)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700142{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700143 int i;
144 struct eap_method_type *m;
145
146 if (config == NULL || config->eap_methods == NULL)
147 return 1;
148
149 m = config->eap_methods;
150 for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
151 m[i].method != EAP_TYPE_NONE; i++) {
152 if (m[i].vendor == vendor && m[i].method == method)
153 return 1;
154 }
155 return 0;
156}
157
158
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700159/**
160 * eap_allowed_method - Check whether EAP method is allowed
161 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
162 * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
163 * @method: EAP type
164 * Returns: 1 = allowed EAP method, 0 = not allowed
165 */
166int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
167{
168 return eap_config_allowed_method(sm, eap_get_config(sm), vendor,
169 method);
170}
171
172
173#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
174static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
175 size_t max_len, size_t *imsi_len,
176 int mnc_len)
177{
178 char *pos, mnc[4];
179
180 if (*imsi_len + 36 > max_len) {
181 wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
182 return -1;
183 }
184
185 if (mnc_len != 2 && mnc_len != 3)
186 mnc_len = 3;
187
188 if (mnc_len == 2) {
189 mnc[0] = '0';
190 mnc[1] = imsi[3];
191 mnc[2] = imsi[4];
192 } else if (mnc_len == 3) {
193 mnc[0] = imsi[3];
194 mnc[1] = imsi[4];
195 mnc[2] = imsi[5];
196 }
197 mnc[3] = '\0';
198
199 pos = imsi + *imsi_len;
200 pos += os_snprintf(pos, imsi + max_len - pos,
201 "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
202 mnc, imsi[0], imsi[1], imsi[2]);
203 *imsi_len = pos - imsi;
204
205 return 0;
206}
207#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
208
209
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700210/*
211 * This state initializes state machine variables when the machine is
212 * activated (portEnabled = TRUE). This is also used when re-starting
213 * authentication (eapRestart == TRUE).
214 */
215SM_STATE(EAP, INITIALIZE)
216{
217 SM_ENTRY(EAP, INITIALIZE);
218 if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
219 sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
Dmitry Shmidt7f0b69e2014-07-28 10:35:20 -0700220 !sm->prev_failure &&
221 sm->last_config == eap_get_config(sm)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700222 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
223 "fast reauthentication");
224 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
225 } else {
Dmitry Shmidt7f0b69e2014-07-28 10:35:20 -0700226 sm->last_config = eap_get_config(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700227 eap_deinit_prev_method(sm, "INITIALIZE");
228 }
229 sm->selectedMethod = EAP_TYPE_NONE;
230 sm->methodState = METHOD_NONE;
231 sm->allowNotifications = TRUE;
232 sm->decision = DECISION_FAIL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800233 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700234 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
235 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
236 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700237 eap_sm_free_key(sm);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800238 os_free(sm->eapSessionId);
239 sm->eapSessionId = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700240 sm->eapKeyAvailable = FALSE;
241 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
242 sm->lastId = -1; /* new session - make sure this does not match with
243 * the first EAP-Packet */
244 /*
245 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
246 * seemed to be able to trigger cases where both were set and if EAPOL
247 * state machine uses eapNoResp first, it may end up not sending a real
248 * reply correctly. This occurred when the workaround in FAIL state set
249 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
250 * something else(?)
251 */
252 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
253 eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800254 /*
255 * RFC 4137 does not reset ignore here, but since it is possible for
256 * some method code paths to end up not setting ignore=FALSE, clear the
257 * value here to avoid issues if a previous authentication attempt
258 * failed with ignore=TRUE being left behind in the last
259 * m.check(eapReqData) operation.
260 */
261 sm->ignore = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700262 sm->num_rounds = 0;
263 sm->prev_failure = 0;
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800264 sm->expected_failure = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800265 sm->reauthInit = FALSE;
266 sm->erp_seq = (u32) -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700267}
268
269
270/*
271 * This state is reached whenever service from the lower layer is interrupted
272 * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
273 * occurs when the port becomes enabled.
274 */
275SM_STATE(EAP, DISABLED)
276{
277 SM_ENTRY(EAP, DISABLED);
278 sm->num_rounds = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700279 /*
280 * RFC 4137 does not describe clearing of idleWhile here, but doing so
281 * allows the timer tick to be stopped more quickly when EAP is not in
282 * use.
283 */
284 eapol_set_int(sm, EAPOL_idleWhile, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700285}
286
287
288/*
289 * The state machine spends most of its time here, waiting for something to
290 * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
291 * SEND_RESPONSE states.
292 */
293SM_STATE(EAP, IDLE)
294{
295 SM_ENTRY(EAP, IDLE);
296}
297
298
299/*
300 * This state is entered when an EAP packet is received (eapReq == TRUE) to
301 * parse the packet header.
302 */
303SM_STATE(EAP, RECEIVED)
304{
305 const struct wpabuf *eapReqData;
306
307 SM_ENTRY(EAP, RECEIVED);
308 eapReqData = eapol_get_eapReqData(sm);
309 /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
310 eap_sm_parseEapReq(sm, eapReqData);
311 sm->num_rounds++;
312}
313
314
315/*
316 * This state is entered when a request for a new type comes in. Either the
317 * correct method is started, or a Nak response is built.
318 */
319SM_STATE(EAP, GET_METHOD)
320{
321 int reinit;
322 EapType method;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700323 const struct eap_method *eap_method;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700324
325 SM_ENTRY(EAP, GET_METHOD);
326
327 if (sm->reqMethod == EAP_TYPE_EXPANDED)
328 method = sm->reqVendorMethod;
329 else
330 method = sm->reqMethod;
331
Dmitry Shmidt04949592012-07-19 12:16:46 -0700332 eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
333
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700334 if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
335 wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
336 sm->reqVendor, method);
337 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
338 "vendor=%u method=%u -> NAK",
339 sm->reqVendor, method);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700340 eap_notify_status(sm, "refuse proposed method",
341 eap_method ? eap_method->name : "unknown");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342 goto nak;
343 }
344
345 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
346 "vendor=%u method=%u", sm->reqVendor, method);
347
Dmitry Shmidt04949592012-07-19 12:16:46 -0700348 eap_notify_status(sm, "accept proposed method",
349 eap_method ? eap_method->name : "unknown");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700350 /*
351 * RFC 4137 does not define specific operation for fast
352 * re-authentication (session resumption). The design here is to allow
353 * the previously used method data to be maintained for
354 * re-authentication if the method support session resumption.
355 * Otherwise, the previously used method data is freed and a new method
356 * is allocated here.
357 */
358 if (sm->fast_reauth &&
359 sm->m && sm->m->vendor == sm->reqVendor &&
360 sm->m->method == method &&
361 sm->m->has_reauth_data &&
362 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
363 wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
364 " for fast re-authentication");
365 reinit = 1;
366 } else {
367 eap_deinit_prev_method(sm, "GET_METHOD");
368 reinit = 0;
369 }
370
371 sm->selectedMethod = sm->reqMethod;
372 if (sm->m == NULL)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700373 sm->m = eap_method;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700374 if (!sm->m) {
375 wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
376 "vendor %d method %d",
377 sm->reqVendor, method);
378 goto nak;
379 }
380
381 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
382
383 wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
384 "vendor %u method %u (%s)",
385 sm->reqVendor, method, sm->m->name);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800386 if (reinit) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700387 sm->eap_method_priv = sm->m->init_for_reauth(
388 sm, sm->eap_method_priv);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800389 } else {
390 sm->waiting_ext_cert_check = 0;
391 sm->ext_cert_check = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700392 sm->eap_method_priv = sm->m->init(sm);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800393 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700394
395 if (sm->eap_method_priv == NULL) {
396 struct eap_peer_config *config = eap_get_config(sm);
397 wpa_msg(sm->msg_ctx, MSG_INFO,
398 "EAP: Failed to initialize EAP method: vendor %u "
399 "method %u (%s)",
400 sm->reqVendor, method, sm->m->name);
401 sm->m = NULL;
402 sm->methodState = METHOD_NONE;
403 sm->selectedMethod = EAP_TYPE_NONE;
404 if (sm->reqMethod == EAP_TYPE_TLS && config &&
405 (config->pending_req_pin ||
406 config->pending_req_passphrase)) {
407 /*
408 * Return without generating Nak in order to allow
409 * entering of PIN code or passphrase to retry the
410 * current EAP packet.
411 */
412 wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
413 "request - skip Nak");
414 return;
415 }
416
417 goto nak;
418 }
419
420 sm->methodState = METHOD_INIT;
421 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
422 "EAP vendor %u method %u (%s) selected",
423 sm->reqVendor, method, sm->m->name);
424 return;
425
426nak:
427 wpabuf_free(sm->eapRespData);
428 sm->eapRespData = NULL;
429 sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
430}
431
432
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800433#ifdef CONFIG_ERP
434
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700435static char * eap_get_realm(struct eap_sm *sm, struct eap_peer_config *config)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800436{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800437 char *realm;
438 size_t i, realm_len;
439
440 if (!config)
441 return NULL;
442
443 if (config->identity) {
444 for (i = 0; i < config->identity_len; i++) {
445 if (config->identity[i] == '@')
446 break;
447 }
448 if (i < config->identity_len) {
449 realm_len = config->identity_len - i - 1;
450 realm = os_malloc(realm_len + 1);
451 if (realm == NULL)
452 return NULL;
453 os_memcpy(realm, &config->identity[i + 1], realm_len);
454 realm[realm_len] = '\0';
455 return realm;
456 }
457 }
458
459 if (config->anonymous_identity) {
460 for (i = 0; i < config->anonymous_identity_len; i++) {
461 if (config->anonymous_identity[i] == '@')
462 break;
463 }
464 if (i < config->anonymous_identity_len) {
465 realm_len = config->anonymous_identity_len - i - 1;
466 realm = os_malloc(realm_len + 1);
467 if (realm == NULL)
468 return NULL;
469 os_memcpy(realm, &config->anonymous_identity[i + 1],
470 realm_len);
471 realm[realm_len] = '\0';
472 return realm;
473 }
474 }
475
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700476#ifdef CONFIG_EAP_PROXY
477 /* When identity is not provided in the config, build the realm from
478 * IMSI for eap_proxy based methods.
479 */
480 if (!config->identity && !config->anonymous_identity &&
481 sm->eapol_cb->get_imsi &&
482 (eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
483 EAP_TYPE_SIM) ||
484 eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
485 EAP_TYPE_AKA) ||
486 eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
487 EAP_TYPE_AKA_PRIME))) {
488 char imsi[100];
489 size_t imsi_len;
490 int mnc_len, pos;
491
492 wpa_printf(MSG_DEBUG, "EAP: Build realm from IMSI (eap_proxy)");
493 mnc_len = sm->eapol_cb->get_imsi(sm->eapol_ctx, config->sim_num,
494 imsi, &imsi_len);
495 if (mnc_len < 0)
496 return NULL;
497
498 pos = imsi_len + 1; /* points to the beginning of the realm */
499 if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
500 mnc_len) < 0) {
501 wpa_printf(MSG_WARNING, "Could not append realm");
502 return NULL;
503 }
504
505 realm = os_strdup(&imsi[pos]);
506 if (!realm)
507 return NULL;
508
509 wpa_printf(MSG_DEBUG, "EAP: Generated realm '%s'", realm);
510 return realm;
511 }
512#endif /* CONFIG_EAP_PROXY */
513
514 return NULL;
515}
516
517
518static char * eap_home_realm(struct eap_sm *sm)
519{
520 return eap_get_realm(sm, eap_get_config(sm));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800521}
522
523
524static struct eap_erp_key *
525eap_erp_get_key(struct eap_sm *sm, const char *realm)
526{
527 struct eap_erp_key *erp;
528
529 dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
530 char *pos;
531
532 pos = os_strchr(erp->keyname_nai, '@');
533 if (!pos)
534 continue;
535 pos++;
536 if (os_strcmp(pos, realm) == 0)
537 return erp;
538 }
539
540 return NULL;
541}
542
543
544static struct eap_erp_key *
545eap_erp_get_key_nai(struct eap_sm *sm, const char *nai)
546{
547 struct eap_erp_key *erp;
548
549 dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
550 if (os_strcmp(erp->keyname_nai, nai) == 0)
551 return erp;
552 }
553
554 return NULL;
555}
556
557
558static void eap_peer_erp_free_key(struct eap_erp_key *erp)
559{
560 dl_list_del(&erp->list);
561 bin_clear_free(erp, sizeof(*erp));
562}
563
564
565static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
566{
567 struct eap_erp_key *erp;
568
569 while ((erp = eap_erp_get_key(sm, realm)) != NULL) {
570 wpa_printf(MSG_DEBUG, "EAP: Delete old ERP key %s",
571 erp->keyname_nai);
572 eap_peer_erp_free_key(erp);
573 }
574}
575
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700576
577int eap_peer_update_erp_next_seq_num(struct eap_sm *sm, u16 next_seq_num)
578{
579 struct eap_erp_key *erp;
580 char *home_realm;
581
582 home_realm = eap_home_realm(sm);
583 if (!home_realm || os_strlen(home_realm) == 0) {
584 os_free(home_realm);
585 return -1;
586 }
587
588 erp = eap_erp_get_key(sm, home_realm);
589 if (!erp) {
590 wpa_printf(MSG_DEBUG,
591 "EAP: Failed to find ERP key for realm: %s",
592 home_realm);
593 os_free(home_realm);
594 return -1;
595 }
596
597 if ((u32) next_seq_num < erp->next_seq) {
598 /* Sequence number has wrapped around, clear this ERP
599 * info and do a full auth next time.
600 */
601 eap_peer_erp_free_key(erp);
602 } else {
603 erp->next_seq = (u32) next_seq_num;
604 }
605
606 os_free(home_realm);
607 return 0;
608}
609
610
611int eap_peer_get_erp_info(struct eap_sm *sm, struct eap_peer_config *config,
612 const u8 **username, size_t *username_len,
613 const u8 **realm, size_t *realm_len,
614 u16 *erp_next_seq_num, const u8 **rrk,
615 size_t *rrk_len)
616{
617 struct eap_erp_key *erp;
618 char *home_realm;
619 char *pos;
620
621 if (config)
622 home_realm = eap_get_realm(sm, config);
623 else
624 home_realm = eap_home_realm(sm);
625 if (!home_realm || os_strlen(home_realm) == 0) {
626 os_free(home_realm);
627 return -1;
628 }
629
630 erp = eap_erp_get_key(sm, home_realm);
631 os_free(home_realm);
632 if (!erp)
633 return -1;
634
635 if (erp->next_seq >= 65536)
636 return -1; /* SEQ has range of 0..65535 */
637
638 pos = os_strchr(erp->keyname_nai, '@');
639 if (!pos)
640 return -1; /* this cannot really happen */
641 *username_len = pos - erp->keyname_nai;
642 *username = (u8 *) erp->keyname_nai;
643
644 pos++;
645 *realm_len = os_strlen(pos);
646 *realm = (u8 *) pos;
647
648 *erp_next_seq_num = (u16) erp->next_seq;
649
650 *rrk_len = erp->rRK_len;
651 *rrk = erp->rRK;
652
653 if (*username_len == 0 || *realm_len == 0 || *rrk_len == 0)
654 return -1;
655
656 return 0;
657}
658
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800659#endif /* CONFIG_ERP */
660
661
662void eap_peer_erp_free_keys(struct eap_sm *sm)
663{
664#ifdef CONFIG_ERP
665 struct eap_erp_key *erp, *tmp;
666
667 dl_list_for_each_safe(erp, tmp, &sm->erp_keys, struct eap_erp_key, list)
668 eap_peer_erp_free_key(erp);
669#endif /* CONFIG_ERP */
670}
671
672
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700673void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
674 size_t ext_session_id_len, u8 *ext_emsk,
675 size_t ext_emsk_len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800676{
677#ifdef CONFIG_ERP
678 u8 *emsk = NULL;
679 size_t emsk_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700680 u8 *session_id = NULL;
681 size_t session_id_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800682 u8 EMSKname[EAP_EMSK_NAME_LEN];
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800683 u8 len[2], ctx[3];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800684 char *realm;
685 size_t realm_len, nai_buf_len;
686 struct eap_erp_key *erp = NULL;
687 int pos;
688
689 realm = eap_home_realm(sm);
690 if (!realm)
691 return;
692 realm_len = os_strlen(realm);
693 wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
694 eap_erp_remove_keys_realm(sm, realm);
695
696 nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + realm_len;
697 if (nai_buf_len > 253) {
698 /*
699 * keyName-NAI has a maximum length of 253 octet to fit in
700 * RADIUS attributes.
701 */
702 wpa_printf(MSG_DEBUG,
703 "EAP: Too long realm for ERP keyName-NAI maximum length");
704 goto fail;
705 }
706 nai_buf_len++; /* null termination */
707 erp = os_zalloc(sizeof(*erp) + nai_buf_len);
708 if (erp == NULL)
709 goto fail;
710
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700711 if (ext_emsk) {
712 emsk = ext_emsk;
713 emsk_len = ext_emsk_len;
714 } else {
715 emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
716 }
717
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800718 if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
719 wpa_printf(MSG_DEBUG,
720 "EAP: No suitable EMSK available for ERP");
721 goto fail;
722 }
723
724 wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
725
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700726 if (ext_session_id) {
727 session_id = ext_session_id;
728 session_id_len = ext_session_id_len;
729 } else {
730 session_id = sm->eapSessionId;
731 session_id_len = sm->eapSessionIdLen;
732 }
733
734 if (!session_id || session_id_len == 0) {
735 wpa_printf(MSG_DEBUG,
736 "EAP: No suitable session id available for ERP");
737 goto fail;
738 }
739
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800740 WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700741 if (hmac_sha256_kdf(session_id, session_id_len, "EMSK", len,
742 sizeof(len), EMSKname, EAP_EMSK_NAME_LEN) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800743 wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
744 goto fail;
745 }
746 wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
747
748 pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
749 EMSKname, EAP_EMSK_NAME_LEN);
750 erp->keyname_nai[pos] = '@';
751 os_memcpy(&erp->keyname_nai[pos + 1], realm, realm_len);
752
753 WPA_PUT_BE16(len, emsk_len);
754 if (hmac_sha256_kdf(emsk, emsk_len,
755 "EAP Re-authentication Root Key@ietf.org",
756 len, sizeof(len), erp->rRK, emsk_len) < 0) {
757 wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
758 goto fail;
759 }
760 erp->rRK_len = emsk_len;
761 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
762
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800763 ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
764 WPA_PUT_BE16(&ctx[1], erp->rRK_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800765 if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800766 "Re-authentication Integrity Key@ietf.org",
767 ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800768 wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
769 goto fail;
770 }
771 erp->rIK_len = erp->rRK_len;
772 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
773
774 wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", erp->keyname_nai);
775 dl_list_add(&sm->erp_keys, &erp->list);
776 erp = NULL;
777fail:
778 bin_clear_free(emsk, emsk_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700779 bin_clear_free(ext_session_id, ext_session_id_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800780 bin_clear_free(erp, sizeof(*erp));
781 os_free(realm);
782#endif /* CONFIG_ERP */
783}
784
785
786#ifdef CONFIG_ERP
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800787struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800788{
789 char *realm;
790 struct eap_erp_key *erp;
791 struct wpabuf *msg;
792 u8 hash[SHA256_MAC_LEN];
793
794 realm = eap_home_realm(sm);
795 if (!realm)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800796 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800797
798 erp = eap_erp_get_key(sm, realm);
799 os_free(realm);
800 realm = NULL;
801 if (!erp)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800802 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800803
804 if (erp->next_seq >= 65536)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800805 return NULL; /* SEQ has range of 0..65535 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800806
807 /* TODO: check rRK lifetime expiration */
808
809 wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
810 erp->keyname_nai, erp->next_seq);
811
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800812 msg = eap_msg_alloc(EAP_VENDOR_IETF, (EapType) EAP_ERP_TYPE_REAUTH,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800813 1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800814 EAP_CODE_INITIATE, eap_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800815 if (msg == NULL)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800816 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800817
818 wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
819 wpabuf_put_be16(msg, erp->next_seq);
820
821 wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
822 wpabuf_put_u8(msg, os_strlen(erp->keyname_nai));
823 wpabuf_put_str(msg, erp->keyname_nai);
824
825 wpabuf_put_u8(msg, EAP_ERP_CS_HMAC_SHA256_128); /* Cryptosuite */
826
827 if (hmac_sha256(erp->rIK, erp->rIK_len,
828 wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
829 wpabuf_free(msg);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800830 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800831 }
832 wpabuf_put_data(msg, hash, 16);
833
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800834 sm->erp_seq = erp->next_seq;
835 erp->next_seq++;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800836
837 wpa_hexdump_buf(MSG_DEBUG, "ERP: EAP-Initiate/Re-auth", msg);
838
839 return msg;
840}
841
842
843static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
844{
845 struct wpabuf *msg;
846
847 msg = eap_peer_build_erp_reauth_start(sm, eap_id);
848 if (!msg)
849 return -1;
850
851 wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800852 wpabuf_free(sm->eapRespData);
853 sm->eapRespData = msg;
854 sm->reauthInit = TRUE;
855 return 0;
856}
857#endif /* CONFIG_ERP */
858
859
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700860/*
861 * The method processing happens here. The request from the authenticator is
862 * processed, and an appropriate response packet is built.
863 */
864SM_STATE(EAP, METHOD)
865{
866 struct wpabuf *eapReqData;
867 struct eap_method_ret ret;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800868 int min_len = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700869
870 SM_ENTRY(EAP, METHOD);
871 if (sm->m == NULL) {
872 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
873 return;
874 }
875
876 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800877 if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP)
878 min_len = 0; /* LEAP uses EAP-Success without payload */
879 if (!eap_hdr_len_valid(eapReqData, min_len))
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700880 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700881
882 /*
883 * Get ignore, methodState, decision, allowNotifications, and
884 * eapRespData. RFC 4137 uses three separate method procedure (check,
885 * process, and buildResp) in this state. These have been combined into
886 * a single function call to m->process() in order to optimize EAP
887 * method implementation interface a bit. These procedures are only
888 * used from within this METHOD state, so there is no need to keep
889 * these as separate C functions.
890 *
891 * The RFC 4137 procedures return values as follows:
892 * ignore = m.check(eapReqData)
893 * (methodState, decision, allowNotifications) = m.process(eapReqData)
894 * eapRespData = m.buildResp(reqId)
895 */
896 os_memset(&ret, 0, sizeof(ret));
897 ret.ignore = sm->ignore;
898 ret.methodState = sm->methodState;
899 ret.decision = sm->decision;
900 ret.allowNotifications = sm->allowNotifications;
901 wpabuf_free(sm->eapRespData);
902 sm->eapRespData = NULL;
903 sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
904 eapReqData);
905 wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800906 "methodState=%s decision=%s eapRespData=%p",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700907 ret.ignore ? "TRUE" : "FALSE",
908 eap_sm_method_state_txt(ret.methodState),
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800909 eap_sm_decision_txt(ret.decision),
910 sm->eapRespData);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700911
912 sm->ignore = ret.ignore;
913 if (sm->ignore)
914 return;
915 sm->methodState = ret.methodState;
916 sm->decision = ret.decision;
917 sm->allowNotifications = ret.allowNotifications;
918
919 if (sm->m->isKeyAvailable && sm->m->getKey &&
920 sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700921 eap_sm_free_key(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700922 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
923 &sm->eapKeyDataLen);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800924 os_free(sm->eapSessionId);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700925 sm->eapSessionId = NULL;
926 if (sm->m->getSessionId) {
927 sm->eapSessionId = sm->m->getSessionId(
928 sm, sm->eap_method_priv,
929 &sm->eapSessionIdLen);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800930 wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
931 sm->eapSessionId, sm->eapSessionIdLen);
932 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 }
934}
935
936
937/*
938 * This state signals the lower layer that a response packet is ready to be
939 * sent.
940 */
941SM_STATE(EAP, SEND_RESPONSE)
942{
943 SM_ENTRY(EAP, SEND_RESPONSE);
944 wpabuf_free(sm->lastRespData);
945 if (sm->eapRespData) {
946 if (sm->workaround)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800947 os_memcpy(sm->last_sha1, sm->req_sha1, 20);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700948 sm->lastId = sm->reqId;
949 sm->lastRespData = wpabuf_dup(sm->eapRespData);
950 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800951 } else {
952 wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700953 sm->lastRespData = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800954 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700955 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
956 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800957 sm->reauthInit = FALSE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700958}
959
960
961/*
962 * This state signals the lower layer that the request was discarded, and no
963 * response packet will be sent at this time.
964 */
965SM_STATE(EAP, DISCARD)
966{
967 SM_ENTRY(EAP, DISCARD);
968 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
969 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
970}
971
972
973/*
974 * Handles requests for Identity method and builds a response.
975 */
976SM_STATE(EAP, IDENTITY)
977{
978 const struct wpabuf *eapReqData;
979
980 SM_ENTRY(EAP, IDENTITY);
981 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700982 if (!eap_hdr_len_valid(eapReqData, 1))
983 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700984 eap_sm_processIdentity(sm, eapReqData);
985 wpabuf_free(sm->eapRespData);
986 sm->eapRespData = NULL;
987 sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
988}
989
990
991/*
992 * Handles requests for Notification method and builds a response.
993 */
994SM_STATE(EAP, NOTIFICATION)
995{
996 const struct wpabuf *eapReqData;
997
998 SM_ENTRY(EAP, NOTIFICATION);
999 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001000 if (!eap_hdr_len_valid(eapReqData, 1))
1001 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001002 eap_sm_processNotify(sm, eapReqData);
1003 wpabuf_free(sm->eapRespData);
1004 sm->eapRespData = NULL;
1005 sm->eapRespData = eap_sm_buildNotify(sm->reqId);
1006}
1007
1008
1009/*
1010 * This state retransmits the previous response packet.
1011 */
1012SM_STATE(EAP, RETRANSMIT)
1013{
1014 SM_ENTRY(EAP, RETRANSMIT);
1015 wpabuf_free(sm->eapRespData);
1016 if (sm->lastRespData)
1017 sm->eapRespData = wpabuf_dup(sm->lastRespData);
1018 else
1019 sm->eapRespData = NULL;
1020}
1021
1022
1023/*
1024 * This state is entered in case of a successful completion of authentication
1025 * and state machine waits here until port is disabled or EAP authentication is
1026 * restarted.
1027 */
1028SM_STATE(EAP, SUCCESS)
1029{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001030 struct eap_peer_config *config = eap_get_config(sm);
1031
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001032 SM_ENTRY(EAP, SUCCESS);
1033 if (sm->eapKeyData != NULL)
1034 sm->eapKeyAvailable = TRUE;
1035 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
1036
1037 /*
1038 * RFC 4137 does not clear eapReq here, but this seems to be required
1039 * to avoid processing the same request twice when state machine is
1040 * initialized.
1041 */
1042 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
1043
1044 /*
1045 * RFC 4137 does not set eapNoResp here, but this seems to be required
1046 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
1047 * addition, either eapResp or eapNoResp is required to be set after
1048 * processing the received EAP frame.
1049 */
1050 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
1051
1052 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1053 "EAP authentication completed successfully");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001054
1055 if (config->erp && sm->m->get_emsk && sm->eapSessionId &&
1056 sm->m->isKeyAvailable &&
1057 sm->m->isKeyAvailable(sm, sm->eap_method_priv))
1058 eap_peer_erp_init(sm, NULL, 0, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001059}
1060
1061
1062/*
1063 * This state is entered in case of a failure and state machine waits here
1064 * until port is disabled or EAP authentication is restarted.
1065 */
1066SM_STATE(EAP, FAILURE)
1067{
1068 SM_ENTRY(EAP, FAILURE);
1069 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
1070
1071 /*
1072 * RFC 4137 does not clear eapReq here, but this seems to be required
1073 * to avoid processing the same request twice when state machine is
1074 * initialized.
1075 */
1076 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
1077
1078 /*
1079 * RFC 4137 does not set eapNoResp here. However, either eapResp or
1080 * eapNoResp is required to be set after processing the received EAP
1081 * frame.
1082 */
1083 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
1084
1085 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
1086 "EAP authentication failed");
1087
1088 sm->prev_failure = 1;
1089}
1090
1091
1092static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
1093{
1094 /*
1095 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
1096 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
1097 * RFC 4137 require that reqId == lastId. In addition, it looks like
1098 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
1099 *
1100 * Accept this kind of Id if EAP workarounds are enabled. These are
1101 * unauthenticated plaintext messages, so this should have minimal
1102 * security implications (bit easier to fake EAP-Success/Failure).
1103 */
1104 if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
1105 reqId == ((lastId + 2) & 0xff))) {
1106 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
1107 "identifier field in EAP Success: "
1108 "reqId=%d lastId=%d (these are supposed to be "
1109 "same)", reqId, lastId);
1110 return 1;
1111 }
1112 wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
1113 "lastId=%d", reqId, lastId);
1114 return 0;
1115}
1116
1117
1118/*
1119 * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
1120 */
1121
1122static void eap_peer_sm_step_idle(struct eap_sm *sm)
1123{
1124 /*
1125 * The first three transitions are from RFC 4137. The last two are
1126 * local additions to handle special cases with LEAP and PEAP server
1127 * not sending EAP-Success in some cases.
1128 */
1129 if (eapol_get_bool(sm, EAPOL_eapReq))
1130 SM_ENTER(EAP, RECEIVED);
1131 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
1132 sm->decision != DECISION_FAIL) ||
1133 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
1134 sm->decision == DECISION_UNCOND_SUCC))
1135 SM_ENTER(EAP, SUCCESS);
1136 else if (eapol_get_bool(sm, EAPOL_altReject) ||
1137 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
1138 sm->decision != DECISION_UNCOND_SUCC) ||
1139 (eapol_get_bool(sm, EAPOL_altAccept) &&
1140 sm->methodState != METHOD_CONT &&
1141 sm->decision == DECISION_FAIL))
1142 SM_ENTER(EAP, FAILURE);
1143 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
1144 sm->leap_done && sm->decision != DECISION_FAIL &&
1145 sm->methodState == METHOD_DONE)
1146 SM_ENTER(EAP, SUCCESS);
1147 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
1148 sm->peap_done && sm->decision != DECISION_FAIL &&
1149 sm->methodState == METHOD_DONE)
1150 SM_ENTER(EAP, SUCCESS);
1151}
1152
1153
1154static int eap_peer_req_is_duplicate(struct eap_sm *sm)
1155{
1156 int duplicate;
1157
1158 duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
1159 if (sm->workaround && duplicate &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001160 os_memcmp(sm->req_sha1, sm->last_sha1, 20) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001161 /*
1162 * RFC 4137 uses (reqId == lastId) as the only verification for
1163 * duplicate EAP requests. However, this misses cases where the
1164 * AS is incorrectly using the same id again; and
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001165 * unfortunately, such implementations exist. Use SHA1 hash as
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001166 * an extra verification for the packets being duplicate to
1167 * workaround these issues.
1168 */
1169 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
1170 "EAP packets were not identical");
1171 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
1172 "duplicate packet");
1173 duplicate = 0;
1174 }
1175
1176 return duplicate;
1177}
1178
1179
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001180static int eap_peer_sm_allow_canned(struct eap_sm *sm)
1181{
1182 struct eap_peer_config *config = eap_get_config(sm);
1183
1184 return config && config->phase1 &&
1185 os_strstr(config->phase1, "allow_canned_success=1");
1186}
1187
1188
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001189static void eap_peer_sm_step_received(struct eap_sm *sm)
1190{
1191 int duplicate = eap_peer_req_is_duplicate(sm);
1192
1193 /*
1194 * Two special cases below for LEAP are local additions to work around
1195 * odd LEAP behavior (EAP-Success in the middle of authentication and
1196 * then swapped roles). Other transitions are based on RFC 4137.
1197 */
1198 if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
1199 (sm->reqId == sm->lastId ||
1200 eap_success_workaround(sm, sm->reqId, sm->lastId)))
1201 SM_ENTER(EAP, SUCCESS);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001202 else if (sm->workaround && sm->lastId == -1 && sm->rxSuccess &&
1203 !sm->rxFailure && !sm->rxReq && eap_peer_sm_allow_canned(sm))
1204 SM_ENTER(EAP, SUCCESS); /* EAP-Success prior any EAP method */
1205 else if (sm->workaround && sm->lastId == -1 && sm->rxFailure &&
1206 !sm->rxReq && sm->methodState != METHOD_CONT &&
1207 eap_peer_sm_allow_canned(sm))
1208 SM_ENTER(EAP, FAILURE); /* EAP-Failure prior any EAP method */
1209 else if (sm->workaround && sm->rxSuccess && !sm->rxFailure &&
1210 !sm->rxReq && sm->methodState != METHOD_CONT &&
1211 eap_peer_sm_allow_canned(sm))
1212 SM_ENTER(EAP, SUCCESS); /* EAP-Success after Identity */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213 else if (sm->methodState != METHOD_CONT &&
1214 ((sm->rxFailure &&
1215 sm->decision != DECISION_UNCOND_SUCC) ||
1216 (sm->rxSuccess && sm->decision == DECISION_FAIL &&
1217 (sm->selectedMethod != EAP_TYPE_LEAP ||
1218 sm->methodState != METHOD_MAY_CONT))) &&
1219 (sm->reqId == sm->lastId ||
1220 eap_success_workaround(sm, sm->reqId, sm->lastId)))
1221 SM_ENTER(EAP, FAILURE);
1222 else if (sm->rxReq && duplicate)
1223 SM_ENTER(EAP, RETRANSMIT);
1224 else if (sm->rxReq && !duplicate &&
1225 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
1226 sm->allowNotifications)
1227 SM_ENTER(EAP, NOTIFICATION);
1228 else if (sm->rxReq && !duplicate &&
1229 sm->selectedMethod == EAP_TYPE_NONE &&
1230 sm->reqMethod == EAP_TYPE_IDENTITY)
1231 SM_ENTER(EAP, IDENTITY);
1232 else if (sm->rxReq && !duplicate &&
1233 sm->selectedMethod == EAP_TYPE_NONE &&
1234 sm->reqMethod != EAP_TYPE_IDENTITY &&
1235 sm->reqMethod != EAP_TYPE_NOTIFICATION)
1236 SM_ENTER(EAP, GET_METHOD);
1237 else if (sm->rxReq && !duplicate &&
1238 sm->reqMethod == sm->selectedMethod &&
1239 sm->methodState != METHOD_DONE)
1240 SM_ENTER(EAP, METHOD);
1241 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
1242 (sm->rxSuccess || sm->rxResp))
1243 SM_ENTER(EAP, METHOD);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001244 else if (sm->reauthInit)
1245 SM_ENTER(EAP, SEND_RESPONSE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001246 else
1247 SM_ENTER(EAP, DISCARD);
1248}
1249
1250
1251static void eap_peer_sm_step_local(struct eap_sm *sm)
1252{
1253 switch (sm->EAP_state) {
1254 case EAP_INITIALIZE:
1255 SM_ENTER(EAP, IDLE);
1256 break;
1257 case EAP_DISABLED:
1258 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
1259 !sm->force_disabled)
1260 SM_ENTER(EAP, INITIALIZE);
1261 break;
1262 case EAP_IDLE:
1263 eap_peer_sm_step_idle(sm);
1264 break;
1265 case EAP_RECEIVED:
1266 eap_peer_sm_step_received(sm);
1267 break;
1268 case EAP_GET_METHOD:
1269 if (sm->selectedMethod == sm->reqMethod)
1270 SM_ENTER(EAP, METHOD);
1271 else
1272 SM_ENTER(EAP, SEND_RESPONSE);
1273 break;
1274 case EAP_METHOD:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001275 /*
1276 * Note: RFC 4137 uses methodState == DONE && decision == FAIL
1277 * as the condition. eapRespData == NULL here is used to allow
1278 * final EAP method response to be sent without having to change
1279 * all methods to either use methodState MAY_CONT or leaving
1280 * decision to something else than FAIL in cases where the only
1281 * expected response is EAP-Failure.
1282 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001283 if (sm->ignore)
1284 SM_ENTER(EAP, DISCARD);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001285 else if (sm->methodState == METHOD_DONE &&
1286 sm->decision == DECISION_FAIL && !sm->eapRespData)
1287 SM_ENTER(EAP, FAILURE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288 else
1289 SM_ENTER(EAP, SEND_RESPONSE);
1290 break;
1291 case EAP_SEND_RESPONSE:
1292 SM_ENTER(EAP, IDLE);
1293 break;
1294 case EAP_DISCARD:
1295 SM_ENTER(EAP, IDLE);
1296 break;
1297 case EAP_IDENTITY:
1298 SM_ENTER(EAP, SEND_RESPONSE);
1299 break;
1300 case EAP_NOTIFICATION:
1301 SM_ENTER(EAP, SEND_RESPONSE);
1302 break;
1303 case EAP_RETRANSMIT:
1304 SM_ENTER(EAP, SEND_RESPONSE);
1305 break;
1306 case EAP_SUCCESS:
1307 break;
1308 case EAP_FAILURE:
1309 break;
1310 }
1311}
1312
1313
1314SM_STEP(EAP)
1315{
1316 /* Global transitions */
1317 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
1318 eapol_get_bool(sm, EAPOL_portEnabled))
1319 SM_ENTER_GLOBAL(EAP, INITIALIZE);
1320 else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
1321 SM_ENTER_GLOBAL(EAP, DISABLED);
1322 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
1323 /* RFC 4137 does not place any limit on number of EAP messages
1324 * in an authentication session. However, some error cases have
1325 * ended up in a state were EAP messages were sent between the
1326 * peer and server in a loop (e.g., TLS ACK frame in both
1327 * direction). Since this is quite undesired outcome, limit the
1328 * total number of EAP round-trips and abort authentication if
1329 * this limit is exceeded.
1330 */
1331 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
1332 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
1333 "authentication rounds - abort",
1334 EAP_MAX_AUTH_ROUNDS);
1335 sm->num_rounds++;
1336 SM_ENTER_GLOBAL(EAP, FAILURE);
1337 }
1338 } else {
1339 /* Local transitions */
1340 eap_peer_sm_step_local(sm);
1341 }
1342}
1343
1344
1345static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
1346 EapType method)
1347{
1348 if (!eap_allowed_method(sm, vendor, method)) {
1349 wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
1350 "vendor %u method %u", vendor, method);
1351 return FALSE;
1352 }
1353 if (eap_peer_get_eap_method(vendor, method))
1354 return TRUE;
1355 wpa_printf(MSG_DEBUG, "EAP: not included in build: "
1356 "vendor %u method %u", vendor, method);
1357 return FALSE;
1358}
1359
1360
1361static struct wpabuf * eap_sm_build_expanded_nak(
1362 struct eap_sm *sm, int id, const struct eap_method *methods,
1363 size_t count)
1364{
1365 struct wpabuf *resp;
1366 int found = 0;
1367 const struct eap_method *m;
1368
1369 wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
1370
1371 /* RFC 3748 - 5.3.2: Expanded Nak */
1372 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
1373 8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
1374 if (resp == NULL)
1375 return NULL;
1376
1377 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
1378 wpabuf_put_be32(resp, EAP_TYPE_NAK);
1379
1380 for (m = methods; m; m = m->next) {
1381 if (sm->reqVendor == m->vendor &&
1382 sm->reqVendorMethod == m->method)
1383 continue; /* do not allow the current method again */
1384 if (eap_allowed_method(sm, m->vendor, m->method)) {
1385 wpa_printf(MSG_DEBUG, "EAP: allowed type: "
1386 "vendor=%u method=%u",
1387 m->vendor, m->method);
1388 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1389 wpabuf_put_be24(resp, m->vendor);
1390 wpabuf_put_be32(resp, m->method);
1391
1392 found++;
1393 }
1394 }
1395 if (!found) {
1396 wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
1397 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1398 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
1399 wpabuf_put_be32(resp, EAP_TYPE_NONE);
1400 }
1401
1402 eap_update_len(resp);
1403
1404 return resp;
1405}
1406
1407
1408static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
1409{
1410 struct wpabuf *resp;
1411 u8 *start;
1412 int found = 0, expanded_found = 0;
1413 size_t count;
1414 const struct eap_method *methods, *m;
1415
1416 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
1417 "vendor=%u method=%u not allowed)", sm->reqMethod,
1418 sm->reqVendor, sm->reqVendorMethod);
1419 methods = eap_peer_get_methods(&count);
1420 if (methods == NULL)
1421 return NULL;
1422 if (sm->reqMethod == EAP_TYPE_EXPANDED)
1423 return eap_sm_build_expanded_nak(sm, id, methods, count);
1424
1425 /* RFC 3748 - 5.3.1: Legacy Nak */
1426 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
1427 sizeof(struct eap_hdr) + 1 + count + 1,
1428 EAP_CODE_RESPONSE, id);
1429 if (resp == NULL)
1430 return NULL;
1431
1432 start = wpabuf_put(resp, 0);
1433 for (m = methods; m; m = m->next) {
1434 if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
1435 continue; /* do not allow the current method again */
1436 if (eap_allowed_method(sm, m->vendor, m->method)) {
1437 if (m->vendor != EAP_VENDOR_IETF) {
1438 if (expanded_found)
1439 continue;
1440 expanded_found = 1;
1441 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1442 } else
1443 wpabuf_put_u8(resp, m->method);
1444 found++;
1445 }
1446 }
1447 if (!found)
1448 wpabuf_put_u8(resp, EAP_TYPE_NONE);
1449 wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
1450
1451 eap_update_len(resp);
1452
1453 return resp;
1454}
1455
1456
1457static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
1458{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001459 const u8 *pos;
1460 size_t msg_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001461
1462 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
1463 "EAP authentication started");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001464 eap_notify_status(sm, "started", "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001465
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001466 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
1467 &msg_len);
1468 if (pos == NULL)
1469 return;
1470
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001471 /*
1472 * RFC 3748 - 5.1: Identity
1473 * Data field may contain a displayable message in UTF-8. If this
1474 * includes NUL-character, only the data before that should be
1475 * displayed. Some EAP implementasitons may piggy-back additional
1476 * options after the NUL.
1477 */
1478 /* TODO: could save displayable message so that it can be shown to the
1479 * user in case of interaction is required */
1480 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001481 pos, msg_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001482}
1483
1484
1485#ifdef PCSC_FUNCS
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001486
1487/*
1488 * Rules for figuring out MNC length based on IMSI for SIM cards that do not
1489 * include MNC length field.
1490 */
1491static int mnc_len_from_imsi(const char *imsi)
1492{
1493 char mcc_str[4];
1494 unsigned int mcc;
1495
1496 os_memcpy(mcc_str, imsi, 3);
1497 mcc_str[3] = '\0';
1498 mcc = atoi(mcc_str);
1499
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001500 if (mcc == 228)
1501 return 2; /* Networks in Switzerland use 2-digit MNC */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001502 if (mcc == 244)
1503 return 2; /* Networks in Finland use 2-digit MNC */
1504
1505 return -1;
1506}
1507
1508
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001509static int eap_sm_imsi_identity(struct eap_sm *sm,
1510 struct eap_peer_config *conf)
1511{
Dmitry Shmidt04949592012-07-19 12:16:46 -07001512 enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001513 char imsi[100];
1514 size_t imsi_len;
1515 struct eap_method_type *m = conf->eap_methods;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001516 int i, mnc_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001517
1518 imsi_len = sizeof(imsi);
1519 if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
1520 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
1521 return -1;
1522 }
1523
1524 wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
1525
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001526 if (imsi_len < 7) {
1527 wpa_printf(MSG_WARNING, "Too short IMSI for SIM identity");
1528 return -1;
1529 }
1530
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001531 /* MNC (2 or 3 digits) */
1532 mnc_len = scard_get_mnc_len(sm->scard_ctx);
1533 if (mnc_len < 0)
1534 mnc_len = mnc_len_from_imsi(imsi);
1535 if (mnc_len < 0) {
1536 wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
1537 "assuming 3");
1538 mnc_len = 3;
1539 }
1540
1541 if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
1542 mnc_len) < 0) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001543 wpa_printf(MSG_WARNING, "Could not add realm to SIM identity");
1544 return -1;
1545 }
1546 wpa_hexdump_ascii(MSG_DEBUG, "IMSI + realm", (u8 *) imsi, imsi_len);
1547
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001548 for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
1549 m[i].method != EAP_TYPE_NONE); i++) {
1550 if (m[i].vendor == EAP_VENDOR_IETF &&
Dmitry Shmidt04949592012-07-19 12:16:46 -07001551 m[i].method == EAP_TYPE_AKA_PRIME) {
1552 method = EAP_SM_AKA_PRIME;
1553 break;
1554 }
1555
1556 if (m[i].vendor == EAP_VENDOR_IETF &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001557 m[i].method == EAP_TYPE_AKA) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001558 method = EAP_SM_AKA;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001559 break;
1560 }
1561 }
1562
1563 os_free(conf->identity);
1564 conf->identity = os_malloc(1 + imsi_len);
1565 if (conf->identity == NULL) {
1566 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
1567 "IMSI-based identity");
1568 return -1;
1569 }
1570
Dmitry Shmidt04949592012-07-19 12:16:46 -07001571 switch (method) {
1572 case EAP_SM_SIM:
1573 conf->identity[0] = '1';
1574 break;
1575 case EAP_SM_AKA:
1576 conf->identity[0] = '0';
1577 break;
1578 case EAP_SM_AKA_PRIME:
1579 conf->identity[0] = '6';
1580 break;
1581 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001582 os_memcpy(conf->identity + 1, imsi, imsi_len);
1583 conf->identity_len = 1 + imsi_len;
1584
1585 return 0;
1586}
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001587
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001588
1589static int eap_sm_set_scard_pin(struct eap_sm *sm,
1590 struct eap_peer_config *conf)
1591{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001592 if (scard_set_pin(sm->scard_ctx, conf->pin)) {
1593 /*
1594 * Make sure the same PIN is not tried again in order to avoid
1595 * blocking SIM.
1596 */
1597 os_free(conf->pin);
1598 conf->pin = NULL;
1599
1600 wpa_printf(MSG_WARNING, "PIN validation failed");
1601 eap_sm_request_pin(sm);
1602 return -1;
1603 }
1604 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001605}
1606
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001607
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001608static int eap_sm_get_scard_identity(struct eap_sm *sm,
1609 struct eap_peer_config *conf)
1610{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001611 if (eap_sm_set_scard_pin(sm, conf))
1612 return -1;
1613
1614 return eap_sm_imsi_identity(sm, conf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001615}
1616
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001617#endif /* PCSC_FUNCS */
1618
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001619
1620/**
1621 * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
1622 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1623 * @id: EAP identifier for the packet
1624 * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
1625 * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
1626 * failure
1627 *
1628 * This function allocates and builds an EAP-Identity/Response packet for the
1629 * current network. The caller is responsible for freeing the returned data.
1630 */
1631struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
1632{
1633 struct eap_peer_config *config = eap_get_config(sm);
1634 struct wpabuf *resp;
1635 const u8 *identity;
1636 size_t identity_len;
1637
1638 if (config == NULL) {
1639 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
1640 "was not available");
1641 return NULL;
1642 }
1643
1644 if (sm->m && sm->m->get_identity &&
1645 (identity = sm->m->get_identity(sm, sm->eap_method_priv,
1646 &identity_len)) != NULL) {
1647 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
1648 "identity", identity, identity_len);
1649 } else if (!encrypted && config->anonymous_identity) {
1650 identity = config->anonymous_identity;
1651 identity_len = config->anonymous_identity_len;
1652 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
1653 identity, identity_len);
1654 } else {
1655 identity = config->identity;
1656 identity_len = config->identity_len;
1657 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
1658 identity, identity_len);
1659 }
1660
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001661 if (config->pcsc) {
1662#ifdef PCSC_FUNCS
1663 if (!identity) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001664 if (eap_sm_get_scard_identity(sm, config) < 0)
1665 return NULL;
1666 identity = config->identity;
1667 identity_len = config->identity_len;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001668 wpa_hexdump_ascii(MSG_DEBUG,
1669 "permanent identity from IMSI",
1670 identity, identity_len);
1671 } else if (eap_sm_set_scard_pin(sm, config) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001672 return NULL;
1673 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001674#else /* PCSC_FUNCS */
1675 return NULL;
1676#endif /* PCSC_FUNCS */
1677 } else if (!identity) {
1678 wpa_printf(MSG_WARNING,
1679 "EAP: buildIdentity: identity configuration was not available");
1680 eap_sm_request_identity(sm);
1681 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001682 }
1683
1684 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
1685 EAP_CODE_RESPONSE, id);
1686 if (resp == NULL)
1687 return NULL;
1688
1689 wpabuf_put_data(resp, identity, identity_len);
1690
1691 return resp;
1692}
1693
1694
1695static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
1696{
1697 const u8 *pos;
1698 char *msg;
1699 size_t i, msg_len;
1700
1701 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
1702 &msg_len);
1703 if (pos == NULL)
1704 return;
1705 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
1706 pos, msg_len);
1707
1708 msg = os_malloc(msg_len + 1);
1709 if (msg == NULL)
1710 return;
1711 for (i = 0; i < msg_len; i++)
1712 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
1713 msg[msg_len] = '\0';
1714 wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
1715 WPA_EVENT_EAP_NOTIFICATION, msg);
1716 os_free(msg);
1717}
1718
1719
1720static struct wpabuf * eap_sm_buildNotify(int id)
1721{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001722 wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001723 return eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
1724 EAP_CODE_RESPONSE, id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001725}
1726
1727
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001728static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
1729 size_t len)
1730{
1731#ifdef CONFIG_ERP
1732 const u8 *pos = (const u8 *) (hdr + 1);
1733 const u8 *end = ((const u8 *) hdr) + len;
1734 struct erp_tlvs parse;
1735
1736 if (len < sizeof(*hdr) + 1) {
1737 wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Initiate");
1738 return;
1739 }
1740
1741 if (*pos != EAP_ERP_TYPE_REAUTH_START) {
1742 wpa_printf(MSG_DEBUG,
1743 "EAP: Ignored unexpected EAP-Initiate Type=%u",
1744 *pos);
1745 return;
1746 }
1747
1748 pos++;
1749 if (pos >= end) {
1750 wpa_printf(MSG_DEBUG,
1751 "EAP: Too short EAP-Initiate/Re-auth-Start");
1752 return;
1753 }
1754 pos++; /* Reserved */
1755 wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth-Start TVs/TLVs",
1756 pos, end - pos);
1757
1758 if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
1759 goto invalid;
1760
1761 if (parse.domain) {
1762 wpa_hexdump_ascii(MSG_DEBUG,
1763 "EAP: EAP-Initiate/Re-auth-Start - Domain name",
1764 parse.domain, parse.domain_len);
1765 /* TODO: Derivation of domain specific keys for local ER */
1766 }
1767
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001768 if (eap_peer_erp_reauth_start(sm, hdr->identifier) == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001769 return;
1770
1771invalid:
1772#endif /* CONFIG_ERP */
1773 wpa_printf(MSG_DEBUG,
1774 "EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
1775 eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
1776}
1777
1778
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001779void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001780{
1781#ifdef CONFIG_ERP
1782 const u8 *pos = (const u8 *) (hdr + 1);
1783 const u8 *end = ((const u8 *) hdr) + len;
1784 const u8 *start;
1785 struct erp_tlvs parse;
1786 u8 flags;
1787 u16 seq;
1788 u8 hash[SHA256_MAC_LEN];
1789 size_t hash_len;
1790 struct eap_erp_key *erp;
1791 int max_len;
1792 char nai[254];
1793 u8 seed[4];
1794 int auth_tag_ok = 0;
1795
1796 if (len < sizeof(*hdr) + 1) {
1797 wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Finish");
1798 return;
1799 }
1800
1801 if (*pos != EAP_ERP_TYPE_REAUTH) {
1802 wpa_printf(MSG_DEBUG,
1803 "EAP: Ignored unexpected EAP-Finish Type=%u", *pos);
1804 return;
1805 }
1806
1807 if (len < sizeof(*hdr) + 4) {
1808 wpa_printf(MSG_DEBUG,
1809 "EAP: Ignored too short EAP-Finish/Re-auth");
1810 return;
1811 }
1812
1813 pos++;
1814 flags = *pos++;
1815 seq = WPA_GET_BE16(pos);
1816 pos += 2;
1817 wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
1818
1819 if (seq != sm->erp_seq) {
1820 wpa_printf(MSG_DEBUG,
1821 "EAP: Unexpected EAP-Finish/Re-auth SEQ=%u", seq);
1822 return;
1823 }
1824
1825 /*
1826 * Parse TVs/TLVs. Since we do not yet know the length of the
1827 * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
1828 * just try to find the keyName-NAI first so that we can check the
1829 * Authentication Tag.
1830 */
1831 if (erp_parse_tlvs(pos, end, &parse, 1) < 0)
1832 return;
1833
1834 if (!parse.keyname) {
1835 wpa_printf(MSG_DEBUG,
1836 "EAP: No keyName-NAI in EAP-Finish/Re-auth Packet");
1837 return;
1838 }
1839
1840 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Finish/Re-auth - keyName-NAI",
1841 parse.keyname, parse.keyname_len);
1842 if (parse.keyname_len > 253) {
1843 wpa_printf(MSG_DEBUG,
1844 "EAP: Too long keyName-NAI in EAP-Finish/Re-auth");
1845 return;
1846 }
1847 os_memcpy(nai, parse.keyname, parse.keyname_len);
1848 nai[parse.keyname_len] = '\0';
1849
1850 erp = eap_erp_get_key_nai(sm, nai);
1851 if (!erp) {
1852 wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
1853 nai);
1854 return;
1855 }
1856
1857 /* Is there enough room for Cryptosuite and Authentication Tag? */
1858 start = parse.keyname + parse.keyname_len;
1859 max_len = end - start;
1860 hash_len = 16;
1861 if (max_len < 1 + (int) hash_len) {
1862 wpa_printf(MSG_DEBUG,
1863 "EAP: Not enough room for Authentication Tag");
1864 if (flags & 0x80)
1865 goto no_auth_tag;
1866 return;
1867 }
1868 if (end[-17] != EAP_ERP_CS_HMAC_SHA256_128) {
1869 wpa_printf(MSG_DEBUG, "EAP: Different Cryptosuite used");
1870 if (flags & 0x80)
1871 goto no_auth_tag;
1872 return;
1873 }
1874
1875 if (hmac_sha256(erp->rIK, erp->rIK_len, (const u8 *) hdr,
1876 end - ((const u8 *) hdr) - hash_len, hash) < 0)
1877 return;
1878 if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
1879 wpa_printf(MSG_DEBUG,
1880 "EAP: Authentication Tag mismatch");
1881 return;
1882 }
1883 auth_tag_ok = 1;
1884 end -= 1 + hash_len;
1885
1886no_auth_tag:
1887 /*
1888 * Parse TVs/TLVs again now that we know the exact part of the buffer
1889 * that contains them.
1890 */
1891 wpa_hexdump(MSG_DEBUG, "EAP: EAP-Finish/Re-Auth TVs/TLVs",
1892 pos, end - pos);
1893 if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
1894 return;
1895
1896 if (flags & 0x80 || !auth_tag_ok) {
1897 wpa_printf(MSG_DEBUG,
1898 "EAP: EAP-Finish/Re-auth indicated failure");
1899 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
1900 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
1901 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
1902 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
1903 "EAP authentication failed");
1904 sm->prev_failure = 1;
1905 wpa_printf(MSG_DEBUG,
1906 "EAP: Drop ERP key to try full authentication on next attempt");
1907 eap_peer_erp_free_key(erp);
1908 return;
1909 }
1910
1911 eap_sm_free_key(sm);
1912 sm->eapKeyDataLen = 0;
1913 sm->eapKeyData = os_malloc(erp->rRK_len);
1914 if (!sm->eapKeyData)
1915 return;
1916 sm->eapKeyDataLen = erp->rRK_len;
1917
1918 WPA_PUT_BE16(seed, seq);
1919 WPA_PUT_BE16(&seed[2], erp->rRK_len);
1920 if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
1921 "Re-authentication Master Session Key@ietf.org",
1922 seed, sizeof(seed),
1923 sm->eapKeyData, erp->rRK_len) < 0) {
1924 wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
1925 eap_sm_free_key(sm);
1926 return;
1927 }
1928 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
1929 sm->eapKeyData, sm->eapKeyDataLen);
1930 sm->eapKeyAvailable = TRUE;
1931 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
1932 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
1933 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
1934 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1935 "EAP re-authentication completed successfully");
1936#endif /* CONFIG_ERP */
1937}
1938
1939
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001940static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
1941{
1942 const struct eap_hdr *hdr;
1943 size_t plen;
1944 const u8 *pos;
1945
1946 sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
1947 sm->reqId = 0;
1948 sm->reqMethod = EAP_TYPE_NONE;
1949 sm->reqVendor = EAP_VENDOR_IETF;
1950 sm->reqVendorMethod = EAP_TYPE_NONE;
1951
1952 if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
1953 return;
1954
1955 hdr = wpabuf_head(req);
1956 plen = be_to_host16(hdr->length);
1957 if (plen > wpabuf_len(req)) {
1958 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
1959 "(len=%lu plen=%lu)",
1960 (unsigned long) wpabuf_len(req),
1961 (unsigned long) plen);
1962 return;
1963 }
1964
1965 sm->reqId = hdr->identifier;
1966
1967 if (sm->workaround) {
1968 const u8 *addr[1];
1969 addr[0] = wpabuf_head(req);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001970 sha1_vector(1, addr, &plen, sm->req_sha1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001971 }
1972
1973 switch (hdr->code) {
1974 case EAP_CODE_REQUEST:
1975 if (plen < sizeof(*hdr) + 1) {
1976 wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
1977 "no Type field");
1978 return;
1979 }
1980 sm->rxReq = TRUE;
1981 pos = (const u8 *) (hdr + 1);
1982 sm->reqMethod = *pos++;
1983 if (sm->reqMethod == EAP_TYPE_EXPANDED) {
1984 if (plen < sizeof(*hdr) + 8) {
1985 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
1986 "expanded EAP-Packet (plen=%lu)",
1987 (unsigned long) plen);
1988 return;
1989 }
1990 sm->reqVendor = WPA_GET_BE24(pos);
1991 pos += 3;
1992 sm->reqVendorMethod = WPA_GET_BE32(pos);
1993 }
1994 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
1995 "method=%u vendor=%u vendorMethod=%u",
1996 sm->reqId, sm->reqMethod, sm->reqVendor,
1997 sm->reqVendorMethod);
1998 break;
1999 case EAP_CODE_RESPONSE:
2000 if (sm->selectedMethod == EAP_TYPE_LEAP) {
2001 /*
2002 * LEAP differs from RFC 4137 by using reversed roles
2003 * for mutual authentication and because of this, we
2004 * need to accept EAP-Response frames if LEAP is used.
2005 */
2006 if (plen < sizeof(*hdr) + 1) {
2007 wpa_printf(MSG_DEBUG, "EAP: Too short "
2008 "EAP-Response - no Type field");
2009 return;
2010 }
2011 sm->rxResp = TRUE;
2012 pos = (const u8 *) (hdr + 1);
2013 sm->reqMethod = *pos;
2014 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
2015 "LEAP method=%d id=%d",
2016 sm->reqMethod, sm->reqId);
2017 break;
2018 }
2019 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
2020 break;
2021 case EAP_CODE_SUCCESS:
2022 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002023 eap_notify_status(sm, "completion", "success");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002024 sm->rxSuccess = TRUE;
2025 break;
2026 case EAP_CODE_FAILURE:
2027 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002028 eap_notify_status(sm, "completion", "failure");
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -07002029
2030 /* Get the error code from method */
Ahmed ElArabawyab9f5af2018-04-04 18:56:43 -07002031 if (sm->m && sm->m->get_error_code) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002032 int error_code;
2033
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -07002034 error_code = sm->m->get_error_code(sm->eap_method_priv);
2035 if (error_code != NO_EAP_METHOD_ERROR)
2036 eap_report_error(sm, error_code);
2037 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002038 sm->rxFailure = TRUE;
2039 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002040 case EAP_CODE_INITIATE:
2041 eap_peer_initiate(sm, hdr, plen);
2042 break;
2043 case EAP_CODE_FINISH:
2044 eap_peer_finish(sm, hdr, plen);
2045 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002046 default:
2047 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
2048 "code %d", hdr->code);
2049 break;
2050 }
2051}
2052
2053
2054static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
2055 union tls_event_data *data)
2056{
2057 struct eap_sm *sm = ctx;
2058 char *hash_hex = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002059
2060 switch (ev) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002061 case TLS_CERT_CHAIN_SUCCESS:
2062 eap_notify_status(sm, "remote certificate verification",
2063 "success");
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002064 if (sm->ext_cert_check) {
2065 sm->waiting_ext_cert_check = 1;
2066 eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
2067 NULL, 0);
2068 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002069 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002070 case TLS_CERT_CHAIN_FAILURE:
2071 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
2072 "reason=%d depth=%d subject='%s' err='%s'",
2073 data->cert_fail.reason,
2074 data->cert_fail.depth,
2075 data->cert_fail.subject,
2076 data->cert_fail.reason_txt);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002077 eap_notify_status(sm, "remote certificate verification",
2078 data->cert_fail.reason_txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002079 break;
2080 case TLS_PEER_CERTIFICATE:
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002081 if (!sm->eapol_cb->notify_cert)
2082 break;
2083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002084 if (data->peer_cert.hash) {
2085 size_t len = data->peer_cert.hash_len * 2 + 1;
2086 hash_hex = os_malloc(len);
2087 if (hash_hex) {
2088 wpa_snprintf_hex(hash_hex, len,
2089 data->peer_cert.hash,
2090 data->peer_cert.hash_len);
2091 }
2092 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002093
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002094 sm->eapol_cb->notify_cert(sm->eapol_ctx,
2095 data->peer_cert.depth,
2096 data->peer_cert.subject,
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08002097 data->peer_cert.altsubject,
2098 data->peer_cert.num_altsubject,
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002099 hash_hex, data->peer_cert.cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002100 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002101 case TLS_ALERT:
2102 if (data->alert.is_local)
2103 eap_notify_status(sm, "local TLS alert",
2104 data->alert.description);
2105 else
2106 eap_notify_status(sm, "remote TLS alert",
2107 data->alert.description);
2108 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002109 }
2110
2111 os_free(hash_hex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002112}
2113
2114
2115/**
2116 * eap_peer_sm_init - Allocate and initialize EAP peer state machine
2117 * @eapol_ctx: Context data to be used with eapol_cb calls
2118 * @eapol_cb: Pointer to EAPOL callback functions
2119 * @msg_ctx: Context data for wpa_msg() calls
2120 * @conf: EAP configuration
2121 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
2122 *
2123 * This function allocates and initializes an EAP state machine. In addition,
2124 * this initializes TLS library for the new EAP state machine. eapol_cb pointer
2125 * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
2126 * state machine. Consequently, the caller must make sure that this data
2127 * structure remains alive while the EAP state machine is active.
2128 */
2129struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07002130 const struct eapol_callbacks *eapol_cb,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002131 void *msg_ctx, struct eap_config *conf)
2132{
2133 struct eap_sm *sm;
2134 struct tls_config tlsconf;
2135
2136 sm = os_zalloc(sizeof(*sm));
2137 if (sm == NULL)
2138 return NULL;
2139 sm->eapol_ctx = eapol_ctx;
2140 sm->eapol_cb = eapol_cb;
2141 sm->msg_ctx = msg_ctx;
2142 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
2143 sm->wps = conf->wps;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002144 dl_list_init(&sm->erp_keys);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002145
2146 os_memset(&tlsconf, 0, sizeof(tlsconf));
2147 tlsconf.opensc_engine_path = conf->opensc_engine_path;
2148 tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
2149 tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002150 tlsconf.openssl_ciphers = conf->openssl_ciphers;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002151#ifdef CONFIG_FIPS
2152 tlsconf.fips_mode = 1;
2153#endif /* CONFIG_FIPS */
2154 tlsconf.event_cb = eap_peer_sm_tls_event;
2155 tlsconf.cb_ctx = sm;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002156 tlsconf.cert_in_cb = conf->cert_in_cb;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002157 sm->ssl_ctx = tls_init(&tlsconf);
2158 if (sm->ssl_ctx == NULL) {
2159 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
2160 "context.");
2161 os_free(sm);
2162 return NULL;
2163 }
2164
Dmitry Shmidt04949592012-07-19 12:16:46 -07002165 sm->ssl_ctx2 = tls_init(&tlsconf);
2166 if (sm->ssl_ctx2 == NULL) {
2167 wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
2168 "context (2).");
2169 /* Run without separate TLS context within TLS tunnel */
2170 }
2171
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002172 return sm;
2173}
2174
2175
2176/**
2177 * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
2178 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2179 *
2180 * This function deinitializes EAP state machine and frees all allocated
2181 * resources.
2182 */
2183void eap_peer_sm_deinit(struct eap_sm *sm)
2184{
2185 if (sm == NULL)
2186 return;
2187 eap_deinit_prev_method(sm, "EAP deinit");
2188 eap_sm_abort(sm);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002189 if (sm->ssl_ctx2)
2190 tls_deinit(sm->ssl_ctx2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002191 tls_deinit(sm->ssl_ctx);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002192 eap_peer_erp_free_keys(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002193 os_free(sm);
2194}
2195
2196
2197/**
2198 * eap_peer_sm_step - Step EAP peer state machine
2199 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2200 * Returns: 1 if EAP state was changed or 0 if not
2201 *
2202 * This function advances EAP state machine to a new state to match with the
2203 * current variables. This should be called whenever variables used by the EAP
2204 * state machine have changed.
2205 */
2206int eap_peer_sm_step(struct eap_sm *sm)
2207{
2208 int res = 0;
2209 do {
2210 sm->changed = FALSE;
2211 SM_STEP_RUN(EAP);
2212 if (sm->changed)
2213 res = 1;
2214 } while (sm->changed);
2215 return res;
2216}
2217
2218
2219/**
2220 * eap_sm_abort - Abort EAP authentication
2221 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2222 *
2223 * Release system resources that have been allocated for the authentication
2224 * session without fully deinitializing the EAP state machine.
2225 */
2226void eap_sm_abort(struct eap_sm *sm)
2227{
2228 wpabuf_free(sm->lastRespData);
2229 sm->lastRespData = NULL;
2230 wpabuf_free(sm->eapRespData);
2231 sm->eapRespData = NULL;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002232 eap_sm_free_key(sm);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002233 os_free(sm->eapSessionId);
2234 sm->eapSessionId = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002235
2236 /* This is not clearly specified in the EAP statemachines draft, but
2237 * it seems necessary to make sure that some of the EAPOL variables get
2238 * cleared for the next authentication. */
2239 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
2240}
2241
2242
2243#ifdef CONFIG_CTRL_IFACE
2244static const char * eap_sm_state_txt(int state)
2245{
2246 switch (state) {
2247 case EAP_INITIALIZE:
2248 return "INITIALIZE";
2249 case EAP_DISABLED:
2250 return "DISABLED";
2251 case EAP_IDLE:
2252 return "IDLE";
2253 case EAP_RECEIVED:
2254 return "RECEIVED";
2255 case EAP_GET_METHOD:
2256 return "GET_METHOD";
2257 case EAP_METHOD:
2258 return "METHOD";
2259 case EAP_SEND_RESPONSE:
2260 return "SEND_RESPONSE";
2261 case EAP_DISCARD:
2262 return "DISCARD";
2263 case EAP_IDENTITY:
2264 return "IDENTITY";
2265 case EAP_NOTIFICATION:
2266 return "NOTIFICATION";
2267 case EAP_RETRANSMIT:
2268 return "RETRANSMIT";
2269 case EAP_SUCCESS:
2270 return "SUCCESS";
2271 case EAP_FAILURE:
2272 return "FAILURE";
2273 default:
2274 return "UNKNOWN";
2275 }
2276}
2277#endif /* CONFIG_CTRL_IFACE */
2278
2279
2280#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
2281static const char * eap_sm_method_state_txt(EapMethodState state)
2282{
2283 switch (state) {
2284 case METHOD_NONE:
2285 return "NONE";
2286 case METHOD_INIT:
2287 return "INIT";
2288 case METHOD_CONT:
2289 return "CONT";
2290 case METHOD_MAY_CONT:
2291 return "MAY_CONT";
2292 case METHOD_DONE:
2293 return "DONE";
2294 default:
2295 return "UNKNOWN";
2296 }
2297}
2298
2299
2300static const char * eap_sm_decision_txt(EapDecision decision)
2301{
2302 switch (decision) {
2303 case DECISION_FAIL:
2304 return "FAIL";
2305 case DECISION_COND_SUCC:
2306 return "COND_SUCC";
2307 case DECISION_UNCOND_SUCC:
2308 return "UNCOND_SUCC";
2309 default:
2310 return "UNKNOWN";
2311 }
2312}
2313#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
2314
2315
2316#ifdef CONFIG_CTRL_IFACE
2317
2318/**
2319 * eap_sm_get_status - Get EAP state machine status
2320 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2321 * @buf: Buffer for status information
2322 * @buflen: Maximum buffer length
2323 * @verbose: Whether to include verbose status information
2324 * Returns: Number of bytes written to buf.
2325 *
2326 * Query EAP state machine for status information. This function fills in a
2327 * text area with current status information from the EAPOL state machine. If
2328 * the buffer (buf) is not large enough, status information will be truncated
2329 * to fit the buffer.
2330 */
2331int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
2332{
2333 int len, ret;
2334
2335 if (sm == NULL)
2336 return 0;
2337
2338 len = os_snprintf(buf, buflen,
2339 "EAP state=%s\n",
2340 eap_sm_state_txt(sm->EAP_state));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002341 if (os_snprintf_error(buflen, len))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002342 return 0;
2343
2344 if (sm->selectedMethod != EAP_TYPE_NONE) {
2345 const char *name;
2346 if (sm->m) {
2347 name = sm->m->name;
2348 } else {
2349 const struct eap_method *m =
2350 eap_peer_get_eap_method(EAP_VENDOR_IETF,
2351 sm->selectedMethod);
2352 if (m)
2353 name = m->name;
2354 else
2355 name = "?";
2356 }
2357 ret = os_snprintf(buf + len, buflen - len,
2358 "selectedMethod=%d (EAP-%s)\n",
2359 sm->selectedMethod, name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002360 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002361 return len;
2362 len += ret;
2363
2364 if (sm->m && sm->m->get_status) {
2365 len += sm->m->get_status(sm, sm->eap_method_priv,
2366 buf + len, buflen - len,
2367 verbose);
2368 }
2369 }
2370
2371 if (verbose) {
2372 ret = os_snprintf(buf + len, buflen - len,
2373 "reqMethod=%d\n"
2374 "methodState=%s\n"
2375 "decision=%s\n"
2376 "ClientTimeout=%d\n",
2377 sm->reqMethod,
2378 eap_sm_method_state_txt(sm->methodState),
2379 eap_sm_decision_txt(sm->decision),
2380 sm->ClientTimeout);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002381 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002382 return len;
2383 len += ret;
2384 }
2385
2386 return len;
2387}
2388#endif /* CONFIG_CTRL_IFACE */
2389
2390
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002391static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002392 const char *msg, size_t msglen)
2393{
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002394#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002395 struct eap_peer_config *config;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002396 const char *txt = NULL;
2397 char *tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002398
2399 if (sm == NULL)
2400 return;
2401 config = eap_get_config(sm);
2402 if (config == NULL)
2403 return;
2404
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002405 switch (field) {
2406 case WPA_CTRL_REQ_EAP_IDENTITY:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002407 config->pending_req_identity++;
2408 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002409 case WPA_CTRL_REQ_EAP_PASSWORD:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002410 config->pending_req_password++;
2411 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002412 case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002413 config->pending_req_new_password++;
2414 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002415 case WPA_CTRL_REQ_EAP_PIN:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002416 config->pending_req_pin++;
2417 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002418 case WPA_CTRL_REQ_EAP_OTP:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002419 if (msg) {
2420 tmp = os_malloc(msglen + 3);
2421 if (tmp == NULL)
2422 return;
2423 tmp[0] = '[';
2424 os_memcpy(tmp + 1, msg, msglen);
2425 tmp[msglen + 1] = ']';
2426 tmp[msglen + 2] = '\0';
2427 txt = tmp;
2428 os_free(config->pending_req_otp);
2429 config->pending_req_otp = tmp;
2430 config->pending_req_otp_len = msglen + 3;
2431 } else {
2432 if (config->pending_req_otp == NULL)
2433 return;
2434 txt = config->pending_req_otp;
2435 }
2436 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002437 case WPA_CTRL_REQ_EAP_PASSPHRASE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002438 config->pending_req_passphrase++;
2439 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002440 case WPA_CTRL_REQ_SIM:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002441 config->pending_req_sim++;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002442 txt = msg;
2443 break;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002444 case WPA_CTRL_REQ_EXT_CERT_CHECK:
2445 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002446 default:
2447 return;
2448 }
2449
2450 if (sm->eapol_cb->eap_param_needed)
2451 sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002452#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002453}
2454
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002455
2456const char * eap_sm_get_method_name(struct eap_sm *sm)
2457{
2458 if (sm->m == NULL)
2459 return "UNKNOWN";
2460 return sm->m->name;
2461}
2462
2463
2464/**
2465 * eap_sm_request_identity - Request identity from user (ctrl_iface)
2466 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2467 *
2468 * EAP methods can call this function to request identity information for the
2469 * current network. This is normally called when the identity is not included
2470 * in the network configuration. The request will be sent to monitor programs
2471 * through the control interface.
2472 */
2473void eap_sm_request_identity(struct eap_sm *sm)
2474{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002475 eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002476}
2477
2478
2479/**
2480 * eap_sm_request_password - Request password from user (ctrl_iface)
2481 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2482 *
2483 * EAP methods can call this function to request password information for the
2484 * current network. This is normally called when the password is not included
2485 * in the network configuration. The request will be sent to monitor programs
2486 * through the control interface.
2487 */
2488void eap_sm_request_password(struct eap_sm *sm)
2489{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002490 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002491}
2492
2493
2494/**
2495 * eap_sm_request_new_password - Request new password from user (ctrl_iface)
2496 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2497 *
2498 * EAP methods can call this function to request new password information for
2499 * the current network. This is normally called when the EAP method indicates
2500 * that the current password has expired and password change is required. The
2501 * request will be sent to monitor programs through the control interface.
2502 */
2503void eap_sm_request_new_password(struct eap_sm *sm)
2504{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002505 eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002506}
2507
2508
2509/**
2510 * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
2511 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2512 *
2513 * EAP methods can call this function to request SIM or smart card PIN
2514 * information for the current network. This is normally called when the PIN is
2515 * not included in the network configuration. The request will be sent to
2516 * monitor programs through the control interface.
2517 */
2518void eap_sm_request_pin(struct eap_sm *sm)
2519{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002520 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002521}
2522
2523
2524/**
2525 * eap_sm_request_otp - Request one time password from user (ctrl_iface)
2526 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2527 * @msg: Message to be displayed to the user when asking for OTP
2528 * @msg_len: Length of the user displayable message
2529 *
2530 * EAP methods can call this function to request open time password (OTP) for
2531 * the current network. The request will be sent to monitor programs through
2532 * the control interface.
2533 */
2534void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
2535{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002536 eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002537}
2538
2539
2540/**
2541 * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
2542 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2543 *
2544 * EAP methods can call this function to request passphrase for a private key
2545 * for the current network. This is normally called when the passphrase is not
2546 * included in the network configuration. The request will be sent to monitor
2547 * programs through the control interface.
2548 */
2549void eap_sm_request_passphrase(struct eap_sm *sm)
2550{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002551 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002552}
2553
2554
2555/**
Dmitry Shmidt051af732013-10-22 13:52:46 -07002556 * eap_sm_request_sim - Request external SIM processing
2557 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2558 * @req: EAP method specific request
2559 */
2560void eap_sm_request_sim(struct eap_sm *sm, const char *req)
2561{
2562 eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req));
2563}
2564
2565
2566/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002567 * eap_sm_notify_ctrl_attached - Notification of attached monitor
2568 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2569 *
2570 * Notify EAP state machines that a monitor was attached to the control
2571 * interface to trigger re-sending of pending requests for user input.
2572 */
2573void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
2574{
2575 struct eap_peer_config *config = eap_get_config(sm);
2576
2577 if (config == NULL)
2578 return;
2579
2580 /* Re-send any pending requests for user data since a new control
2581 * interface was added. This handles cases where the EAP authentication
2582 * starts immediately after system startup when the user interface is
2583 * not yet running. */
2584 if (config->pending_req_identity)
2585 eap_sm_request_identity(sm);
2586 if (config->pending_req_password)
2587 eap_sm_request_password(sm);
2588 if (config->pending_req_new_password)
2589 eap_sm_request_new_password(sm);
2590 if (config->pending_req_otp)
2591 eap_sm_request_otp(sm, NULL, 0);
2592 if (config->pending_req_pin)
2593 eap_sm_request_pin(sm);
2594 if (config->pending_req_passphrase)
2595 eap_sm_request_passphrase(sm);
2596}
2597
2598
2599static int eap_allowed_phase2_type(int vendor, int type)
2600{
2601 if (vendor != EAP_VENDOR_IETF)
2602 return 0;
2603 return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
2604 type != EAP_TYPE_FAST;
2605}
2606
2607
2608/**
2609 * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
2610 * @name: EAP method name, e.g., MD5
2611 * @vendor: Buffer for returning EAP Vendor-Id
2612 * Returns: EAP method type or %EAP_TYPE_NONE if not found
2613 *
2614 * This function maps EAP type names into EAP type numbers that are allowed for
2615 * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
2616 * EAP-PEAP, EAP-TTLS, and EAP-FAST.
2617 */
2618u32 eap_get_phase2_type(const char *name, int *vendor)
2619{
2620 int v;
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07002621 u32 type = eap_peer_get_type(name, &v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002622 if (eap_allowed_phase2_type(v, type)) {
2623 *vendor = v;
2624 return type;
2625 }
2626 *vendor = EAP_VENDOR_IETF;
2627 return EAP_TYPE_NONE;
2628}
2629
2630
2631/**
2632 * eap_get_phase2_types - Get list of allowed EAP phase 2 types
2633 * @config: Pointer to a network configuration
2634 * @count: Pointer to a variable to be filled with number of returned EAP types
2635 * Returns: Pointer to allocated type list or %NULL on failure
2636 *
2637 * This function generates an array of allowed EAP phase 2 (tunneled) types for
2638 * the given network configuration.
2639 */
2640struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
2641 size_t *count)
2642{
2643 struct eap_method_type *buf;
2644 u32 method;
2645 int vendor;
2646 size_t mcount;
2647 const struct eap_method *methods, *m;
2648
2649 methods = eap_peer_get_methods(&mcount);
2650 if (methods == NULL)
2651 return NULL;
2652 *count = 0;
2653 buf = os_malloc(mcount * sizeof(struct eap_method_type));
2654 if (buf == NULL)
2655 return NULL;
2656
2657 for (m = methods; m; m = m->next) {
2658 vendor = m->vendor;
2659 method = m->method;
2660 if (eap_allowed_phase2_type(vendor, method)) {
2661 if (vendor == EAP_VENDOR_IETF &&
2662 method == EAP_TYPE_TLS && config &&
2663 config->private_key2 == NULL)
2664 continue;
2665 buf[*count].vendor = vendor;
2666 buf[*count].method = method;
2667 (*count)++;
2668 }
2669 }
2670
2671 return buf;
2672}
2673
2674
2675/**
2676 * eap_set_fast_reauth - Update fast_reauth setting
2677 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2678 * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
2679 */
2680void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
2681{
2682 sm->fast_reauth = enabled;
2683}
2684
2685
2686/**
2687 * eap_set_workaround - Update EAP workarounds setting
2688 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2689 * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
2690 */
2691void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
2692{
2693 sm->workaround = workaround;
2694}
2695
2696
2697/**
2698 * eap_get_config - Get current network configuration
2699 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2700 * Returns: Pointer to the current network configuration or %NULL if not found
2701 *
2702 * EAP peer methods should avoid using this function if they can use other
2703 * access functions, like eap_get_config_identity() and
2704 * eap_get_config_password(), that do not require direct access to
2705 * struct eap_peer_config.
2706 */
2707struct eap_peer_config * eap_get_config(struct eap_sm *sm)
2708{
2709 return sm->eapol_cb->get_config(sm->eapol_ctx);
2710}
2711
2712
2713/**
2714 * eap_get_config_identity - Get identity from the network configuration
2715 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2716 * @len: Buffer for the length of the identity
2717 * Returns: Pointer to the identity or %NULL if not found
2718 */
2719const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
2720{
2721 struct eap_peer_config *config = eap_get_config(sm);
2722 if (config == NULL)
2723 return NULL;
2724 *len = config->identity_len;
2725 return config->identity;
2726}
2727
2728
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002729static int eap_get_ext_password(struct eap_sm *sm,
2730 struct eap_peer_config *config)
2731{
2732 char *name;
2733
2734 if (config->password == NULL)
2735 return -1;
2736
2737 name = os_zalloc(config->password_len + 1);
2738 if (name == NULL)
2739 return -1;
2740 os_memcpy(name, config->password, config->password_len);
2741
2742 ext_password_free(sm->ext_pw_buf);
2743 sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
2744 os_free(name);
2745
2746 return sm->ext_pw_buf == NULL ? -1 : 0;
2747}
2748
2749
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002750/**
2751 * eap_get_config_password - Get password from the network configuration
2752 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2753 * @len: Buffer for the length of the password
2754 * Returns: Pointer to the password or %NULL if not found
2755 */
2756const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
2757{
2758 struct eap_peer_config *config = eap_get_config(sm);
2759 if (config == NULL)
2760 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002761
2762 if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
2763 if (eap_get_ext_password(sm, config) < 0)
2764 return NULL;
2765 *len = wpabuf_len(sm->ext_pw_buf);
2766 return wpabuf_head(sm->ext_pw_buf);
2767 }
2768
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002769 *len = config->password_len;
2770 return config->password;
2771}
2772
2773
2774/**
2775 * eap_get_config_password2 - Get password from the network configuration
2776 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2777 * @len: Buffer for the length of the password
2778 * @hash: Buffer for returning whether the password is stored as a
2779 * NtPasswordHash instead of plaintext password; can be %NULL if this
2780 * information is not needed
2781 * Returns: Pointer to the password or %NULL if not found
2782 */
2783const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
2784{
2785 struct eap_peer_config *config = eap_get_config(sm);
2786 if (config == NULL)
2787 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002788
2789 if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
2790 if (eap_get_ext_password(sm, config) < 0)
2791 return NULL;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002792 if (hash)
2793 *hash = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002794 *len = wpabuf_len(sm->ext_pw_buf);
2795 return wpabuf_head(sm->ext_pw_buf);
2796 }
2797
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002798 *len = config->password_len;
2799 if (hash)
2800 *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
2801 return config->password;
2802}
2803
2804
2805/**
2806 * eap_get_config_new_password - Get new password from network configuration
2807 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2808 * @len: Buffer for the length of the new password
2809 * Returns: Pointer to the new password or %NULL if not found
2810 */
2811const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
2812{
2813 struct eap_peer_config *config = eap_get_config(sm);
2814 if (config == NULL)
2815 return NULL;
2816 *len = config->new_password_len;
2817 return config->new_password;
2818}
2819
2820
2821/**
2822 * eap_get_config_otp - Get one-time password from the network configuration
2823 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2824 * @len: Buffer for the length of the one-time password
2825 * Returns: Pointer to the one-time password or %NULL if not found
2826 */
2827const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
2828{
2829 struct eap_peer_config *config = eap_get_config(sm);
2830 if (config == NULL)
2831 return NULL;
2832 *len = config->otp_len;
2833 return config->otp;
2834}
2835
2836
2837/**
2838 * eap_clear_config_otp - Clear used one-time password
2839 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2840 *
2841 * This function clears a used one-time password (OTP) from the current network
2842 * configuration. This should be called when the OTP has been used and is not
2843 * needed anymore.
2844 */
2845void eap_clear_config_otp(struct eap_sm *sm)
2846{
2847 struct eap_peer_config *config = eap_get_config(sm);
2848 if (config == NULL)
2849 return;
2850 os_memset(config->otp, 0, config->otp_len);
2851 os_free(config->otp);
2852 config->otp = NULL;
2853 config->otp_len = 0;
2854}
2855
2856
2857/**
2858 * eap_get_config_phase1 - Get phase1 data from the network configuration
2859 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2860 * Returns: Pointer to the phase1 data or %NULL if not found
2861 */
2862const char * eap_get_config_phase1(struct eap_sm *sm)
2863{
2864 struct eap_peer_config *config = eap_get_config(sm);
2865 if (config == NULL)
2866 return NULL;
2867 return config->phase1;
2868}
2869
2870
2871/**
2872 * eap_get_config_phase2 - Get phase2 data from the network configuration
2873 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2874 * Returns: Pointer to the phase1 data or %NULL if not found
2875 */
2876const char * eap_get_config_phase2(struct eap_sm *sm)
2877{
2878 struct eap_peer_config *config = eap_get_config(sm);
2879 if (config == NULL)
2880 return NULL;
2881 return config->phase2;
2882}
2883
2884
2885int eap_get_config_fragment_size(struct eap_sm *sm)
2886{
2887 struct eap_peer_config *config = eap_get_config(sm);
2888 if (config == NULL)
2889 return -1;
2890 return config->fragment_size;
2891}
2892
2893
2894/**
2895 * eap_key_available - Get key availability (eapKeyAvailable variable)
2896 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2897 * Returns: 1 if EAP keying material is available, 0 if not
2898 */
2899int eap_key_available(struct eap_sm *sm)
2900{
2901 return sm ? sm->eapKeyAvailable : 0;
2902}
2903
2904
2905/**
2906 * eap_notify_success - Notify EAP state machine about external success trigger
2907 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2908 *
2909 * This function is called when external event, e.g., successful completion of
2910 * WPA-PSK key handshake, is indicating that EAP state machine should move to
2911 * success state. This is mainly used with security modes that do not use EAP
2912 * state machine (e.g., WPA-PSK).
2913 */
2914void eap_notify_success(struct eap_sm *sm)
2915{
2916 if (sm) {
2917 sm->decision = DECISION_COND_SUCC;
2918 sm->EAP_state = EAP_SUCCESS;
2919 }
2920}
2921
2922
2923/**
2924 * eap_notify_lower_layer_success - Notification of lower layer success
2925 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2926 *
2927 * Notify EAP state machines that a lower layer has detected a successful
2928 * authentication. This is used to recover from dropped EAP-Success messages.
2929 */
2930void eap_notify_lower_layer_success(struct eap_sm *sm)
2931{
2932 if (sm == NULL)
2933 return;
2934
2935 if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
2936 sm->decision == DECISION_FAIL ||
2937 (sm->methodState != METHOD_MAY_CONT &&
2938 sm->methodState != METHOD_DONE))
2939 return;
2940
2941 if (sm->eapKeyData != NULL)
2942 sm->eapKeyAvailable = TRUE;
2943 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
2944 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
2945 "EAP authentication completed successfully (based on lower "
2946 "layer success)");
2947}
2948
2949
2950/**
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002951 * eap_get_eapSessionId - Get Session-Id from EAP state machine
2952 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2953 * @len: Pointer to variable that will be set to number of bytes in the session
2954 * Returns: Pointer to the EAP Session-Id or %NULL on failure
2955 *
2956 * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
2957 * only after a successful authentication. EAP state machine continues to manage
2958 * the Session-Id and the caller must not change or free the returned data.
2959 */
2960const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
2961{
2962 if (sm == NULL || sm->eapSessionId == NULL) {
2963 *len = 0;
2964 return NULL;
2965 }
2966
2967 *len = sm->eapSessionIdLen;
2968 return sm->eapSessionId;
2969}
2970
2971
2972/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002973 * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
2974 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2975 * @len: Pointer to variable that will be set to number of bytes in the key
2976 * Returns: Pointer to the EAP keying data or %NULL on failure
2977 *
2978 * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
2979 * key is available only after a successful authentication. EAP state machine
2980 * continues to manage the key data and the caller must not change or free the
2981 * returned data.
2982 */
2983const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
2984{
2985 if (sm == NULL || sm->eapKeyData == NULL) {
2986 *len = 0;
2987 return NULL;
2988 }
2989
2990 *len = sm->eapKeyDataLen;
2991 return sm->eapKeyData;
2992}
2993
2994
2995/**
2996 * eap_get_eapKeyData - Get EAP response data
2997 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2998 * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
2999 *
3000 * Fetch EAP response (eapRespData) from the EAP state machine. This data is
3001 * available when EAP state machine has processed an incoming EAP request. The
3002 * EAP state machine does not maintain a reference to the response after this
3003 * function is called and the caller is responsible for freeing the data.
3004 */
3005struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
3006{
3007 struct wpabuf *resp;
3008
3009 if (sm == NULL || sm->eapRespData == NULL)
3010 return NULL;
3011
3012 resp = sm->eapRespData;
3013 sm->eapRespData = NULL;
3014
3015 return resp;
3016}
3017
3018
3019/**
3020 * eap_sm_register_scard_ctx - Notification of smart card context
3021 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3022 * @ctx: Context data for smart card operations
3023 *
3024 * Notify EAP state machines of context data for smart card operations. This
3025 * context data will be used as a parameter for scard_*() functions.
3026 */
3027void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
3028{
3029 if (sm)
3030 sm->scard_ctx = ctx;
3031}
3032
3033
3034/**
3035 * eap_set_config_blob - Set or add a named configuration blob
3036 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3037 * @blob: New value for the blob
3038 *
3039 * Adds a new configuration blob or replaces the current value of an existing
3040 * blob.
3041 */
3042void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
3043{
3044#ifndef CONFIG_NO_CONFIG_BLOBS
3045 sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
3046#endif /* CONFIG_NO_CONFIG_BLOBS */
3047}
3048
3049
3050/**
3051 * eap_get_config_blob - Get a named configuration blob
3052 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3053 * @name: Name of the blob
3054 * Returns: Pointer to blob data or %NULL if not found
3055 */
3056const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
3057 const char *name)
3058{
3059#ifndef CONFIG_NO_CONFIG_BLOBS
3060 return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
3061#else /* CONFIG_NO_CONFIG_BLOBS */
3062 return NULL;
3063#endif /* CONFIG_NO_CONFIG_BLOBS */
3064}
3065
3066
3067/**
3068 * eap_set_force_disabled - Set force_disabled flag
3069 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3070 * @disabled: 1 = EAP disabled, 0 = EAP enabled
3071 *
3072 * This function is used to force EAP state machine to be disabled when it is
3073 * not in use (e.g., with WPA-PSK or plaintext connections).
3074 */
3075void eap_set_force_disabled(struct eap_sm *sm, int disabled)
3076{
3077 sm->force_disabled = disabled;
3078}
3079
3080
Dmitry Shmidt051af732013-10-22 13:52:46 -07003081/**
3082 * eap_set_external_sim - Set external_sim flag
3083 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3084 * @external_sim: Whether external SIM/USIM processing is used
3085 */
3086void eap_set_external_sim(struct eap_sm *sm, int external_sim)
3087{
3088 sm->external_sim = external_sim;
3089}
3090
3091
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003092 /**
3093 * eap_notify_pending - Notify that EAP method is ready to re-process a request
3094 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3095 *
3096 * An EAP method can perform a pending operation (e.g., to get a response from
3097 * an external process). Once the response is available, this function can be
3098 * used to request EAPOL state machine to retry delivering the previously
3099 * received (and still unanswered) EAP request to EAP state machine.
3100 */
3101void eap_notify_pending(struct eap_sm *sm)
3102{
3103 sm->eapol_cb->notify_pending(sm->eapol_ctx);
3104}
3105
3106
3107/**
3108 * eap_invalidate_cached_session - Mark cached session data invalid
3109 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3110 */
3111void eap_invalidate_cached_session(struct eap_sm *sm)
3112{
3113 if (sm)
3114 eap_deinit_prev_method(sm, "invalidate");
3115}
3116
3117
3118int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
3119{
3120 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
3121 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
3122 return 0; /* Not a WPS Enrollee */
3123
3124 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
3125 return 0; /* Not using PBC */
3126
3127 return 1;
3128}
3129
3130
3131int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
3132{
3133 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
3134 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
3135 return 0; /* Not a WPS Enrollee */
3136
3137 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
3138 return 0; /* Not using PIN */
3139
3140 return 1;
3141}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003142
3143
3144void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
3145{
3146 ext_password_free(sm->ext_pw_buf);
3147 sm->ext_pw_buf = NULL;
3148 sm->ext_pw = ext;
3149}
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003150
3151
3152/**
3153 * eap_set_anon_id - Set or add anonymous identity
3154 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3155 * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
3156 * @len: Length of anonymous identity in octets
3157 */
3158void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
3159{
3160 if (sm->eapol_cb->set_anon_id)
3161 sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
3162}
Dmitry Shmidt344abd32014-01-14 13:17:00 -08003163
3164
3165int eap_peer_was_failure_expected(struct eap_sm *sm)
3166{
3167 return sm->expected_failure;
3168}