blob: 5fd370f7f216bf5e9433f2efbfd1177a2b3fe5a8 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * EAP peer state machines (RFC 4137)
Hai Shalomc3565922019-10-28 11:58:20 -07003 * Copyright (c) 2004-2019, 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
Hai Shalomc3565922019-10-28 11:58:20 -070035#define EAP_MAX_AUTH_ROUNDS 100
36#define EAP_MAX_AUTH_ROUNDS_SHORT 50
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070037#define EAP_CLIENT_TIMEOUT_DEFAULT 60
38
39
Hai Shalome21d4e82020-04-29 16:34:06 -070040static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
41 enum eap_type method);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
43static void eap_sm_processIdentity(struct eap_sm *sm,
44 const struct wpabuf *req);
45static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
46static struct wpabuf * eap_sm_buildNotify(int id);
47static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
48#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
49static const char * eap_sm_method_state_txt(EapMethodState state);
50static const char * eap_sm_decision_txt(EapDecision decision);
51#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt55840ad2015-12-14 12:45:46 -080052static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
53 const char *msg, size_t msglen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054
55
56
Hai Shalome21d4e82020-04-29 16:34:06 -070057static bool eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070058{
59 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
60}
61
62
63static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
Hai Shalome21d4e82020-04-29 16:34:06 -070064 bool value)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070065{
66 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
67}
68
69
70static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
71{
72 return sm->eapol_cb->get_int(sm->eapol_ctx, var);
73}
74
75
76static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
77 unsigned int value)
78{
79 sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
80}
81
82
83static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
84{
85 return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
86}
87
88
Dmitry Shmidt04949592012-07-19 12:16:46 -070089static void eap_notify_status(struct eap_sm *sm, const char *status,
90 const char *parameter)
91{
92 wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
93 status, parameter);
94 if (sm->eapol_cb->notify_status)
95 sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
96}
97
Roshan Pius3a1667e2018-07-03 15:17:14 -070098
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -070099static void eap_report_error(struct eap_sm *sm, int error_code)
100{
101 wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
102 if (sm->eapol_cb->notify_eap_error)
103 sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
104}
Dmitry Shmidt04949592012-07-19 12:16:46 -0700105
Roshan Pius3a1667e2018-07-03 15:17:14 -0700106
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700107static void eap_sm_free_key(struct eap_sm *sm)
108{
109 if (sm->eapKeyData) {
110 bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen);
111 sm->eapKeyData = NULL;
112 }
113}
114
115
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700116static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
117{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700118 ext_password_free(sm->ext_pw_buf);
119 sm->ext_pw_buf = NULL;
120
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700121 if (sm->m == NULL || sm->eap_method_priv == NULL)
122 return;
123
124 wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
125 "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
126 sm->m->deinit(sm, sm->eap_method_priv);
127 sm->eap_method_priv = NULL;
128 sm->m = NULL;
129}
130
131
132/**
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700133 * eap_config_allowed_method - Check whether EAP method is allowed
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700134 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700135 * @config: EAP configuration
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700136 * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
137 * @method: EAP type
138 * Returns: 1 = allowed EAP method, 0 = not allowed
139 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700140static int eap_config_allowed_method(struct eap_sm *sm,
141 struct eap_peer_config *config,
142 int vendor, u32 method)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700143{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700144 int i;
145 struct eap_method_type *m;
146
147 if (config == NULL || config->eap_methods == NULL)
148 return 1;
149
150 m = config->eap_methods;
151 for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
152 m[i].method != EAP_TYPE_NONE; i++) {
153 if (m[i].vendor == vendor && m[i].method == method)
154 return 1;
155 }
156 return 0;
157}
158
159
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700160/**
161 * eap_allowed_method - Check whether EAP method is allowed
162 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
163 * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
164 * @method: EAP type
165 * Returns: 1 = allowed EAP method, 0 = not allowed
166 */
167int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
168{
169 return eap_config_allowed_method(sm, eap_get_config(sm), vendor,
170 method);
171}
172
173
174#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
175static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
176 size_t max_len, size_t *imsi_len,
177 int mnc_len)
178{
179 char *pos, mnc[4];
180
181 if (*imsi_len + 36 > max_len) {
182 wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
183 return -1;
184 }
185
186 if (mnc_len != 2 && mnc_len != 3)
187 mnc_len = 3;
188
189 if (mnc_len == 2) {
190 mnc[0] = '0';
191 mnc[1] = imsi[3];
192 mnc[2] = imsi[4];
193 } else if (mnc_len == 3) {
194 mnc[0] = imsi[3];
195 mnc[1] = imsi[4];
196 mnc[2] = imsi[5];
197 }
198 mnc[3] = '\0';
199
200 pos = imsi + *imsi_len;
201 pos += os_snprintf(pos, imsi + max_len - pos,
202 "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
203 mnc, imsi[0], imsi[1], imsi[2]);
204 *imsi_len = pos - imsi;
205
206 return 0;
207}
208#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
209
210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700211/*
212 * This state initializes state machine variables when the machine is
Hai Shalome21d4e82020-04-29 16:34:06 -0700213 * activated (portEnabled = true). This is also used when re-starting
214 * authentication (eapRestart == true).
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700215 */
216SM_STATE(EAP, INITIALIZE)
217{
218 SM_ENTRY(EAP, INITIALIZE);
219 if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
220 sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
Dmitry Shmidt7f0b69e2014-07-28 10:35:20 -0700221 !sm->prev_failure &&
222 sm->last_config == eap_get_config(sm)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
224 "fast reauthentication");
225 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
226 } else {
Dmitry Shmidt7f0b69e2014-07-28 10:35:20 -0700227 sm->last_config = eap_get_config(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700228 eap_deinit_prev_method(sm, "INITIALIZE");
229 }
230 sm->selectedMethod = EAP_TYPE_NONE;
231 sm->methodState = METHOD_NONE;
Hai Shalome21d4e82020-04-29 16:34:06 -0700232 sm->allowNotifications = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700233 sm->decision = DECISION_FAIL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800234 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700235 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
Hai Shalome21d4e82020-04-29 16:34:06 -0700236 eapol_set_bool(sm, EAPOL_eapSuccess, false);
237 eapol_set_bool(sm, EAPOL_eapFail, false);
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700238 eap_sm_free_key(sm);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800239 os_free(sm->eapSessionId);
240 sm->eapSessionId = NULL;
Hai Shalome21d4e82020-04-29 16:34:06 -0700241 sm->eapKeyAvailable = false;
242 eapol_set_bool(sm, EAPOL_eapRestart, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700243 sm->lastId = -1; /* new session - make sure this does not match with
244 * the first EAP-Packet */
245 /*
246 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
247 * seemed to be able to trigger cases where both were set and if EAPOL
248 * state machine uses eapNoResp first, it may end up not sending a real
249 * reply correctly. This occurred when the workaround in FAIL state set
Hai Shalome21d4e82020-04-29 16:34:06 -0700250 * eapNoResp = true.. Maybe that workaround needs to be fixed to do
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700251 * something else(?)
252 */
Hai Shalome21d4e82020-04-29 16:34:06 -0700253 eapol_set_bool(sm, EAPOL_eapResp, false);
254 eapol_set_bool(sm, EAPOL_eapNoResp, false);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800255 /*
256 * RFC 4137 does not reset ignore here, but since it is possible for
Hai Shalome21d4e82020-04-29 16:34:06 -0700257 * some method code paths to end up not setting ignore=false, clear the
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800258 * value here to avoid issues if a previous authentication attempt
Hai Shalome21d4e82020-04-29 16:34:06 -0700259 * failed with ignore=true being left behind in the last
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800260 * m.check(eapReqData) operation.
261 */
262 sm->ignore = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700263 sm->num_rounds = 0;
Hai Shalomc3565922019-10-28 11:58:20 -0700264 sm->num_rounds_short = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700265 sm->prev_failure = 0;
Dmitry Shmidt344abd32014-01-14 13:17:00 -0800266 sm->expected_failure = 0;
Hai Shalome21d4e82020-04-29 16:34:06 -0700267 sm->reauthInit = false;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800268 sm->erp_seq = (u32) -1;
Hai Shalomc3565922019-10-28 11:58:20 -0700269 sm->use_machine_cred = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700270}
271
272
273/*
274 * This state is reached whenever service from the lower layer is interrupted
Hai Shalome21d4e82020-04-29 16:34:06 -0700275 * or unavailable (portEnabled == false). Immediate transition to INITIALIZE
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700276 * occurs when the port becomes enabled.
277 */
278SM_STATE(EAP, DISABLED)
279{
280 SM_ENTRY(EAP, DISABLED);
281 sm->num_rounds = 0;
Hai Shalomc3565922019-10-28 11:58:20 -0700282 sm->num_rounds_short = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700283 /*
284 * RFC 4137 does not describe clearing of idleWhile here, but doing so
285 * allows the timer tick to be stopped more quickly when EAP is not in
286 * use.
287 */
288 eapol_set_int(sm, EAPOL_idleWhile, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700289}
290
291
292/*
293 * The state machine spends most of its time here, waiting for something to
294 * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
295 * SEND_RESPONSE states.
296 */
297SM_STATE(EAP, IDLE)
298{
299 SM_ENTRY(EAP, IDLE);
300}
301
302
303/*
Hai Shalome21d4e82020-04-29 16:34:06 -0700304 * This state is entered when an EAP packet is received (eapReq == true) to
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700305 * parse the packet header.
306 */
307SM_STATE(EAP, RECEIVED)
308{
309 const struct wpabuf *eapReqData;
310
311 SM_ENTRY(EAP, RECEIVED);
312 eapReqData = eapol_get_eapReqData(sm);
313 /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
314 eap_sm_parseEapReq(sm, eapReqData);
315 sm->num_rounds++;
Hai Shalomc3565922019-10-28 11:58:20 -0700316 if (!eapReqData || wpabuf_len(eapReqData) < 20)
317 sm->num_rounds_short++;
318 else
319 sm->num_rounds_short = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700320}
321
322
323/*
324 * This state is entered when a request for a new type comes in. Either the
325 * correct method is started, or a Nak response is built.
326 */
327SM_STATE(EAP, GET_METHOD)
328{
329 int reinit;
Hai Shalomc3565922019-10-28 11:58:20 -0700330 enum eap_type method;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700331 const struct eap_method *eap_method;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700332
333 SM_ENTRY(EAP, GET_METHOD);
334
335 if (sm->reqMethod == EAP_TYPE_EXPANDED)
336 method = sm->reqVendorMethod;
337 else
338 method = sm->reqMethod;
339
Dmitry Shmidt04949592012-07-19 12:16:46 -0700340 eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
341
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700342 if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
343 wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
344 sm->reqVendor, method);
345 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
346 "vendor=%u method=%u -> NAK",
347 sm->reqVendor, method);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700348 eap_notify_status(sm, "refuse proposed method",
349 eap_method ? eap_method->name : "unknown");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700350 goto nak;
351 }
352
353 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
354 "vendor=%u method=%u", sm->reqVendor, method);
355
Dmitry Shmidt04949592012-07-19 12:16:46 -0700356 eap_notify_status(sm, "accept proposed method",
357 eap_method ? eap_method->name : "unknown");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700358 /*
359 * RFC 4137 does not define specific operation for fast
360 * re-authentication (session resumption). The design here is to allow
361 * the previously used method data to be maintained for
362 * re-authentication if the method support session resumption.
363 * Otherwise, the previously used method data is freed and a new method
364 * is allocated here.
365 */
366 if (sm->fast_reauth &&
367 sm->m && sm->m->vendor == sm->reqVendor &&
368 sm->m->method == method &&
369 sm->m->has_reauth_data &&
370 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
371 wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
372 " for fast re-authentication");
373 reinit = 1;
374 } else {
375 eap_deinit_prev_method(sm, "GET_METHOD");
376 reinit = 0;
377 }
378
379 sm->selectedMethod = sm->reqMethod;
380 if (sm->m == NULL)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700381 sm->m = eap_method;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700382 if (!sm->m) {
383 wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
384 "vendor %d method %d",
385 sm->reqVendor, method);
386 goto nak;
387 }
388
389 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
390
391 wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
392 "vendor %u method %u (%s)",
393 sm->reqVendor, method, sm->m->name);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800394 if (reinit) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700395 sm->eap_method_priv = sm->m->init_for_reauth(
396 sm, sm->eap_method_priv);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800397 } else {
398 sm->waiting_ext_cert_check = 0;
399 sm->ext_cert_check = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700400 sm->eap_method_priv = sm->m->init(sm);
Dmitry Shmidt55840ad2015-12-14 12:45:46 -0800401 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700402
403 if (sm->eap_method_priv == NULL) {
404 struct eap_peer_config *config = eap_get_config(sm);
405 wpa_msg(sm->msg_ctx, MSG_INFO,
406 "EAP: Failed to initialize EAP method: vendor %u "
407 "method %u (%s)",
408 sm->reqVendor, method, sm->m->name);
409 sm->m = NULL;
410 sm->methodState = METHOD_NONE;
411 sm->selectedMethod = EAP_TYPE_NONE;
412 if (sm->reqMethod == EAP_TYPE_TLS && config &&
413 (config->pending_req_pin ||
414 config->pending_req_passphrase)) {
415 /*
416 * Return without generating Nak in order to allow
417 * entering of PIN code or passphrase to retry the
418 * current EAP packet.
419 */
420 wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
421 "request - skip Nak");
422 return;
423 }
424
425 goto nak;
426 }
427
428 sm->methodState = METHOD_INIT;
429 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
430 "EAP vendor %u method %u (%s) selected",
431 sm->reqVendor, method, sm->m->name);
Gabriel Biren3a2ec2c2022-03-07 17:59:41 +0000432
433 if (sm->eapol_cb->notify_eap_method_selected) {
434 char *format_str = "EAP vendor %u method %u (%s) selected";
435 int msg_len = snprintf(NULL, 0, format_str,
436 sm->reqVendor, method, sm->m->name) + 1;
437 char *msg = os_malloc(msg_len);
438 snprintf(msg, msg_len, format_str,
439 sm->reqVendor, method, sm->m->name);
440 sm->eapol_cb->notify_eap_method_selected(sm->eapol_ctx, msg);
441 os_free(msg);
442 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700443 return;
444
445nak:
446 wpabuf_free(sm->eapRespData);
447 sm->eapRespData = NULL;
448 sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
449}
450
451
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800452#ifdef CONFIG_ERP
453
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700454static char * eap_get_realm(struct eap_sm *sm, struct eap_peer_config *config)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800455{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800456 char *realm;
457 size_t i, realm_len;
458
459 if (!config)
460 return NULL;
461
462 if (config->identity) {
463 for (i = 0; i < config->identity_len; i++) {
464 if (config->identity[i] == '@')
465 break;
466 }
467 if (i < config->identity_len) {
468 realm_len = config->identity_len - i - 1;
469 realm = os_malloc(realm_len + 1);
470 if (realm == NULL)
471 return NULL;
472 os_memcpy(realm, &config->identity[i + 1], realm_len);
473 realm[realm_len] = '\0';
474 return realm;
475 }
476 }
477
478 if (config->anonymous_identity) {
479 for (i = 0; i < config->anonymous_identity_len; i++) {
480 if (config->anonymous_identity[i] == '@')
481 break;
482 }
483 if (i < config->anonymous_identity_len) {
484 realm_len = config->anonymous_identity_len - i - 1;
485 realm = os_malloc(realm_len + 1);
486 if (realm == NULL)
487 return NULL;
488 os_memcpy(realm, &config->anonymous_identity[i + 1],
489 realm_len);
490 realm[realm_len] = '\0';
491 return realm;
492 }
493 }
494
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700495#ifdef CONFIG_EAP_PROXY
496 /* When identity is not provided in the config, build the realm from
497 * IMSI for eap_proxy based methods.
498 */
499 if (!config->identity && !config->anonymous_identity &&
500 sm->eapol_cb->get_imsi &&
501 (eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
502 EAP_TYPE_SIM) ||
503 eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
504 EAP_TYPE_AKA) ||
505 eap_config_allowed_method(sm, config, EAP_VENDOR_IETF,
506 EAP_TYPE_AKA_PRIME))) {
507 char imsi[100];
508 size_t imsi_len;
509 int mnc_len, pos;
510
511 wpa_printf(MSG_DEBUG, "EAP: Build realm from IMSI (eap_proxy)");
512 mnc_len = sm->eapol_cb->get_imsi(sm->eapol_ctx, config->sim_num,
513 imsi, &imsi_len);
514 if (mnc_len < 0)
515 return NULL;
516
517 pos = imsi_len + 1; /* points to the beginning of the realm */
518 if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
519 mnc_len) < 0) {
520 wpa_printf(MSG_WARNING, "Could not append realm");
521 return NULL;
522 }
523
524 realm = os_strdup(&imsi[pos]);
525 if (!realm)
526 return NULL;
527
528 wpa_printf(MSG_DEBUG, "EAP: Generated realm '%s'", realm);
529 return realm;
530 }
531#endif /* CONFIG_EAP_PROXY */
532
533 return NULL;
534}
535
536
537static char * eap_home_realm(struct eap_sm *sm)
538{
539 return eap_get_realm(sm, eap_get_config(sm));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800540}
541
542
543static struct eap_erp_key *
544eap_erp_get_key(struct eap_sm *sm, const char *realm)
545{
546 struct eap_erp_key *erp;
547
548 dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
549 char *pos;
550
551 pos = os_strchr(erp->keyname_nai, '@');
552 if (!pos)
553 continue;
554 pos++;
555 if (os_strcmp(pos, realm) == 0)
556 return erp;
557 }
558
559 return NULL;
560}
561
562
563static struct eap_erp_key *
564eap_erp_get_key_nai(struct eap_sm *sm, const char *nai)
565{
566 struct eap_erp_key *erp;
567
568 dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
569 if (os_strcmp(erp->keyname_nai, nai) == 0)
570 return erp;
571 }
572
573 return NULL;
574}
575
576
577static void eap_peer_erp_free_key(struct eap_erp_key *erp)
578{
579 dl_list_del(&erp->list);
580 bin_clear_free(erp, sizeof(*erp));
581}
582
583
584static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
585{
586 struct eap_erp_key *erp;
587
588 while ((erp = eap_erp_get_key(sm, realm)) != NULL) {
589 wpa_printf(MSG_DEBUG, "EAP: Delete old ERP key %s",
590 erp->keyname_nai);
591 eap_peer_erp_free_key(erp);
592 }
593}
594
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700595
596int eap_peer_update_erp_next_seq_num(struct eap_sm *sm, u16 next_seq_num)
597{
598 struct eap_erp_key *erp;
599 char *home_realm;
600
601 home_realm = eap_home_realm(sm);
602 if (!home_realm || os_strlen(home_realm) == 0) {
603 os_free(home_realm);
604 return -1;
605 }
606
607 erp = eap_erp_get_key(sm, home_realm);
608 if (!erp) {
609 wpa_printf(MSG_DEBUG,
610 "EAP: Failed to find ERP key for realm: %s",
611 home_realm);
612 os_free(home_realm);
613 return -1;
614 }
615
616 if ((u32) next_seq_num < erp->next_seq) {
617 /* Sequence number has wrapped around, clear this ERP
618 * info and do a full auth next time.
619 */
620 eap_peer_erp_free_key(erp);
621 } else {
622 erp->next_seq = (u32) next_seq_num;
623 }
624
625 os_free(home_realm);
626 return 0;
627}
628
629
630int eap_peer_get_erp_info(struct eap_sm *sm, struct eap_peer_config *config,
631 const u8 **username, size_t *username_len,
632 const u8 **realm, size_t *realm_len,
633 u16 *erp_next_seq_num, const u8 **rrk,
634 size_t *rrk_len)
635{
636 struct eap_erp_key *erp;
637 char *home_realm;
638 char *pos;
639
640 if (config)
641 home_realm = eap_get_realm(sm, config);
642 else
643 home_realm = eap_home_realm(sm);
644 if (!home_realm || os_strlen(home_realm) == 0) {
645 os_free(home_realm);
646 return -1;
647 }
648
649 erp = eap_erp_get_key(sm, home_realm);
650 os_free(home_realm);
651 if (!erp)
652 return -1;
653
654 if (erp->next_seq >= 65536)
655 return -1; /* SEQ has range of 0..65535 */
656
657 pos = os_strchr(erp->keyname_nai, '@');
658 if (!pos)
659 return -1; /* this cannot really happen */
660 *username_len = pos - erp->keyname_nai;
661 *username = (u8 *) erp->keyname_nai;
662
663 pos++;
664 *realm_len = os_strlen(pos);
665 *realm = (u8 *) pos;
666
667 *erp_next_seq_num = (u16) erp->next_seq;
668
669 *rrk_len = erp->rRK_len;
670 *rrk = erp->rRK;
671
672 if (*username_len == 0 || *realm_len == 0 || *rrk_len == 0)
673 return -1;
674
675 return 0;
676}
677
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800678#endif /* CONFIG_ERP */
679
680
681void eap_peer_erp_free_keys(struct eap_sm *sm)
682{
683#ifdef CONFIG_ERP
684 struct eap_erp_key *erp, *tmp;
685
686 dl_list_for_each_safe(erp, tmp, &sm->erp_keys, struct eap_erp_key, list)
687 eap_peer_erp_free_key(erp);
688#endif /* CONFIG_ERP */
689}
690
691
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800692/* Note: If ext_session and/or ext_emsk are passed to this function, they are
693 * expected to point to allocated memory and those allocations will be freed
694 * unconditionally. */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700695void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id,
696 size_t ext_session_id_len, u8 *ext_emsk,
697 size_t ext_emsk_len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800698{
699#ifdef CONFIG_ERP
700 u8 *emsk = NULL;
701 size_t emsk_len = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700702 u8 *session_id = NULL;
703 size_t session_id_len = 0;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800704 u8 EMSKname[EAP_EMSK_NAME_LEN];
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800705 u8 len[2], ctx[3];
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800706 char *realm;
707 size_t realm_len, nai_buf_len;
708 struct eap_erp_key *erp = NULL;
709 int pos;
710
711 realm = eap_home_realm(sm);
712 if (!realm)
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800713 goto fail;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800714 realm_len = os_strlen(realm);
715 wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
716 eap_erp_remove_keys_realm(sm, realm);
717
718 nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + realm_len;
719 if (nai_buf_len > 253) {
720 /*
721 * keyName-NAI has a maximum length of 253 octet to fit in
722 * RADIUS attributes.
723 */
724 wpa_printf(MSG_DEBUG,
725 "EAP: Too long realm for ERP keyName-NAI maximum length");
726 goto fail;
727 }
728 nai_buf_len++; /* null termination */
729 erp = os_zalloc(sizeof(*erp) + nai_buf_len);
730 if (erp == NULL)
731 goto fail;
732
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700733 if (ext_emsk) {
734 emsk = ext_emsk;
735 emsk_len = ext_emsk_len;
736 } else {
737 emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
738 }
739
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800740 if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
741 wpa_printf(MSG_DEBUG,
742 "EAP: No suitable EMSK available for ERP");
743 goto fail;
744 }
745
746 wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
747
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700748 if (ext_session_id) {
749 session_id = ext_session_id;
750 session_id_len = ext_session_id_len;
751 } else {
752 session_id = sm->eapSessionId;
753 session_id_len = sm->eapSessionIdLen;
754 }
755
756 if (!session_id || session_id_len == 0) {
757 wpa_printf(MSG_DEBUG,
758 "EAP: No suitable session id available for ERP");
759 goto fail;
760 }
761
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800762 WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700763 if (hmac_sha256_kdf(session_id, session_id_len, "EMSK", len,
764 sizeof(len), EMSKname, EAP_EMSK_NAME_LEN) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800765 wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
766 goto fail;
767 }
768 wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
769
770 pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
771 EMSKname, EAP_EMSK_NAME_LEN);
772 erp->keyname_nai[pos] = '@';
773 os_memcpy(&erp->keyname_nai[pos + 1], realm, realm_len);
774
775 WPA_PUT_BE16(len, emsk_len);
776 if (hmac_sha256_kdf(emsk, emsk_len,
777 "EAP Re-authentication Root Key@ietf.org",
778 len, sizeof(len), erp->rRK, emsk_len) < 0) {
779 wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
780 goto fail;
781 }
782 erp->rRK_len = emsk_len;
783 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
784
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800785 ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
786 WPA_PUT_BE16(&ctx[1], erp->rRK_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800787 if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800788 "Re-authentication Integrity Key@ietf.org",
789 ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800790 wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
791 goto fail;
792 }
793 erp->rIK_len = erp->rRK_len;
794 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
795
796 wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", erp->keyname_nai);
797 dl_list_add(&sm->erp_keys, &erp->list);
798 erp = NULL;
799fail:
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800800 if (ext_emsk)
801 bin_clear_free(ext_emsk, ext_emsk_len);
802 else
803 bin_clear_free(emsk, emsk_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700804 bin_clear_free(ext_session_id, ext_session_id_len);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800805 bin_clear_free(erp, sizeof(*erp));
806 os_free(realm);
807#endif /* CONFIG_ERP */
808}
809
810
811#ifdef CONFIG_ERP
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800812struct wpabuf * eap_peer_build_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800813{
814 char *realm;
815 struct eap_erp_key *erp;
816 struct wpabuf *msg;
817 u8 hash[SHA256_MAC_LEN];
818
819 realm = eap_home_realm(sm);
820 if (!realm)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800821 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800822
823 erp = eap_erp_get_key(sm, realm);
824 os_free(realm);
825 realm = NULL;
826 if (!erp)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800827 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800828
829 if (erp->next_seq >= 65536)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800830 return NULL; /* SEQ has range of 0..65535 */
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800831
832 /* TODO: check rRK lifetime expiration */
833
834 wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
835 erp->keyname_nai, erp->next_seq);
836
Hai Shalomc3565922019-10-28 11:58:20 -0700837 msg = eap_msg_alloc(EAP_VENDOR_IETF,
838 (enum eap_type) EAP_ERP_TYPE_REAUTH,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800839 1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800840 EAP_CODE_INITIATE, eap_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800841 if (msg == NULL)
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800842 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800843
844 wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
845 wpabuf_put_be16(msg, erp->next_seq);
846
847 wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
848 wpabuf_put_u8(msg, os_strlen(erp->keyname_nai));
849 wpabuf_put_str(msg, erp->keyname_nai);
850
851 wpabuf_put_u8(msg, EAP_ERP_CS_HMAC_SHA256_128); /* Cryptosuite */
852
853 if (hmac_sha256(erp->rIK, erp->rIK_len,
854 wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
855 wpabuf_free(msg);
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800856 return NULL;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800857 }
858 wpabuf_put_data(msg, hash, 16);
859
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800860 sm->erp_seq = erp->next_seq;
861 erp->next_seq++;
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -0800862
863 wpa_hexdump_buf(MSG_DEBUG, "ERP: EAP-Initiate/Re-auth", msg);
864
865 return msg;
866}
867
868
869static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id)
870{
871 struct wpabuf *msg;
872
873 msg = eap_peer_build_erp_reauth_start(sm, eap_id);
874 if (!msg)
875 return -1;
876
877 wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800878 wpabuf_free(sm->eapRespData);
879 sm->eapRespData = msg;
Hai Shalome21d4e82020-04-29 16:34:06 -0700880 sm->reauthInit = true;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800881 return 0;
882}
883#endif /* CONFIG_ERP */
884
885
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700886/*
887 * The method processing happens here. The request from the authenticator is
888 * processed, and an appropriate response packet is built.
889 */
890SM_STATE(EAP, METHOD)
891{
892 struct wpabuf *eapReqData;
893 struct eap_method_ret ret;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800894 int min_len = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700895
896 SM_ENTRY(EAP, METHOD);
897 if (sm->m == NULL) {
898 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
899 return;
900 }
901
902 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800903 if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP)
904 min_len = 0; /* LEAP uses EAP-Success without payload */
905 if (!eap_hdr_len_valid(eapReqData, min_len))
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700906 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700907
908 /*
909 * Get ignore, methodState, decision, allowNotifications, and
910 * eapRespData. RFC 4137 uses three separate method procedure (check,
911 * process, and buildResp) in this state. These have been combined into
912 * a single function call to m->process() in order to optimize EAP
913 * method implementation interface a bit. These procedures are only
914 * used from within this METHOD state, so there is no need to keep
915 * these as separate C functions.
916 *
917 * The RFC 4137 procedures return values as follows:
918 * ignore = m.check(eapReqData)
919 * (methodState, decision, allowNotifications) = m.process(eapReqData)
920 * eapRespData = m.buildResp(reqId)
921 */
922 os_memset(&ret, 0, sizeof(ret));
923 ret.ignore = sm->ignore;
924 ret.methodState = sm->methodState;
925 ret.decision = sm->decision;
926 ret.allowNotifications = sm->allowNotifications;
927 wpabuf_free(sm->eapRespData);
928 sm->eapRespData = NULL;
929 sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
930 eapReqData);
931 wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800932 "methodState=%s decision=%s eapRespData=%p",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 ret.ignore ? "TRUE" : "FALSE",
934 eap_sm_method_state_txt(ret.methodState),
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800935 eap_sm_decision_txt(ret.decision),
936 sm->eapRespData);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700937
938 sm->ignore = ret.ignore;
939 if (sm->ignore)
940 return;
941 sm->methodState = ret.methodState;
942 sm->decision = ret.decision;
943 sm->allowNotifications = ret.allowNotifications;
944
945 if (sm->m->isKeyAvailable && sm->m->getKey &&
946 sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
Dmitry Shmidtc2817022014-07-02 10:32:10 -0700947 eap_sm_free_key(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700948 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
949 &sm->eapKeyDataLen);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800950 os_free(sm->eapSessionId);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700951 sm->eapSessionId = NULL;
952 if (sm->m->getSessionId) {
953 sm->eapSessionId = sm->m->getSessionId(
954 sm, sm->eap_method_priv,
955 &sm->eapSessionIdLen);
Dmitry Shmidtf8623282013-02-20 14:34:59 -0800956 wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
957 sm->eapSessionId, sm->eapSessionIdLen);
958 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700959 }
960}
961
962
963/*
964 * This state signals the lower layer that a response packet is ready to be
965 * sent.
966 */
967SM_STATE(EAP, SEND_RESPONSE)
968{
969 SM_ENTRY(EAP, SEND_RESPONSE);
970 wpabuf_free(sm->lastRespData);
971 if (sm->eapRespData) {
Hai Shalomc3565922019-10-28 11:58:20 -0700972 if (wpabuf_len(sm->eapRespData) >= 20)
973 sm->num_rounds_short = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700974 if (sm->workaround)
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800975 os_memcpy(sm->last_sha1, sm->req_sha1, 20);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700976 sm->lastId = sm->reqId;
977 sm->lastRespData = wpabuf_dup(sm->eapRespData);
Hai Shalome21d4e82020-04-29 16:34:06 -0700978 eapol_set_bool(sm, EAPOL_eapResp, true);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800979 } else {
980 wpa_printf(MSG_DEBUG, "EAP: No eapRespData available");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700981 sm->lastRespData = NULL;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800982 }
Hai Shalome21d4e82020-04-29 16:34:06 -0700983 eapol_set_bool(sm, EAPOL_eapReq, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700984 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
Hai Shalome21d4e82020-04-29 16:34:06 -0700985 sm->reauthInit = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700986}
987
988
989/*
990 * This state signals the lower layer that the request was discarded, and no
991 * response packet will be sent at this time.
992 */
993SM_STATE(EAP, DISCARD)
994{
995 SM_ENTRY(EAP, DISCARD);
Hai Shalome21d4e82020-04-29 16:34:06 -0700996 eapol_set_bool(sm, EAPOL_eapReq, false);
997 eapol_set_bool(sm, EAPOL_eapNoResp, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700998}
999
1000
1001/*
1002 * Handles requests for Identity method and builds a response.
1003 */
1004SM_STATE(EAP, IDENTITY)
1005{
1006 const struct wpabuf *eapReqData;
1007
1008 SM_ENTRY(EAP, IDENTITY);
1009 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001010 if (!eap_hdr_len_valid(eapReqData, 1))
1011 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001012 eap_sm_processIdentity(sm, eapReqData);
1013 wpabuf_free(sm->eapRespData);
1014 sm->eapRespData = NULL;
1015 sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
1016}
1017
1018
1019/*
1020 * Handles requests for Notification method and builds a response.
1021 */
1022SM_STATE(EAP, NOTIFICATION)
1023{
1024 const struct wpabuf *eapReqData;
1025
1026 SM_ENTRY(EAP, NOTIFICATION);
1027 eapReqData = eapol_get_eapReqData(sm);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001028 if (!eap_hdr_len_valid(eapReqData, 1))
1029 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001030 eap_sm_processNotify(sm, eapReqData);
1031 wpabuf_free(sm->eapRespData);
1032 sm->eapRespData = NULL;
1033 sm->eapRespData = eap_sm_buildNotify(sm->reqId);
1034}
1035
1036
1037/*
1038 * This state retransmits the previous response packet.
1039 */
1040SM_STATE(EAP, RETRANSMIT)
1041{
1042 SM_ENTRY(EAP, RETRANSMIT);
1043 wpabuf_free(sm->eapRespData);
1044 if (sm->lastRespData)
1045 sm->eapRespData = wpabuf_dup(sm->lastRespData);
1046 else
1047 sm->eapRespData = NULL;
1048}
1049
1050
1051/*
1052 * This state is entered in case of a successful completion of authentication
1053 * and state machine waits here until port is disabled or EAP authentication is
1054 * restarted.
1055 */
1056SM_STATE(EAP, SUCCESS)
1057{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001058 struct eap_peer_config *config = eap_get_config(sm);
1059
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001060 SM_ENTRY(EAP, SUCCESS);
1061 if (sm->eapKeyData != NULL)
Hai Shalome21d4e82020-04-29 16:34:06 -07001062 sm->eapKeyAvailable = true;
1063 eapol_set_bool(sm, EAPOL_eapSuccess, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064
1065 /*
1066 * RFC 4137 does not clear eapReq here, but this seems to be required
1067 * to avoid processing the same request twice when state machine is
1068 * initialized.
1069 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001070 eapol_set_bool(sm, EAPOL_eapReq, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071
1072 /*
1073 * RFC 4137 does not set eapNoResp here, but this seems to be required
1074 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
1075 * addition, either eapResp or eapNoResp is required to be set after
1076 * processing the received EAP frame.
1077 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001078 eapol_set_bool(sm, EAPOL_eapNoResp, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001079
1080 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1081 "EAP authentication completed successfully");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001082
Hai Shalomc1a21442022-02-04 13:43:00 -08001083 if (!config || !sm->m) {
1084 /*
1085 * This should not happen under normal conditions, but be more
1086 * careful here since there was an earlier case where
1087 * EAP-Success could end up getting delivered to the state
1088 * machine for processing after the state had been cleaned with
1089 * a call to eap_invalidate_cached_session() (and also
1090 * eapol_sm_notify_config() having been used to clear EAP
1091 * configuration in the EAPOL state machine).
1092 */
1093 wpa_printf(MSG_DEBUG,
1094 "EAP: State machine not configured - cannot initialize ERP");
1095 return;
1096 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001097 if (config->erp && sm->m->get_emsk && sm->eapSessionId &&
1098 sm->m->isKeyAvailable &&
1099 sm->m->isKeyAvailable(sm, sm->eap_method_priv))
1100 eap_peer_erp_init(sm, NULL, 0, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001101}
1102
1103
1104/*
1105 * This state is entered in case of a failure and state machine waits here
1106 * until port is disabled or EAP authentication is restarted.
1107 */
1108SM_STATE(EAP, FAILURE)
1109{
1110 SM_ENTRY(EAP, FAILURE);
Hai Shalome21d4e82020-04-29 16:34:06 -07001111 eapol_set_bool(sm, EAPOL_eapFail, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001112
1113 /*
1114 * RFC 4137 does not clear eapReq here, but this seems to be required
1115 * to avoid processing the same request twice when state machine is
1116 * initialized.
1117 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001118 eapol_set_bool(sm, EAPOL_eapReq, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001119
1120 /*
1121 * RFC 4137 does not set eapNoResp here. However, either eapResp or
1122 * eapNoResp is required to be set after processing the received EAP
1123 * frame.
1124 */
Hai Shalome21d4e82020-04-29 16:34:06 -07001125 eapol_set_bool(sm, EAPOL_eapNoResp, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001126
1127 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
1128 "EAP authentication failed");
1129
1130 sm->prev_failure = 1;
1131}
1132
1133
1134static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
1135{
1136 /*
1137 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
1138 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
1139 * RFC 4137 require that reqId == lastId. In addition, it looks like
1140 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
1141 *
1142 * Accept this kind of Id if EAP workarounds are enabled. These are
1143 * unauthenticated plaintext messages, so this should have minimal
1144 * security implications (bit easier to fake EAP-Success/Failure).
1145 */
1146 if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
1147 reqId == ((lastId + 2) & 0xff))) {
1148 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
1149 "identifier field in EAP Success: "
1150 "reqId=%d lastId=%d (these are supposed to be "
1151 "same)", reqId, lastId);
1152 return 1;
1153 }
1154 wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
1155 "lastId=%d", reqId, lastId);
1156 return 0;
1157}
1158
1159
1160/*
1161 * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
1162 */
1163
1164static void eap_peer_sm_step_idle(struct eap_sm *sm)
1165{
1166 /*
1167 * The first three transitions are from RFC 4137. The last two are
1168 * local additions to handle special cases with LEAP and PEAP server
1169 * not sending EAP-Success in some cases.
1170 */
1171 if (eapol_get_bool(sm, EAPOL_eapReq))
1172 SM_ENTER(EAP, RECEIVED);
1173 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
1174 sm->decision != DECISION_FAIL) ||
1175 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
1176 sm->decision == DECISION_UNCOND_SUCC))
1177 SM_ENTER(EAP, SUCCESS);
1178 else if (eapol_get_bool(sm, EAPOL_altReject) ||
1179 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
1180 sm->decision != DECISION_UNCOND_SUCC) ||
1181 (eapol_get_bool(sm, EAPOL_altAccept) &&
1182 sm->methodState != METHOD_CONT &&
1183 sm->decision == DECISION_FAIL))
1184 SM_ENTER(EAP, FAILURE);
1185 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
1186 sm->leap_done && sm->decision != DECISION_FAIL &&
1187 sm->methodState == METHOD_DONE)
1188 SM_ENTER(EAP, SUCCESS);
1189 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
1190 sm->peap_done && sm->decision != DECISION_FAIL &&
1191 sm->methodState == METHOD_DONE)
1192 SM_ENTER(EAP, SUCCESS);
1193}
1194
1195
1196static int eap_peer_req_is_duplicate(struct eap_sm *sm)
1197{
1198 int duplicate;
1199
1200 duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
1201 if (sm->workaround && duplicate &&
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001202 os_memcmp(sm->req_sha1, sm->last_sha1, 20) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001203 /*
1204 * RFC 4137 uses (reqId == lastId) as the only verification for
1205 * duplicate EAP requests. However, this misses cases where the
1206 * AS is incorrectly using the same id again; and
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001207 * unfortunately, such implementations exist. Use SHA1 hash as
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001208 * an extra verification for the packets being duplicate to
1209 * workaround these issues.
1210 */
1211 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
1212 "EAP packets were not identical");
1213 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
1214 "duplicate packet");
1215 duplicate = 0;
1216 }
1217
1218 return duplicate;
1219}
1220
1221
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001222static int eap_peer_sm_allow_canned(struct eap_sm *sm)
1223{
1224 struct eap_peer_config *config = eap_get_config(sm);
1225
1226 return config && config->phase1 &&
1227 os_strstr(config->phase1, "allow_canned_success=1");
1228}
1229
1230
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001231static void eap_peer_sm_step_received(struct eap_sm *sm)
1232{
1233 int duplicate = eap_peer_req_is_duplicate(sm);
1234
1235 /*
1236 * Two special cases below for LEAP are local additions to work around
1237 * odd LEAP behavior (EAP-Success in the middle of authentication and
1238 * then swapped roles). Other transitions are based on RFC 4137.
1239 */
1240 if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
1241 (sm->reqId == sm->lastId ||
1242 eap_success_workaround(sm, sm->reqId, sm->lastId)))
1243 SM_ENTER(EAP, SUCCESS);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001244 else if (sm->workaround && sm->lastId == -1 && sm->rxSuccess &&
1245 !sm->rxFailure && !sm->rxReq && eap_peer_sm_allow_canned(sm))
1246 SM_ENTER(EAP, SUCCESS); /* EAP-Success prior any EAP method */
1247 else if (sm->workaround && sm->lastId == -1 && sm->rxFailure &&
1248 !sm->rxReq && sm->methodState != METHOD_CONT &&
1249 eap_peer_sm_allow_canned(sm))
1250 SM_ENTER(EAP, FAILURE); /* EAP-Failure prior any EAP method */
1251 else if (sm->workaround && sm->rxSuccess && !sm->rxFailure &&
1252 !sm->rxReq && sm->methodState != METHOD_CONT &&
1253 eap_peer_sm_allow_canned(sm))
1254 SM_ENTER(EAP, SUCCESS); /* EAP-Success after Identity */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001255 else if (sm->methodState != METHOD_CONT &&
1256 ((sm->rxFailure &&
1257 sm->decision != DECISION_UNCOND_SUCC) ||
1258 (sm->rxSuccess && sm->decision == DECISION_FAIL &&
1259 (sm->selectedMethod != EAP_TYPE_LEAP ||
1260 sm->methodState != METHOD_MAY_CONT))) &&
1261 (sm->reqId == sm->lastId ||
1262 eap_success_workaround(sm, sm->reqId, sm->lastId)))
1263 SM_ENTER(EAP, FAILURE);
1264 else if (sm->rxReq && duplicate)
1265 SM_ENTER(EAP, RETRANSMIT);
1266 else if (sm->rxReq && !duplicate &&
1267 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
1268 sm->allowNotifications)
1269 SM_ENTER(EAP, NOTIFICATION);
1270 else if (sm->rxReq && !duplicate &&
1271 sm->selectedMethod == EAP_TYPE_NONE &&
1272 sm->reqMethod == EAP_TYPE_IDENTITY)
1273 SM_ENTER(EAP, IDENTITY);
1274 else if (sm->rxReq && !duplicate &&
1275 sm->selectedMethod == EAP_TYPE_NONE &&
1276 sm->reqMethod != EAP_TYPE_IDENTITY &&
1277 sm->reqMethod != EAP_TYPE_NOTIFICATION)
1278 SM_ENTER(EAP, GET_METHOD);
1279 else if (sm->rxReq && !duplicate &&
1280 sm->reqMethod == sm->selectedMethod &&
1281 sm->methodState != METHOD_DONE)
1282 SM_ENTER(EAP, METHOD);
1283 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
1284 (sm->rxSuccess || sm->rxResp))
1285 SM_ENTER(EAP, METHOD);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001286 else if (sm->reauthInit)
1287 SM_ENTER(EAP, SEND_RESPONSE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001288 else
1289 SM_ENTER(EAP, DISCARD);
1290}
1291
1292
1293static void eap_peer_sm_step_local(struct eap_sm *sm)
1294{
1295 switch (sm->EAP_state) {
1296 case EAP_INITIALIZE:
1297 SM_ENTER(EAP, IDLE);
1298 break;
1299 case EAP_DISABLED:
1300 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
1301 !sm->force_disabled)
1302 SM_ENTER(EAP, INITIALIZE);
1303 break;
1304 case EAP_IDLE:
1305 eap_peer_sm_step_idle(sm);
1306 break;
1307 case EAP_RECEIVED:
1308 eap_peer_sm_step_received(sm);
1309 break;
1310 case EAP_GET_METHOD:
1311 if (sm->selectedMethod == sm->reqMethod)
1312 SM_ENTER(EAP, METHOD);
1313 else
1314 SM_ENTER(EAP, SEND_RESPONSE);
1315 break;
1316 case EAP_METHOD:
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001317 /*
1318 * Note: RFC 4137 uses methodState == DONE && decision == FAIL
1319 * as the condition. eapRespData == NULL here is used to allow
1320 * final EAP method response to be sent without having to change
1321 * all methods to either use methodState MAY_CONT or leaving
1322 * decision to something else than FAIL in cases where the only
1323 * expected response is EAP-Failure.
1324 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001325 if (sm->ignore)
1326 SM_ENTER(EAP, DISCARD);
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001327 else if (sm->methodState == METHOD_DONE &&
1328 sm->decision == DECISION_FAIL && !sm->eapRespData)
1329 SM_ENTER(EAP, FAILURE);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001330 else
1331 SM_ENTER(EAP, SEND_RESPONSE);
1332 break;
1333 case EAP_SEND_RESPONSE:
1334 SM_ENTER(EAP, IDLE);
1335 break;
1336 case EAP_DISCARD:
1337 SM_ENTER(EAP, IDLE);
1338 break;
1339 case EAP_IDENTITY:
1340 SM_ENTER(EAP, SEND_RESPONSE);
1341 break;
1342 case EAP_NOTIFICATION:
1343 SM_ENTER(EAP, SEND_RESPONSE);
1344 break;
1345 case EAP_RETRANSMIT:
1346 SM_ENTER(EAP, SEND_RESPONSE);
1347 break;
1348 case EAP_SUCCESS:
1349 break;
1350 case EAP_FAILURE:
1351 break;
1352 }
1353}
1354
1355
1356SM_STEP(EAP)
1357{
1358 /* Global transitions */
1359 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
1360 eapol_get_bool(sm, EAPOL_portEnabled))
1361 SM_ENTER_GLOBAL(EAP, INITIALIZE);
1362 else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
1363 SM_ENTER_GLOBAL(EAP, DISABLED);
1364 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
1365 /* RFC 4137 does not place any limit on number of EAP messages
1366 * in an authentication session. However, some error cases have
1367 * ended up in a state were EAP messages were sent between the
1368 * peer and server in a loop (e.g., TLS ACK frame in both
1369 * direction). Since this is quite undesired outcome, limit the
1370 * total number of EAP round-trips and abort authentication if
1371 * this limit is exceeded.
1372 */
1373 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
1374 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
1375 "authentication rounds - abort",
1376 EAP_MAX_AUTH_ROUNDS);
1377 sm->num_rounds++;
1378 SM_ENTER_GLOBAL(EAP, FAILURE);
1379 }
Hai Shalomc3565922019-10-28 11:58:20 -07001380 } else if (sm->num_rounds_short > EAP_MAX_AUTH_ROUNDS_SHORT) {
1381 if (sm->num_rounds_short == EAP_MAX_AUTH_ROUNDS_SHORT + 1) {
1382 wpa_msg(sm->msg_ctx, MSG_INFO,
1383 "EAP: more than %d authentication rounds (short) - abort",
1384 EAP_MAX_AUTH_ROUNDS_SHORT);
1385 sm->num_rounds_short++;
1386 SM_ENTER_GLOBAL(EAP, FAILURE);
1387 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001388 } else {
1389 /* Local transitions */
1390 eap_peer_sm_step_local(sm);
1391 }
1392}
1393
1394
Hai Shalome21d4e82020-04-29 16:34:06 -07001395static bool eap_sm_allowMethod(struct eap_sm *sm, int vendor,
1396 enum eap_type method)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001397{
1398 if (!eap_allowed_method(sm, vendor, method)) {
1399 wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
1400 "vendor %u method %u", vendor, method);
Hai Shalome21d4e82020-04-29 16:34:06 -07001401 return false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001402 }
1403 if (eap_peer_get_eap_method(vendor, method))
Hai Shalome21d4e82020-04-29 16:34:06 -07001404 return true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001405 wpa_printf(MSG_DEBUG, "EAP: not included in build: "
1406 "vendor %u method %u", vendor, method);
Hai Shalome21d4e82020-04-29 16:34:06 -07001407 return false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001408}
1409
1410
1411static struct wpabuf * eap_sm_build_expanded_nak(
1412 struct eap_sm *sm, int id, const struct eap_method *methods,
1413 size_t count)
1414{
1415 struct wpabuf *resp;
1416 int found = 0;
1417 const struct eap_method *m;
1418
1419 wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
1420
1421 /* RFC 3748 - 5.3.2: Expanded Nak */
1422 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
1423 8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
1424 if (resp == NULL)
1425 return NULL;
1426
1427 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
1428 wpabuf_put_be32(resp, EAP_TYPE_NAK);
1429
1430 for (m = methods; m; m = m->next) {
1431 if (sm->reqVendor == m->vendor &&
1432 sm->reqVendorMethod == m->method)
1433 continue; /* do not allow the current method again */
1434 if (eap_allowed_method(sm, m->vendor, m->method)) {
1435 wpa_printf(MSG_DEBUG, "EAP: allowed type: "
1436 "vendor=%u method=%u",
1437 m->vendor, m->method);
1438 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1439 wpabuf_put_be24(resp, m->vendor);
1440 wpabuf_put_be32(resp, m->method);
1441
1442 found++;
1443 }
1444 }
1445 if (!found) {
1446 wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
1447 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1448 wpabuf_put_be24(resp, EAP_VENDOR_IETF);
1449 wpabuf_put_be32(resp, EAP_TYPE_NONE);
1450 }
1451
1452 eap_update_len(resp);
1453
1454 return resp;
1455}
1456
1457
1458static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
1459{
1460 struct wpabuf *resp;
1461 u8 *start;
1462 int found = 0, expanded_found = 0;
1463 size_t count;
1464 const struct eap_method *methods, *m;
1465
1466 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
1467 "vendor=%u method=%u not allowed)", sm->reqMethod,
1468 sm->reqVendor, sm->reqVendorMethod);
1469 methods = eap_peer_get_methods(&count);
1470 if (methods == NULL)
1471 return NULL;
1472 if (sm->reqMethod == EAP_TYPE_EXPANDED)
1473 return eap_sm_build_expanded_nak(sm, id, methods, count);
1474
1475 /* RFC 3748 - 5.3.1: Legacy Nak */
1476 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
1477 sizeof(struct eap_hdr) + 1 + count + 1,
1478 EAP_CODE_RESPONSE, id);
1479 if (resp == NULL)
1480 return NULL;
1481
1482 start = wpabuf_put(resp, 0);
1483 for (m = methods; m; m = m->next) {
1484 if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
1485 continue; /* do not allow the current method again */
1486 if (eap_allowed_method(sm, m->vendor, m->method)) {
1487 if (m->vendor != EAP_VENDOR_IETF) {
1488 if (expanded_found)
1489 continue;
1490 expanded_found = 1;
1491 wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
1492 } else
1493 wpabuf_put_u8(resp, m->method);
1494 found++;
1495 }
1496 }
1497 if (!found)
1498 wpabuf_put_u8(resp, EAP_TYPE_NONE);
1499 wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
1500
1501 eap_update_len(resp);
1502
1503 return resp;
1504}
1505
1506
1507static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
1508{
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001509 const u8 *pos;
1510 size_t msg_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001511
1512 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
1513 "EAP authentication started");
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001514 eap_notify_status(sm, "started", "");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001515
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001516 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
1517 &msg_len);
1518 if (pos == NULL)
1519 return;
1520
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001521 /*
1522 * RFC 3748 - 5.1: Identity
1523 * Data field may contain a displayable message in UTF-8. If this
1524 * includes NUL-character, only the data before that should be
1525 * displayed. Some EAP implementasitons may piggy-back additional
1526 * options after the NUL.
1527 */
1528 /* TODO: could save displayable message so that it can be shown to the
1529 * user in case of interaction is required */
1530 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001531 pos, msg_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001532}
1533
1534
1535#ifdef PCSC_FUNCS
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001536
1537/*
1538 * Rules for figuring out MNC length based on IMSI for SIM cards that do not
1539 * include MNC length field.
1540 */
1541static int mnc_len_from_imsi(const char *imsi)
1542{
1543 char mcc_str[4];
1544 unsigned int mcc;
1545
1546 os_memcpy(mcc_str, imsi, 3);
1547 mcc_str[3] = '\0';
1548 mcc = atoi(mcc_str);
1549
Dmitry Shmidt391c59f2013-09-03 12:16:28 -07001550 if (mcc == 228)
1551 return 2; /* Networks in Switzerland use 2-digit MNC */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001552 if (mcc == 244)
1553 return 2; /* Networks in Finland use 2-digit MNC */
1554
1555 return -1;
1556}
1557
1558
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001559static int eap_sm_imsi_identity(struct eap_sm *sm,
1560 struct eap_peer_config *conf)
1561{
Dmitry Shmidt04949592012-07-19 12:16:46 -07001562 enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001563 char imsi[100];
1564 size_t imsi_len;
1565 struct eap_method_type *m = conf->eap_methods;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001566 int i, mnc_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001567
1568 imsi_len = sizeof(imsi);
1569 if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
1570 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
1571 return -1;
1572 }
1573
1574 wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
1575
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001576 if (imsi_len < 7) {
1577 wpa_printf(MSG_WARNING, "Too short IMSI for SIM identity");
1578 return -1;
1579 }
1580
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001581 /* MNC (2 or 3 digits) */
1582 mnc_len = scard_get_mnc_len(sm->scard_ctx);
1583 if (mnc_len < 0)
1584 mnc_len = mnc_len_from_imsi(imsi);
1585 if (mnc_len < 0) {
1586 wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
1587 "assuming 3");
1588 mnc_len = 3;
1589 }
1590
1591 if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len,
1592 mnc_len) < 0) {
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001593 wpa_printf(MSG_WARNING, "Could not add realm to SIM identity");
1594 return -1;
1595 }
1596 wpa_hexdump_ascii(MSG_DEBUG, "IMSI + realm", (u8 *) imsi, imsi_len);
1597
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001598 for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
1599 m[i].method != EAP_TYPE_NONE); i++) {
1600 if (m[i].vendor == EAP_VENDOR_IETF &&
Dmitry Shmidt04949592012-07-19 12:16:46 -07001601 m[i].method == EAP_TYPE_AKA_PRIME) {
1602 method = EAP_SM_AKA_PRIME;
1603 break;
1604 }
1605
1606 if (m[i].vendor == EAP_VENDOR_IETF &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001607 m[i].method == EAP_TYPE_AKA) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001608 method = EAP_SM_AKA;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001609 break;
1610 }
1611 }
1612
1613 os_free(conf->identity);
1614 conf->identity = os_malloc(1 + imsi_len);
1615 if (conf->identity == NULL) {
1616 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
1617 "IMSI-based identity");
1618 return -1;
1619 }
1620
Dmitry Shmidt04949592012-07-19 12:16:46 -07001621 switch (method) {
1622 case EAP_SM_SIM:
1623 conf->identity[0] = '1';
1624 break;
1625 case EAP_SM_AKA:
1626 conf->identity[0] = '0';
1627 break;
1628 case EAP_SM_AKA_PRIME:
1629 conf->identity[0] = '6';
1630 break;
1631 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001632 os_memcpy(conf->identity + 1, imsi, imsi_len);
1633 conf->identity_len = 1 + imsi_len;
1634
1635 return 0;
1636}
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001637
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001638
1639static int eap_sm_set_scard_pin(struct eap_sm *sm,
1640 struct eap_peer_config *conf)
1641{
Hai Shalomc3565922019-10-28 11:58:20 -07001642 if (scard_set_pin(sm->scard_ctx, conf->cert.pin)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001643 /*
1644 * Make sure the same PIN is not tried again in order to avoid
1645 * blocking SIM.
1646 */
Hai Shalomc3565922019-10-28 11:58:20 -07001647 os_free(conf->cert.pin);
1648 conf->cert.pin = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001649
1650 wpa_printf(MSG_WARNING, "PIN validation failed");
1651 eap_sm_request_pin(sm);
1652 return -1;
1653 }
1654 return 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001655}
1656
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001657
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001658static int eap_sm_get_scard_identity(struct eap_sm *sm,
1659 struct eap_peer_config *conf)
1660{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001661 if (eap_sm_set_scard_pin(sm, conf))
1662 return -1;
1663
1664 return eap_sm_imsi_identity(sm, conf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001665}
1666
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001667#endif /* PCSC_FUNCS */
1668
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001669
1670/**
1671 * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
1672 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1673 * @id: EAP identifier for the packet
1674 * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
1675 * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
1676 * failure
1677 *
1678 * This function allocates and builds an EAP-Identity/Response packet for the
1679 * current network. The caller is responsible for freeing the returned data.
1680 */
1681struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
1682{
1683 struct eap_peer_config *config = eap_get_config(sm);
1684 struct wpabuf *resp;
1685 const u8 *identity;
1686 size_t identity_len;
1687
1688 if (config == NULL) {
1689 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
1690 "was not available");
1691 return NULL;
1692 }
1693
1694 if (sm->m && sm->m->get_identity &&
1695 (identity = sm->m->get_identity(sm, sm->eap_method_priv,
1696 &identity_len)) != NULL) {
1697 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
1698 "identity", identity, identity_len);
1699 } else if (!encrypted && config->anonymous_identity) {
1700 identity = config->anonymous_identity;
1701 identity_len = config->anonymous_identity_len;
1702 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
1703 identity, identity_len);
Hai Shalomc3565922019-10-28 11:58:20 -07001704 } else if (sm->use_machine_cred) {
1705 identity = config->machine_identity;
1706 identity_len = config->machine_identity_len;
1707 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
1708 identity, identity_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001709 } else {
1710 identity = config->identity;
1711 identity_len = config->identity_len;
1712 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
1713 identity, identity_len);
1714 }
1715
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001716 if (config->pcsc) {
1717#ifdef PCSC_FUNCS
1718 if (!identity) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001719 if (eap_sm_get_scard_identity(sm, config) < 0)
1720 return NULL;
1721 identity = config->identity;
1722 identity_len = config->identity_len;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001723 wpa_hexdump_ascii(MSG_DEBUG,
1724 "permanent identity from IMSI",
1725 identity, identity_len);
1726 } else if (eap_sm_set_scard_pin(sm, config) < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001727 return NULL;
1728 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001729#else /* PCSC_FUNCS */
1730 return NULL;
1731#endif /* PCSC_FUNCS */
1732 } else if (!identity) {
1733 wpa_printf(MSG_WARNING,
1734 "EAP: buildIdentity: identity configuration was not available");
1735 eap_sm_request_identity(sm);
1736 return NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001737 }
1738
1739 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
1740 EAP_CODE_RESPONSE, id);
1741 if (resp == NULL)
1742 return NULL;
1743
1744 wpabuf_put_data(resp, identity, identity_len);
1745
1746 return resp;
1747}
1748
1749
1750static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
1751{
1752 const u8 *pos;
1753 char *msg;
1754 size_t i, msg_len;
1755
1756 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
1757 &msg_len);
1758 if (pos == NULL)
1759 return;
1760 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
1761 pos, msg_len);
1762
1763 msg = os_malloc(msg_len + 1);
1764 if (msg == NULL)
1765 return;
1766 for (i = 0; i < msg_len; i++)
1767 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
1768 msg[msg_len] = '\0';
1769 wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
1770 WPA_EVENT_EAP_NOTIFICATION, msg);
1771 os_free(msg);
1772}
1773
1774
1775static struct wpabuf * eap_sm_buildNotify(int id)
1776{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001777 wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001778 return eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
1779 EAP_CODE_RESPONSE, id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001780}
1781
1782
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001783static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
1784 size_t len)
1785{
1786#ifdef CONFIG_ERP
1787 const u8 *pos = (const u8 *) (hdr + 1);
1788 const u8 *end = ((const u8 *) hdr) + len;
1789 struct erp_tlvs parse;
1790
1791 if (len < sizeof(*hdr) + 1) {
1792 wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Initiate");
1793 return;
1794 }
1795
1796 if (*pos != EAP_ERP_TYPE_REAUTH_START) {
1797 wpa_printf(MSG_DEBUG,
1798 "EAP: Ignored unexpected EAP-Initiate Type=%u",
1799 *pos);
1800 return;
1801 }
1802
1803 pos++;
1804 if (pos >= end) {
1805 wpa_printf(MSG_DEBUG,
1806 "EAP: Too short EAP-Initiate/Re-auth-Start");
1807 return;
1808 }
1809 pos++; /* Reserved */
1810 wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth-Start TVs/TLVs",
1811 pos, end - pos);
1812
1813 if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
1814 goto invalid;
1815
1816 if (parse.domain) {
1817 wpa_hexdump_ascii(MSG_DEBUG,
1818 "EAP: EAP-Initiate/Re-auth-Start - Domain name",
1819 parse.domain, parse.domain_len);
1820 /* TODO: Derivation of domain specific keys for local ER */
1821 }
1822
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001823 if (eap_peer_erp_reauth_start(sm, hdr->identifier) == 0)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001824 return;
1825
1826invalid:
1827#endif /* CONFIG_ERP */
1828 wpa_printf(MSG_DEBUG,
1829 "EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
Hai Shalome21d4e82020-04-29 16:34:06 -07001830 eapol_set_bool(sm, EAPOL_eapTriggerStart, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001831}
1832
1833
Dmitry Shmidt9839ecd2016-11-07 11:05:47 -08001834void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr, size_t len)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001835{
1836#ifdef CONFIG_ERP
1837 const u8 *pos = (const u8 *) (hdr + 1);
1838 const u8 *end = ((const u8 *) hdr) + len;
1839 const u8 *start;
1840 struct erp_tlvs parse;
1841 u8 flags;
1842 u16 seq;
1843 u8 hash[SHA256_MAC_LEN];
1844 size_t hash_len;
1845 struct eap_erp_key *erp;
1846 int max_len;
1847 char nai[254];
1848 u8 seed[4];
1849 int auth_tag_ok = 0;
1850
1851 if (len < sizeof(*hdr) + 1) {
1852 wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Finish");
1853 return;
1854 }
1855
1856 if (*pos != EAP_ERP_TYPE_REAUTH) {
1857 wpa_printf(MSG_DEBUG,
1858 "EAP: Ignored unexpected EAP-Finish Type=%u", *pos);
1859 return;
1860 }
1861
1862 if (len < sizeof(*hdr) + 4) {
1863 wpa_printf(MSG_DEBUG,
1864 "EAP: Ignored too short EAP-Finish/Re-auth");
1865 return;
1866 }
1867
1868 pos++;
1869 flags = *pos++;
1870 seq = WPA_GET_BE16(pos);
1871 pos += 2;
1872 wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
1873
1874 if (seq != sm->erp_seq) {
1875 wpa_printf(MSG_DEBUG,
1876 "EAP: Unexpected EAP-Finish/Re-auth SEQ=%u", seq);
1877 return;
1878 }
1879
1880 /*
1881 * Parse TVs/TLVs. Since we do not yet know the length of the
1882 * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
1883 * just try to find the keyName-NAI first so that we can check the
1884 * Authentication Tag.
1885 */
1886 if (erp_parse_tlvs(pos, end, &parse, 1) < 0)
1887 return;
1888
1889 if (!parse.keyname) {
1890 wpa_printf(MSG_DEBUG,
1891 "EAP: No keyName-NAI in EAP-Finish/Re-auth Packet");
1892 return;
1893 }
1894
1895 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Finish/Re-auth - keyName-NAI",
1896 parse.keyname, parse.keyname_len);
1897 if (parse.keyname_len > 253) {
1898 wpa_printf(MSG_DEBUG,
1899 "EAP: Too long keyName-NAI in EAP-Finish/Re-auth");
1900 return;
1901 }
1902 os_memcpy(nai, parse.keyname, parse.keyname_len);
1903 nai[parse.keyname_len] = '\0';
1904
1905 erp = eap_erp_get_key_nai(sm, nai);
1906 if (!erp) {
1907 wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
1908 nai);
1909 return;
1910 }
1911
1912 /* Is there enough room for Cryptosuite and Authentication Tag? */
1913 start = parse.keyname + parse.keyname_len;
1914 max_len = end - start;
1915 hash_len = 16;
1916 if (max_len < 1 + (int) hash_len) {
1917 wpa_printf(MSG_DEBUG,
1918 "EAP: Not enough room for Authentication Tag");
1919 if (flags & 0x80)
1920 goto no_auth_tag;
1921 return;
1922 }
1923 if (end[-17] != EAP_ERP_CS_HMAC_SHA256_128) {
1924 wpa_printf(MSG_DEBUG, "EAP: Different Cryptosuite used");
1925 if (flags & 0x80)
1926 goto no_auth_tag;
1927 return;
1928 }
1929
1930 if (hmac_sha256(erp->rIK, erp->rIK_len, (const u8 *) hdr,
1931 end - ((const u8 *) hdr) - hash_len, hash) < 0)
1932 return;
1933 if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
1934 wpa_printf(MSG_DEBUG,
1935 "EAP: Authentication Tag mismatch");
1936 return;
1937 }
1938 auth_tag_ok = 1;
1939 end -= 1 + hash_len;
1940
1941no_auth_tag:
1942 /*
1943 * Parse TVs/TLVs again now that we know the exact part of the buffer
1944 * that contains them.
1945 */
1946 wpa_hexdump(MSG_DEBUG, "EAP: EAP-Finish/Re-Auth TVs/TLVs",
1947 pos, end - pos);
1948 if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
1949 return;
1950
1951 if (flags & 0x80 || !auth_tag_ok) {
1952 wpa_printf(MSG_DEBUG,
1953 "EAP: EAP-Finish/Re-auth indicated failure");
Hai Shalome21d4e82020-04-29 16:34:06 -07001954 eapol_set_bool(sm, EAPOL_eapFail, true);
1955 eapol_set_bool(sm, EAPOL_eapReq, false);
1956 eapol_set_bool(sm, EAPOL_eapNoResp, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001957 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
1958 "EAP authentication failed");
1959 sm->prev_failure = 1;
1960 wpa_printf(MSG_DEBUG,
1961 "EAP: Drop ERP key to try full authentication on next attempt");
1962 eap_peer_erp_free_key(erp);
1963 return;
1964 }
1965
1966 eap_sm_free_key(sm);
1967 sm->eapKeyDataLen = 0;
1968 sm->eapKeyData = os_malloc(erp->rRK_len);
1969 if (!sm->eapKeyData)
1970 return;
1971 sm->eapKeyDataLen = erp->rRK_len;
1972
1973 WPA_PUT_BE16(seed, seq);
1974 WPA_PUT_BE16(&seed[2], erp->rRK_len);
1975 if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
1976 "Re-authentication Master Session Key@ietf.org",
1977 seed, sizeof(seed),
1978 sm->eapKeyData, erp->rRK_len) < 0) {
1979 wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
1980 eap_sm_free_key(sm);
1981 return;
1982 }
1983 wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
1984 sm->eapKeyData, sm->eapKeyDataLen);
Hai Shalome21d4e82020-04-29 16:34:06 -07001985 sm->eapKeyAvailable = true;
1986 eapol_set_bool(sm, EAPOL_eapSuccess, true);
1987 eapol_set_bool(sm, EAPOL_eapReq, false);
1988 eapol_set_bool(sm, EAPOL_eapNoResp, true);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001989 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1990 "EAP re-authentication completed successfully");
1991#endif /* CONFIG_ERP */
1992}
1993
1994
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001995static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
1996{
1997 const struct eap_hdr *hdr;
1998 size_t plen;
1999 const u8 *pos;
2000
Hai Shalome21d4e82020-04-29 16:34:06 -07002001 sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002002 sm->reqId = 0;
2003 sm->reqMethod = EAP_TYPE_NONE;
2004 sm->reqVendor = EAP_VENDOR_IETF;
2005 sm->reqVendorMethod = EAP_TYPE_NONE;
2006
2007 if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
2008 return;
2009
2010 hdr = wpabuf_head(req);
2011 plen = be_to_host16(hdr->length);
2012 if (plen > wpabuf_len(req)) {
2013 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
2014 "(len=%lu plen=%lu)",
2015 (unsigned long) wpabuf_len(req),
2016 (unsigned long) plen);
2017 return;
2018 }
2019
2020 sm->reqId = hdr->identifier;
2021
2022 if (sm->workaround) {
2023 const u8 *addr[1];
2024 addr[0] = wpabuf_head(req);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002025 sha1_vector(1, addr, &plen, sm->req_sha1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002026 }
2027
2028 switch (hdr->code) {
2029 case EAP_CODE_REQUEST:
2030 if (plen < sizeof(*hdr) + 1) {
2031 wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
2032 "no Type field");
2033 return;
2034 }
Hai Shalome21d4e82020-04-29 16:34:06 -07002035 sm->rxReq = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002036 pos = (const u8 *) (hdr + 1);
2037 sm->reqMethod = *pos++;
2038 if (sm->reqMethod == EAP_TYPE_EXPANDED) {
2039 if (plen < sizeof(*hdr) + 8) {
2040 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
2041 "expanded EAP-Packet (plen=%lu)",
2042 (unsigned long) plen);
2043 return;
2044 }
2045 sm->reqVendor = WPA_GET_BE24(pos);
2046 pos += 3;
2047 sm->reqVendorMethod = WPA_GET_BE32(pos);
2048 }
2049 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
2050 "method=%u vendor=%u vendorMethod=%u",
2051 sm->reqId, sm->reqMethod, sm->reqVendor,
2052 sm->reqVendorMethod);
2053 break;
2054 case EAP_CODE_RESPONSE:
2055 if (sm->selectedMethod == EAP_TYPE_LEAP) {
2056 /*
2057 * LEAP differs from RFC 4137 by using reversed roles
2058 * for mutual authentication and because of this, we
2059 * need to accept EAP-Response frames if LEAP is used.
2060 */
2061 if (plen < sizeof(*hdr) + 1) {
2062 wpa_printf(MSG_DEBUG, "EAP: Too short "
2063 "EAP-Response - no Type field");
2064 return;
2065 }
Hai Shalome21d4e82020-04-29 16:34:06 -07002066 sm->rxResp = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002067 pos = (const u8 *) (hdr + 1);
2068 sm->reqMethod = *pos;
2069 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
2070 "LEAP method=%d id=%d",
2071 sm->reqMethod, sm->reqId);
2072 break;
2073 }
2074 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
2075 break;
2076 case EAP_CODE_SUCCESS:
2077 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002078 eap_notify_status(sm, "completion", "success");
Hai Shalome21d4e82020-04-29 16:34:06 -07002079 sm->rxSuccess = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002080 break;
2081 case EAP_CODE_FAILURE:
2082 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
Dmitry Shmidt04949592012-07-19 12:16:46 -07002083 eap_notify_status(sm, "completion", "failure");
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -07002084
2085 /* Get the error code from method */
Ahmed ElArabawyab9f5af2018-04-04 18:56:43 -07002086 if (sm->m && sm->m->get_error_code) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002087 int error_code;
2088
Ahmed ElArabawy9c86a7f2018-03-15 09:00:10 -07002089 error_code = sm->m->get_error_code(sm->eap_method_priv);
2090 if (error_code != NO_EAP_METHOD_ERROR)
2091 eap_report_error(sm, error_code);
2092 }
Hai Shalome21d4e82020-04-29 16:34:06 -07002093 sm->rxFailure = true;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002094 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002095 case EAP_CODE_INITIATE:
2096 eap_peer_initiate(sm, hdr, plen);
2097 break;
2098 case EAP_CODE_FINISH:
2099 eap_peer_finish(sm, hdr, plen);
2100 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002101 default:
2102 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
2103 "code %d", hdr->code);
2104 break;
2105 }
2106}
2107
2108
2109static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
2110 union tls_event_data *data)
2111{
2112 struct eap_sm *sm = ctx;
2113 char *hash_hex = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002114
2115 switch (ev) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07002116 case TLS_CERT_CHAIN_SUCCESS:
2117 eap_notify_status(sm, "remote certificate verification",
2118 "success");
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002119 if (sm->ext_cert_check) {
2120 sm->waiting_ext_cert_check = 1;
2121 eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
2122 NULL, 0);
2123 }
Dmitry Shmidt04949592012-07-19 12:16:46 -07002124 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002125 case TLS_CERT_CHAIN_FAILURE:
2126 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
2127 "reason=%d depth=%d subject='%s' err='%s'",
2128 data->cert_fail.reason,
2129 data->cert_fail.depth,
2130 data->cert_fail.subject,
2131 data->cert_fail.reason_txt);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002132 eap_notify_status(sm, "remote certificate verification",
2133 data->cert_fail.reason_txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002134 break;
2135 case TLS_PEER_CERTIFICATE:
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002136 if (!sm->eapol_cb->notify_cert)
2137 break;
2138
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002139 if (data->peer_cert.hash) {
2140 size_t len = data->peer_cert.hash_len * 2 + 1;
2141 hash_hex = os_malloc(len);
2142 if (hash_hex) {
2143 wpa_snprintf_hex(hash_hex, len,
2144 data->peer_cert.hash,
2145 data->peer_cert.hash_len);
2146 }
2147 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002148
Hai Shalom81f62d82019-07-22 12:10:00 -07002149 sm->eapol_cb->notify_cert(sm->eapol_ctx, &data->peer_cert,
2150 hash_hex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002151 break;
Dmitry Shmidt04949592012-07-19 12:16:46 -07002152 case TLS_ALERT:
2153 if (data->alert.is_local)
2154 eap_notify_status(sm, "local TLS alert",
2155 data->alert.description);
2156 else
2157 eap_notify_status(sm, "remote TLS alert",
2158 data->alert.description);
2159 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002160 }
2161
2162 os_free(hash_hex);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002163}
2164
2165
2166/**
2167 * eap_peer_sm_init - Allocate and initialize EAP peer state machine
2168 * @eapol_ctx: Context data to be used with eapol_cb calls
2169 * @eapol_cb: Pointer to EAPOL callback functions
2170 * @msg_ctx: Context data for wpa_msg() calls
2171 * @conf: EAP configuration
2172 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
2173 *
2174 * This function allocates and initializes an EAP state machine. In addition,
2175 * this initializes TLS library for the new EAP state machine. eapol_cb pointer
2176 * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
2177 * state machine. Consequently, the caller must make sure that this data
2178 * structure remains alive while the EAP state machine is active.
2179 */
2180struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
Dmitry Shmidt1d755d02015-04-28 10:34:29 -07002181 const struct eapol_callbacks *eapol_cb,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002182 void *msg_ctx, struct eap_config *conf)
2183{
2184 struct eap_sm *sm;
2185 struct tls_config tlsconf;
2186
2187 sm = os_zalloc(sizeof(*sm));
2188 if (sm == NULL)
2189 return NULL;
2190 sm->eapol_ctx = eapol_ctx;
2191 sm->eapol_cb = eapol_cb;
2192 sm->msg_ctx = msg_ctx;
2193 sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
2194 sm->wps = conf->wps;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002195 dl_list_init(&sm->erp_keys);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002196
2197 os_memset(&tlsconf, 0, sizeof(tlsconf));
2198 tlsconf.opensc_engine_path = conf->opensc_engine_path;
2199 tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
2200 tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002201 tlsconf.openssl_ciphers = conf->openssl_ciphers;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002202#ifdef CONFIG_FIPS
2203 tlsconf.fips_mode = 1;
2204#endif /* CONFIG_FIPS */
2205 tlsconf.event_cb = eap_peer_sm_tls_event;
2206 tlsconf.cb_ctx = sm;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002207 tlsconf.cert_in_cb = conf->cert_in_cb;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002208 sm->ssl_ctx = tls_init(&tlsconf);
2209 if (sm->ssl_ctx == NULL) {
2210 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
2211 "context.");
2212 os_free(sm);
2213 return NULL;
2214 }
2215
Dmitry Shmidt04949592012-07-19 12:16:46 -07002216 sm->ssl_ctx2 = tls_init(&tlsconf);
2217 if (sm->ssl_ctx2 == NULL) {
2218 wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
2219 "context (2).");
2220 /* Run without separate TLS context within TLS tunnel */
2221 }
2222
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002223 return sm;
2224}
2225
2226
2227/**
2228 * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
2229 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2230 *
2231 * This function deinitializes EAP state machine and frees all allocated
2232 * resources.
2233 */
2234void eap_peer_sm_deinit(struct eap_sm *sm)
2235{
2236 if (sm == NULL)
2237 return;
2238 eap_deinit_prev_method(sm, "EAP deinit");
2239 eap_sm_abort(sm);
Dmitry Shmidt04949592012-07-19 12:16:46 -07002240 if (sm->ssl_ctx2)
2241 tls_deinit(sm->ssl_ctx2);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002242 tls_deinit(sm->ssl_ctx);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002243 eap_peer_erp_free_keys(sm);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002244 os_free(sm);
2245}
2246
2247
2248/**
2249 * eap_peer_sm_step - Step EAP peer state machine
2250 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2251 * Returns: 1 if EAP state was changed or 0 if not
2252 *
2253 * This function advances EAP state machine to a new state to match with the
2254 * current variables. This should be called whenever variables used by the EAP
2255 * state machine have changed.
2256 */
2257int eap_peer_sm_step(struct eap_sm *sm)
2258{
2259 int res = 0;
2260 do {
Hai Shalome21d4e82020-04-29 16:34:06 -07002261 sm->changed = false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002262 SM_STEP_RUN(EAP);
2263 if (sm->changed)
2264 res = 1;
2265 } while (sm->changed);
2266 return res;
2267}
2268
2269
2270/**
2271 * eap_sm_abort - Abort EAP authentication
2272 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2273 *
2274 * Release system resources that have been allocated for the authentication
2275 * session without fully deinitializing the EAP state machine.
2276 */
2277void eap_sm_abort(struct eap_sm *sm)
2278{
2279 wpabuf_free(sm->lastRespData);
2280 sm->lastRespData = NULL;
2281 wpabuf_free(sm->eapRespData);
2282 sm->eapRespData = NULL;
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002283 eap_sm_free_key(sm);
Dmitry Shmidtf8623282013-02-20 14:34:59 -08002284 os_free(sm->eapSessionId);
2285 sm->eapSessionId = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002286
2287 /* This is not clearly specified in the EAP statemachines draft, but
2288 * it seems necessary to make sure that some of the EAPOL variables get
2289 * cleared for the next authentication. */
Hai Shalome21d4e82020-04-29 16:34:06 -07002290 eapol_set_bool(sm, EAPOL_eapSuccess, false);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002291}
2292
2293
2294#ifdef CONFIG_CTRL_IFACE
2295static const char * eap_sm_state_txt(int state)
2296{
2297 switch (state) {
2298 case EAP_INITIALIZE:
2299 return "INITIALIZE";
2300 case EAP_DISABLED:
2301 return "DISABLED";
2302 case EAP_IDLE:
2303 return "IDLE";
2304 case EAP_RECEIVED:
2305 return "RECEIVED";
2306 case EAP_GET_METHOD:
2307 return "GET_METHOD";
2308 case EAP_METHOD:
2309 return "METHOD";
2310 case EAP_SEND_RESPONSE:
2311 return "SEND_RESPONSE";
2312 case EAP_DISCARD:
2313 return "DISCARD";
2314 case EAP_IDENTITY:
2315 return "IDENTITY";
2316 case EAP_NOTIFICATION:
2317 return "NOTIFICATION";
2318 case EAP_RETRANSMIT:
2319 return "RETRANSMIT";
2320 case EAP_SUCCESS:
2321 return "SUCCESS";
2322 case EAP_FAILURE:
2323 return "FAILURE";
2324 default:
2325 return "UNKNOWN";
2326 }
2327}
2328#endif /* CONFIG_CTRL_IFACE */
2329
2330
2331#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
2332static const char * eap_sm_method_state_txt(EapMethodState state)
2333{
2334 switch (state) {
2335 case METHOD_NONE:
2336 return "NONE";
2337 case METHOD_INIT:
2338 return "INIT";
2339 case METHOD_CONT:
2340 return "CONT";
2341 case METHOD_MAY_CONT:
2342 return "MAY_CONT";
2343 case METHOD_DONE:
2344 return "DONE";
2345 default:
2346 return "UNKNOWN";
2347 }
2348}
2349
2350
2351static const char * eap_sm_decision_txt(EapDecision decision)
2352{
2353 switch (decision) {
2354 case DECISION_FAIL:
2355 return "FAIL";
2356 case DECISION_COND_SUCC:
2357 return "COND_SUCC";
2358 case DECISION_UNCOND_SUCC:
2359 return "UNCOND_SUCC";
2360 default:
2361 return "UNKNOWN";
2362 }
2363}
2364#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
2365
2366
2367#ifdef CONFIG_CTRL_IFACE
2368
2369/**
2370 * eap_sm_get_status - Get EAP state machine status
2371 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2372 * @buf: Buffer for status information
2373 * @buflen: Maximum buffer length
2374 * @verbose: Whether to include verbose status information
2375 * Returns: Number of bytes written to buf.
2376 *
2377 * Query EAP state machine for status information. This function fills in a
2378 * text area with current status information from the EAPOL state machine. If
2379 * the buffer (buf) is not large enough, status information will be truncated
2380 * to fit the buffer.
2381 */
2382int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
2383{
2384 int len, ret;
2385
2386 if (sm == NULL)
2387 return 0;
2388
2389 len = os_snprintf(buf, buflen,
2390 "EAP state=%s\n",
2391 eap_sm_state_txt(sm->EAP_state));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002392 if (os_snprintf_error(buflen, len))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002393 return 0;
2394
2395 if (sm->selectedMethod != EAP_TYPE_NONE) {
2396 const char *name;
2397 if (sm->m) {
2398 name = sm->m->name;
2399 } else {
2400 const struct eap_method *m =
2401 eap_peer_get_eap_method(EAP_VENDOR_IETF,
2402 sm->selectedMethod);
2403 if (m)
2404 name = m->name;
2405 else
2406 name = "?";
2407 }
2408 ret = os_snprintf(buf + len, buflen - len,
2409 "selectedMethod=%d (EAP-%s)\n",
2410 sm->selectedMethod, name);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002411 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002412 return len;
2413 len += ret;
2414
2415 if (sm->m && sm->m->get_status) {
2416 len += sm->m->get_status(sm, sm->eap_method_priv,
2417 buf + len, buflen - len,
2418 verbose);
2419 }
2420 }
2421
2422 if (verbose) {
2423 ret = os_snprintf(buf + len, buflen - len,
2424 "reqMethod=%d\n"
2425 "methodState=%s\n"
2426 "decision=%s\n"
2427 "ClientTimeout=%d\n",
2428 sm->reqMethod,
2429 eap_sm_method_state_txt(sm->methodState),
2430 eap_sm_decision_txt(sm->decision),
2431 sm->ClientTimeout);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08002432 if (os_snprintf_error(buflen - len, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002433 return len;
2434 len += ret;
2435 }
2436
2437 return len;
2438}
2439#endif /* CONFIG_CTRL_IFACE */
2440
2441
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002442static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002443 const char *msg, size_t msglen)
2444{
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002445#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002446 struct eap_peer_config *config;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002447 const char *txt = NULL;
2448 char *tmp;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002449
2450 if (sm == NULL)
2451 return;
2452 config = eap_get_config(sm);
2453 if (config == NULL)
2454 return;
2455
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002456 switch (field) {
2457 case WPA_CTRL_REQ_EAP_IDENTITY:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002458 config->pending_req_identity++;
2459 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002460 case WPA_CTRL_REQ_EAP_PASSWORD:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002461 config->pending_req_password++;
2462 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002463 case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002464 config->pending_req_new_password++;
2465 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002466 case WPA_CTRL_REQ_EAP_PIN:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002467 config->pending_req_pin++;
2468 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002469 case WPA_CTRL_REQ_EAP_OTP:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002470 if (msg) {
2471 tmp = os_malloc(msglen + 3);
2472 if (tmp == NULL)
2473 return;
2474 tmp[0] = '[';
2475 os_memcpy(tmp + 1, msg, msglen);
2476 tmp[msglen + 1] = ']';
2477 tmp[msglen + 2] = '\0';
2478 txt = tmp;
2479 os_free(config->pending_req_otp);
2480 config->pending_req_otp = tmp;
2481 config->pending_req_otp_len = msglen + 3;
2482 } else {
2483 if (config->pending_req_otp == NULL)
2484 return;
2485 txt = config->pending_req_otp;
2486 }
2487 break;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002488 case WPA_CTRL_REQ_EAP_PASSPHRASE:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002489 config->pending_req_passphrase++;
2490 break;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002491 case WPA_CTRL_REQ_SIM:
Dmitry Shmidtebd93af2017-02-21 13:40:44 -08002492 config->pending_req_sim++;
Dmitry Shmidt051af732013-10-22 13:52:46 -07002493 txt = msg;
2494 break;
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002495 case WPA_CTRL_REQ_EXT_CERT_CHECK:
2496 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002497 default:
2498 return;
2499 }
2500
2501 if (sm->eapol_cb->eap_param_needed)
2502 sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002503#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
Dmitry Shmidt55840ad2015-12-14 12:45:46 -08002504}
2505
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002506
2507const char * eap_sm_get_method_name(struct eap_sm *sm)
2508{
2509 if (sm->m == NULL)
2510 return "UNKNOWN";
2511 return sm->m->name;
2512}
2513
2514
2515/**
2516 * eap_sm_request_identity - Request identity from user (ctrl_iface)
2517 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2518 *
2519 * EAP methods can call this function to request identity information for the
2520 * current network. This is normally called when the identity is not included
2521 * in the network configuration. The request will be sent to monitor programs
2522 * through the control interface.
2523 */
2524void eap_sm_request_identity(struct eap_sm *sm)
2525{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002526 eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002527}
2528
2529
2530/**
2531 * eap_sm_request_password - Request password from user (ctrl_iface)
2532 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2533 *
2534 * EAP methods can call this function to request password information for the
2535 * current network. This is normally called when the password is not included
2536 * in the network configuration. The request will be sent to monitor programs
2537 * through the control interface.
2538 */
2539void eap_sm_request_password(struct eap_sm *sm)
2540{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002541 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002542}
2543
2544
2545/**
2546 * eap_sm_request_new_password - Request new password from user (ctrl_iface)
2547 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2548 *
2549 * EAP methods can call this function to request new password information for
2550 * the current network. This is normally called when the EAP method indicates
2551 * that the current password has expired and password change is required. The
2552 * request will be sent to monitor programs through the control interface.
2553 */
2554void eap_sm_request_new_password(struct eap_sm *sm)
2555{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002556 eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002557}
2558
2559
2560/**
2561 * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
2562 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2563 *
2564 * EAP methods can call this function to request SIM or smart card PIN
2565 * information for the current network. This is normally called when the PIN is
2566 * not included in the network configuration. The request will be sent to
2567 * monitor programs through the control interface.
2568 */
2569void eap_sm_request_pin(struct eap_sm *sm)
2570{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002571 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002572}
2573
2574
2575/**
2576 * eap_sm_request_otp - Request one time password from user (ctrl_iface)
2577 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2578 * @msg: Message to be displayed to the user when asking for OTP
2579 * @msg_len: Length of the user displayable message
2580 *
2581 * EAP methods can call this function to request open time password (OTP) for
2582 * the current network. The request will be sent to monitor programs through
2583 * the control interface.
2584 */
2585void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
2586{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002587 eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002588}
2589
2590
2591/**
2592 * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
2593 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2594 *
2595 * EAP methods can call this function to request passphrase for a private key
2596 * for the current network. This is normally called when the passphrase is not
2597 * included in the network configuration. The request will be sent to monitor
2598 * programs through the control interface.
2599 */
2600void eap_sm_request_passphrase(struct eap_sm *sm)
2601{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002602 eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002603}
2604
2605
2606/**
Dmitry Shmidt051af732013-10-22 13:52:46 -07002607 * eap_sm_request_sim - Request external SIM processing
2608 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2609 * @req: EAP method specific request
2610 */
2611void eap_sm_request_sim(struct eap_sm *sm, const char *req)
2612{
2613 eap_sm_request(sm, WPA_CTRL_REQ_SIM, req, os_strlen(req));
2614}
2615
2616
2617/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002618 * eap_sm_notify_ctrl_attached - Notification of attached monitor
2619 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2620 *
2621 * Notify EAP state machines that a monitor was attached to the control
2622 * interface to trigger re-sending of pending requests for user input.
2623 */
2624void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
2625{
2626 struct eap_peer_config *config = eap_get_config(sm);
2627
2628 if (config == NULL)
2629 return;
2630
2631 /* Re-send any pending requests for user data since a new control
2632 * interface was added. This handles cases where the EAP authentication
2633 * starts immediately after system startup when the user interface is
2634 * not yet running. */
2635 if (config->pending_req_identity)
2636 eap_sm_request_identity(sm);
2637 if (config->pending_req_password)
2638 eap_sm_request_password(sm);
2639 if (config->pending_req_new_password)
2640 eap_sm_request_new_password(sm);
2641 if (config->pending_req_otp)
2642 eap_sm_request_otp(sm, NULL, 0);
2643 if (config->pending_req_pin)
2644 eap_sm_request_pin(sm);
2645 if (config->pending_req_passphrase)
2646 eap_sm_request_passphrase(sm);
2647}
2648
2649
2650static int eap_allowed_phase2_type(int vendor, int type)
2651{
Hai Shalomc3565922019-10-28 11:58:20 -07002652 if (vendor == EAP_VENDOR_HOSTAP)
2653 return 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002654 if (vendor != EAP_VENDOR_IETF)
2655 return 0;
2656 return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
Hai Shalom81f62d82019-07-22 12:10:00 -07002657 type != EAP_TYPE_FAST && type != EAP_TYPE_TEAP;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002658}
2659
2660
2661/**
2662 * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
2663 * @name: EAP method name, e.g., MD5
2664 * @vendor: Buffer for returning EAP Vendor-Id
2665 * Returns: EAP method type or %EAP_TYPE_NONE if not found
2666 *
2667 * This function maps EAP type names into EAP type numbers that are allowed for
2668 * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
2669 * EAP-PEAP, EAP-TTLS, and EAP-FAST.
2670 */
2671u32 eap_get_phase2_type(const char *name, int *vendor)
2672{
2673 int v;
Dmitry Shmidtaf9da312015-04-03 10:03:11 -07002674 u32 type = eap_peer_get_type(name, &v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002675 if (eap_allowed_phase2_type(v, type)) {
2676 *vendor = v;
2677 return type;
2678 }
2679 *vendor = EAP_VENDOR_IETF;
2680 return EAP_TYPE_NONE;
2681}
2682
2683
2684/**
2685 * eap_get_phase2_types - Get list of allowed EAP phase 2 types
2686 * @config: Pointer to a network configuration
2687 * @count: Pointer to a variable to be filled with number of returned EAP types
2688 * Returns: Pointer to allocated type list or %NULL on failure
2689 *
2690 * This function generates an array of allowed EAP phase 2 (tunneled) types for
2691 * the given network configuration.
2692 */
2693struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
2694 size_t *count)
2695{
2696 struct eap_method_type *buf;
2697 u32 method;
2698 int vendor;
2699 size_t mcount;
2700 const struct eap_method *methods, *m;
2701
2702 methods = eap_peer_get_methods(&mcount);
2703 if (methods == NULL)
2704 return NULL;
2705 *count = 0;
2706 buf = os_malloc(mcount * sizeof(struct eap_method_type));
2707 if (buf == NULL)
2708 return NULL;
2709
2710 for (m = methods; m; m = m->next) {
2711 vendor = m->vendor;
2712 method = m->method;
2713 if (eap_allowed_phase2_type(vendor, method)) {
2714 if (vendor == EAP_VENDOR_IETF &&
2715 method == EAP_TYPE_TLS && config &&
Hai Shalomc3565922019-10-28 11:58:20 -07002716 !config->phase2_cert.private_key)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002717 continue;
2718 buf[*count].vendor = vendor;
2719 buf[*count].method = method;
2720 (*count)++;
2721 }
2722 }
2723
2724 return buf;
2725}
2726
2727
2728/**
2729 * eap_set_fast_reauth - Update fast_reauth setting
2730 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2731 * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
2732 */
2733void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
2734{
2735 sm->fast_reauth = enabled;
2736}
2737
2738
2739/**
2740 * eap_set_workaround - Update EAP workarounds setting
2741 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2742 * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
2743 */
2744void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
2745{
2746 sm->workaround = workaround;
2747}
2748
2749
2750/**
2751 * eap_get_config - Get current network configuration
2752 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2753 * Returns: Pointer to the current network configuration or %NULL if not found
2754 *
2755 * EAP peer methods should avoid using this function if they can use other
2756 * access functions, like eap_get_config_identity() and
2757 * eap_get_config_password(), that do not require direct access to
2758 * struct eap_peer_config.
2759 */
2760struct eap_peer_config * eap_get_config(struct eap_sm *sm)
2761{
2762 return sm->eapol_cb->get_config(sm->eapol_ctx);
2763}
2764
2765
2766/**
2767 * eap_get_config_identity - Get identity from the network configuration
2768 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2769 * @len: Buffer for the length of the identity
2770 * Returns: Pointer to the identity or %NULL if not found
2771 */
2772const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
2773{
2774 struct eap_peer_config *config = eap_get_config(sm);
Hai Shalomc3565922019-10-28 11:58:20 -07002775
2776 if (!config)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002777 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07002778
2779 if (sm->use_machine_cred) {
2780 *len = config->machine_identity_len;
2781 return config->machine_identity;
2782 }
2783
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002784 *len = config->identity_len;
2785 return config->identity;
2786}
2787
2788
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002789static int eap_get_ext_password(struct eap_sm *sm,
2790 struct eap_peer_config *config)
2791{
2792 char *name;
Hai Shalomc3565922019-10-28 11:58:20 -07002793 const u8 *password;
2794 size_t password_len;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002795
Hai Shalomc3565922019-10-28 11:58:20 -07002796 if (sm->use_machine_cred) {
2797 password = config->machine_password;
2798 password_len = config->machine_password_len;
2799 } else {
2800 password = config->password;
2801 password_len = config->password_len;
2802 }
2803
2804 if (!password)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002805 return -1;
2806
Hai Shalomc3565922019-10-28 11:58:20 -07002807 name = os_zalloc(password_len + 1);
2808 if (!name)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002809 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07002810 os_memcpy(name, password, password_len);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002811
2812 ext_password_free(sm->ext_pw_buf);
2813 sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
2814 os_free(name);
2815
2816 return sm->ext_pw_buf == NULL ? -1 : 0;
2817}
2818
2819
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002820/**
2821 * eap_get_config_password - Get password from the network configuration
2822 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2823 * @len: Buffer for the length of the password
2824 * Returns: Pointer to the password or %NULL if not found
2825 */
2826const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
2827{
2828 struct eap_peer_config *config = eap_get_config(sm);
Hai Shalomc3565922019-10-28 11:58:20 -07002829
2830 if (!config)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002831 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002832
Hai Shalomc3565922019-10-28 11:58:20 -07002833 if ((sm->use_machine_cred &&
2834 (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
2835 (!sm->use_machine_cred &&
2836 (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002837 if (eap_get_ext_password(sm, config) < 0)
2838 return NULL;
2839 *len = wpabuf_len(sm->ext_pw_buf);
2840 return wpabuf_head(sm->ext_pw_buf);
2841 }
2842
Hai Shalomc3565922019-10-28 11:58:20 -07002843 if (sm->use_machine_cred) {
2844 *len = config->machine_password_len;
2845 return config->machine_password;
2846 }
2847
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002848 *len = config->password_len;
2849 return config->password;
2850}
2851
2852
2853/**
2854 * eap_get_config_password2 - Get password from the network configuration
2855 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2856 * @len: Buffer for the length of the password
2857 * @hash: Buffer for returning whether the password is stored as a
2858 * NtPasswordHash instead of plaintext password; can be %NULL if this
2859 * information is not needed
2860 * Returns: Pointer to the password or %NULL if not found
2861 */
2862const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
2863{
2864 struct eap_peer_config *config = eap_get_config(sm);
Hai Shalomc3565922019-10-28 11:58:20 -07002865
2866 if (!config)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002867 return NULL;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002868
Hai Shalomc3565922019-10-28 11:58:20 -07002869 if ((sm->use_machine_cred &&
2870 (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
2871 (!sm->use_machine_cred &&
2872 (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002873 if (eap_get_ext_password(sm, config) < 0)
2874 return NULL;
Dmitry Shmidt344abd32014-01-14 13:17:00 -08002875 if (hash)
2876 *hash = 0;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002877 *len = wpabuf_len(sm->ext_pw_buf);
2878 return wpabuf_head(sm->ext_pw_buf);
2879 }
2880
Hai Shalomc3565922019-10-28 11:58:20 -07002881 if (sm->use_machine_cred) {
2882 *len = config->machine_password_len;
2883 if (hash)
2884 *hash = !!(config->flags &
2885 EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
2886 return config->machine_password;
2887 }
2888
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002889 *len = config->password_len;
2890 if (hash)
2891 *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
2892 return config->password;
2893}
2894
2895
2896/**
2897 * eap_get_config_new_password - Get new password from network configuration
2898 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2899 * @len: Buffer for the length of the new password
2900 * Returns: Pointer to the new password or %NULL if not found
2901 */
2902const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
2903{
2904 struct eap_peer_config *config = eap_get_config(sm);
2905 if (config == NULL)
2906 return NULL;
2907 *len = config->new_password_len;
2908 return config->new_password;
2909}
2910
2911
2912/**
2913 * eap_get_config_otp - Get one-time password from the network configuration
2914 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2915 * @len: Buffer for the length of the one-time password
2916 * Returns: Pointer to the one-time password or %NULL if not found
2917 */
2918const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
2919{
2920 struct eap_peer_config *config = eap_get_config(sm);
2921 if (config == NULL)
2922 return NULL;
2923 *len = config->otp_len;
2924 return config->otp;
2925}
2926
2927
2928/**
2929 * eap_clear_config_otp - Clear used one-time password
2930 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2931 *
2932 * This function clears a used one-time password (OTP) from the current network
2933 * configuration. This should be called when the OTP has been used and is not
2934 * needed anymore.
2935 */
2936void eap_clear_config_otp(struct eap_sm *sm)
2937{
2938 struct eap_peer_config *config = eap_get_config(sm);
2939 if (config == NULL)
2940 return;
2941 os_memset(config->otp, 0, config->otp_len);
2942 os_free(config->otp);
2943 config->otp = NULL;
2944 config->otp_len = 0;
2945}
2946
2947
2948/**
2949 * eap_get_config_phase1 - Get phase1 data from the network configuration
2950 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2951 * Returns: Pointer to the phase1 data or %NULL if not found
2952 */
2953const char * eap_get_config_phase1(struct eap_sm *sm)
2954{
2955 struct eap_peer_config *config = eap_get_config(sm);
2956 if (config == NULL)
2957 return NULL;
2958 return config->phase1;
2959}
2960
2961
2962/**
2963 * eap_get_config_phase2 - Get phase2 data from the network configuration
2964 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2965 * Returns: Pointer to the phase1 data or %NULL if not found
2966 */
2967const char * eap_get_config_phase2(struct eap_sm *sm)
2968{
2969 struct eap_peer_config *config = eap_get_config(sm);
2970 if (config == NULL)
2971 return NULL;
2972 return config->phase2;
2973}
2974
2975
2976int eap_get_config_fragment_size(struct eap_sm *sm)
2977{
2978 struct eap_peer_config *config = eap_get_config(sm);
2979 if (config == NULL)
2980 return -1;
2981 return config->fragment_size;
2982}
2983
2984
2985/**
2986 * eap_key_available - Get key availability (eapKeyAvailable variable)
2987 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2988 * Returns: 1 if EAP keying material is available, 0 if not
2989 */
2990int eap_key_available(struct eap_sm *sm)
2991{
2992 return sm ? sm->eapKeyAvailable : 0;
2993}
2994
2995
2996/**
2997 * eap_notify_success - Notify EAP state machine about external success trigger
2998 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2999 *
3000 * This function is called when external event, e.g., successful completion of
3001 * WPA-PSK key handshake, is indicating that EAP state machine should move to
3002 * success state. This is mainly used with security modes that do not use EAP
3003 * state machine (e.g., WPA-PSK).
3004 */
3005void eap_notify_success(struct eap_sm *sm)
3006{
3007 if (sm) {
3008 sm->decision = DECISION_COND_SUCC;
3009 sm->EAP_state = EAP_SUCCESS;
3010 }
3011}
3012
3013
3014/**
3015 * eap_notify_lower_layer_success - Notification of lower layer success
3016 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3017 *
3018 * Notify EAP state machines that a lower layer has detected a successful
3019 * authentication. This is used to recover from dropped EAP-Success messages.
3020 */
3021void eap_notify_lower_layer_success(struct eap_sm *sm)
3022{
3023 if (sm == NULL)
3024 return;
3025
3026 if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
3027 sm->decision == DECISION_FAIL ||
3028 (sm->methodState != METHOD_MAY_CONT &&
3029 sm->methodState != METHOD_DONE))
3030 return;
3031
3032 if (sm->eapKeyData != NULL)
Hai Shalome21d4e82020-04-29 16:34:06 -07003033 sm->eapKeyAvailable = true;
3034 eapol_set_bool(sm, EAPOL_eapSuccess, true);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003035 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
3036 "EAP authentication completed successfully (based on lower "
3037 "layer success)");
3038}
3039
3040
3041/**
Dmitry Shmidtf8623282013-02-20 14:34:59 -08003042 * eap_get_eapSessionId - Get Session-Id from EAP state machine
3043 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3044 * @len: Pointer to variable that will be set to number of bytes in the session
3045 * Returns: Pointer to the EAP Session-Id or %NULL on failure
3046 *
3047 * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
3048 * only after a successful authentication. EAP state machine continues to manage
3049 * the Session-Id and the caller must not change or free the returned data.
3050 */
3051const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
3052{
3053 if (sm == NULL || sm->eapSessionId == NULL) {
3054 *len = 0;
3055 return NULL;
3056 }
3057
3058 *len = sm->eapSessionIdLen;
3059 return sm->eapSessionId;
3060}
3061
3062
3063/**
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003064 * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
3065 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3066 * @len: Pointer to variable that will be set to number of bytes in the key
3067 * Returns: Pointer to the EAP keying data or %NULL on failure
3068 *
3069 * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
3070 * key is available only after a successful authentication. EAP state machine
3071 * continues to manage the key data and the caller must not change or free the
3072 * returned data.
3073 */
3074const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
3075{
3076 if (sm == NULL || sm->eapKeyData == NULL) {
3077 *len = 0;
3078 return NULL;
3079 }
3080
3081 *len = sm->eapKeyDataLen;
3082 return sm->eapKeyData;
3083}
3084
3085
3086/**
3087 * eap_get_eapKeyData - Get EAP response data
3088 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3089 * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
3090 *
3091 * Fetch EAP response (eapRespData) from the EAP state machine. This data is
3092 * available when EAP state machine has processed an incoming EAP request. The
3093 * EAP state machine does not maintain a reference to the response after this
3094 * function is called and the caller is responsible for freeing the data.
3095 */
3096struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
3097{
3098 struct wpabuf *resp;
3099
3100 if (sm == NULL || sm->eapRespData == NULL)
3101 return NULL;
3102
3103 resp = sm->eapRespData;
3104 sm->eapRespData = NULL;
3105
3106 return resp;
3107}
3108
3109
3110/**
3111 * eap_sm_register_scard_ctx - Notification of smart card context
3112 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3113 * @ctx: Context data for smart card operations
3114 *
3115 * Notify EAP state machines of context data for smart card operations. This
3116 * context data will be used as a parameter for scard_*() functions.
3117 */
3118void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
3119{
3120 if (sm)
3121 sm->scard_ctx = ctx;
3122}
3123
3124
3125/**
3126 * eap_set_config_blob - Set or add a named configuration blob
3127 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3128 * @blob: New value for the blob
3129 *
3130 * Adds a new configuration blob or replaces the current value of an existing
3131 * blob.
3132 */
3133void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
3134{
3135#ifndef CONFIG_NO_CONFIG_BLOBS
3136 sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
3137#endif /* CONFIG_NO_CONFIG_BLOBS */
3138}
3139
3140
3141/**
3142 * eap_get_config_blob - Get a named configuration blob
3143 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3144 * @name: Name of the blob
3145 * Returns: Pointer to blob data or %NULL if not found
3146 */
3147const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
3148 const char *name)
3149{
3150#ifndef CONFIG_NO_CONFIG_BLOBS
3151 return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
3152#else /* CONFIG_NO_CONFIG_BLOBS */
3153 return NULL;
3154#endif /* CONFIG_NO_CONFIG_BLOBS */
3155}
3156
3157
3158/**
3159 * eap_set_force_disabled - Set force_disabled flag
3160 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3161 * @disabled: 1 = EAP disabled, 0 = EAP enabled
3162 *
3163 * This function is used to force EAP state machine to be disabled when it is
3164 * not in use (e.g., with WPA-PSK or plaintext connections).
3165 */
3166void eap_set_force_disabled(struct eap_sm *sm, int disabled)
3167{
3168 sm->force_disabled = disabled;
3169}
3170
3171
Dmitry Shmidt051af732013-10-22 13:52:46 -07003172/**
3173 * eap_set_external_sim - Set external_sim flag
3174 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3175 * @external_sim: Whether external SIM/USIM processing is used
3176 */
3177void eap_set_external_sim(struct eap_sm *sm, int external_sim)
3178{
3179 sm->external_sim = external_sim;
3180}
3181
3182
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07003183 /**
3184 * eap_notify_pending - Notify that EAP method is ready to re-process a request
3185 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3186 *
3187 * An EAP method can perform a pending operation (e.g., to get a response from
3188 * an external process). Once the response is available, this function can be
3189 * used to request EAPOL state machine to retry delivering the previously
3190 * received (and still unanswered) EAP request to EAP state machine.
3191 */
3192void eap_notify_pending(struct eap_sm *sm)
3193{
3194 sm->eapol_cb->notify_pending(sm->eapol_ctx);
3195}
3196
3197
3198/**
3199 * eap_invalidate_cached_session - Mark cached session data invalid
3200 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3201 */
3202void eap_invalidate_cached_session(struct eap_sm *sm)
3203{
3204 if (sm)
3205 eap_deinit_prev_method(sm, "invalidate");
3206}
3207
3208
3209int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
3210{
3211 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
3212 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
3213 return 0; /* Not a WPS Enrollee */
3214
3215 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
3216 return 0; /* Not using PBC */
3217
3218 return 1;
3219}
3220
3221
3222int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
3223{
3224 if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
3225 os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
3226 return 0; /* Not a WPS Enrollee */
3227
3228 if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
3229 return 0; /* Not using PIN */
3230
3231 return 1;
3232}
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07003233
3234
3235void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
3236{
3237 ext_password_free(sm->ext_pw_buf);
3238 sm->ext_pw_buf = NULL;
3239 sm->ext_pw = ext;
3240}
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -07003241
3242
3243/**
3244 * eap_set_anon_id - Set or add anonymous identity
3245 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
3246 * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
3247 * @len: Length of anonymous identity in octets
3248 */
3249void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
3250{
3251 if (sm->eapol_cb->set_anon_id)
3252 sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
3253}
Dmitry Shmidt344abd32014-01-14 13:17:00 -08003254
3255
3256int eap_peer_was_failure_expected(struct eap_sm *sm)
3257{
3258 return sm->expected_failure;
3259}