1189251Ssam/*
2189251Ssam * EAP peer state machines (RFC 4137)
3214734Srpaulo * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam *
14189251Ssam * This file implements the Peer State Machine as defined in RFC 4137. The used
15189251Ssam * states and state transitions match mostly with the RFC. However, there are
16189251Ssam * couple of additional transitions for working around small issues noticed
17189251Ssam * during testing. These exceptions are explained in comments within the
18189251Ssam * functions in this file. The method functions, m.func(), are similar to the
19189251Ssam * ones used in RFC 4137, but some small changes have used here to optimize
20189251Ssam * operations and to add functionality needed for fast re-authentication
21189251Ssam * (session resumption).
22189251Ssam */
23189251Ssam
24189251Ssam#include "includes.h"
25189251Ssam
26189251Ssam#include "common.h"
27189251Ssam#include "pcsc_funcs.h"
28189251Ssam#include "state_machine.h"
29214734Srpaulo#include "crypto/crypto.h"
30214734Srpaulo#include "crypto/tls.h"
31214734Srpaulo#include "common/wpa_ctrl.h"
32189251Ssam#include "eap_common/eap_wsc_common.h"
33214734Srpaulo#include "eap_i.h"
34214734Srpaulo#include "eap_config.h"
35189251Ssam
36189251Ssam#define STATE_MACHINE_DATA struct eap_sm
37189251Ssam#define STATE_MACHINE_DEBUG_PREFIX "EAP"
38189251Ssam
39189251Ssam#define EAP_MAX_AUTH_ROUNDS 50
40189251Ssam
41189251Ssam
42189251Ssamstatic Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
43189251Ssam				  EapType method);
44189251Ssamstatic struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
45189251Ssamstatic void eap_sm_processIdentity(struct eap_sm *sm,
46189251Ssam				   const struct wpabuf *req);
47189251Ssamstatic void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
48189251Ssamstatic struct wpabuf * eap_sm_buildNotify(int id);
49189251Ssamstatic void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
50189251Ssam#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
51189251Ssamstatic const char * eap_sm_method_state_txt(EapMethodState state);
52189251Ssamstatic const char * eap_sm_decision_txt(EapDecision decision);
53189251Ssam#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
54189251Ssam
55189251Ssam
56189251Ssam
57189251Ssamstatic Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
58189251Ssam{
59189251Ssam	return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
60189251Ssam}
61189251Ssam
62189251Ssam
63189251Ssamstatic void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
64189251Ssam			   Boolean value)
65189251Ssam{
66189251Ssam	sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
67189251Ssam}
68189251Ssam
69189251Ssam
70189251Ssamstatic unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
71189251Ssam{
72189251Ssam	return sm->eapol_cb->get_int(sm->eapol_ctx, var);
73189251Ssam}
74189251Ssam
75189251Ssam
76189251Ssamstatic void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
77189251Ssam			  unsigned int value)
78189251Ssam{
79189251Ssam	sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
80189251Ssam}
81189251Ssam
82189251Ssam
83189251Ssamstatic struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
84189251Ssam{
85189251Ssam	return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
86189251Ssam}
87189251Ssam
88189251Ssam
89189251Ssamstatic void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
90189251Ssam{
91189251Ssam	if (sm->m == NULL || sm->eap_method_priv == NULL)
92189251Ssam		return;
93189251Ssam
94189251Ssam	wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
95189251Ssam		   "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
96189251Ssam	sm->m->deinit(sm, sm->eap_method_priv);
97189251Ssam	sm->eap_method_priv = NULL;
98189251Ssam	sm->m = NULL;
99189251Ssam}
100189251Ssam
101189251Ssam
102189251Ssam/**
103189251Ssam * eap_allowed_method - Check whether EAP method is allowed
104189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
105189251Ssam * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
106189251Ssam * @method: EAP type
107189251Ssam * Returns: 1 = allowed EAP method, 0 = not allowed
108189251Ssam */
109189251Ssamint eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
110189251Ssam{
111189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
112189251Ssam	int i;
113189251Ssam	struct eap_method_type *m;
114189251Ssam
115189251Ssam	if (config == NULL || config->eap_methods == NULL)
116189251Ssam		return 1;
117189251Ssam
118189251Ssam	m = config->eap_methods;
119189251Ssam	for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
120189251Ssam		     m[i].method != EAP_TYPE_NONE; i++) {
121189251Ssam		if (m[i].vendor == vendor && m[i].method == method)
122189251Ssam			return 1;
123189251Ssam	}
124189251Ssam	return 0;
125189251Ssam}
126189251Ssam
127189251Ssam
128189251Ssam/*
129189251Ssam * This state initializes state machine variables when the machine is
130189251Ssam * activated (portEnabled = TRUE). This is also used when re-starting
131189251Ssam * authentication (eapRestart == TRUE).
132189251Ssam */
133189251SsamSM_STATE(EAP, INITIALIZE)
134189251Ssam{
135189251Ssam	SM_ENTRY(EAP, INITIALIZE);
136189251Ssam	if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
137189251Ssam	    sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
138189251Ssam	    !sm->prev_failure) {
139189251Ssam		wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
140189251Ssam			   "fast reauthentication");
141189251Ssam		sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
142189251Ssam	} else {
143189251Ssam		eap_deinit_prev_method(sm, "INITIALIZE");
144189251Ssam	}
145189251Ssam	sm->selectedMethod = EAP_TYPE_NONE;
146189251Ssam	sm->methodState = METHOD_NONE;
147189251Ssam	sm->allowNotifications = TRUE;
148189251Ssam	sm->decision = DECISION_FAIL;
149189251Ssam	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
150189251Ssam	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
151189251Ssam	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
152189251Ssam	os_free(sm->eapKeyData);
153189251Ssam	sm->eapKeyData = NULL;
154189251Ssam	sm->eapKeyAvailable = FALSE;
155189251Ssam	eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
156189251Ssam	sm->lastId = -1; /* new session - make sure this does not match with
157189251Ssam			  * the first EAP-Packet */
158189251Ssam	/*
159189251Ssam	 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
160189251Ssam	 * seemed to be able to trigger cases where both were set and if EAPOL
161189251Ssam	 * state machine uses eapNoResp first, it may end up not sending a real
162189251Ssam	 * reply correctly. This occurred when the workaround in FAIL state set
163189251Ssam	 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
164189251Ssam	 * something else(?)
165189251Ssam	 */
166189251Ssam	eapol_set_bool(sm, EAPOL_eapResp, FALSE);
167189251Ssam	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
168189251Ssam	sm->num_rounds = 0;
169189251Ssam	sm->prev_failure = 0;
170189251Ssam}
171189251Ssam
172189251Ssam
173189251Ssam/*
174189251Ssam * This state is reached whenever service from the lower layer is interrupted
175189251Ssam * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
176189251Ssam * occurs when the port becomes enabled.
177189251Ssam */
178189251SsamSM_STATE(EAP, DISABLED)
179189251Ssam{
180189251Ssam	SM_ENTRY(EAP, DISABLED);
181189251Ssam	sm->num_rounds = 0;
182189251Ssam}
183189251Ssam
184189251Ssam
185189251Ssam/*
186189251Ssam * The state machine spends most of its time here, waiting for something to
187189251Ssam * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
188189251Ssam * SEND_RESPONSE states.
189189251Ssam */
190189251SsamSM_STATE(EAP, IDLE)
191189251Ssam{
192189251Ssam	SM_ENTRY(EAP, IDLE);
193189251Ssam}
194189251Ssam
195189251Ssam
196189251Ssam/*
197189251Ssam * This state is entered when an EAP packet is received (eapReq == TRUE) to
198189251Ssam * parse the packet header.
199189251Ssam */
200189251SsamSM_STATE(EAP, RECEIVED)
201189251Ssam{
202189251Ssam	const struct wpabuf *eapReqData;
203189251Ssam
204189251Ssam	SM_ENTRY(EAP, RECEIVED);
205189251Ssam	eapReqData = eapol_get_eapReqData(sm);
206189251Ssam	/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
207189251Ssam	eap_sm_parseEapReq(sm, eapReqData);
208189251Ssam	sm->num_rounds++;
209189251Ssam}
210189251Ssam
211189251Ssam
212189251Ssam/*
213189251Ssam * This state is entered when a request for a new type comes in. Either the
214189251Ssam * correct method is started, or a Nak response is built.
215189251Ssam */
216189251SsamSM_STATE(EAP, GET_METHOD)
217189251Ssam{
218189251Ssam	int reinit;
219189251Ssam	EapType method;
220189251Ssam
221189251Ssam	SM_ENTRY(EAP, GET_METHOD);
222189251Ssam
223189251Ssam	if (sm->reqMethod == EAP_TYPE_EXPANDED)
224189251Ssam		method = sm->reqVendorMethod;
225189251Ssam	else
226189251Ssam		method = sm->reqMethod;
227189251Ssam
228189251Ssam	if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
229189251Ssam		wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
230189251Ssam			   sm->reqVendor, method);
231214734Srpaulo		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
232214734Srpaulo			"vendor=%u method=%u -> NAK",
233214734Srpaulo			sm->reqVendor, method);
234189251Ssam		goto nak;
235189251Ssam	}
236189251Ssam
237214734Srpaulo	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
238214734Srpaulo		"vendor=%u method=%u", sm->reqVendor, method);
239214734Srpaulo
240189251Ssam	/*
241189251Ssam	 * RFC 4137 does not define specific operation for fast
242189251Ssam	 * re-authentication (session resumption). The design here is to allow
243189251Ssam	 * the previously used method data to be maintained for
244189251Ssam	 * re-authentication if the method support session resumption.
245189251Ssam	 * Otherwise, the previously used method data is freed and a new method
246189251Ssam	 * is allocated here.
247189251Ssam	 */
248189251Ssam	if (sm->fast_reauth &&
249189251Ssam	    sm->m && sm->m->vendor == sm->reqVendor &&
250189251Ssam	    sm->m->method == method &&
251189251Ssam	    sm->m->has_reauth_data &&
252189251Ssam	    sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
253189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
254189251Ssam			   " for fast re-authentication");
255189251Ssam		reinit = 1;
256189251Ssam	} else {
257189251Ssam		eap_deinit_prev_method(sm, "GET_METHOD");
258189251Ssam		reinit = 0;
259189251Ssam	}
260189251Ssam
261189251Ssam	sm->selectedMethod = sm->reqMethod;
262189251Ssam	if (sm->m == NULL)
263189251Ssam		sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
264189251Ssam	if (!sm->m) {
265189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
266189251Ssam			   "vendor %d method %d",
267189251Ssam			   sm->reqVendor, method);
268189251Ssam		goto nak;
269189251Ssam	}
270189251Ssam
271189251Ssam	wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
272189251Ssam		   "vendor %u method %u (%s)",
273189251Ssam		   sm->reqVendor, method, sm->m->name);
274189251Ssam	if (reinit)
275189251Ssam		sm->eap_method_priv = sm->m->init_for_reauth(
276189251Ssam			sm, sm->eap_method_priv);
277189251Ssam	else
278189251Ssam		sm->eap_method_priv = sm->m->init(sm);
279189251Ssam
280189251Ssam	if (sm->eap_method_priv == NULL) {
281189251Ssam		struct eap_peer_config *config = eap_get_config(sm);
282189251Ssam		wpa_msg(sm->msg_ctx, MSG_INFO,
283189251Ssam			"EAP: Failed to initialize EAP method: vendor %u "
284189251Ssam			"method %u (%s)",
285189251Ssam			sm->reqVendor, method, sm->m->name);
286189251Ssam		sm->m = NULL;
287189251Ssam		sm->methodState = METHOD_NONE;
288189251Ssam		sm->selectedMethod = EAP_TYPE_NONE;
289189251Ssam		if (sm->reqMethod == EAP_TYPE_TLS && config &&
290189251Ssam		    (config->pending_req_pin ||
291189251Ssam		     config->pending_req_passphrase)) {
292189251Ssam			/*
293189251Ssam			 * Return without generating Nak in order to allow
294189251Ssam			 * entering of PIN code or passphrase to retry the
295189251Ssam			 * current EAP packet.
296189251Ssam			 */
297189251Ssam			wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
298189251Ssam				   "request - skip Nak");
299189251Ssam			return;
300189251Ssam		}
301189251Ssam
302189251Ssam		goto nak;
303189251Ssam	}
304189251Ssam
305189251Ssam	sm->methodState = METHOD_INIT;
306189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
307189251Ssam		"EAP vendor %u method %u (%s) selected",
308189251Ssam		sm->reqVendor, method, sm->m->name);
309189251Ssam	return;
310189251Ssam
311189251Ssamnak:
312189251Ssam	wpabuf_free(sm->eapRespData);
313189251Ssam	sm->eapRespData = NULL;
314189251Ssam	sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
315189251Ssam}
316189251Ssam
317189251Ssam
318189251Ssam/*
319189251Ssam * The method processing happens here. The request from the authenticator is
320189251Ssam * processed, and an appropriate response packet is built.
321189251Ssam */
322189251SsamSM_STATE(EAP, METHOD)
323189251Ssam{
324189251Ssam	struct wpabuf *eapReqData;
325189251Ssam	struct eap_method_ret ret;
326189251Ssam
327189251Ssam	SM_ENTRY(EAP, METHOD);
328189251Ssam	if (sm->m == NULL) {
329189251Ssam		wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
330189251Ssam		return;
331189251Ssam	}
332189251Ssam
333189251Ssam	eapReqData = eapol_get_eapReqData(sm);
334189251Ssam
335189251Ssam	/*
336189251Ssam	 * Get ignore, methodState, decision, allowNotifications, and
337189251Ssam	 * eapRespData. RFC 4137 uses three separate method procedure (check,
338189251Ssam	 * process, and buildResp) in this state. These have been combined into
339189251Ssam	 * a single function call to m->process() in order to optimize EAP
340189251Ssam	 * method implementation interface a bit. These procedures are only
341189251Ssam	 * used from within this METHOD state, so there is no need to keep
342189251Ssam	 * these as separate C functions.
343189251Ssam	 *
344189251Ssam	 * The RFC 4137 procedures return values as follows:
345189251Ssam	 * ignore = m.check(eapReqData)
346189251Ssam	 * (methodState, decision, allowNotifications) = m.process(eapReqData)
347189251Ssam	 * eapRespData = m.buildResp(reqId)
348189251Ssam	 */
349189251Ssam	os_memset(&ret, 0, sizeof(ret));
350189251Ssam	ret.ignore = sm->ignore;
351189251Ssam	ret.methodState = sm->methodState;
352189251Ssam	ret.decision = sm->decision;
353189251Ssam	ret.allowNotifications = sm->allowNotifications;
354189251Ssam	wpabuf_free(sm->eapRespData);
355189251Ssam	sm->eapRespData = NULL;
356189251Ssam	sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
357189251Ssam					 eapReqData);
358189251Ssam	wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
359189251Ssam		   "methodState=%s decision=%s",
360189251Ssam		   ret.ignore ? "TRUE" : "FALSE",
361189251Ssam		   eap_sm_method_state_txt(ret.methodState),
362189251Ssam		   eap_sm_decision_txt(ret.decision));
363189251Ssam
364189251Ssam	sm->ignore = ret.ignore;
365189251Ssam	if (sm->ignore)
366189251Ssam		return;
367189251Ssam	sm->methodState = ret.methodState;
368189251Ssam	sm->decision = ret.decision;
369189251Ssam	sm->allowNotifications = ret.allowNotifications;
370189251Ssam
371189251Ssam	if (sm->m->isKeyAvailable && sm->m->getKey &&
372189251Ssam	    sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
373189251Ssam		os_free(sm->eapKeyData);
374189251Ssam		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
375189251Ssam					       &sm->eapKeyDataLen);
376189251Ssam	}
377189251Ssam}
378189251Ssam
379189251Ssam
380189251Ssam/*
381189251Ssam * This state signals the lower layer that a response packet is ready to be
382189251Ssam * sent.
383189251Ssam */
384189251SsamSM_STATE(EAP, SEND_RESPONSE)
385189251Ssam{
386189251Ssam	SM_ENTRY(EAP, SEND_RESPONSE);
387189251Ssam	wpabuf_free(sm->lastRespData);
388189251Ssam	if (sm->eapRespData) {
389189251Ssam		if (sm->workaround)
390189251Ssam			os_memcpy(sm->last_md5, sm->req_md5, 16);
391189251Ssam		sm->lastId = sm->reqId;
392189251Ssam		sm->lastRespData = wpabuf_dup(sm->eapRespData);
393189251Ssam		eapol_set_bool(sm, EAPOL_eapResp, TRUE);
394189251Ssam	} else
395189251Ssam		sm->lastRespData = NULL;
396189251Ssam	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
397189251Ssam	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
398189251Ssam}
399189251Ssam
400189251Ssam
401189251Ssam/*
402189251Ssam * This state signals the lower layer that the request was discarded, and no
403189251Ssam * response packet will be sent at this time.
404189251Ssam */
405189251SsamSM_STATE(EAP, DISCARD)
406189251Ssam{
407189251Ssam	SM_ENTRY(EAP, DISCARD);
408189251Ssam	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
409189251Ssam	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
410189251Ssam}
411189251Ssam
412189251Ssam
413189251Ssam/*
414189251Ssam * Handles requests for Identity method and builds a response.
415189251Ssam */
416189251SsamSM_STATE(EAP, IDENTITY)
417189251Ssam{
418189251Ssam	const struct wpabuf *eapReqData;
419189251Ssam
420189251Ssam	SM_ENTRY(EAP, IDENTITY);
421189251Ssam	eapReqData = eapol_get_eapReqData(sm);
422189251Ssam	eap_sm_processIdentity(sm, eapReqData);
423189251Ssam	wpabuf_free(sm->eapRespData);
424189251Ssam	sm->eapRespData = NULL;
425189251Ssam	sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
426189251Ssam}
427189251Ssam
428189251Ssam
429189251Ssam/*
430189251Ssam * Handles requests for Notification method and builds a response.
431189251Ssam */
432189251SsamSM_STATE(EAP, NOTIFICATION)
433189251Ssam{
434189251Ssam	const struct wpabuf *eapReqData;
435189251Ssam
436189251Ssam	SM_ENTRY(EAP, NOTIFICATION);
437189251Ssam	eapReqData = eapol_get_eapReqData(sm);
438189251Ssam	eap_sm_processNotify(sm, eapReqData);
439189251Ssam	wpabuf_free(sm->eapRespData);
440189251Ssam	sm->eapRespData = NULL;
441189251Ssam	sm->eapRespData = eap_sm_buildNotify(sm->reqId);
442189251Ssam}
443189251Ssam
444189251Ssam
445189251Ssam/*
446189251Ssam * This state retransmits the previous response packet.
447189251Ssam */
448189251SsamSM_STATE(EAP, RETRANSMIT)
449189251Ssam{
450189251Ssam	SM_ENTRY(EAP, RETRANSMIT);
451189251Ssam	wpabuf_free(sm->eapRespData);
452189251Ssam	if (sm->lastRespData)
453189251Ssam		sm->eapRespData = wpabuf_dup(sm->lastRespData);
454189251Ssam	else
455189251Ssam		sm->eapRespData = NULL;
456189251Ssam}
457189251Ssam
458189251Ssam
459189251Ssam/*
460189251Ssam * This state is entered in case of a successful completion of authentication
461189251Ssam * and state machine waits here until port is disabled or EAP authentication is
462189251Ssam * restarted.
463189251Ssam */
464189251SsamSM_STATE(EAP, SUCCESS)
465189251Ssam{
466189251Ssam	SM_ENTRY(EAP, SUCCESS);
467189251Ssam	if (sm->eapKeyData != NULL)
468189251Ssam		sm->eapKeyAvailable = TRUE;
469189251Ssam	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
470189251Ssam
471189251Ssam	/*
472189251Ssam	 * RFC 4137 does not clear eapReq here, but this seems to be required
473189251Ssam	 * to avoid processing the same request twice when state machine is
474189251Ssam	 * initialized.
475189251Ssam	 */
476189251Ssam	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
477189251Ssam
478189251Ssam	/*
479189251Ssam	 * RFC 4137 does not set eapNoResp here, but this seems to be required
480189251Ssam	 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
481189251Ssam	 * addition, either eapResp or eapNoResp is required to be set after
482189251Ssam	 * processing the received EAP frame.
483189251Ssam	 */
484189251Ssam	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
485189251Ssam
486189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
487189251Ssam		"EAP authentication completed successfully");
488189251Ssam}
489189251Ssam
490189251Ssam
491189251Ssam/*
492189251Ssam * This state is entered in case of a failure and state machine waits here
493189251Ssam * until port is disabled or EAP authentication is restarted.
494189251Ssam */
495189251SsamSM_STATE(EAP, FAILURE)
496189251Ssam{
497189251Ssam	SM_ENTRY(EAP, FAILURE);
498189251Ssam	eapol_set_bool(sm, EAPOL_eapFail, TRUE);
499189251Ssam
500189251Ssam	/*
501189251Ssam	 * RFC 4137 does not clear eapReq here, but this seems to be required
502189251Ssam	 * to avoid processing the same request twice when state machine is
503189251Ssam	 * initialized.
504189251Ssam	 */
505189251Ssam	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
506189251Ssam
507189251Ssam	/*
508189251Ssam	 * RFC 4137 does not set eapNoResp here. However, either eapResp or
509189251Ssam	 * eapNoResp is required to be set after processing the received EAP
510189251Ssam	 * frame.
511189251Ssam	 */
512189251Ssam	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
513189251Ssam
514189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
515189251Ssam		"EAP authentication failed");
516189251Ssam
517189251Ssam	sm->prev_failure = 1;
518189251Ssam}
519189251Ssam
520189251Ssam
521189251Ssamstatic int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
522189251Ssam{
523189251Ssam	/*
524189251Ssam	 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
525189251Ssam	 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
526189251Ssam	 * RFC 4137 require that reqId == lastId. In addition, it looks like
527189251Ssam	 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
528189251Ssam	 *
529189251Ssam	 * Accept this kind of Id if EAP workarounds are enabled. These are
530189251Ssam	 * unauthenticated plaintext messages, so this should have minimal
531189251Ssam	 * security implications (bit easier to fake EAP-Success/Failure).
532189251Ssam	 */
533189251Ssam	if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
534189251Ssam			       reqId == ((lastId + 2) & 0xff))) {
535189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
536189251Ssam			   "identifier field in EAP Success: "
537189251Ssam			   "reqId=%d lastId=%d (these are supposed to be "
538189251Ssam			   "same)", reqId, lastId);
539189251Ssam		return 1;
540189251Ssam	}
541189251Ssam	wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
542189251Ssam		   "lastId=%d", reqId, lastId);
543189251Ssam	return 0;
544189251Ssam}
545189251Ssam
546189251Ssam
547189251Ssam/*
548189251Ssam * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
549189251Ssam */
550189251Ssam
551189251Ssamstatic void eap_peer_sm_step_idle(struct eap_sm *sm)
552189251Ssam{
553189251Ssam	/*
554189251Ssam	 * The first three transitions are from RFC 4137. The last two are
555189251Ssam	 * local additions to handle special cases with LEAP and PEAP server
556189251Ssam	 * not sending EAP-Success in some cases.
557189251Ssam	 */
558189251Ssam	if (eapol_get_bool(sm, EAPOL_eapReq))
559189251Ssam		SM_ENTER(EAP, RECEIVED);
560189251Ssam	else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
561189251Ssam		  sm->decision != DECISION_FAIL) ||
562189251Ssam		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
563189251Ssam		  sm->decision == DECISION_UNCOND_SUCC))
564189251Ssam		SM_ENTER(EAP, SUCCESS);
565189251Ssam	else if (eapol_get_bool(sm, EAPOL_altReject) ||
566189251Ssam		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
567189251Ssam		  sm->decision != DECISION_UNCOND_SUCC) ||
568189251Ssam		 (eapol_get_bool(sm, EAPOL_altAccept) &&
569189251Ssam		  sm->methodState != METHOD_CONT &&
570189251Ssam		  sm->decision == DECISION_FAIL))
571189251Ssam		SM_ENTER(EAP, FAILURE);
572189251Ssam	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
573189251Ssam		 sm->leap_done && sm->decision != DECISION_FAIL &&
574189251Ssam		 sm->methodState == METHOD_DONE)
575189251Ssam		SM_ENTER(EAP, SUCCESS);
576189251Ssam	else if (sm->selectedMethod == EAP_TYPE_PEAP &&
577189251Ssam		 sm->peap_done && sm->decision != DECISION_FAIL &&
578189251Ssam		 sm->methodState == METHOD_DONE)
579189251Ssam		SM_ENTER(EAP, SUCCESS);
580189251Ssam}
581189251Ssam
582189251Ssam
583189251Ssamstatic int eap_peer_req_is_duplicate(struct eap_sm *sm)
584189251Ssam{
585189251Ssam	int duplicate;
586189251Ssam
587189251Ssam	duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
588189251Ssam	if (sm->workaround && duplicate &&
589189251Ssam	    os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
590189251Ssam		/*
591189251Ssam		 * RFC 4137 uses (reqId == lastId) as the only verification for
592189251Ssam		 * duplicate EAP requests. However, this misses cases where the
593189251Ssam		 * AS is incorrectly using the same id again; and
594189251Ssam		 * unfortunately, such implementations exist. Use MD5 hash as
595189251Ssam		 * an extra verification for the packets being duplicate to
596189251Ssam		 * workaround these issues.
597189251Ssam		 */
598189251Ssam		wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
599189251Ssam			   "EAP packets were not identical");
600189251Ssam		wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
601189251Ssam			   "duplicate packet");
602189251Ssam		duplicate = 0;
603189251Ssam	}
604189251Ssam
605189251Ssam	return duplicate;
606189251Ssam}
607189251Ssam
608189251Ssam
609189251Ssamstatic void eap_peer_sm_step_received(struct eap_sm *sm)
610189251Ssam{
611189251Ssam	int duplicate = eap_peer_req_is_duplicate(sm);
612189251Ssam
613189251Ssam	/*
614189251Ssam	 * Two special cases below for LEAP are local additions to work around
615189251Ssam	 * odd LEAP behavior (EAP-Success in the middle of authentication and
616189251Ssam	 * then swapped roles). Other transitions are based on RFC 4137.
617189251Ssam	 */
618189251Ssam	if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
619189251Ssam	    (sm->reqId == sm->lastId ||
620189251Ssam	     eap_success_workaround(sm, sm->reqId, sm->lastId)))
621189251Ssam		SM_ENTER(EAP, SUCCESS);
622189251Ssam	else if (sm->methodState != METHOD_CONT &&
623189251Ssam		 ((sm->rxFailure &&
624189251Ssam		   sm->decision != DECISION_UNCOND_SUCC) ||
625189251Ssam		  (sm->rxSuccess && sm->decision == DECISION_FAIL &&
626189251Ssam		   (sm->selectedMethod != EAP_TYPE_LEAP ||
627189251Ssam		    sm->methodState != METHOD_MAY_CONT))) &&
628189251Ssam		 (sm->reqId == sm->lastId ||
629189251Ssam		  eap_success_workaround(sm, sm->reqId, sm->lastId)))
630189251Ssam		SM_ENTER(EAP, FAILURE);
631189251Ssam	else if (sm->rxReq && duplicate)
632189251Ssam		SM_ENTER(EAP, RETRANSMIT);
633189251Ssam	else if (sm->rxReq && !duplicate &&
634189251Ssam		 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
635189251Ssam		 sm->allowNotifications)
636189251Ssam		SM_ENTER(EAP, NOTIFICATION);
637189251Ssam	else if (sm->rxReq && !duplicate &&
638189251Ssam		 sm->selectedMethod == EAP_TYPE_NONE &&
639189251Ssam		 sm->reqMethod == EAP_TYPE_IDENTITY)
640189251Ssam		SM_ENTER(EAP, IDENTITY);
641189251Ssam	else if (sm->rxReq && !duplicate &&
642189251Ssam		 sm->selectedMethod == EAP_TYPE_NONE &&
643189251Ssam		 sm->reqMethod != EAP_TYPE_IDENTITY &&
644189251Ssam		 sm->reqMethod != EAP_TYPE_NOTIFICATION)
645189251Ssam		SM_ENTER(EAP, GET_METHOD);
646189251Ssam	else if (sm->rxReq && !duplicate &&
647189251Ssam		 sm->reqMethod == sm->selectedMethod &&
648189251Ssam		 sm->methodState != METHOD_DONE)
649189251Ssam		SM_ENTER(EAP, METHOD);
650189251Ssam	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
651189251Ssam		 (sm->rxSuccess || sm->rxResp))
652189251Ssam		SM_ENTER(EAP, METHOD);
653189251Ssam	else
654189251Ssam		SM_ENTER(EAP, DISCARD);
655189251Ssam}
656189251Ssam
657189251Ssam
658189251Ssamstatic void eap_peer_sm_step_local(struct eap_sm *sm)
659189251Ssam{
660189251Ssam	switch (sm->EAP_state) {
661189251Ssam	case EAP_INITIALIZE:
662189251Ssam		SM_ENTER(EAP, IDLE);
663189251Ssam		break;
664189251Ssam	case EAP_DISABLED:
665189251Ssam		if (eapol_get_bool(sm, EAPOL_portEnabled) &&
666189251Ssam		    !sm->force_disabled)
667189251Ssam			SM_ENTER(EAP, INITIALIZE);
668189251Ssam		break;
669189251Ssam	case EAP_IDLE:
670189251Ssam		eap_peer_sm_step_idle(sm);
671189251Ssam		break;
672189251Ssam	case EAP_RECEIVED:
673189251Ssam		eap_peer_sm_step_received(sm);
674189251Ssam		break;
675189251Ssam	case EAP_GET_METHOD:
676189251Ssam		if (sm->selectedMethod == sm->reqMethod)
677189251Ssam			SM_ENTER(EAP, METHOD);
678189251Ssam		else
679189251Ssam			SM_ENTER(EAP, SEND_RESPONSE);
680189251Ssam		break;
681189251Ssam	case EAP_METHOD:
682189251Ssam		if (sm->ignore)
683189251Ssam			SM_ENTER(EAP, DISCARD);
684189251Ssam		else
685189251Ssam			SM_ENTER(EAP, SEND_RESPONSE);
686189251Ssam		break;
687189251Ssam	case EAP_SEND_RESPONSE:
688189251Ssam		SM_ENTER(EAP, IDLE);
689189251Ssam		break;
690189251Ssam	case EAP_DISCARD:
691189251Ssam		SM_ENTER(EAP, IDLE);
692189251Ssam		break;
693189251Ssam	case EAP_IDENTITY:
694189251Ssam		SM_ENTER(EAP, SEND_RESPONSE);
695189251Ssam		break;
696189251Ssam	case EAP_NOTIFICATION:
697189251Ssam		SM_ENTER(EAP, SEND_RESPONSE);
698189251Ssam		break;
699189251Ssam	case EAP_RETRANSMIT:
700189251Ssam		SM_ENTER(EAP, SEND_RESPONSE);
701189251Ssam		break;
702189251Ssam	case EAP_SUCCESS:
703189251Ssam		break;
704189251Ssam	case EAP_FAILURE:
705189251Ssam		break;
706189251Ssam	}
707189251Ssam}
708189251Ssam
709189251Ssam
710189251SsamSM_STEP(EAP)
711189251Ssam{
712189251Ssam	/* Global transitions */
713189251Ssam	if (eapol_get_bool(sm, EAPOL_eapRestart) &&
714189251Ssam	    eapol_get_bool(sm, EAPOL_portEnabled))
715189251Ssam		SM_ENTER_GLOBAL(EAP, INITIALIZE);
716189251Ssam	else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
717189251Ssam		SM_ENTER_GLOBAL(EAP, DISABLED);
718189251Ssam	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
719189251Ssam		/* RFC 4137 does not place any limit on number of EAP messages
720189251Ssam		 * in an authentication session. However, some error cases have
721189251Ssam		 * ended up in a state were EAP messages were sent between the
722189251Ssam		 * peer and server in a loop (e.g., TLS ACK frame in both
723189251Ssam		 * direction). Since this is quite undesired outcome, limit the
724189251Ssam		 * total number of EAP round-trips and abort authentication if
725189251Ssam		 * this limit is exceeded.
726189251Ssam		 */
727189251Ssam		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
728189251Ssam			wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
729189251Ssam				"authentication rounds - abort",
730189251Ssam				EAP_MAX_AUTH_ROUNDS);
731189251Ssam			sm->num_rounds++;
732189251Ssam			SM_ENTER_GLOBAL(EAP, FAILURE);
733189251Ssam		}
734189251Ssam	} else {
735189251Ssam		/* Local transitions */
736189251Ssam		eap_peer_sm_step_local(sm);
737189251Ssam	}
738189251Ssam}
739189251Ssam
740189251Ssam
741189251Ssamstatic Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
742189251Ssam				  EapType method)
743189251Ssam{
744189251Ssam	if (!eap_allowed_method(sm, vendor, method)) {
745189251Ssam		wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
746189251Ssam			   "vendor %u method %u", vendor, method);
747189251Ssam		return FALSE;
748189251Ssam	}
749189251Ssam	if (eap_peer_get_eap_method(vendor, method))
750189251Ssam		return TRUE;
751189251Ssam	wpa_printf(MSG_DEBUG, "EAP: not included in build: "
752189251Ssam		   "vendor %u method %u", vendor, method);
753189251Ssam	return FALSE;
754189251Ssam}
755189251Ssam
756189251Ssam
757189251Ssamstatic struct wpabuf * eap_sm_build_expanded_nak(
758189251Ssam	struct eap_sm *sm, int id, const struct eap_method *methods,
759189251Ssam	size_t count)
760189251Ssam{
761189251Ssam	struct wpabuf *resp;
762189251Ssam	int found = 0;
763189251Ssam	const struct eap_method *m;
764189251Ssam
765189251Ssam	wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
766189251Ssam
767189251Ssam	/* RFC 3748 - 5.3.2: Expanded Nak */
768189251Ssam	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
769189251Ssam			     8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
770189251Ssam	if (resp == NULL)
771189251Ssam		return NULL;
772189251Ssam
773189251Ssam	wpabuf_put_be24(resp, EAP_VENDOR_IETF);
774189251Ssam	wpabuf_put_be32(resp, EAP_TYPE_NAK);
775189251Ssam
776189251Ssam	for (m = methods; m; m = m->next) {
777189251Ssam		if (sm->reqVendor == m->vendor &&
778189251Ssam		    sm->reqVendorMethod == m->method)
779189251Ssam			continue; /* do not allow the current method again */
780189251Ssam		if (eap_allowed_method(sm, m->vendor, m->method)) {
781189251Ssam			wpa_printf(MSG_DEBUG, "EAP: allowed type: "
782189251Ssam				   "vendor=%u method=%u",
783189251Ssam				   m->vendor, m->method);
784189251Ssam			wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
785189251Ssam			wpabuf_put_be24(resp, m->vendor);
786189251Ssam			wpabuf_put_be32(resp, m->method);
787189251Ssam
788189251Ssam			found++;
789189251Ssam		}
790189251Ssam	}
791189251Ssam	if (!found) {
792189251Ssam		wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
793189251Ssam		wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
794189251Ssam		wpabuf_put_be24(resp, EAP_VENDOR_IETF);
795189251Ssam		wpabuf_put_be32(resp, EAP_TYPE_NONE);
796189251Ssam	}
797189251Ssam
798189251Ssam	eap_update_len(resp);
799189251Ssam
800189251Ssam	return resp;
801189251Ssam}
802189251Ssam
803189251Ssam
804189251Ssamstatic struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
805189251Ssam{
806189251Ssam	struct wpabuf *resp;
807189251Ssam	u8 *start;
808189251Ssam	int found = 0, expanded_found = 0;
809189251Ssam	size_t count;
810189251Ssam	const struct eap_method *methods, *m;
811189251Ssam
812189251Ssam	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
813189251Ssam		   "vendor=%u method=%u not allowed)", sm->reqMethod,
814189251Ssam		   sm->reqVendor, sm->reqVendorMethod);
815189251Ssam	methods = eap_peer_get_methods(&count);
816189251Ssam	if (methods == NULL)
817189251Ssam		return NULL;
818189251Ssam	if (sm->reqMethod == EAP_TYPE_EXPANDED)
819189251Ssam		return eap_sm_build_expanded_nak(sm, id, methods, count);
820189251Ssam
821189251Ssam	/* RFC 3748 - 5.3.1: Legacy Nak */
822189251Ssam	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
823189251Ssam			     sizeof(struct eap_hdr) + 1 + count + 1,
824189251Ssam			     EAP_CODE_RESPONSE, id);
825189251Ssam	if (resp == NULL)
826189251Ssam		return NULL;
827189251Ssam
828189251Ssam	start = wpabuf_put(resp, 0);
829189251Ssam	for (m = methods; m; m = m->next) {
830189251Ssam		if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
831189251Ssam			continue; /* do not allow the current method again */
832189251Ssam		if (eap_allowed_method(sm, m->vendor, m->method)) {
833189251Ssam			if (m->vendor != EAP_VENDOR_IETF) {
834189251Ssam				if (expanded_found)
835189251Ssam					continue;
836189251Ssam				expanded_found = 1;
837189251Ssam				wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
838189251Ssam			} else
839189251Ssam				wpabuf_put_u8(resp, m->method);
840189251Ssam			found++;
841189251Ssam		}
842189251Ssam	}
843189251Ssam	if (!found)
844189251Ssam		wpabuf_put_u8(resp, EAP_TYPE_NONE);
845189251Ssam	wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
846189251Ssam
847189251Ssam	eap_update_len(resp);
848189251Ssam
849189251Ssam	return resp;
850189251Ssam}
851189251Ssam
852189251Ssam
853189251Ssamstatic void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
854189251Ssam{
855189251Ssam	const struct eap_hdr *hdr = wpabuf_head(req);
856189251Ssam	const u8 *pos = (const u8 *) (hdr + 1);
857189251Ssam	pos++;
858189251Ssam
859189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
860189251Ssam		"EAP authentication started");
861189251Ssam
862189251Ssam	/*
863189251Ssam	 * RFC 3748 - 5.1: Identity
864189251Ssam	 * Data field may contain a displayable message in UTF-8. If this
865189251Ssam	 * includes NUL-character, only the data before that should be
866189251Ssam	 * displayed. Some EAP implementasitons may piggy-back additional
867189251Ssam	 * options after the NUL.
868189251Ssam	 */
869189251Ssam	/* TODO: could save displayable message so that it can be shown to the
870189251Ssam	 * user in case of interaction is required */
871189251Ssam	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
872189251Ssam			  pos, be_to_host16(hdr->length) - 5);
873189251Ssam}
874189251Ssam
875189251Ssam
876189251Ssam#ifdef PCSC_FUNCS
877189251Ssamstatic int eap_sm_imsi_identity(struct eap_sm *sm,
878189251Ssam				struct eap_peer_config *conf)
879189251Ssam{
880189251Ssam	int aka = 0;
881189251Ssam	char imsi[100];
882189251Ssam	size_t imsi_len;
883189251Ssam	struct eap_method_type *m = conf->eap_methods;
884189251Ssam	int i;
885189251Ssam
886189251Ssam	imsi_len = sizeof(imsi);
887189251Ssam	if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
888189251Ssam		wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
889189251Ssam		return -1;
890189251Ssam	}
891189251Ssam
892189251Ssam	wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
893189251Ssam
894189251Ssam	for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
895189251Ssam			  m[i].method != EAP_TYPE_NONE); i++) {
896189251Ssam		if (m[i].vendor == EAP_VENDOR_IETF &&
897189251Ssam		    m[i].method == EAP_TYPE_AKA) {
898189251Ssam			aka = 1;
899189251Ssam			break;
900189251Ssam		}
901189251Ssam	}
902189251Ssam
903189251Ssam	os_free(conf->identity);
904189251Ssam	conf->identity = os_malloc(1 + imsi_len);
905189251Ssam	if (conf->identity == NULL) {
906189251Ssam		wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
907189251Ssam			   "IMSI-based identity");
908189251Ssam		return -1;
909189251Ssam	}
910189251Ssam
911189251Ssam	conf->identity[0] = aka ? '0' : '1';
912189251Ssam	os_memcpy(conf->identity + 1, imsi, imsi_len);
913189251Ssam	conf->identity_len = 1 + imsi_len;
914189251Ssam
915189251Ssam	return 0;
916189251Ssam}
917189251Ssam#endif /* PCSC_FUNCS */
918189251Ssam
919189251Ssam
920189251Ssamstatic int eap_sm_set_scard_pin(struct eap_sm *sm,
921189251Ssam				struct eap_peer_config *conf)
922189251Ssam{
923189251Ssam#ifdef PCSC_FUNCS
924189251Ssam	if (scard_set_pin(sm->scard_ctx, conf->pin)) {
925189251Ssam		/*
926189251Ssam		 * Make sure the same PIN is not tried again in order to avoid
927189251Ssam		 * blocking SIM.
928189251Ssam		 */
929189251Ssam		os_free(conf->pin);
930189251Ssam		conf->pin = NULL;
931189251Ssam
932189251Ssam		wpa_printf(MSG_WARNING, "PIN validation failed");
933189251Ssam		eap_sm_request_pin(sm);
934189251Ssam		return -1;
935189251Ssam	}
936189251Ssam	return 0;
937189251Ssam#else /* PCSC_FUNCS */
938189251Ssam	return -1;
939189251Ssam#endif /* PCSC_FUNCS */
940189251Ssam}
941189251Ssam
942189251Ssamstatic int eap_sm_get_scard_identity(struct eap_sm *sm,
943189251Ssam				     struct eap_peer_config *conf)
944189251Ssam{
945189251Ssam#ifdef PCSC_FUNCS
946189251Ssam	if (eap_sm_set_scard_pin(sm, conf))
947189251Ssam		return -1;
948189251Ssam
949189251Ssam	return eap_sm_imsi_identity(sm, conf);
950189251Ssam#else /* PCSC_FUNCS */
951189251Ssam	return -1;
952189251Ssam#endif /* PCSC_FUNCS */
953189251Ssam}
954189251Ssam
955189251Ssam
956189251Ssam/**
957189251Ssam * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
958189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
959189251Ssam * @id: EAP identifier for the packet
960189251Ssam * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
961189251Ssam * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
962189251Ssam * failure
963189251Ssam *
964189251Ssam * This function allocates and builds an EAP-Identity/Response packet for the
965189251Ssam * current network. The caller is responsible for freeing the returned data.
966189251Ssam */
967189251Ssamstruct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
968189251Ssam{
969189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
970189251Ssam	struct wpabuf *resp;
971189251Ssam	const u8 *identity;
972189251Ssam	size_t identity_len;
973189251Ssam
974189251Ssam	if (config == NULL) {
975189251Ssam		wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
976189251Ssam			   "was not available");
977189251Ssam		return NULL;
978189251Ssam	}
979189251Ssam
980189251Ssam	if (sm->m && sm->m->get_identity &&
981189251Ssam	    (identity = sm->m->get_identity(sm, sm->eap_method_priv,
982189251Ssam					    &identity_len)) != NULL) {
983189251Ssam		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
984189251Ssam				  "identity", identity, identity_len);
985189251Ssam	} else if (!encrypted && config->anonymous_identity) {
986189251Ssam		identity = config->anonymous_identity;
987189251Ssam		identity_len = config->anonymous_identity_len;
988189251Ssam		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
989189251Ssam				  identity, identity_len);
990189251Ssam	} else {
991189251Ssam		identity = config->identity;
992189251Ssam		identity_len = config->identity_len;
993189251Ssam		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
994189251Ssam				  identity, identity_len);
995189251Ssam	}
996189251Ssam
997189251Ssam	if (identity == NULL) {
998189251Ssam		wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
999189251Ssam			   "configuration was not available");
1000189251Ssam		if (config->pcsc) {
1001189251Ssam			if (eap_sm_get_scard_identity(sm, config) < 0)
1002189251Ssam				return NULL;
1003189251Ssam			identity = config->identity;
1004189251Ssam			identity_len = config->identity_len;
1005189251Ssam			wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
1006189251Ssam					  "IMSI", identity, identity_len);
1007189251Ssam		} else {
1008189251Ssam			eap_sm_request_identity(sm);
1009189251Ssam			return NULL;
1010189251Ssam		}
1011189251Ssam	} else if (config->pcsc) {
1012189251Ssam		if (eap_sm_set_scard_pin(sm, config) < 0)
1013189251Ssam			return NULL;
1014189251Ssam	}
1015189251Ssam
1016189251Ssam	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
1017189251Ssam			     EAP_CODE_RESPONSE, id);
1018189251Ssam	if (resp == NULL)
1019189251Ssam		return NULL;
1020189251Ssam
1021189251Ssam	wpabuf_put_data(resp, identity, identity_len);
1022189251Ssam
1023189251Ssam	return resp;
1024189251Ssam}
1025189251Ssam
1026189251Ssam
1027189251Ssamstatic void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
1028189251Ssam{
1029189251Ssam	const u8 *pos;
1030189251Ssam	char *msg;
1031189251Ssam	size_t i, msg_len;
1032189251Ssam
1033189251Ssam	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
1034189251Ssam			       &msg_len);
1035189251Ssam	if (pos == NULL)
1036189251Ssam		return;
1037189251Ssam	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
1038189251Ssam			  pos, msg_len);
1039189251Ssam
1040189251Ssam	msg = os_malloc(msg_len + 1);
1041189251Ssam	if (msg == NULL)
1042189251Ssam		return;
1043189251Ssam	for (i = 0; i < msg_len; i++)
1044189251Ssam		msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
1045189251Ssam	msg[msg_len] = '\0';
1046189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
1047189251Ssam		WPA_EVENT_EAP_NOTIFICATION, msg);
1048189251Ssam	os_free(msg);
1049189251Ssam}
1050189251Ssam
1051189251Ssam
1052189251Ssamstatic struct wpabuf * eap_sm_buildNotify(int id)
1053189251Ssam{
1054189251Ssam	struct wpabuf *resp;
1055189251Ssam
1056189251Ssam	wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
1057189251Ssam	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
1058189251Ssam			     EAP_CODE_RESPONSE, id);
1059189251Ssam	if (resp == NULL)
1060189251Ssam		return NULL;
1061189251Ssam
1062189251Ssam	return resp;
1063189251Ssam}
1064189251Ssam
1065189251Ssam
1066189251Ssamstatic void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
1067189251Ssam{
1068189251Ssam	const struct eap_hdr *hdr;
1069189251Ssam	size_t plen;
1070189251Ssam	const u8 *pos;
1071189251Ssam
1072189251Ssam	sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
1073189251Ssam	sm->reqId = 0;
1074189251Ssam	sm->reqMethod = EAP_TYPE_NONE;
1075189251Ssam	sm->reqVendor = EAP_VENDOR_IETF;
1076189251Ssam	sm->reqVendorMethod = EAP_TYPE_NONE;
1077189251Ssam
1078189251Ssam	if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
1079189251Ssam		return;
1080189251Ssam
1081189251Ssam	hdr = wpabuf_head(req);
1082189251Ssam	plen = be_to_host16(hdr->length);
1083189251Ssam	if (plen > wpabuf_len(req)) {
1084189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
1085189251Ssam			   "(len=%lu plen=%lu)",
1086189251Ssam			   (unsigned long) wpabuf_len(req),
1087189251Ssam			   (unsigned long) plen);
1088189251Ssam		return;
1089189251Ssam	}
1090189251Ssam
1091189251Ssam	sm->reqId = hdr->identifier;
1092189251Ssam
1093189251Ssam	if (sm->workaround) {
1094189251Ssam		const u8 *addr[1];
1095189251Ssam		addr[0] = wpabuf_head(req);
1096189251Ssam		md5_vector(1, addr, &plen, sm->req_md5);
1097189251Ssam	}
1098189251Ssam
1099189251Ssam	switch (hdr->code) {
1100189251Ssam	case EAP_CODE_REQUEST:
1101189251Ssam		if (plen < sizeof(*hdr) + 1) {
1102189251Ssam			wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
1103189251Ssam				   "no Type field");
1104189251Ssam			return;
1105189251Ssam		}
1106189251Ssam		sm->rxReq = TRUE;
1107189251Ssam		pos = (const u8 *) (hdr + 1);
1108189251Ssam		sm->reqMethod = *pos++;
1109189251Ssam		if (sm->reqMethod == EAP_TYPE_EXPANDED) {
1110189251Ssam			if (plen < sizeof(*hdr) + 8) {
1111189251Ssam				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
1112189251Ssam					   "expanded EAP-Packet (plen=%lu)",
1113189251Ssam					   (unsigned long) plen);
1114189251Ssam				return;
1115189251Ssam			}
1116189251Ssam			sm->reqVendor = WPA_GET_BE24(pos);
1117189251Ssam			pos += 3;
1118189251Ssam			sm->reqVendorMethod = WPA_GET_BE32(pos);
1119189251Ssam		}
1120189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
1121189251Ssam			   "method=%u vendor=%u vendorMethod=%u",
1122189251Ssam			   sm->reqId, sm->reqMethod, sm->reqVendor,
1123189251Ssam			   sm->reqVendorMethod);
1124189251Ssam		break;
1125189251Ssam	case EAP_CODE_RESPONSE:
1126189251Ssam		if (sm->selectedMethod == EAP_TYPE_LEAP) {
1127189251Ssam			/*
1128189251Ssam			 * LEAP differs from RFC 4137 by using reversed roles
1129189251Ssam			 * for mutual authentication and because of this, we
1130189251Ssam			 * need to accept EAP-Response frames if LEAP is used.
1131189251Ssam			 */
1132189251Ssam			if (plen < sizeof(*hdr) + 1) {
1133189251Ssam				wpa_printf(MSG_DEBUG, "EAP: Too short "
1134189251Ssam					   "EAP-Response - no Type field");
1135189251Ssam				return;
1136189251Ssam			}
1137189251Ssam			sm->rxResp = TRUE;
1138189251Ssam			pos = (const u8 *) (hdr + 1);
1139189251Ssam			sm->reqMethod = *pos;
1140189251Ssam			wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
1141189251Ssam				   "LEAP method=%d id=%d",
1142189251Ssam				   sm->reqMethod, sm->reqId);
1143189251Ssam			break;
1144189251Ssam		}
1145189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
1146189251Ssam		break;
1147189251Ssam	case EAP_CODE_SUCCESS:
1148189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
1149189251Ssam		sm->rxSuccess = TRUE;
1150189251Ssam		break;
1151189251Ssam	case EAP_CODE_FAILURE:
1152189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
1153189251Ssam		sm->rxFailure = TRUE;
1154189251Ssam		break;
1155189251Ssam	default:
1156189251Ssam		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
1157189251Ssam			   "code %d", hdr->code);
1158189251Ssam		break;
1159189251Ssam	}
1160189251Ssam}
1161189251Ssam
1162189251Ssam
1163214734Srpaulostatic void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
1164214734Srpaulo				  union tls_event_data *data)
1165214734Srpaulo{
1166214734Srpaulo	struct eap_sm *sm = ctx;
1167214734Srpaulo	char *hash_hex = NULL;
1168214734Srpaulo	char *cert_hex = NULL;
1169214734Srpaulo
1170214734Srpaulo	switch (ev) {
1171214734Srpaulo	case TLS_CERT_CHAIN_FAILURE:
1172214734Srpaulo		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
1173214734Srpaulo			"reason=%d depth=%d subject='%s' err='%s'",
1174214734Srpaulo			data->cert_fail.reason,
1175214734Srpaulo			data->cert_fail.depth,
1176214734Srpaulo			data->cert_fail.subject,
1177214734Srpaulo			data->cert_fail.reason_txt);
1178214734Srpaulo		break;
1179214734Srpaulo	case TLS_PEER_CERTIFICATE:
1180214734Srpaulo		if (data->peer_cert.hash) {
1181214734Srpaulo			size_t len = data->peer_cert.hash_len * 2 + 1;
1182214734Srpaulo			hash_hex = os_malloc(len);
1183214734Srpaulo			if (hash_hex) {
1184214734Srpaulo				wpa_snprintf_hex(hash_hex, len,
1185214734Srpaulo						 data->peer_cert.hash,
1186214734Srpaulo						 data->peer_cert.hash_len);
1187214734Srpaulo			}
1188214734Srpaulo		}
1189214734Srpaulo		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
1190214734Srpaulo			"depth=%d subject='%s'%s%s",
1191214734Srpaulo			data->peer_cert.depth, data->peer_cert.subject,
1192214734Srpaulo			hash_hex ? " hash=" : "", hash_hex ? hash_hex : "");
1193214734Srpaulo
1194214734Srpaulo		if (data->peer_cert.cert) {
1195214734Srpaulo			size_t len = wpabuf_len(data->peer_cert.cert) * 2 + 1;
1196214734Srpaulo			cert_hex = os_malloc(len);
1197214734Srpaulo			if (cert_hex == NULL)
1198214734Srpaulo				break;
1199214734Srpaulo			wpa_snprintf_hex(cert_hex, len,
1200214734Srpaulo					 wpabuf_head(data->peer_cert.cert),
1201214734Srpaulo					 wpabuf_len(data->peer_cert.cert));
1202214734Srpaulo			wpa_msg_ctrl(sm->msg_ctx, MSG_INFO,
1203214734Srpaulo				     WPA_EVENT_EAP_PEER_CERT
1204214734Srpaulo				     "depth=%d subject='%s' cert=%s",
1205214734Srpaulo				     data->peer_cert.depth,
1206214734Srpaulo				     data->peer_cert.subject,
1207214734Srpaulo				     cert_hex);
1208214734Srpaulo		}
1209214734Srpaulo		break;
1210214734Srpaulo	}
1211214734Srpaulo
1212214734Srpaulo	os_free(hash_hex);
1213214734Srpaulo	os_free(cert_hex);
1214214734Srpaulo}
1215214734Srpaulo
1216214734Srpaulo
1217189251Ssam/**
1218189251Ssam * eap_peer_sm_init - Allocate and initialize EAP peer state machine
1219189251Ssam * @eapol_ctx: Context data to be used with eapol_cb calls
1220189251Ssam * @eapol_cb: Pointer to EAPOL callback functions
1221189251Ssam * @msg_ctx: Context data for wpa_msg() calls
1222189251Ssam * @conf: EAP configuration
1223189251Ssam * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1224189251Ssam *
1225189251Ssam * This function allocates and initializes an EAP state machine. In addition,
1226189251Ssam * this initializes TLS library for the new EAP state machine. eapol_cb pointer
1227189251Ssam * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
1228189251Ssam * state machine. Consequently, the caller must make sure that this data
1229189251Ssam * structure remains alive while the EAP state machine is active.
1230189251Ssam */
1231189251Ssamstruct eap_sm * eap_peer_sm_init(void *eapol_ctx,
1232189251Ssam				 struct eapol_callbacks *eapol_cb,
1233189251Ssam				 void *msg_ctx, struct eap_config *conf)
1234189251Ssam{
1235189251Ssam	struct eap_sm *sm;
1236189251Ssam	struct tls_config tlsconf;
1237189251Ssam
1238189251Ssam	sm = os_zalloc(sizeof(*sm));
1239189251Ssam	if (sm == NULL)
1240189251Ssam		return NULL;
1241189251Ssam	sm->eapol_ctx = eapol_ctx;
1242189251Ssam	sm->eapol_cb = eapol_cb;
1243189251Ssam	sm->msg_ctx = msg_ctx;
1244189251Ssam	sm->ClientTimeout = 60;
1245189251Ssam	sm->wps = conf->wps;
1246189251Ssam
1247189251Ssam	os_memset(&tlsconf, 0, sizeof(tlsconf));
1248189251Ssam	tlsconf.opensc_engine_path = conf->opensc_engine_path;
1249189251Ssam	tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
1250189251Ssam	tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
1251214734Srpaulo#ifdef CONFIG_FIPS
1252214734Srpaulo	tlsconf.fips_mode = 1;
1253214734Srpaulo#endif /* CONFIG_FIPS */
1254214734Srpaulo	tlsconf.event_cb = eap_peer_sm_tls_event;
1255214734Srpaulo	tlsconf.cb_ctx = sm;
1256189251Ssam	sm->ssl_ctx = tls_init(&tlsconf);
1257189251Ssam	if (sm->ssl_ctx == NULL) {
1258189251Ssam		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
1259189251Ssam			   "context.");
1260189251Ssam		os_free(sm);
1261189251Ssam		return NULL;
1262189251Ssam	}
1263189251Ssam
1264189251Ssam	return sm;
1265189251Ssam}
1266189251Ssam
1267189251Ssam
1268189251Ssam/**
1269189251Ssam * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
1270189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1271189251Ssam *
1272189251Ssam * This function deinitializes EAP state machine and frees all allocated
1273189251Ssam * resources.
1274189251Ssam */
1275189251Ssamvoid eap_peer_sm_deinit(struct eap_sm *sm)
1276189251Ssam{
1277189251Ssam	if (sm == NULL)
1278189251Ssam		return;
1279189251Ssam	eap_deinit_prev_method(sm, "EAP deinit");
1280189251Ssam	eap_sm_abort(sm);
1281189251Ssam	tls_deinit(sm->ssl_ctx);
1282189251Ssam	os_free(sm);
1283189251Ssam}
1284189251Ssam
1285189251Ssam
1286189251Ssam/**
1287189251Ssam * eap_peer_sm_step - Step EAP peer state machine
1288189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1289189251Ssam * Returns: 1 if EAP state was changed or 0 if not
1290189251Ssam *
1291189251Ssam * This function advances EAP state machine to a new state to match with the
1292189251Ssam * current variables. This should be called whenever variables used by the EAP
1293189251Ssam * state machine have changed.
1294189251Ssam */
1295189251Ssamint eap_peer_sm_step(struct eap_sm *sm)
1296189251Ssam{
1297189251Ssam	int res = 0;
1298189251Ssam	do {
1299189251Ssam		sm->changed = FALSE;
1300189251Ssam		SM_STEP_RUN(EAP);
1301189251Ssam		if (sm->changed)
1302189251Ssam			res = 1;
1303189251Ssam	} while (sm->changed);
1304189251Ssam	return res;
1305189251Ssam}
1306189251Ssam
1307189251Ssam
1308189251Ssam/**
1309189251Ssam * eap_sm_abort - Abort EAP authentication
1310189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1311189251Ssam *
1312189251Ssam * Release system resources that have been allocated for the authentication
1313189251Ssam * session without fully deinitializing the EAP state machine.
1314189251Ssam */
1315189251Ssamvoid eap_sm_abort(struct eap_sm *sm)
1316189251Ssam{
1317189251Ssam	wpabuf_free(sm->lastRespData);
1318189251Ssam	sm->lastRespData = NULL;
1319189251Ssam	wpabuf_free(sm->eapRespData);
1320189251Ssam	sm->eapRespData = NULL;
1321189251Ssam	os_free(sm->eapKeyData);
1322189251Ssam	sm->eapKeyData = NULL;
1323189251Ssam
1324189251Ssam	/* This is not clearly specified in the EAP statemachines draft, but
1325189251Ssam	 * it seems necessary to make sure that some of the EAPOL variables get
1326189251Ssam	 * cleared for the next authentication. */
1327189251Ssam	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
1328189251Ssam}
1329189251Ssam
1330189251Ssam
1331189251Ssam#ifdef CONFIG_CTRL_IFACE
1332189251Ssamstatic const char * eap_sm_state_txt(int state)
1333189251Ssam{
1334189251Ssam	switch (state) {
1335189251Ssam	case EAP_INITIALIZE:
1336189251Ssam		return "INITIALIZE";
1337189251Ssam	case EAP_DISABLED:
1338189251Ssam		return "DISABLED";
1339189251Ssam	case EAP_IDLE:
1340189251Ssam		return "IDLE";
1341189251Ssam	case EAP_RECEIVED:
1342189251Ssam		return "RECEIVED";
1343189251Ssam	case EAP_GET_METHOD:
1344189251Ssam		return "GET_METHOD";
1345189251Ssam	case EAP_METHOD:
1346189251Ssam		return "METHOD";
1347189251Ssam	case EAP_SEND_RESPONSE:
1348189251Ssam		return "SEND_RESPONSE";
1349189251Ssam	case EAP_DISCARD:
1350189251Ssam		return "DISCARD";
1351189251Ssam	case EAP_IDENTITY:
1352189251Ssam		return "IDENTITY";
1353189251Ssam	case EAP_NOTIFICATION:
1354189251Ssam		return "NOTIFICATION";
1355189251Ssam	case EAP_RETRANSMIT:
1356189251Ssam		return "RETRANSMIT";
1357189251Ssam	case EAP_SUCCESS:
1358189251Ssam		return "SUCCESS";
1359189251Ssam	case EAP_FAILURE:
1360189251Ssam		return "FAILURE";
1361189251Ssam	default:
1362189251Ssam		return "UNKNOWN";
1363189251Ssam	}
1364189251Ssam}
1365189251Ssam#endif /* CONFIG_CTRL_IFACE */
1366189251Ssam
1367189251Ssam
1368189251Ssam#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1369189251Ssamstatic const char * eap_sm_method_state_txt(EapMethodState state)
1370189251Ssam{
1371189251Ssam	switch (state) {
1372189251Ssam	case METHOD_NONE:
1373189251Ssam		return "NONE";
1374189251Ssam	case METHOD_INIT:
1375189251Ssam		return "INIT";
1376189251Ssam	case METHOD_CONT:
1377189251Ssam		return "CONT";
1378189251Ssam	case METHOD_MAY_CONT:
1379189251Ssam		return "MAY_CONT";
1380189251Ssam	case METHOD_DONE:
1381189251Ssam		return "DONE";
1382189251Ssam	default:
1383189251Ssam		return "UNKNOWN";
1384189251Ssam	}
1385189251Ssam}
1386189251Ssam
1387189251Ssam
1388189251Ssamstatic const char * eap_sm_decision_txt(EapDecision decision)
1389189251Ssam{
1390189251Ssam	switch (decision) {
1391189251Ssam	case DECISION_FAIL:
1392189251Ssam		return "FAIL";
1393189251Ssam	case DECISION_COND_SUCC:
1394189251Ssam		return "COND_SUCC";
1395189251Ssam	case DECISION_UNCOND_SUCC:
1396189251Ssam		return "UNCOND_SUCC";
1397189251Ssam	default:
1398189251Ssam		return "UNKNOWN";
1399189251Ssam	}
1400189251Ssam}
1401189251Ssam#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1402189251Ssam
1403189251Ssam
1404189251Ssam#ifdef CONFIG_CTRL_IFACE
1405189251Ssam
1406189251Ssam/**
1407189251Ssam * eap_sm_get_status - Get EAP state machine status
1408189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1409189251Ssam * @buf: Buffer for status information
1410189251Ssam * @buflen: Maximum buffer length
1411189251Ssam * @verbose: Whether to include verbose status information
1412189251Ssam * Returns: Number of bytes written to buf.
1413189251Ssam *
1414189251Ssam * Query EAP state machine for status information. This function fills in a
1415189251Ssam * text area with current status information from the EAPOL state machine. If
1416189251Ssam * the buffer (buf) is not large enough, status information will be truncated
1417189251Ssam * to fit the buffer.
1418189251Ssam */
1419189251Ssamint eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
1420189251Ssam{
1421189251Ssam	int len, ret;
1422189251Ssam
1423189251Ssam	if (sm == NULL)
1424189251Ssam		return 0;
1425189251Ssam
1426189251Ssam	len = os_snprintf(buf, buflen,
1427189251Ssam			  "EAP state=%s\n",
1428189251Ssam			  eap_sm_state_txt(sm->EAP_state));
1429189251Ssam	if (len < 0 || (size_t) len >= buflen)
1430189251Ssam		return 0;
1431189251Ssam
1432189251Ssam	if (sm->selectedMethod != EAP_TYPE_NONE) {
1433189251Ssam		const char *name;
1434189251Ssam		if (sm->m) {
1435189251Ssam			name = sm->m->name;
1436189251Ssam		} else {
1437189251Ssam			const struct eap_method *m =
1438189251Ssam				eap_peer_get_eap_method(EAP_VENDOR_IETF,
1439189251Ssam							sm->selectedMethod);
1440189251Ssam			if (m)
1441189251Ssam				name = m->name;
1442189251Ssam			else
1443189251Ssam				name = "?";
1444189251Ssam		}
1445189251Ssam		ret = os_snprintf(buf + len, buflen - len,
1446189251Ssam				  "selectedMethod=%d (EAP-%s)\n",
1447189251Ssam				  sm->selectedMethod, name);
1448189251Ssam		if (ret < 0 || (size_t) ret >= buflen - len)
1449189251Ssam			return len;
1450189251Ssam		len += ret;
1451189251Ssam
1452189251Ssam		if (sm->m && sm->m->get_status) {
1453189251Ssam			len += sm->m->get_status(sm, sm->eap_method_priv,
1454189251Ssam						 buf + len, buflen - len,
1455189251Ssam						 verbose);
1456189251Ssam		}
1457189251Ssam	}
1458189251Ssam
1459189251Ssam	if (verbose) {
1460189251Ssam		ret = os_snprintf(buf + len, buflen - len,
1461189251Ssam				  "reqMethod=%d\n"
1462189251Ssam				  "methodState=%s\n"
1463189251Ssam				  "decision=%s\n"
1464189251Ssam				  "ClientTimeout=%d\n",
1465189251Ssam				  sm->reqMethod,
1466189251Ssam				  eap_sm_method_state_txt(sm->methodState),
1467189251Ssam				  eap_sm_decision_txt(sm->decision),
1468189251Ssam				  sm->ClientTimeout);
1469189251Ssam		if (ret < 0 || (size_t) ret >= buflen - len)
1470189251Ssam			return len;
1471189251Ssam		len += ret;
1472189251Ssam	}
1473189251Ssam
1474189251Ssam	return len;
1475189251Ssam}
1476189251Ssam#endif /* CONFIG_CTRL_IFACE */
1477189251Ssam
1478189251Ssam
1479189251Ssam#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1480189251Ssamtypedef enum {
1481189251Ssam	TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
1482189251Ssam	TYPE_PASSPHRASE
1483189251Ssam} eap_ctrl_req_type;
1484189251Ssam
1485189251Ssamstatic void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
1486189251Ssam			   const char *msg, size_t msglen)
1487189251Ssam{
1488189251Ssam	struct eap_peer_config *config;
1489189251Ssam	char *field, *txt, *tmp;
1490189251Ssam
1491189251Ssam	if (sm == NULL)
1492189251Ssam		return;
1493189251Ssam	config = eap_get_config(sm);
1494189251Ssam	if (config == NULL)
1495189251Ssam		return;
1496189251Ssam
1497189251Ssam	switch (type) {
1498189251Ssam	case TYPE_IDENTITY:
1499189251Ssam		field = "IDENTITY";
1500189251Ssam		txt = "Identity";
1501189251Ssam		config->pending_req_identity++;
1502189251Ssam		break;
1503189251Ssam	case TYPE_PASSWORD:
1504189251Ssam		field = "PASSWORD";
1505189251Ssam		txt = "Password";
1506189251Ssam		config->pending_req_password++;
1507189251Ssam		break;
1508189251Ssam	case TYPE_NEW_PASSWORD:
1509189251Ssam		field = "NEW_PASSWORD";
1510189251Ssam		txt = "New Password";
1511189251Ssam		config->pending_req_new_password++;
1512189251Ssam		break;
1513189251Ssam	case TYPE_PIN:
1514189251Ssam		field = "PIN";
1515189251Ssam		txt = "PIN";
1516189251Ssam		config->pending_req_pin++;
1517189251Ssam		break;
1518189251Ssam	case TYPE_OTP:
1519189251Ssam		field = "OTP";
1520189251Ssam		if (msg) {
1521189251Ssam			tmp = os_malloc(msglen + 3);
1522189251Ssam			if (tmp == NULL)
1523189251Ssam				return;
1524189251Ssam			tmp[0] = '[';
1525189251Ssam			os_memcpy(tmp + 1, msg, msglen);
1526189251Ssam			tmp[msglen + 1] = ']';
1527189251Ssam			tmp[msglen + 2] = '\0';
1528189251Ssam			txt = tmp;
1529189251Ssam			os_free(config->pending_req_otp);
1530189251Ssam			config->pending_req_otp = tmp;
1531189251Ssam			config->pending_req_otp_len = msglen + 3;
1532189251Ssam		} else {
1533189251Ssam			if (config->pending_req_otp == NULL)
1534189251Ssam				return;
1535189251Ssam			txt = config->pending_req_otp;
1536189251Ssam		}
1537189251Ssam		break;
1538189251Ssam	case TYPE_PASSPHRASE:
1539189251Ssam		field = "PASSPHRASE";
1540189251Ssam		txt = "Private key passphrase";
1541189251Ssam		config->pending_req_passphrase++;
1542189251Ssam		break;
1543189251Ssam	default:
1544189251Ssam		return;
1545189251Ssam	}
1546189251Ssam
1547189251Ssam	if (sm->eapol_cb->eap_param_needed)
1548189251Ssam		sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
1549189251Ssam}
1550189251Ssam#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1551189251Ssam#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
1552189251Ssam#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1553189251Ssam
1554189251Ssam
1555189251Ssam/**
1556189251Ssam * eap_sm_request_identity - Request identity from user (ctrl_iface)
1557189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1558189251Ssam *
1559189251Ssam * EAP methods can call this function to request identity information for the
1560189251Ssam * current network. This is normally called when the identity is not included
1561189251Ssam * in the network configuration. The request will be sent to monitor programs
1562189251Ssam * through the control interface.
1563189251Ssam */
1564189251Ssamvoid eap_sm_request_identity(struct eap_sm *sm)
1565189251Ssam{
1566189251Ssam	eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
1567189251Ssam}
1568189251Ssam
1569189251Ssam
1570189251Ssam/**
1571189251Ssam * eap_sm_request_password - Request password from user (ctrl_iface)
1572189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1573189251Ssam *
1574189251Ssam * EAP methods can call this function to request password information for the
1575189251Ssam * current network. This is normally called when the password is not included
1576189251Ssam * in the network configuration. The request will be sent to monitor programs
1577189251Ssam * through the control interface.
1578189251Ssam */
1579189251Ssamvoid eap_sm_request_password(struct eap_sm *sm)
1580189251Ssam{
1581189251Ssam	eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
1582189251Ssam}
1583189251Ssam
1584189251Ssam
1585189251Ssam/**
1586189251Ssam * eap_sm_request_new_password - Request new password from user (ctrl_iface)
1587189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1588189251Ssam *
1589189251Ssam * EAP methods can call this function to request new password information for
1590189251Ssam * the current network. This is normally called when the EAP method indicates
1591189251Ssam * that the current password has expired and password change is required. The
1592189251Ssam * request will be sent to monitor programs through the control interface.
1593189251Ssam */
1594189251Ssamvoid eap_sm_request_new_password(struct eap_sm *sm)
1595189251Ssam{
1596189251Ssam	eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
1597189251Ssam}
1598189251Ssam
1599189251Ssam
1600189251Ssam/**
1601189251Ssam * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
1602189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1603189251Ssam *
1604189251Ssam * EAP methods can call this function to request SIM or smart card PIN
1605189251Ssam * information for the current network. This is normally called when the PIN is
1606189251Ssam * not included in the network configuration. The request will be sent to
1607189251Ssam * monitor programs through the control interface.
1608189251Ssam */
1609189251Ssamvoid eap_sm_request_pin(struct eap_sm *sm)
1610189251Ssam{
1611189251Ssam	eap_sm_request(sm, TYPE_PIN, NULL, 0);
1612189251Ssam}
1613189251Ssam
1614189251Ssam
1615189251Ssam/**
1616189251Ssam * eap_sm_request_otp - Request one time password from user (ctrl_iface)
1617189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1618189251Ssam * @msg: Message to be displayed to the user when asking for OTP
1619189251Ssam * @msg_len: Length of the user displayable message
1620189251Ssam *
1621189251Ssam * EAP methods can call this function to request open time password (OTP) for
1622189251Ssam * the current network. The request will be sent to monitor programs through
1623189251Ssam * the control interface.
1624189251Ssam */
1625189251Ssamvoid eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
1626189251Ssam{
1627189251Ssam	eap_sm_request(sm, TYPE_OTP, msg, msg_len);
1628189251Ssam}
1629189251Ssam
1630189251Ssam
1631189251Ssam/**
1632189251Ssam * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
1633189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1634189251Ssam *
1635189251Ssam * EAP methods can call this function to request passphrase for a private key
1636189251Ssam * for the current network. This is normally called when the passphrase is not
1637189251Ssam * included in the network configuration. The request will be sent to monitor
1638189251Ssam * programs through the control interface.
1639189251Ssam */
1640189251Ssamvoid eap_sm_request_passphrase(struct eap_sm *sm)
1641189251Ssam{
1642189251Ssam	eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
1643189251Ssam}
1644189251Ssam
1645189251Ssam
1646189251Ssam/**
1647189251Ssam * eap_sm_notify_ctrl_attached - Notification of attached monitor
1648189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1649189251Ssam *
1650189251Ssam * Notify EAP state machines that a monitor was attached to the control
1651189251Ssam * interface to trigger re-sending of pending requests for user input.
1652189251Ssam */
1653189251Ssamvoid eap_sm_notify_ctrl_attached(struct eap_sm *sm)
1654189251Ssam{
1655189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1656189251Ssam
1657189251Ssam	if (config == NULL)
1658189251Ssam		return;
1659189251Ssam
1660189251Ssam	/* Re-send any pending requests for user data since a new control
1661189251Ssam	 * interface was added. This handles cases where the EAP authentication
1662189251Ssam	 * starts immediately after system startup when the user interface is
1663189251Ssam	 * not yet running. */
1664189251Ssam	if (config->pending_req_identity)
1665189251Ssam		eap_sm_request_identity(sm);
1666189251Ssam	if (config->pending_req_password)
1667189251Ssam		eap_sm_request_password(sm);
1668189251Ssam	if (config->pending_req_new_password)
1669189251Ssam		eap_sm_request_new_password(sm);
1670189251Ssam	if (config->pending_req_otp)
1671189251Ssam		eap_sm_request_otp(sm, NULL, 0);
1672189251Ssam	if (config->pending_req_pin)
1673189251Ssam		eap_sm_request_pin(sm);
1674189251Ssam	if (config->pending_req_passphrase)
1675189251Ssam		eap_sm_request_passphrase(sm);
1676189251Ssam}
1677189251Ssam
1678189251Ssam
1679189251Ssamstatic int eap_allowed_phase2_type(int vendor, int type)
1680189251Ssam{
1681189251Ssam	if (vendor != EAP_VENDOR_IETF)
1682189251Ssam		return 0;
1683189251Ssam	return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
1684189251Ssam		type != EAP_TYPE_FAST;
1685189251Ssam}
1686189251Ssam
1687189251Ssam
1688189251Ssam/**
1689189251Ssam * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
1690189251Ssam * @name: EAP method name, e.g., MD5
1691189251Ssam * @vendor: Buffer for returning EAP Vendor-Id
1692189251Ssam * Returns: EAP method type or %EAP_TYPE_NONE if not found
1693189251Ssam *
1694189251Ssam * This function maps EAP type names into EAP type numbers that are allowed for
1695189251Ssam * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
1696189251Ssam * EAP-PEAP, EAP-TTLS, and EAP-FAST.
1697189251Ssam */
1698189251Ssamu32 eap_get_phase2_type(const char *name, int *vendor)
1699189251Ssam{
1700189251Ssam	int v;
1701189251Ssam	u8 type = eap_peer_get_type(name, &v);
1702189251Ssam	if (eap_allowed_phase2_type(v, type)) {
1703189251Ssam		*vendor = v;
1704189251Ssam		return type;
1705189251Ssam	}
1706189251Ssam	*vendor = EAP_VENDOR_IETF;
1707189251Ssam	return EAP_TYPE_NONE;
1708189251Ssam}
1709189251Ssam
1710189251Ssam
1711189251Ssam/**
1712189251Ssam * eap_get_phase2_types - Get list of allowed EAP phase 2 types
1713189251Ssam * @config: Pointer to a network configuration
1714189251Ssam * @count: Pointer to a variable to be filled with number of returned EAP types
1715189251Ssam * Returns: Pointer to allocated type list or %NULL on failure
1716189251Ssam *
1717189251Ssam * This function generates an array of allowed EAP phase 2 (tunneled) types for
1718189251Ssam * the given network configuration.
1719189251Ssam */
1720189251Ssamstruct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
1721189251Ssam					      size_t *count)
1722189251Ssam{
1723189251Ssam	struct eap_method_type *buf;
1724189251Ssam	u32 method;
1725189251Ssam	int vendor;
1726189251Ssam	size_t mcount;
1727189251Ssam	const struct eap_method *methods, *m;
1728189251Ssam
1729189251Ssam	methods = eap_peer_get_methods(&mcount);
1730189251Ssam	if (methods == NULL)
1731189251Ssam		return NULL;
1732189251Ssam	*count = 0;
1733189251Ssam	buf = os_malloc(mcount * sizeof(struct eap_method_type));
1734189251Ssam	if (buf == NULL)
1735189251Ssam		return NULL;
1736189251Ssam
1737189251Ssam	for (m = methods; m; m = m->next) {
1738189251Ssam		vendor = m->vendor;
1739189251Ssam		method = m->method;
1740189251Ssam		if (eap_allowed_phase2_type(vendor, method)) {
1741189251Ssam			if (vendor == EAP_VENDOR_IETF &&
1742189251Ssam			    method == EAP_TYPE_TLS && config &&
1743189251Ssam			    config->private_key2 == NULL)
1744189251Ssam				continue;
1745189251Ssam			buf[*count].vendor = vendor;
1746189251Ssam			buf[*count].method = method;
1747189251Ssam			(*count)++;
1748189251Ssam		}
1749189251Ssam	}
1750189251Ssam
1751189251Ssam	return buf;
1752189251Ssam}
1753189251Ssam
1754189251Ssam
1755189251Ssam/**
1756189251Ssam * eap_set_fast_reauth - Update fast_reauth setting
1757189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1758189251Ssam * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
1759189251Ssam */
1760189251Ssamvoid eap_set_fast_reauth(struct eap_sm *sm, int enabled)
1761189251Ssam{
1762189251Ssam	sm->fast_reauth = enabled;
1763189251Ssam}
1764189251Ssam
1765189251Ssam
1766189251Ssam/**
1767189251Ssam * eap_set_workaround - Update EAP workarounds setting
1768189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1769189251Ssam * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
1770189251Ssam */
1771189251Ssamvoid eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
1772189251Ssam{
1773189251Ssam	sm->workaround = workaround;
1774189251Ssam}
1775189251Ssam
1776189251Ssam
1777189251Ssam/**
1778189251Ssam * eap_get_config - Get current network configuration
1779189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1780189251Ssam * Returns: Pointer to the current network configuration or %NULL if not found
1781189251Ssam *
1782189251Ssam * EAP peer methods should avoid using this function if they can use other
1783189251Ssam * access functions, like eap_get_config_identity() and
1784189251Ssam * eap_get_config_password(), that do not require direct access to
1785189251Ssam * struct eap_peer_config.
1786189251Ssam */
1787189251Ssamstruct eap_peer_config * eap_get_config(struct eap_sm *sm)
1788189251Ssam{
1789189251Ssam	return sm->eapol_cb->get_config(sm->eapol_ctx);
1790189251Ssam}
1791189251Ssam
1792189251Ssam
1793189251Ssam/**
1794189251Ssam * eap_get_config_identity - Get identity from the network configuration
1795189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1796189251Ssam * @len: Buffer for the length of the identity
1797189251Ssam * Returns: Pointer to the identity or %NULL if not found
1798189251Ssam */
1799189251Ssamconst u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
1800189251Ssam{
1801189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1802189251Ssam	if (config == NULL)
1803189251Ssam		return NULL;
1804189251Ssam	*len = config->identity_len;
1805189251Ssam	return config->identity;
1806189251Ssam}
1807189251Ssam
1808189251Ssam
1809189251Ssam/**
1810189251Ssam * eap_get_config_password - Get password from the network configuration
1811189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1812189251Ssam * @len: Buffer for the length of the password
1813189251Ssam * Returns: Pointer to the password or %NULL if not found
1814189251Ssam */
1815189251Ssamconst u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
1816189251Ssam{
1817189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1818189251Ssam	if (config == NULL)
1819189251Ssam		return NULL;
1820189251Ssam	*len = config->password_len;
1821189251Ssam	return config->password;
1822189251Ssam}
1823189251Ssam
1824189251Ssam
1825189251Ssam/**
1826189251Ssam * eap_get_config_password2 - Get password from the network configuration
1827189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1828189251Ssam * @len: Buffer for the length of the password
1829189251Ssam * @hash: Buffer for returning whether the password is stored as a
1830189251Ssam * NtPasswordHash instead of plaintext password; can be %NULL if this
1831189251Ssam * information is not needed
1832189251Ssam * Returns: Pointer to the password or %NULL if not found
1833189251Ssam */
1834189251Ssamconst u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
1835189251Ssam{
1836189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1837189251Ssam	if (config == NULL)
1838189251Ssam		return NULL;
1839189251Ssam	*len = config->password_len;
1840189251Ssam	if (hash)
1841189251Ssam		*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
1842189251Ssam	return config->password;
1843189251Ssam}
1844189251Ssam
1845189251Ssam
1846189251Ssam/**
1847189251Ssam * eap_get_config_new_password - Get new password from network configuration
1848189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1849189251Ssam * @len: Buffer for the length of the new password
1850189251Ssam * Returns: Pointer to the new password or %NULL if not found
1851189251Ssam */
1852189251Ssamconst u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
1853189251Ssam{
1854189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1855189251Ssam	if (config == NULL)
1856189251Ssam		return NULL;
1857189251Ssam	*len = config->new_password_len;
1858189251Ssam	return config->new_password;
1859189251Ssam}
1860189251Ssam
1861189251Ssam
1862189251Ssam/**
1863189251Ssam * eap_get_config_otp - Get one-time password from the network configuration
1864189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1865189251Ssam * @len: Buffer for the length of the one-time password
1866189251Ssam * Returns: Pointer to the one-time password or %NULL if not found
1867189251Ssam */
1868189251Ssamconst u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
1869189251Ssam{
1870189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1871189251Ssam	if (config == NULL)
1872189251Ssam		return NULL;
1873189251Ssam	*len = config->otp_len;
1874189251Ssam	return config->otp;
1875189251Ssam}
1876189251Ssam
1877189251Ssam
1878189251Ssam/**
1879189251Ssam * eap_clear_config_otp - Clear used one-time password
1880189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1881189251Ssam *
1882189251Ssam * This function clears a used one-time password (OTP) from the current network
1883189251Ssam * configuration. This should be called when the OTP has been used and is not
1884189251Ssam * needed anymore.
1885189251Ssam */
1886189251Ssamvoid eap_clear_config_otp(struct eap_sm *sm)
1887189251Ssam{
1888189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1889189251Ssam	if (config == NULL)
1890189251Ssam		return;
1891189251Ssam	os_memset(config->otp, 0, config->otp_len);
1892189251Ssam	os_free(config->otp);
1893189251Ssam	config->otp = NULL;
1894189251Ssam	config->otp_len = 0;
1895189251Ssam}
1896189251Ssam
1897189251Ssam
1898189251Ssam/**
1899189251Ssam * eap_get_config_phase1 - Get phase1 data from the network configuration
1900189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1901189251Ssam * Returns: Pointer to the phase1 data or %NULL if not found
1902189251Ssam */
1903189251Ssamconst char * eap_get_config_phase1(struct eap_sm *sm)
1904189251Ssam{
1905189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1906189251Ssam	if (config == NULL)
1907189251Ssam		return NULL;
1908189251Ssam	return config->phase1;
1909189251Ssam}
1910189251Ssam
1911189251Ssam
1912189251Ssam/**
1913189251Ssam * eap_get_config_phase2 - Get phase2 data from the network configuration
1914189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1915189251Ssam * Returns: Pointer to the phase1 data or %NULL if not found
1916189251Ssam */
1917189251Ssamconst char * eap_get_config_phase2(struct eap_sm *sm)
1918189251Ssam{
1919189251Ssam	struct eap_peer_config *config = eap_get_config(sm);
1920189251Ssam	if (config == NULL)
1921189251Ssam		return NULL;
1922189251Ssam	return config->phase2;
1923189251Ssam}
1924189251Ssam
1925189251Ssam
1926189251Ssam/**
1927189251Ssam * eap_key_available - Get key availability (eapKeyAvailable variable)
1928189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1929189251Ssam * Returns: 1 if EAP keying material is available, 0 if not
1930189251Ssam */
1931189251Ssamint eap_key_available(struct eap_sm *sm)
1932189251Ssam{
1933189251Ssam	return sm ? sm->eapKeyAvailable : 0;
1934189251Ssam}
1935189251Ssam
1936189251Ssam
1937189251Ssam/**
1938189251Ssam * eap_notify_success - Notify EAP state machine about external success trigger
1939189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1940189251Ssam *
1941189251Ssam * This function is called when external event, e.g., successful completion of
1942189251Ssam * WPA-PSK key handshake, is indicating that EAP state machine should move to
1943189251Ssam * success state. This is mainly used with security modes that do not use EAP
1944189251Ssam * state machine (e.g., WPA-PSK).
1945189251Ssam */
1946189251Ssamvoid eap_notify_success(struct eap_sm *sm)
1947189251Ssam{
1948189251Ssam	if (sm) {
1949189251Ssam		sm->decision = DECISION_COND_SUCC;
1950189251Ssam		sm->EAP_state = EAP_SUCCESS;
1951189251Ssam	}
1952189251Ssam}
1953189251Ssam
1954189251Ssam
1955189251Ssam/**
1956189251Ssam * eap_notify_lower_layer_success - Notification of lower layer success
1957189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1958189251Ssam *
1959189251Ssam * Notify EAP state machines that a lower layer has detected a successful
1960189251Ssam * authentication. This is used to recover from dropped EAP-Success messages.
1961189251Ssam */
1962189251Ssamvoid eap_notify_lower_layer_success(struct eap_sm *sm)
1963189251Ssam{
1964189251Ssam	if (sm == NULL)
1965189251Ssam		return;
1966189251Ssam
1967189251Ssam	if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
1968189251Ssam	    sm->decision == DECISION_FAIL ||
1969189251Ssam	    (sm->methodState != METHOD_MAY_CONT &&
1970189251Ssam	     sm->methodState != METHOD_DONE))
1971189251Ssam		return;
1972189251Ssam
1973189251Ssam	if (sm->eapKeyData != NULL)
1974189251Ssam		sm->eapKeyAvailable = TRUE;
1975189251Ssam	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
1976189251Ssam	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1977189251Ssam		"EAP authentication completed successfully (based on lower "
1978189251Ssam		"layer success)");
1979189251Ssam}
1980189251Ssam
1981189251Ssam
1982189251Ssam/**
1983189251Ssam * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
1984189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
1985189251Ssam * @len: Pointer to variable that will be set to number of bytes in the key
1986189251Ssam * Returns: Pointer to the EAP keying data or %NULL on failure
1987189251Ssam *
1988189251Ssam * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
1989189251Ssam * key is available only after a successful authentication. EAP state machine
1990189251Ssam * continues to manage the key data and the caller must not change or free the
1991189251Ssam * returned data.
1992189251Ssam */
1993189251Ssamconst u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
1994189251Ssam{
1995189251Ssam	if (sm == NULL || sm->eapKeyData == NULL) {
1996189251Ssam		*len = 0;
1997189251Ssam		return NULL;
1998189251Ssam	}
1999189251Ssam
2000189251Ssam	*len = sm->eapKeyDataLen;
2001189251Ssam	return sm->eapKeyData;
2002189251Ssam}
2003189251Ssam
2004189251Ssam
2005189251Ssam/**
2006189251Ssam * eap_get_eapKeyData - Get EAP response data
2007189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2008189251Ssam * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
2009189251Ssam *
2010189251Ssam * Fetch EAP response (eapRespData) from the EAP state machine. This data is
2011189251Ssam * available when EAP state machine has processed an incoming EAP request. The
2012189251Ssam * EAP state machine does not maintain a reference to the response after this
2013189251Ssam * function is called and the caller is responsible for freeing the data.
2014189251Ssam */
2015189251Ssamstruct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
2016189251Ssam{
2017189251Ssam	struct wpabuf *resp;
2018189251Ssam
2019189251Ssam	if (sm == NULL || sm->eapRespData == NULL)
2020189251Ssam		return NULL;
2021189251Ssam
2022189251Ssam	resp = sm->eapRespData;
2023189251Ssam	sm->eapRespData = NULL;
2024189251Ssam
2025189251Ssam	return resp;
2026189251Ssam}
2027189251Ssam
2028189251Ssam
2029189251Ssam/**
2030189251Ssam * eap_sm_register_scard_ctx - Notification of smart card context
2031189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2032189251Ssam * @ctx: Context data for smart card operations
2033189251Ssam *
2034189251Ssam * Notify EAP state machines of context data for smart card operations. This
2035189251Ssam * context data will be used as a parameter for scard_*() functions.
2036189251Ssam */
2037189251Ssamvoid eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
2038189251Ssam{
2039189251Ssam	if (sm)
2040189251Ssam		sm->scard_ctx = ctx;
2041189251Ssam}
2042189251Ssam
2043189251Ssam
2044189251Ssam/**
2045189251Ssam * eap_set_config_blob - Set or add a named configuration blob
2046189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2047189251Ssam * @blob: New value for the blob
2048189251Ssam *
2049189251Ssam * Adds a new configuration blob or replaces the current value of an existing
2050189251Ssam * blob.
2051189251Ssam */
2052189251Ssamvoid eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
2053189251Ssam{
2054189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS
2055189251Ssam	sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
2056189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */
2057189251Ssam}
2058189251Ssam
2059189251Ssam
2060189251Ssam/**
2061189251Ssam * eap_get_config_blob - Get a named configuration blob
2062189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2063189251Ssam * @name: Name of the blob
2064189251Ssam * Returns: Pointer to blob data or %NULL if not found
2065189251Ssam */
2066189251Ssamconst struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
2067189251Ssam						   const char *name)
2068189251Ssam{
2069189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS
2070189251Ssam	return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
2071189251Ssam#else /* CONFIG_NO_CONFIG_BLOBS */
2072189251Ssam	return NULL;
2073189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */
2074189251Ssam}
2075189251Ssam
2076189251Ssam
2077189251Ssam/**
2078189251Ssam * eap_set_force_disabled - Set force_disabled flag
2079189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2080189251Ssam * @disabled: 1 = EAP disabled, 0 = EAP enabled
2081189251Ssam *
2082189251Ssam * This function is used to force EAP state machine to be disabled when it is
2083189251Ssam * not in use (e.g., with WPA-PSK or plaintext connections).
2084189251Ssam */
2085189251Ssamvoid eap_set_force_disabled(struct eap_sm *sm, int disabled)
2086189251Ssam{
2087189251Ssam	sm->force_disabled = disabled;
2088189251Ssam}
2089189251Ssam
2090189251Ssam
2091189251Ssam /**
2092189251Ssam * eap_notify_pending - Notify that EAP method is ready to re-process a request
2093189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2094189251Ssam *
2095189251Ssam * An EAP method can perform a pending operation (e.g., to get a response from
2096189251Ssam * an external process). Once the response is available, this function can be
2097189251Ssam * used to request EAPOL state machine to retry delivering the previously
2098189251Ssam * received (and still unanswered) EAP request to EAP state machine.
2099189251Ssam */
2100189251Ssamvoid eap_notify_pending(struct eap_sm *sm)
2101189251Ssam{
2102189251Ssam	sm->eapol_cb->notify_pending(sm->eapol_ctx);
2103189251Ssam}
2104189251Ssam
2105189251Ssam
2106189251Ssam/**
2107189251Ssam * eap_invalidate_cached_session - Mark cached session data invalid
2108189251Ssam * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
2109189251Ssam */
2110189251Ssamvoid eap_invalidate_cached_session(struct eap_sm *sm)
2111189251Ssam{
2112189251Ssam	if (sm)
2113189251Ssam		eap_deinit_prev_method(sm, "invalidate");
2114189251Ssam}
2115189251Ssam
2116189251Ssam
2117189251Ssamint eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
2118189251Ssam{
2119189251Ssam	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
2120189251Ssam	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
2121189251Ssam		return 0; /* Not a WPS Enrollee */
2122189251Ssam
2123189251Ssam	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
2124189251Ssam		return 0; /* Not using PBC */
2125189251Ssam
2126189251Ssam	return 1;
2127189251Ssam}
2128189251Ssam
2129189251Ssam
2130189251Ssamint eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
2131189251Ssam{
2132189251Ssam	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
2133189251Ssam	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
2134189251Ssam		return 0; /* Not a WPS Enrollee */
2135189251Ssam
2136189251Ssam	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
2137189251Ssam		return 0; /* Not using PIN */
2138189251Ssam
2139189251Ssam	return 1;
2140189251Ssam}
2141