xref: /freebsd/contrib/wpa/src/eapol_supp/eapol_supp_sm.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*
2  * EAPOL supplicant state machines
3  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "state_machine.h"
13 #include "wpabuf.h"
14 #include "eloop.h"
15 #include "crypto/crypto.h"
16 #include "crypto/md5.h"
17 #include "common/eapol_common.h"
18 #include "eap_peer/eap.h"
19 #include "eap_peer/eap_config.h"
20 #include "eap_peer/eap_proxy.h"
21 #include "eapol_supp_sm.h"
22 
23 #define STATE_MACHINE_DATA struct eapol_sm
24 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
25 
26 
27 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
28 
29 /**
30  * struct eapol_sm - Internal data for EAPOL state machines
31  */
32 struct eapol_sm {
33 	/* Timers */
34 	unsigned int authWhile;
35 	unsigned int heldWhile;
36 	unsigned int startWhen;
37 	unsigned int idleWhile; /* for EAP state machine */
38 	int timer_tick_enabled;
39 
40 	/* Global variables */
41 	bool eapFail;
42 	bool eapolEap;
43 	bool eapSuccess;
44 	bool initialize;
45 	bool keyDone;
46 	bool keyRun;
47 	PortControl portControl;
48 	bool portEnabled;
49 	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
50 	bool portValid;
51 	bool suppAbort;
52 	bool suppFail;
53 	bool suppStart;
54 	bool suppSuccess;
55 	bool suppTimeout;
56 
57 	/* Supplicant PAE state machine */
58 	enum {
59 		SUPP_PAE_UNKNOWN = 0,
60 		SUPP_PAE_DISCONNECTED = 1,
61 		SUPP_PAE_LOGOFF = 2,
62 		SUPP_PAE_CONNECTING = 3,
63 		SUPP_PAE_AUTHENTICATING = 4,
64 		SUPP_PAE_AUTHENTICATED = 5,
65 		/* unused(6) */
66 		SUPP_PAE_HELD = 7,
67 		SUPP_PAE_RESTART = 8,
68 		SUPP_PAE_S_FORCE_AUTH = 9,
69 		SUPP_PAE_S_FORCE_UNAUTH = 10
70 	} SUPP_PAE_state; /* dot1xSuppPaeState */
71 	/* Variables */
72 	bool userLogoff;
73 	bool logoffSent;
74 	unsigned int startCount;
75 	bool eapRestart;
76 	PortControl sPortMode;
77 	/* Constants */
78 	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
79 	unsigned int startPeriod; /* dot1xSuppStartPeriod */
80 	unsigned int maxStart; /* dot1xSuppMaxStart */
81 
82 	/* Key Receive state machine */
83 	enum {
84 		KEY_RX_UNKNOWN = 0,
85 		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
86 	} KEY_RX_state;
87 	/* Variables */
88 	bool rxKey;
89 
90 	/* Supplicant Backend state machine */
91 	enum {
92 		SUPP_BE_UNKNOWN = 0,
93 		SUPP_BE_INITIALIZE = 1,
94 		SUPP_BE_IDLE = 2,
95 		SUPP_BE_REQUEST = 3,
96 		SUPP_BE_RECEIVE = 4,
97 		SUPP_BE_RESPONSE = 5,
98 		SUPP_BE_FAIL = 6,
99 		SUPP_BE_TIMEOUT = 7,
100 		SUPP_BE_SUCCESS = 8
101 	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
102 	/* Variables */
103 	bool eapNoResp;
104 	bool eapReq;
105 	bool eapResp;
106 	/* Constants */
107 	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
108 
109 	/* Statistics */
110 	unsigned int dot1xSuppEapolFramesRx;
111 	unsigned int dot1xSuppEapolFramesTx;
112 	unsigned int dot1xSuppEapolStartFramesTx;
113 	unsigned int dot1xSuppEapolLogoffFramesTx;
114 	unsigned int dot1xSuppEapolRespFramesTx;
115 	unsigned int dot1xSuppEapolReqIdFramesRx;
116 	unsigned int dot1xSuppEapolReqFramesRx;
117 	unsigned int dot1xSuppInvalidEapolFramesRx;
118 	unsigned int dot1xSuppEapLengthErrorFramesRx;
119 	unsigned int dot1xSuppLastEapolFrameVersion;
120 	unsigned char dot1xSuppLastEapolFrameSource[6];
121 
122 	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
123 	bool changed;
124 	struct eap_sm *eap;
125 	struct eap_peer_config *config;
126 	bool initial_req;
127 	u8 *last_rx_key;
128 	size_t last_rx_key_len;
129 	struct wpabuf *eapReqData; /* for EAP */
130 	bool altAccept; /* for EAP */
131 	bool altReject; /* for EAP */
132 	bool eapTriggerStart;
133 	bool replay_counter_valid;
134 	u8 last_replay_counter[16];
135 	struct eapol_config conf;
136 	struct eapol_ctx *ctx;
137 	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
138 		cb_status;
139 	bool cached_pmk;
140 
141 	bool unicast_key_received, broadcast_key_received;
142 
143 	bool force_authorized_update;
144 
145 #ifdef CONFIG_EAP_PROXY
146 	bool use_eap_proxy;
147 	struct eap_proxy_sm *eap_proxy;
148 #endif /* CONFIG_EAP_PROXY */
149 };
150 
151 
152 static void eapol_sm_txLogoff(struct eapol_sm *sm);
153 static void eapol_sm_txStart(struct eapol_sm *sm);
154 static void eapol_sm_processKey(struct eapol_sm *sm);
155 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
156 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
157 static void eapol_sm_abortSupp(struct eapol_sm *sm);
158 static void eapol_sm_abort_cached(struct eapol_sm *sm);
159 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
160 static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
161 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
162 
163 
164 /* Port Timers state machine - implemented as a function that will be called
165  * once a second as a registered event loop timeout */
eapol_port_timers_tick(void * eloop_ctx,void * timeout_ctx)166 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
167 {
168 	struct eapol_sm *sm = timeout_ctx;
169 
170 	if (sm->authWhile > 0) {
171 		sm->authWhile--;
172 		if (sm->authWhile == 0)
173 			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
174 	}
175 	if (sm->heldWhile > 0) {
176 		sm->heldWhile--;
177 		if (sm->heldWhile == 0)
178 			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
179 	}
180 	if (sm->startWhen > 0) {
181 		sm->startWhen--;
182 		if (sm->startWhen == 0)
183 			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
184 	}
185 	if (sm->idleWhile > 0) {
186 		sm->idleWhile--;
187 		if (sm->idleWhile == 0)
188 			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
189 	}
190 
191 	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
192 		if (eloop_register_timeout(1, 0, eapol_port_timers_tick,
193 					   eloop_ctx, sm) < 0)
194 			sm->timer_tick_enabled = 0;
195 	} else {
196 		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
197 		sm->timer_tick_enabled = 0;
198 	}
199 	eapol_sm_step(sm);
200 }
201 
202 
eapol_sm_confirm_auth(struct eapol_sm * sm)203 static int eapol_sm_confirm_auth(struct eapol_sm *sm)
204 {
205 	if (!sm->ctx->confirm_auth_cb)
206 		return 0;
207 
208 	return sm->ctx->confirm_auth_cb(sm->ctx->ctx);
209 }
210 
211 
eapol_enable_timer_tick(struct eapol_sm * sm)212 static void eapol_enable_timer_tick(struct eapol_sm *sm)
213 {
214 	if (sm->timer_tick_enabled)
215 		return;
216 	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
217 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
218 	if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
219 		sm->timer_tick_enabled = 1;
220 }
221 
222 
SM_STATE(SUPP_PAE,LOGOFF)223 SM_STATE(SUPP_PAE, LOGOFF)
224 {
225 	SM_ENTRY(SUPP_PAE, LOGOFF);
226 	eapol_sm_txLogoff(sm);
227 	sm->logoffSent = true;
228 	eapol_sm_set_port_unauthorized(sm);
229 }
230 
231 
SM_STATE(SUPP_PAE,DISCONNECTED)232 SM_STATE(SUPP_PAE, DISCONNECTED)
233 {
234 	SM_ENTRY(SUPP_PAE, DISCONNECTED);
235 	sm->sPortMode = Auto;
236 	sm->startCount = 0;
237 	sm->eapTriggerStart = false;
238 	sm->logoffSent = false;
239 	eapol_sm_set_port_unauthorized(sm);
240 	sm->suppAbort = true;
241 
242 	sm->unicast_key_received = false;
243 	sm->broadcast_key_received = false;
244 
245 	/*
246 	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
247 	 * allows the timer tick to be stopped more quickly when the port is
248 	 * not enabled. Since this variable is used only within HELD state,
249 	 * clearing it on initialization does not change actual state machine
250 	 * behavior.
251 	 */
252 	sm->heldWhile = 0;
253 }
254 
255 
SM_STATE(SUPP_PAE,CONNECTING)256 SM_STATE(SUPP_PAE, CONNECTING)
257 {
258 	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING ||
259 		sm->SUPP_PAE_state == SUPP_PAE_HELD;
260 	SM_ENTRY(SUPP_PAE, CONNECTING);
261 
262 	if (sm->eapTriggerStart)
263 		send_start = 1;
264 	if (sm->ctx->preauth)
265 		send_start = 1;
266 	sm->eapTriggerStart = false;
267 
268 	if (send_start) {
269 		sm->startWhen = sm->startPeriod;
270 		sm->startCount++;
271 	} else {
272 		/*
273 		 * Do not send EAPOL-Start immediately since in most cases,
274 		 * Authenticator is going to start authentication immediately
275 		 * after association and an extra EAPOL-Start is just going to
276 		 * delay authentication. Use a short timeout to send the first
277 		 * EAPOL-Start if Authenticator does not start authentication.
278 		 */
279 		if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
280 			/* Reduce latency on starting WPS negotiation. */
281 			wpa_printf(MSG_DEBUG,
282 				   "EAPOL: Using shorter startWhen for WPS");
283 			sm->startWhen = 1;
284 		} else {
285 			sm->startWhen = 2;
286 		}
287 	}
288 	eapol_enable_timer_tick(sm);
289 	sm->eapolEap = false;
290 	if (send_start)
291 		eapol_sm_txStart(sm);
292 }
293 
294 
SM_STATE(SUPP_PAE,AUTHENTICATING)295 SM_STATE(SUPP_PAE, AUTHENTICATING)
296 {
297 	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
298 	sm->startCount = 0;
299 	sm->suppSuccess = false;
300 	sm->suppFail = false;
301 	sm->suppTimeout = false;
302 	sm->keyRun = false;
303 	sm->keyDone = false;
304 	sm->suppStart = true;
305 }
306 
307 
SM_STATE(SUPP_PAE,HELD)308 SM_STATE(SUPP_PAE, HELD)
309 {
310 	SM_ENTRY(SUPP_PAE, HELD);
311 	sm->heldWhile = sm->heldPeriod;
312 	eapol_enable_timer_tick(sm);
313 	eapol_sm_set_port_unauthorized(sm);
314 	sm->cb_status = EAPOL_CB_FAILURE;
315 }
316 
317 
SM_STATE(SUPP_PAE,AUTHENTICATED)318 SM_STATE(SUPP_PAE, AUTHENTICATED)
319 {
320 	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
321 	eapol_sm_set_port_authorized(sm);
322 	sm->cb_status = EAPOL_CB_SUCCESS;
323 }
324 
325 
SM_STATE(SUPP_PAE,RESTART)326 SM_STATE(SUPP_PAE, RESTART)
327 {
328 	if (eapol_sm_confirm_auth(sm)) {
329 		/* Don't process restart, we are already reconnecting */
330 		return;
331 	}
332 
333 	SM_ENTRY(SUPP_PAE, RESTART);
334 	sm->eapRestart = true;
335 	if (sm->altAccept) {
336 		/*
337 		 * Prevent EAP peer state machine from failing due to prior
338 		 * external EAP success notification (altSuccess=true in the
339 		 * IDLE state could result in a transition to the FAILURE state.
340 		 */
341 		wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
342 		sm->eapSuccess = false;
343 		sm->altAccept = false;
344 	}
345 }
346 
347 
SM_STATE(SUPP_PAE,S_FORCE_AUTH)348 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
349 {
350 	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
351 	eapol_sm_set_port_authorized(sm);
352 	sm->sPortMode = ForceAuthorized;
353 }
354 
355 
SM_STATE(SUPP_PAE,S_FORCE_UNAUTH)356 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
357 {
358 	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
359 	eapol_sm_set_port_unauthorized(sm);
360 	sm->sPortMode = ForceUnauthorized;
361 	eapol_sm_txLogoff(sm);
362 }
363 
364 
SM_STEP(SUPP_PAE)365 SM_STEP(SUPP_PAE)
366 {
367 	if ((sm->userLogoff && !sm->logoffSent) &&
368 	    !(sm->initialize || !sm->portEnabled))
369 		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
370 	else if (((sm->portControl == Auto) &&
371 		  (sm->sPortMode != sm->portControl)) ||
372 		 sm->initialize || !sm->portEnabled)
373 		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
374 	else if ((sm->portControl == ForceAuthorized) &&
375 		 (sm->sPortMode != sm->portControl) &&
376 		 !(sm->initialize || !sm->portEnabled))
377 		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
378 	else if ((sm->portControl == ForceUnauthorized) &&
379 		 (sm->sPortMode != sm->portControl) &&
380 		 !(sm->initialize || !sm->portEnabled))
381 		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
382 	else switch (sm->SUPP_PAE_state) {
383 	case SUPP_PAE_UNKNOWN:
384 		break;
385 	case SUPP_PAE_LOGOFF:
386 		if (!sm->userLogoff)
387 			SM_ENTER(SUPP_PAE, DISCONNECTED);
388 		break;
389 	case SUPP_PAE_DISCONNECTED:
390 		SM_ENTER(SUPP_PAE, CONNECTING);
391 		break;
392 	case SUPP_PAE_CONNECTING:
393 		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
394 			SM_ENTER(SUPP_PAE, CONNECTING);
395 		else if (sm->startWhen == 0 &&
396 			 sm->startCount >= sm->maxStart &&
397 			 sm->portValid)
398 			SM_ENTER(SUPP_PAE, AUTHENTICATED);
399 		else if (sm->eapSuccess || sm->eapFail)
400 			SM_ENTER(SUPP_PAE, AUTHENTICATING);
401 		else if (sm->eapolEap)
402 			SM_ENTER(SUPP_PAE, RESTART);
403 		else if (sm->startWhen == 0 &&
404 			 sm->startCount >= sm->maxStart &&
405 			 !sm->portValid)
406 			SM_ENTER(SUPP_PAE, HELD);
407 		break;
408 	case SUPP_PAE_AUTHENTICATING:
409 		if (sm->eapSuccess && !sm->portValid &&
410 		    sm->conf.accept_802_1x_keys &&
411 		    sm->conf.required_keys == 0) {
412 			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
413 				   "plaintext connection; no EAPOL-Key frames "
414 				   "required");
415 			sm->portValid = true;
416 			if (sm->ctx->eapol_done_cb)
417 				sm->ctx->eapol_done_cb(sm->ctx->ctx);
418 		}
419 		if (sm->eapSuccess && sm->portValid)
420 			SM_ENTER(SUPP_PAE, AUTHENTICATED);
421 		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
422 			SM_ENTER(SUPP_PAE, HELD);
423 		else if (sm->suppTimeout)
424 			SM_ENTER(SUPP_PAE, CONNECTING);
425 		else if (sm->eapTriggerStart)
426 			SM_ENTER(SUPP_PAE, CONNECTING);
427 		break;
428 	case SUPP_PAE_HELD:
429 		if (sm->heldWhile == 0)
430 			SM_ENTER(SUPP_PAE, CONNECTING);
431 		else if (sm->eapolEap)
432 			SM_ENTER(SUPP_PAE, RESTART);
433 		break;
434 	case SUPP_PAE_AUTHENTICATED:
435 		if (sm->eapolEap && sm->portValid)
436 			SM_ENTER(SUPP_PAE, RESTART);
437 		else if (!sm->portValid)
438 			SM_ENTER(SUPP_PAE, DISCONNECTED);
439 		break;
440 	case SUPP_PAE_RESTART:
441 		if (!sm->eapRestart)
442 			SM_ENTER(SUPP_PAE, AUTHENTICATING);
443 		break;
444 	case SUPP_PAE_S_FORCE_AUTH:
445 		break;
446 	case SUPP_PAE_S_FORCE_UNAUTH:
447 		break;
448 	}
449 }
450 
451 
SM_STATE(KEY_RX,NO_KEY_RECEIVE)452 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
453 {
454 	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
455 }
456 
457 
SM_STATE(KEY_RX,KEY_RECEIVE)458 SM_STATE(KEY_RX, KEY_RECEIVE)
459 {
460 	SM_ENTRY(KEY_RX, KEY_RECEIVE);
461 	eapol_sm_processKey(sm);
462 	sm->rxKey = false;
463 }
464 
465 
SM_STEP(KEY_RX)466 SM_STEP(KEY_RX)
467 {
468 	if (sm->initialize || !sm->portEnabled)
469 		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
470 	switch (sm->KEY_RX_state) {
471 	case KEY_RX_UNKNOWN:
472 		break;
473 	case KEY_RX_NO_KEY_RECEIVE:
474 		if (sm->rxKey)
475 			SM_ENTER(KEY_RX, KEY_RECEIVE);
476 		break;
477 	case KEY_RX_KEY_RECEIVE:
478 		if (sm->rxKey)
479 			SM_ENTER(KEY_RX, KEY_RECEIVE);
480 		break;
481 	}
482 }
483 
484 
SM_STATE(SUPP_BE,REQUEST)485 SM_STATE(SUPP_BE, REQUEST)
486 {
487 	SM_ENTRY(SUPP_BE, REQUEST);
488 	sm->authWhile = 0;
489 	sm->eapReq = true;
490 	eapol_sm_getSuppRsp(sm);
491 }
492 
493 
SM_STATE(SUPP_BE,RESPONSE)494 SM_STATE(SUPP_BE, RESPONSE)
495 {
496 	SM_ENTRY(SUPP_BE, RESPONSE);
497 	eapol_sm_txSuppRsp(sm);
498 	sm->eapResp = false;
499 }
500 
501 
SM_STATE(SUPP_BE,SUCCESS)502 SM_STATE(SUPP_BE, SUCCESS)
503 {
504 	SM_ENTRY(SUPP_BE, SUCCESS);
505 	sm->keyRun = true;
506 	sm->suppSuccess = true;
507 
508 #ifdef CONFIG_EAP_PROXY
509 	if (sm->use_eap_proxy) {
510 		if (eap_proxy_key_available(sm->eap_proxy)) {
511 			u8 *session_id, *emsk;
512 			size_t session_id_len, emsk_len;
513 
514 			/* New key received - clear IEEE 802.1X EAPOL-Key replay
515 			 * counter */
516 			sm->replay_counter_valid = false;
517 
518 			session_id = eap_proxy_get_eap_session_id(
519 				sm->eap_proxy, &session_id_len);
520 			emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
521 			if (sm->config->erp && session_id && emsk) {
522 				eap_peer_erp_init(sm->eap, session_id,
523 						  session_id_len, emsk,
524 						  emsk_len);
525 			} else {
526 				os_free(session_id);
527 				bin_clear_free(emsk, emsk_len);
528 			}
529 		}
530 		return;
531 	}
532 #endif /* CONFIG_EAP_PROXY */
533 
534 	if (eap_key_available(sm->eap)) {
535 		/* New key received - clear IEEE 802.1X EAPOL-Key replay
536 		 * counter */
537 		sm->replay_counter_valid = false;
538 	}
539 }
540 
541 
SM_STATE(SUPP_BE,FAIL)542 SM_STATE(SUPP_BE, FAIL)
543 {
544 	SM_ENTRY(SUPP_BE, FAIL);
545 	sm->suppFail = true;
546 }
547 
548 
SM_STATE(SUPP_BE,TIMEOUT)549 SM_STATE(SUPP_BE, TIMEOUT)
550 {
551 	SM_ENTRY(SUPP_BE, TIMEOUT);
552 	sm->suppTimeout = true;
553 }
554 
555 
SM_STATE(SUPP_BE,IDLE)556 SM_STATE(SUPP_BE, IDLE)
557 {
558 	SM_ENTRY(SUPP_BE, IDLE);
559 	sm->suppStart = false;
560 	sm->initial_req = true;
561 }
562 
563 
SM_STATE(SUPP_BE,INITIALIZE)564 SM_STATE(SUPP_BE, INITIALIZE)
565 {
566 	SM_ENTRY(SUPP_BE, INITIALIZE);
567 	eapol_sm_abortSupp(sm);
568 	sm->suppAbort = false;
569 
570 	/*
571 	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
572 	 * allows the timer tick to be stopped more quickly when the port is
573 	 * not enabled. Since this variable is used only within RECEIVE state,
574 	 * clearing it on initialization does not change actual state machine
575 	 * behavior.
576 	 */
577 	sm->authWhile = 0;
578 }
579 
580 
SM_STATE(SUPP_BE,RECEIVE)581 SM_STATE(SUPP_BE, RECEIVE)
582 {
583 	SM_ENTRY(SUPP_BE, RECEIVE);
584 	sm->authWhile = sm->authPeriod;
585 	eapol_enable_timer_tick(sm);
586 	sm->eapolEap = false;
587 	sm->eapNoResp = false;
588 	sm->initial_req = false;
589 }
590 
591 
SM_STEP(SUPP_BE)592 SM_STEP(SUPP_BE)
593 {
594 	if (sm->initialize || sm->suppAbort)
595 		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
596 	else switch (sm->SUPP_BE_state) {
597 	case SUPP_BE_UNKNOWN:
598 		break;
599 	case SUPP_BE_REQUEST:
600 		/*
601 		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
602 		 * and SUCCESS based on eapFail and eapSuccess, respectively.
603 		 * However, IEEE Std 802.1X-2004 is also specifying that
604 		 * eapNoResp should be set in conjunction with eapSuccess and
605 		 * eapFail which would mean that more than one of the
606 		 * transitions here would be activated at the same time.
607 		 * Skipping RESPONSE and/or RECEIVE states in these cases can
608 		 * cause problems and the direct transitions to do not seem
609 		 * correct. Because of this, the conditions for these
610 		 * transitions are verified only after eapNoResp. They are
611 		 * unlikely to be used since eapNoResp should always be set if
612 		 * either of eapSuccess or eapFail is set.
613 		 */
614 		if (sm->eapResp && sm->eapNoResp) {
615 			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
616 				   "eapResp and eapNoResp set?!");
617 		}
618 		if (sm->eapResp)
619 			SM_ENTER(SUPP_BE, RESPONSE);
620 		else if (sm->eapNoResp)
621 			SM_ENTER(SUPP_BE, RECEIVE);
622 		else if (sm->eapFail)
623 			SM_ENTER(SUPP_BE, FAIL);
624 		else if (sm->eapSuccess)
625 			SM_ENTER(SUPP_BE, SUCCESS);
626 		break;
627 	case SUPP_BE_RESPONSE:
628 		SM_ENTER(SUPP_BE, RECEIVE);
629 		break;
630 	case SUPP_BE_SUCCESS:
631 		SM_ENTER(SUPP_BE, IDLE);
632 		break;
633 	case SUPP_BE_FAIL:
634 		SM_ENTER(SUPP_BE, IDLE);
635 		break;
636 	case SUPP_BE_TIMEOUT:
637 		SM_ENTER(SUPP_BE, IDLE);
638 		break;
639 	case SUPP_BE_IDLE:
640 		if (sm->eapFail && sm->suppStart)
641 			SM_ENTER(SUPP_BE, FAIL);
642 		else if (sm->eapolEap && sm->suppStart)
643 			SM_ENTER(SUPP_BE, REQUEST);
644 		else if (sm->eapSuccess && sm->suppStart)
645 			SM_ENTER(SUPP_BE, SUCCESS);
646 		break;
647 	case SUPP_BE_INITIALIZE:
648 		SM_ENTER(SUPP_BE, IDLE);
649 		break;
650 	case SUPP_BE_RECEIVE:
651 		if (sm->eapolEap)
652 			SM_ENTER(SUPP_BE, REQUEST);
653 		else if (sm->eapFail)
654 			SM_ENTER(SUPP_BE, FAIL);
655 		else if (sm->authWhile == 0)
656 			SM_ENTER(SUPP_BE, TIMEOUT);
657 		else if (sm->eapSuccess)
658 			SM_ENTER(SUPP_BE, SUCCESS);
659 		break;
660 	}
661 }
662 
663 
eapol_sm_txLogoff(struct eapol_sm * sm)664 static void eapol_sm_txLogoff(struct eapol_sm *sm)
665 {
666 	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
667 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
668 			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
669 	sm->dot1xSuppEapolLogoffFramesTx++;
670 	sm->dot1xSuppEapolFramesTx++;
671 }
672 
673 
eapol_sm_txStart(struct eapol_sm * sm)674 static void eapol_sm_txStart(struct eapol_sm *sm)
675 {
676 	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
677 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
678 			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
679 	sm->dot1xSuppEapolStartFramesTx++;
680 	sm->dot1xSuppEapolFramesTx++;
681 }
682 
683 
684 #define IEEE8021X_ENCR_KEY_LEN 32
685 #define IEEE8021X_SIGN_KEY_LEN 32
686 
687 struct eap_key_data {
688 	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
689 	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
690 };
691 
692 
eapol_sm_processKey(struct eapol_sm * sm)693 static void eapol_sm_processKey(struct eapol_sm *sm)
694 {
695 #ifdef CONFIG_WEP
696 #ifndef CONFIG_FIPS
697 	struct ieee802_1x_hdr *hdr;
698 	struct ieee802_1x_eapol_key *key;
699 	struct eap_key_data keydata;
700 	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
701 #ifndef CONFIG_NO_RC4
702 	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
703 #endif /* CONFIG_NO_RC4 */
704 	int key_len, res, sign_key_len, encr_key_len;
705 	u16 rx_key_length;
706 	size_t plen;
707 
708 	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
709 	if (sm->last_rx_key == NULL)
710 		return;
711 
712 	if (!sm->conf.accept_802_1x_keys) {
713 		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
714 			   " even though this was not accepted - "
715 			   "ignoring this packet");
716 		return;
717 	}
718 
719 	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
720 		return;
721 	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
722 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
723 	plen = be_to_host16(hdr->length);
724 	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
725 		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
726 		return;
727 	}
728 	rx_key_length = WPA_GET_BE16(key->key_length);
729 	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
730 		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
731 		   hdr->version, hdr->type, be_to_host16(hdr->length),
732 		   key->type, rx_key_length, key->key_index);
733 
734 	eapol_sm_notify_lower_layer_success(sm, 1);
735 	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
736 	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
737 	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
738 	if (res < 0) {
739 		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
740 			   "decrypting EAPOL-Key keys");
741 		return;
742 	}
743 	if (res == 16) {
744 		/* LEAP derives only 16 bytes of keying material. */
745 		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
746 		if (res) {
747 			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
748 				   "master key for decrypting EAPOL-Key keys");
749 			return;
750 		}
751 		sign_key_len = 16;
752 		encr_key_len = 16;
753 		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
754 	} else if (res) {
755 		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
756 			   "data for decrypting EAPOL-Key keys (res=%d)", res);
757 		return;
758 	}
759 
760 	/* The key replay_counter must increase when same master key */
761 	if (sm->replay_counter_valid &&
762 	    os_memcmp(sm->last_replay_counter, key->replay_counter,
763 		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
764 		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
765 			   "not increase - ignoring key");
766 		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
767 			    sm->last_replay_counter,
768 			    IEEE8021X_REPLAY_COUNTER_LEN);
769 		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
770 			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
771 		return;
772 	}
773 
774 	/* Verify key signature (HMAC-MD5) */
775 	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
776 	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
777 	hmac_md5(keydata.sign_key, sign_key_len,
778 		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
779 		 key->key_signature);
780 	if (os_memcmp_const(orig_key_sign, key->key_signature,
781 			    IEEE8021X_KEY_SIGN_LEN) != 0) {
782 		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
783 			   "EAPOL-Key packet");
784 		os_memcpy(key->key_signature, orig_key_sign,
785 			  IEEE8021X_KEY_SIGN_LEN);
786 		return;
787 	}
788 	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
789 
790 	key_len = plen - sizeof(*key);
791 	if (key_len > 32 || rx_key_length > 32) {
792 		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
793 			   key_len ? key_len : rx_key_length);
794 		return;
795 	}
796 	if (key_len == rx_key_length) {
797 #ifdef CONFIG_NO_RC4
798 		if (encr_key_len) {
799 			/* otherwise unused */
800 		}
801 		wpa_printf(MSG_ERROR, "EAPOL: RC4 not supported in the build");
802 		return;
803 #else /* CONFIG_NO_RC4 */
804 		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
805 		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
806 			  encr_key_len);
807 		os_memcpy(datakey, key + 1, key_len);
808 		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
809 			 datakey, key_len);
810 		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
811 				datakey, key_len);
812 #endif /* CONFIG_NO_RC4 */
813 	} else if (key_len == 0) {
814 		/*
815 		 * IEEE 802.1X-2004 specifies that least significant Key Length
816 		 * octets from MS-MPPE-Send-Key are used as the key if the key
817 		 * data is not present. This seems to be meaning the beginning
818 		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
819 		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
820 		 * Anyway, taking the beginning of the keying material from EAP
821 		 * seems to interoperate with Authenticators.
822 		 */
823 		key_len = rx_key_length;
824 		os_memcpy(datakey, keydata.encr_key, key_len);
825 		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
826 				"material data encryption key",
827 				datakey, key_len);
828 	} else {
829 		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
830 			   "(key_length=%d)", key_len, rx_key_length);
831 		return;
832 	}
833 
834 	sm->replay_counter_valid = true;
835 	os_memcpy(sm->last_replay_counter, key->replay_counter,
836 		  IEEE8021X_REPLAY_COUNTER_LEN);
837 
838 	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
839 		   "len %d",
840 		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
841 		   "unicast" : "broadcast",
842 		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
843 
844 	if (sm->ctx->set_wep_key &&
845 	    sm->ctx->set_wep_key(sm->ctx->ctx,
846 				 !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG),
847 				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
848 				 datakey, key_len) < 0) {
849 		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
850 			   " driver.");
851 	} else {
852 		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
853 			sm->unicast_key_received = true;
854 		else
855 			sm->broadcast_key_received = true;
856 
857 		if ((sm->unicast_key_received ||
858 		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
859 		    (sm->broadcast_key_received ||
860 		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
861 		{
862 			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
863 				   "frames received");
864 			sm->portValid = true;
865 			if (sm->ctx->eapol_done_cb)
866 				sm->ctx->eapol_done_cb(sm->ctx->ctx);
867 		}
868 	}
869 #endif /* CONFIG_FIPS */
870 #endif /* CONFIG_WEP */
871 }
872 
873 
eapol_sm_getSuppRsp(struct eapol_sm * sm)874 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
875 {
876 	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
877 	/* EAP layer processing; no special code is needed, since Supplicant
878 	 * Backend state machine is waiting for eapNoResp or eapResp to be set
879 	 * and these are only set in the EAP state machine when the processing
880 	 * has finished. */
881 }
882 
883 
eapol_sm_txSuppRsp(struct eapol_sm * sm)884 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
885 {
886 	struct wpabuf *resp;
887 
888 	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
889 
890 #ifdef CONFIG_EAP_PROXY
891 	if (sm->use_eap_proxy) {
892 		/* Get EAP Response from EAP Proxy */
893 		resp = eap_proxy_get_eapRespData(sm->eap_proxy);
894 		if (resp == NULL) {
895 			wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
896 				   "response data not available");
897 			return;
898 		}
899 	} else
900 #endif /* CONFIG_EAP_PROXY */
901 
902 	resp = eap_get_eapRespData(sm->eap);
903 	if (resp == NULL) {
904 		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
905 			   "not available");
906 		return;
907 	}
908 
909 	/* Send EAP-Packet from the EAP layer to the Authenticator */
910 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
911 			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
912 			    wpabuf_len(resp));
913 
914 	/* eapRespData is not used anymore, so free it here */
915 	wpabuf_free(resp);
916 
917 	if (sm->initial_req)
918 		sm->dot1xSuppEapolReqIdFramesRx++;
919 	else
920 		sm->dot1xSuppEapolReqFramesRx++;
921 	sm->dot1xSuppEapolRespFramesTx++;
922 	sm->dot1xSuppEapolFramesTx++;
923 }
924 
925 
eapol_sm_abortSupp(struct eapol_sm * sm)926 static void eapol_sm_abortSupp(struct eapol_sm *sm)
927 {
928 	/* release system resources that may have been allocated for the
929 	 * authentication session */
930 	os_free(sm->last_rx_key);
931 	sm->last_rx_key = NULL;
932 	wpabuf_free(sm->eapReqData);
933 	sm->eapReqData = NULL;
934 	eap_sm_abort(sm->eap);
935 #ifdef CONFIG_EAP_PROXY
936 	eap_proxy_sm_abort(sm->eap_proxy);
937 #endif /* CONFIG_EAP_PROXY */
938 }
939 
940 
eapol_sm_step_timeout(void * eloop_ctx,void * timeout_ctx)941 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
942 {
943 	eapol_sm_step(timeout_ctx);
944 }
945 
946 
eapol_sm_set_port_authorized(struct eapol_sm * sm)947 static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
948 {
949 	int cb;
950 
951 	cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
952 	sm->force_authorized_update = false;
953 	sm->suppPortStatus = Authorized;
954 	if (cb && sm->ctx->port_cb)
955 		sm->ctx->port_cb(sm->ctx->ctx, 1);
956 }
957 
958 
eapol_sm_set_port_unauthorized(struct eapol_sm * sm)959 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
960 {
961 	int cb;
962 
963 	cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
964 	sm->force_authorized_update = false;
965 	sm->suppPortStatus = Unauthorized;
966 	if (cb && sm->ctx->port_cb)
967 		sm->ctx->port_cb(sm->ctx->ctx, 0);
968 }
969 
970 
971 /**
972  * eapol_sm_step - EAPOL state machine step function
973  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
974  *
975  * This function is called to notify the state machine about changed external
976  * variables. It will step through the EAPOL state machines in loop to process
977  * all triggered state changes.
978  */
eapol_sm_step(struct eapol_sm * sm)979 void eapol_sm_step(struct eapol_sm *sm)
980 {
981 	int i;
982 
983 	/* In theory, it should be ok to run this in loop until !changed.
984 	 * However, it is better to use a limit on number of iterations to
985 	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
986 	 * state machine were to generate a busy loop. */
987 	for (i = 0; i < 100; i++) {
988 		sm->changed = false;
989 		SM_STEP_RUN(SUPP_PAE);
990 		SM_STEP_RUN(KEY_RX);
991 		SM_STEP_RUN(SUPP_BE);
992 #ifdef CONFIG_EAP_PROXY
993 		if (sm->use_eap_proxy) {
994 			/* Drive the EAP proxy state machine */
995 			if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
996 				sm->changed = true;
997 		} else
998 #endif /* CONFIG_EAP_PROXY */
999 		if (eap_peer_sm_step(sm->eap))
1000 			sm->changed = true;
1001 		if (!sm->changed)
1002 			break;
1003 	}
1004 
1005 	if (sm->changed) {
1006 		/* restart EAPOL state machine step from timeout call in order
1007 		 * to allow other events to be processed. */
1008 		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1009 		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
1010 	}
1011 
1012 	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
1013 		enum eapol_supp_result result;
1014 		if (sm->cb_status == EAPOL_CB_SUCCESS)
1015 			result = EAPOL_SUPP_RESULT_SUCCESS;
1016 		else if (eap_peer_was_failure_expected(sm->eap))
1017 			result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
1018 		else
1019 			result = EAPOL_SUPP_RESULT_FAILURE;
1020 		sm->cb_status = EAPOL_CB_IN_PROGRESS;
1021 		sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
1022 	}
1023 }
1024 
1025 
1026 #ifdef CONFIG_CTRL_IFACE
eapol_supp_pae_state(int state)1027 static const char *eapol_supp_pae_state(int state)
1028 {
1029 	switch (state) {
1030 	case SUPP_PAE_LOGOFF:
1031 		return "LOGOFF";
1032 	case SUPP_PAE_DISCONNECTED:
1033 		return "DISCONNECTED";
1034 	case SUPP_PAE_CONNECTING:
1035 		return "CONNECTING";
1036 	case SUPP_PAE_AUTHENTICATING:
1037 		return "AUTHENTICATING";
1038 	case SUPP_PAE_HELD:
1039 		return "HELD";
1040 	case SUPP_PAE_AUTHENTICATED:
1041 		return "AUTHENTICATED";
1042 	case SUPP_PAE_RESTART:
1043 		return "RESTART";
1044 	default:
1045 		return "UNKNOWN";
1046 	}
1047 }
1048 
1049 
eapol_supp_be_state(int state)1050 static const char *eapol_supp_be_state(int state)
1051 {
1052 	switch (state) {
1053 	case SUPP_BE_REQUEST:
1054 		return "REQUEST";
1055 	case SUPP_BE_RESPONSE:
1056 		return "RESPONSE";
1057 	case SUPP_BE_SUCCESS:
1058 		return "SUCCESS";
1059 	case SUPP_BE_FAIL:
1060 		return "FAIL";
1061 	case SUPP_BE_TIMEOUT:
1062 		return "TIMEOUT";
1063 	case SUPP_BE_IDLE:
1064 		return "IDLE";
1065 	case SUPP_BE_INITIALIZE:
1066 		return "INITIALIZE";
1067 	case SUPP_BE_RECEIVE:
1068 		return "RECEIVE";
1069 	default:
1070 		return "UNKNOWN";
1071 	}
1072 }
1073 
1074 
eapol_port_status(PortStatus status)1075 static const char * eapol_port_status(PortStatus status)
1076 {
1077 	if (status == Authorized)
1078 		return "Authorized";
1079 	else
1080 		return "Unauthorized";
1081 }
1082 #endif /* CONFIG_CTRL_IFACE */
1083 
1084 
1085 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
eapol_port_control(PortControl ctrl)1086 static const char * eapol_port_control(PortControl ctrl)
1087 {
1088 	switch (ctrl) {
1089 	case Auto:
1090 		return "Auto";
1091 	case ForceUnauthorized:
1092 		return "ForceUnauthorized";
1093 	case ForceAuthorized:
1094 		return "ForceAuthorized";
1095 	default:
1096 		return "Unknown";
1097 	}
1098 }
1099 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1100 
1101 
1102 /**
1103  * eapol_sm_configure - Set EAPOL variables
1104  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1105  * @heldPeriod: dot1xSuppHeldPeriod
1106  * @authPeriod: dot1xSuppAuthPeriod
1107  * @startPeriod: dot1xSuppStartPeriod
1108  * @maxStart: dot1xSuppMaxStart
1109  *
1110  * Set configurable EAPOL state machine variables. Each variable can be set to
1111  * the given value or ignored if set to -1 (to set only some of the variables).
1112  */
eapol_sm_configure(struct eapol_sm * sm,int heldPeriod,int authPeriod,int startPeriod,int maxStart)1113 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
1114 			int startPeriod, int maxStart)
1115 {
1116 	if (sm == NULL)
1117 		return;
1118 	if (heldPeriod >= 0)
1119 		sm->heldPeriod = heldPeriod;
1120 	if (authPeriod >= 0)
1121 		sm->authPeriod = authPeriod;
1122 	if (startPeriod >= 0)
1123 		sm->startPeriod = startPeriod;
1124 	if (maxStart >= 0)
1125 		sm->maxStart = maxStart;
1126 }
1127 
1128 
1129 /**
1130  * eapol_sm_get_method_name - Get EAPOL method name
1131  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1132  * Returns: Static string containing name of current eap method or NULL
1133  */
eapol_sm_get_method_name(struct eapol_sm * sm)1134 const char * eapol_sm_get_method_name(struct eapol_sm *sm)
1135 {
1136 	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
1137 	    sm->suppPortStatus != Authorized)
1138 		return NULL;
1139 
1140 	return eap_sm_get_method_name(sm->eap);
1141 }
1142 
1143 
1144 #ifdef CONFIG_CTRL_IFACE
1145 /**
1146  * eapol_sm_get_status - Get EAPOL state machine status
1147  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1148  * @buf: Buffer for status information
1149  * @buflen: Maximum buffer length
1150  * @verbose: Whether to include verbose status information
1151  * Returns: Number of bytes written to buf.
1152  *
1153  * Query EAPOL state machine for status information. This function fills in a
1154  * text area with current status information from the EAPOL state machine. If
1155  * the buffer (buf) is not large enough, status information will be truncated
1156  * to fit the buffer.
1157  */
eapol_sm_get_status(struct eapol_sm * sm,char * buf,size_t buflen,int verbose)1158 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1159 			int verbose)
1160 {
1161 	int len, ret;
1162 	if (sm == NULL)
1163 		return 0;
1164 
1165 	len = os_snprintf(buf, buflen,
1166 			  "Supplicant PAE state=%s\n"
1167 			  "suppPortStatus=%s\n",
1168 			  eapol_supp_pae_state(sm->SUPP_PAE_state),
1169 			  eapol_port_status(sm->suppPortStatus));
1170 	if (os_snprintf_error(buflen, len))
1171 		return 0;
1172 
1173 	if (verbose) {
1174 		ret = os_snprintf(buf + len, buflen - len,
1175 				  "heldPeriod=%u\n"
1176 				  "authPeriod=%u\n"
1177 				  "startPeriod=%u\n"
1178 				  "maxStart=%u\n"
1179 				  "portControl=%s\n"
1180 				  "Supplicant Backend state=%s\n",
1181 				  sm->heldPeriod,
1182 				  sm->authPeriod,
1183 				  sm->startPeriod,
1184 				  sm->maxStart,
1185 				  eapol_port_control(sm->portControl),
1186 				  eapol_supp_be_state(sm->SUPP_BE_state));
1187 		if (os_snprintf_error(buflen - len, ret))
1188 			return len;
1189 		len += ret;
1190 	}
1191 
1192 #ifdef CONFIG_EAP_PROXY
1193 	if (sm->use_eap_proxy)
1194 		len += eap_proxy_sm_get_status(sm->eap_proxy,
1195 					       buf + len, buflen - len,
1196 					       verbose);
1197 	else
1198 #endif /* CONFIG_EAP_PROXY */
1199 	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1200 
1201 	return len;
1202 }
1203 
1204 
1205 /**
1206  * eapol_sm_get_mib - Get EAPOL state machine MIBs
1207  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1208  * @buf: Buffer for MIB information
1209  * @buflen: Maximum buffer length
1210  * Returns: Number of bytes written to buf.
1211  *
1212  * Query EAPOL state machine for MIB information. This function fills in a
1213  * text area with current MIB information from the EAPOL state machine. If
1214  * the buffer (buf) is not large enough, MIB information will be truncated to
1215  * fit the buffer.
1216  */
eapol_sm_get_mib(struct eapol_sm * sm,char * buf,size_t buflen)1217 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1218 {
1219 	size_t len;
1220 	int ret;
1221 
1222 	if (sm == NULL)
1223 		return 0;
1224 	ret = os_snprintf(buf, buflen,
1225 			  "dot1xSuppPaeState=%d\n"
1226 			  "dot1xSuppHeldPeriod=%u\n"
1227 			  "dot1xSuppAuthPeriod=%u\n"
1228 			  "dot1xSuppStartPeriod=%u\n"
1229 			  "dot1xSuppMaxStart=%u\n"
1230 			  "dot1xSuppSuppControlledPortStatus=%s\n"
1231 			  "dot1xSuppBackendPaeState=%d\n",
1232 			  sm->SUPP_PAE_state,
1233 			  sm->heldPeriod,
1234 			  sm->authPeriod,
1235 			  sm->startPeriod,
1236 			  sm->maxStart,
1237 			  sm->suppPortStatus == Authorized ?
1238 			  "Authorized" : "Unauthorized",
1239 			  sm->SUPP_BE_state);
1240 
1241 	if (os_snprintf_error(buflen, ret))
1242 		return 0;
1243 	len = ret;
1244 
1245 	ret = os_snprintf(buf + len, buflen - len,
1246 			  "dot1xSuppEapolFramesRx=%u\n"
1247 			  "dot1xSuppEapolFramesTx=%u\n"
1248 			  "dot1xSuppEapolStartFramesTx=%u\n"
1249 			  "dot1xSuppEapolLogoffFramesTx=%u\n"
1250 			  "dot1xSuppEapolRespFramesTx=%u\n"
1251 			  "dot1xSuppEapolReqIdFramesRx=%u\n"
1252 			  "dot1xSuppEapolReqFramesRx=%u\n"
1253 			  "dot1xSuppInvalidEapolFramesRx=%u\n"
1254 			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
1255 			  "dot1xSuppLastEapolFrameVersion=%u\n"
1256 			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1257 			  sm->dot1xSuppEapolFramesRx,
1258 			  sm->dot1xSuppEapolFramesTx,
1259 			  sm->dot1xSuppEapolStartFramesTx,
1260 			  sm->dot1xSuppEapolLogoffFramesTx,
1261 			  sm->dot1xSuppEapolRespFramesTx,
1262 			  sm->dot1xSuppEapolReqIdFramesRx,
1263 			  sm->dot1xSuppEapolReqFramesRx,
1264 			  sm->dot1xSuppInvalidEapolFramesRx,
1265 			  sm->dot1xSuppEapLengthErrorFramesRx,
1266 			  sm->dot1xSuppLastEapolFrameVersion,
1267 			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1268 
1269 	if (os_snprintf_error(buflen - len, ret))
1270 		return len;
1271 	len += ret;
1272 
1273 	return len;
1274 }
1275 #endif /* CONFIG_CTRL_IFACE */
1276 
1277 
1278 /**
1279  * eapol_sm_rx_eapol - Process received EAPOL frames
1280  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1281  * @src: Source MAC address of the EAPOL packet
1282  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1283  * @len: Length of the EAPOL frame
1284  * @encrypted: Whether the frame was encrypted
1285  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1286  * -1 failure
1287  */
eapol_sm_rx_eapol(struct eapol_sm * sm,const u8 * src,const u8 * buf,size_t len,enum frame_encryption encrypted)1288 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1289 		      size_t len, enum frame_encryption encrypted)
1290 {
1291 	const struct ieee802_1x_hdr *hdr;
1292 	const struct ieee802_1x_eapol_key *key;
1293 	int data_len;
1294 	int res = 1;
1295 	size_t plen;
1296 
1297 	if (sm == NULL)
1298 		return 0;
1299 
1300 	if (encrypted == FRAME_NOT_ENCRYPTED && sm->ctx->encryption_required &&
1301 	    sm->ctx->encryption_required(sm->ctx->ctx)) {
1302 		wpa_printf(MSG_DEBUG,
1303 			   "EAPOL: Discard unencrypted EAPOL frame when encryption since encryption was expected");
1304 		return 0;
1305 	}
1306 
1307 	sm->dot1xSuppEapolFramesRx++;
1308 	if (len < sizeof(*hdr)) {
1309 		sm->dot1xSuppInvalidEapolFramesRx++;
1310 		return 0;
1311 	}
1312 	hdr = (const struct ieee802_1x_hdr *) buf;
1313 	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1314 	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1315 	if (hdr->version < EAPOL_VERSION) {
1316 		/* TODO: backwards compatibility */
1317 	}
1318 	plen = be_to_host16(hdr->length);
1319 	if (plen > len - sizeof(*hdr)) {
1320 		sm->dot1xSuppEapLengthErrorFramesRx++;
1321 		return 0;
1322 	}
1323 #ifdef CONFIG_WPS
1324 	if (sm->conf.wps && sm->conf.workaround &&
1325 	    plen < len - sizeof(*hdr) &&
1326 	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1327 	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1328 		const struct eap_hdr *ehdr =
1329 			(const struct eap_hdr *) (hdr + 1);
1330 		u16 elen;
1331 
1332 		elen = be_to_host16(ehdr->length);
1333 		if (elen > plen && elen <= len - sizeof(*hdr)) {
1334 			/*
1335 			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1336 			 * packets with too short EAPOL header length field
1337 			 * (14 octets). This is fixed in firmware Ver.1.49.
1338 			 * As a workaround, fix the EAPOL header based on the
1339 			 * correct length in the EAP packet.
1340 			 */
1341 			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1342 				   "payload length based on EAP header: "
1343 				   "%d -> %d", (int) plen, elen);
1344 			plen = elen;
1345 		}
1346 	}
1347 #endif /* CONFIG_WPS */
1348 	data_len = plen + sizeof(*hdr);
1349 
1350 	switch (hdr->type) {
1351 	case IEEE802_1X_TYPE_EAP_PACKET:
1352 		if (sm->conf.workaround) {
1353 			/*
1354 			 * An AP has been reported to send out EAP message with
1355 			 * undocumented code 10 at some point near the
1356 			 * completion of EAP authentication. This can result in
1357 			 * issues with the unexpected EAP message triggering
1358 			 * restart of EAPOL authentication. Avoid this by
1359 			 * skipping the message without advancing the state
1360 			 * machine.
1361 			 */
1362 			const struct eap_hdr *ehdr =
1363 				(const struct eap_hdr *) (hdr + 1);
1364 			if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
1365 				wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
1366 				break;
1367 			}
1368 		}
1369 
1370 		if (sm->cached_pmk) {
1371 			/* Trying to use PMKSA caching, but Authenticator did
1372 			 * not seem to have a matching entry. Need to restart
1373 			 * EAPOL state machines.
1374 			 */
1375 			eapol_sm_abort_cached(sm);
1376 		}
1377 		wpabuf_free(sm->eapReqData);
1378 		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1379 		if (sm->eapReqData) {
1380 			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1381 				   "frame");
1382 			sm->eapolEap = true;
1383 #ifdef CONFIG_EAP_PROXY
1384 			if (sm->use_eap_proxy) {
1385 				eap_proxy_packet_update(
1386 					sm->eap_proxy,
1387 					wpabuf_mhead_u8(sm->eapReqData),
1388 					wpabuf_len(sm->eapReqData));
1389 				wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
1390 					   "EAP Req updated");
1391 			}
1392 #endif /* CONFIG_EAP_PROXY */
1393 			eapol_sm_step(sm);
1394 		}
1395 		break;
1396 	case IEEE802_1X_TYPE_EAPOL_KEY:
1397 		if (plen < sizeof(*key)) {
1398 			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1399 				   "frame received");
1400 			break;
1401 		}
1402 		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1403 		if (key->type == EAPOL_KEY_TYPE_WPA ||
1404 		    key->type == EAPOL_KEY_TYPE_RSN) {
1405 			/* WPA Supplicant takes care of this frame. */
1406 			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1407 				   "frame in EAPOL state machines");
1408 			res = 0;
1409 			break;
1410 		}
1411 		if (key->type != EAPOL_KEY_TYPE_RC4) {
1412 			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1413 				   "EAPOL-Key type %d", key->type);
1414 			break;
1415 		}
1416 		os_free(sm->last_rx_key);
1417 		sm->last_rx_key = os_malloc(data_len);
1418 		if (sm->last_rx_key) {
1419 			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1420 				   "frame");
1421 			os_memcpy(sm->last_rx_key, buf, data_len);
1422 			sm->last_rx_key_len = data_len;
1423 			sm->rxKey = true;
1424 			eapol_sm_step(sm);
1425 		}
1426 		break;
1427 #ifdef CONFIG_MACSEC
1428 	case IEEE802_1X_TYPE_EAPOL_MKA:
1429 		wpa_printf(MSG_EXCESSIVE,
1430 			   "EAPOL type %d will be handled by MKA",
1431 			   hdr->type);
1432 		break;
1433 #endif /* CONFIG_MACSEC */
1434 	default:
1435 		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1436 			   hdr->type);
1437 		sm->dot1xSuppInvalidEapolFramesRx++;
1438 		break;
1439 	}
1440 
1441 	return res;
1442 }
1443 
1444 
1445 /**
1446  * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1447  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1448  *
1449  * Notify EAPOL state machine about transmitted EAPOL packet from an external
1450  * component, e.g., WPA. This will update the statistics.
1451  */
eapol_sm_notify_tx_eapol_key(struct eapol_sm * sm)1452 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1453 {
1454 	if (sm)
1455 		sm->dot1xSuppEapolFramesTx++;
1456 }
1457 
1458 
1459 /**
1460  * eapol_sm_notify_portEnabled - Notification about portEnabled change
1461  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1462  * @enabled: New portEnabled value
1463  *
1464  * Notify EAPOL state machine about new portEnabled value.
1465  */
eapol_sm_notify_portEnabled(struct eapol_sm * sm,bool enabled)1466 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled)
1467 {
1468 	if (sm == NULL)
1469 		return;
1470 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1471 		   "portEnabled=%d", enabled);
1472 	if (sm->portEnabled != enabled)
1473 		sm->force_authorized_update = true;
1474 	sm->portEnabled = enabled;
1475 	eapol_sm_step(sm);
1476 }
1477 
1478 
1479 /**
1480  * eapol_sm_notify_portValid - Notification about portValid change
1481  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1482  * @valid: New portValid value
1483  *
1484  * Notify EAPOL state machine about new portValid value.
1485  */
eapol_sm_notify_portValid(struct eapol_sm * sm,bool valid)1486 void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid)
1487 {
1488 	if (sm == NULL)
1489 		return;
1490 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1491 		   "portValid=%d", valid);
1492 	sm->portValid = valid;
1493 	eapol_sm_step(sm);
1494 }
1495 
1496 
1497 /**
1498  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1499  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1500  * @success: %true = set success, %false = clear success
1501  *
1502  * Notify the EAPOL state machine that external event has forced EAP state to
1503  * success (success = %true). This can be cleared by setting success = %false.
1504  *
1505  * This function is called to update EAP state when WPA-PSK key handshake has
1506  * been completed successfully since WPA-PSK does not use EAP state machine.
1507  */
eapol_sm_notify_eap_success(struct eapol_sm * sm,bool success)1508 void eapol_sm_notify_eap_success(struct eapol_sm *sm, bool success)
1509 {
1510 	if (sm == NULL)
1511 		return;
1512 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1513 		   "EAP success=%d", success);
1514 	sm->eapSuccess = success;
1515 	sm->altAccept = success;
1516 	if (success)
1517 		eap_notify_success(sm->eap);
1518 	eapol_sm_step(sm);
1519 }
1520 
1521 
1522 /**
1523  * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1524  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1525  * @fail: %true = set failure, %false = clear failure
1526  *
1527  * Notify EAPOL state machine that external event has forced EAP state to
1528  * failure (fail = %true). This can be cleared by setting fail = %false.
1529  */
eapol_sm_notify_eap_fail(struct eapol_sm * sm,bool fail)1530 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, bool fail)
1531 {
1532 	if (sm == NULL)
1533 		return;
1534 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1535 		   "EAP fail=%d", fail);
1536 	sm->eapFail = fail;
1537 	sm->altReject = fail;
1538 	eapol_sm_step(sm);
1539 }
1540 
1541 
1542 /**
1543  * eapol_sm_notify_config - Notification of EAPOL configuration change
1544  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1545  * @config: Pointer to current network EAP configuration
1546  * @conf: Pointer to EAPOL configuration data
1547  *
1548  * Notify EAPOL state machine that configuration has changed. config will be
1549  * stored as a backpointer to network configuration. This can be %NULL to clear
1550  * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1551  * data. If conf is %NULL, this part of the configuration change will be
1552  * skipped.
1553  */
eapol_sm_notify_config(struct eapol_sm * sm,struct eap_peer_config * config,const struct eapol_config * conf)1554 void eapol_sm_notify_config(struct eapol_sm *sm,
1555 			    struct eap_peer_config *config,
1556 			    const struct eapol_config *conf)
1557 {
1558 	if (sm == NULL)
1559 		return;
1560 
1561 	sm->config = config;
1562 #ifdef CONFIG_EAP_PROXY
1563 	sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
1564 #endif /* CONFIG_EAP_PROXY */
1565 
1566 	if (conf == NULL)
1567 		return;
1568 
1569 	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1570 	sm->conf.required_keys = conf->required_keys;
1571 	sm->conf.fast_reauth = conf->fast_reauth;
1572 	sm->conf.workaround = conf->workaround;
1573 	sm->conf.wps = conf->wps;
1574 #ifdef CONFIG_EAP_PROXY
1575 	if (sm->use_eap_proxy) {
1576 		/* Using EAP Proxy, so skip EAP state machine update */
1577 		return;
1578 	}
1579 #endif /* CONFIG_EAP_PROXY */
1580 	if (sm->eap) {
1581 		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1582 		eap_set_workaround(sm->eap, conf->workaround);
1583 		eap_set_force_disabled(sm->eap, conf->eap_disabled);
1584 		eap_set_external_sim(sm->eap, conf->external_sim);
1585 	}
1586 }
1587 
1588 
1589 /**
1590  * eapol_sm_get_key - Get master session key (MSK) from EAP
1591  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1592  * @key: Pointer for key buffer
1593  * @len: Number of bytes to copy to key
1594  * Returns: 0 on success (len of key available), maximum available key len
1595  * (>0) if key is available but it is shorter than len, or -1 on failure.
1596  *
1597  * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1598  * is available only after a successful authentication.
1599  */
eapol_sm_get_key(struct eapol_sm * sm,u8 * key,size_t len)1600 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1601 {
1602 	const u8 *eap_key;
1603 	size_t eap_len;
1604 
1605 #ifdef CONFIG_EAP_PROXY
1606 	if (sm && sm->use_eap_proxy) {
1607 		/* Get key from EAP proxy */
1608 		if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
1609 			wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1610 			return -1;
1611 		}
1612 		eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
1613 		if (eap_key == NULL) {
1614 			wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
1615 				   "eapKeyData");
1616 			return -1;
1617 		}
1618 		goto key_fetched;
1619 	}
1620 #endif /* CONFIG_EAP_PROXY */
1621 	if (sm == NULL || !eap_key_available(sm->eap)) {
1622 		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1623 		return -1;
1624 	}
1625 	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1626 	if (eap_key == NULL) {
1627 		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1628 		return -1;
1629 	}
1630 #ifdef CONFIG_EAP_PROXY
1631 key_fetched:
1632 #endif /* CONFIG_EAP_PROXY */
1633 	if (len > eap_len) {
1634 		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1635 			   "available (len=%lu)",
1636 			   (unsigned long) len, (unsigned long) eap_len);
1637 		return eap_len;
1638 	}
1639 	os_memcpy(key, eap_key, len);
1640 	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1641 		   (unsigned long) len);
1642 	return 0;
1643 }
1644 
1645 
1646 /**
1647  * eapol_sm_get_session_id - Get EAP Session-Id
1648  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1649  * @len: Pointer to variable that will be set to number of bytes in the session
1650  * Returns: Pointer to the EAP Session-Id or %NULL on failure
1651  *
1652  * The Session-Id is available only after a successful authentication.
1653  */
eapol_sm_get_session_id(struct eapol_sm * sm,size_t * len)1654 const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
1655 {
1656 	if (sm == NULL || !eap_key_available(sm->eap)) {
1657 		wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
1658 		return NULL;
1659 	}
1660 	return eap_get_eapSessionId(sm->eap, len);
1661 }
1662 
1663 
1664 /**
1665  * eapol_sm_notify_logoff - Notification of logon/logoff commands
1666  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1667  * @logoff: Whether command was logoff
1668  *
1669  * Notify EAPOL state machines that user requested logon/logoff.
1670  */
eapol_sm_notify_logoff(struct eapol_sm * sm,bool logoff)1671 void eapol_sm_notify_logoff(struct eapol_sm *sm, bool logoff)
1672 {
1673 	if (sm) {
1674 		sm->userLogoff = logoff;
1675 		if (!logoff) {
1676 			/* If there is a delayed txStart queued, start now. */
1677 			sm->startWhen = 0;
1678 		}
1679 		eapol_sm_step(sm);
1680 	}
1681 }
1682 
1683 
1684 /**
1685  * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1686  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1687  *
1688  * Notify EAPOL state machines that PMKSA caching was successful. This is used
1689  * to move EAPOL and EAP state machines into authenticated/successful state.
1690  */
eapol_sm_notify_cached(struct eapol_sm * sm)1691 void eapol_sm_notify_cached(struct eapol_sm *sm)
1692 {
1693 	if (sm == NULL)
1694 		return;
1695 	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1696 	sm->eapSuccess = true;
1697 	eap_notify_success(sm->eap);
1698 	eapol_sm_step(sm);
1699 }
1700 
1701 
1702 /**
1703  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1704  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1705  *
1706  * Notify EAPOL state machines if PMKSA caching is used.
1707  */
eapol_sm_notify_pmkid_attempt(struct eapol_sm * sm)1708 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
1709 {
1710 	if (sm == NULL)
1711 		return;
1712 	wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1713 	sm->cached_pmk = true;
1714 }
1715 
1716 
eapol_sm_abort_cached(struct eapol_sm * sm)1717 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1718 {
1719 	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1720 		   "doing full EAP authentication");
1721 	if (sm == NULL)
1722 		return;
1723 	sm->cached_pmk = false;
1724 	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1725 	eapol_sm_set_port_unauthorized(sm);
1726 
1727 	/* Make sure we do not start sending EAPOL-Start frames first, but
1728 	 * instead move to RESTART state to start EAPOL authentication. */
1729 	sm->startWhen = 3;
1730 	eapol_enable_timer_tick(sm);
1731 
1732 	if (sm->ctx->aborted_cached)
1733 		sm->ctx->aborted_cached(sm->ctx->ctx);
1734 }
1735 
1736 
1737 /**
1738  * eapol_sm_register_scard_ctx - Notification of smart card context
1739  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1740  * @ctx: Context data for smart card operations
1741  *
1742  * Notify EAPOL state machines of context data for smart card operations. This
1743  * context data will be used as a parameter for scard_*() functions.
1744  */
eapol_sm_register_scard_ctx(struct eapol_sm * sm,void * ctx)1745 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1746 {
1747 	if (sm) {
1748 		sm->ctx->scard_ctx = ctx;
1749 		eap_register_scard_ctx(sm->eap, ctx);
1750 	}
1751 }
1752 
1753 
1754 /**
1755  * eapol_sm_notify_portControl - Notification of portControl changes
1756  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1757  * @portControl: New value for portControl variable
1758  *
1759  * Notify EAPOL state machines that portControl variable has changed.
1760  */
eapol_sm_notify_portControl(struct eapol_sm * sm,PortControl portControl)1761 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1762 {
1763 	if (sm == NULL)
1764 		return;
1765 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1766 		   "portControl=%s", eapol_port_control(portControl));
1767 	sm->portControl = portControl;
1768 	eapol_sm_step(sm);
1769 }
1770 
1771 
1772 /**
1773  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1774  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1775  *
1776  * Notify EAPOL state machines that a monitor was attached to the control
1777  * interface to trigger re-sending of pending requests for user input.
1778  */
eapol_sm_notify_ctrl_attached(struct eapol_sm * sm)1779 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1780 {
1781 	if (sm == NULL)
1782 		return;
1783 	eap_sm_notify_ctrl_attached(sm->eap);
1784 }
1785 
1786 
1787 /**
1788  * eapol_sm_notify_ctrl_response - Notification of received user input
1789  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1790  *
1791  * Notify EAPOL state machines that a control response, i.e., user
1792  * input, was received in order to trigger retrying of a pending EAP request.
1793  */
eapol_sm_notify_ctrl_response(struct eapol_sm * sm)1794 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1795 {
1796 	if (sm == NULL)
1797 		return;
1798 	if (sm->eapReqData && !sm->eapReq) {
1799 		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1800 			   "input) notification - retrying pending EAP "
1801 			   "Request");
1802 		sm->eapolEap = true;
1803 		sm->eapReq = true;
1804 		eapol_sm_step(sm);
1805 	}
1806 }
1807 
1808 
1809 /**
1810  * eapol_sm_request_reauth - Request reauthentication
1811  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1812  *
1813  * This function can be used to request EAPOL reauthentication, e.g., when the
1814  * current PMKSA entry is nearing expiration.
1815  */
eapol_sm_request_reauth(struct eapol_sm * sm)1816 void eapol_sm_request_reauth(struct eapol_sm *sm)
1817 {
1818 	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1819 		return;
1820 	eapol_sm_txStart(sm);
1821 }
1822 
1823 
1824 /**
1825  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1826  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1827  * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1828  * machine loop (eapol_sm_step())
1829  *
1830  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1831  * successful authentication. This is used to recover from dropped EAP-Success
1832  * messages.
1833  */
eapol_sm_notify_lower_layer_success(struct eapol_sm * sm,int in_eapol_sm)1834 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1835 {
1836 	if (sm == NULL)
1837 		return;
1838 	eap_notify_lower_layer_success(sm->eap);
1839 	if (!in_eapol_sm)
1840 		eapol_sm_step(sm);
1841 }
1842 
1843 
1844 /**
1845  * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1846  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1847  */
eapol_sm_invalidate_cached_session(struct eapol_sm * sm)1848 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1849 {
1850 	if (sm)
1851 		eap_invalidate_cached_session(sm->eap);
1852 }
1853 
1854 
eapol_sm_get_config(void * ctx)1855 static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1856 {
1857 	struct eapol_sm *sm = ctx;
1858 	return sm ? sm->config : NULL;
1859 }
1860 
1861 
eapol_sm_get_eapReqData(void * ctx)1862 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1863 {
1864 	struct eapol_sm *sm = ctx;
1865 	if (sm == NULL || sm->eapReqData == NULL)
1866 		return NULL;
1867 
1868 	return sm->eapReqData;
1869 }
1870 
1871 
eapol_sm_get_bool(void * ctx,enum eapol_bool_var variable)1872 static bool eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1873 {
1874 	struct eapol_sm *sm = ctx;
1875 	if (sm == NULL)
1876 		return false;
1877 	switch (variable) {
1878 	case EAPOL_eapSuccess:
1879 		return sm->eapSuccess;
1880 	case EAPOL_eapRestart:
1881 		return sm->eapRestart;
1882 	case EAPOL_eapFail:
1883 		return sm->eapFail;
1884 	case EAPOL_eapResp:
1885 		return sm->eapResp;
1886 	case EAPOL_eapNoResp:
1887 		return sm->eapNoResp;
1888 	case EAPOL_eapReq:
1889 		return sm->eapReq;
1890 	case EAPOL_portEnabled:
1891 		return sm->portEnabled;
1892 	case EAPOL_altAccept:
1893 		return sm->altAccept;
1894 	case EAPOL_altReject:
1895 		return sm->altReject;
1896 	case EAPOL_eapTriggerStart:
1897 		return sm->eapTriggerStart;
1898 	}
1899 	return false;
1900 }
1901 
1902 
eapol_sm_set_bool(void * ctx,enum eapol_bool_var variable,bool value)1903 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1904 			      bool value)
1905 {
1906 	struct eapol_sm *sm = ctx;
1907 	if (sm == NULL)
1908 		return;
1909 	switch (variable) {
1910 	case EAPOL_eapSuccess:
1911 		sm->eapSuccess = value;
1912 		break;
1913 	case EAPOL_eapRestart:
1914 		sm->eapRestart = value;
1915 		break;
1916 	case EAPOL_eapFail:
1917 		sm->eapFail = value;
1918 		break;
1919 	case EAPOL_eapResp:
1920 		sm->eapResp = value;
1921 		break;
1922 	case EAPOL_eapNoResp:
1923 		sm->eapNoResp = value;
1924 		break;
1925 	case EAPOL_eapReq:
1926 		sm->eapReq = value;
1927 		break;
1928 	case EAPOL_portEnabled:
1929 		sm->portEnabled = value;
1930 		break;
1931 	case EAPOL_altAccept:
1932 		sm->altAccept = value;
1933 		break;
1934 	case EAPOL_altReject:
1935 		sm->altReject = value;
1936 		break;
1937 	case EAPOL_eapTriggerStart:
1938 		sm->eapTriggerStart = value;
1939 		break;
1940 	}
1941 }
1942 
1943 
eapol_sm_get_int(void * ctx,enum eapol_int_var variable)1944 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1945 {
1946 	struct eapol_sm *sm = ctx;
1947 	if (sm == NULL)
1948 		return 0;
1949 	switch (variable) {
1950 	case EAPOL_idleWhile:
1951 		return sm->idleWhile;
1952 	}
1953 	return 0;
1954 }
1955 
1956 
eapol_sm_set_int(void * ctx,enum eapol_int_var variable,unsigned int value)1957 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1958 			     unsigned int value)
1959 {
1960 	struct eapol_sm *sm = ctx;
1961 	if (sm == NULL)
1962 		return;
1963 	switch (variable) {
1964 	case EAPOL_idleWhile:
1965 		sm->idleWhile = value;
1966 		if (sm->idleWhile > 0)
1967 			eapol_enable_timer_tick(sm);
1968 		break;
1969 	}
1970 }
1971 
1972 
eapol_sm_set_config_blob(void * ctx,struct wpa_config_blob * blob)1973 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1974 {
1975 #ifndef CONFIG_NO_CONFIG_BLOBS
1976 	struct eapol_sm *sm = ctx;
1977 	if (sm && sm->ctx && sm->ctx->set_config_blob)
1978 		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1979 #endif /* CONFIG_NO_CONFIG_BLOBS */
1980 }
1981 
1982 
1983 static const struct wpa_config_blob *
eapol_sm_get_config_blob(void * ctx,const char * name)1984 eapol_sm_get_config_blob(void *ctx, const char *name)
1985 {
1986 #ifndef CONFIG_NO_CONFIG_BLOBS
1987 	struct eapol_sm *sm = ctx;
1988 	if (sm && sm->ctx && sm->ctx->get_config_blob)
1989 		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1990 	else
1991 		return NULL;
1992 #else /* CONFIG_NO_CONFIG_BLOBS */
1993 	return NULL;
1994 #endif /* CONFIG_NO_CONFIG_BLOBS */
1995 }
1996 
1997 
eapol_sm_notify_pending(void * ctx)1998 static void eapol_sm_notify_pending(void *ctx)
1999 {
2000 	struct eapol_sm *sm = ctx;
2001 	if (sm == NULL)
2002 		return;
2003 	if (sm->eapReqData && !sm->eapReq) {
2004 		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
2005 			   "state machine - retrying pending EAP Request");
2006 		sm->eapolEap = true;
2007 		sm->eapReq = true;
2008 		eapol_sm_step(sm);
2009 	}
2010 }
2011 
2012 
2013 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
eapol_sm_eap_param_needed(void * ctx,enum wpa_ctrl_req_type field,const char * txt)2014 static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
2015 				      const char *txt)
2016 {
2017 	struct eapol_sm *sm = ctx;
2018 	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
2019 	if (sm->ctx->eap_param_needed)
2020 		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
2021 }
2022 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
2023 #define eapol_sm_eap_param_needed NULL
2024 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
2025 
eapol_sm_notify_cert(void * ctx,struct tls_cert_data * cert,const char * cert_hash)2026 static void eapol_sm_notify_cert(void *ctx, struct tls_cert_data *cert,
2027 				 const char *cert_hash)
2028 {
2029 	struct eapol_sm *sm = ctx;
2030 	if (sm->ctx->cert_cb)
2031 		sm->ctx->cert_cb(sm->ctx->ctx, cert, cert_hash);
2032 }
2033 
2034 
eapol_sm_notify_status(void * ctx,const char * status,const char * parameter)2035 static void eapol_sm_notify_status(void *ctx, const char *status,
2036 				   const char *parameter)
2037 {
2038 	struct eapol_sm *sm = ctx;
2039 
2040 	if (sm->ctx->status_cb)
2041 		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
2042 }
2043 
2044 
eapol_sm_notify_eap_error(void * ctx,int error_code)2045 static void eapol_sm_notify_eap_error(void *ctx, int error_code)
2046 {
2047 	struct eapol_sm *sm = ctx;
2048 
2049 	if (sm->ctx->eap_error_cb)
2050 		sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
2051 }
2052 
2053 
2054 #ifdef CONFIG_EAP_PROXY
2055 
eapol_sm_eap_proxy_cb(void * ctx)2056 static void eapol_sm_eap_proxy_cb(void *ctx)
2057 {
2058 	struct eapol_sm *sm = ctx;
2059 
2060 	if (sm->ctx->eap_proxy_cb)
2061 		sm->ctx->eap_proxy_cb(sm->ctx->ctx);
2062 }
2063 
2064 
2065 static void
eapol_sm_eap_proxy_notify_sim_status(void * ctx,enum eap_proxy_sim_state sim_state)2066 eapol_sm_eap_proxy_notify_sim_status(void *ctx,
2067 				     enum eap_proxy_sim_state sim_state)
2068 {
2069 	struct eapol_sm *sm = ctx;
2070 
2071 	if (sm->ctx->eap_proxy_notify_sim_status)
2072 		sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
2073 }
2074 
2075 #endif /* CONFIG_EAP_PROXY */
2076 
2077 
eapol_sm_set_anon_id(void * ctx,const u8 * id,size_t len)2078 static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
2079 {
2080 	struct eapol_sm *sm = ctx;
2081 
2082 	if (sm->ctx->set_anon_id)
2083 		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
2084 }
2085 
2086 
2087 static const struct eapol_callbacks eapol_cb =
2088 {
2089 	eapol_sm_get_config,
2090 	eapol_sm_get_bool,
2091 	eapol_sm_set_bool,
2092 	eapol_sm_get_int,
2093 	eapol_sm_set_int,
2094 	eapol_sm_get_eapReqData,
2095 	eapol_sm_set_config_blob,
2096 	eapol_sm_get_config_blob,
2097 	eapol_sm_notify_pending,
2098 	eapol_sm_eap_param_needed,
2099 	eapol_sm_notify_cert,
2100 	eapol_sm_notify_status,
2101 	eapol_sm_notify_eap_error,
2102 #ifdef CONFIG_EAP_PROXY
2103 	eapol_sm_eap_proxy_cb,
2104 	eapol_sm_eap_proxy_notify_sim_status,
2105 	eapol_sm_get_eap_proxy_imsi,
2106 #endif /* CONFIG_EAP_PROXY */
2107 	eapol_sm_set_anon_id
2108 };
2109 
2110 
2111 /**
2112  * eapol_sm_init - Initialize EAPOL state machine
2113  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
2114  * and EAPOL state machine will free it in eapol_sm_deinit()
2115  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
2116  *
2117  * Allocate and initialize an EAPOL state machine.
2118  */
eapol_sm_init(struct eapol_ctx * ctx)2119 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
2120 {
2121 	struct eapol_sm *sm;
2122 	struct eap_config conf;
2123 	sm = os_zalloc(sizeof(*sm));
2124 	if (sm == NULL)
2125 		return NULL;
2126 	sm->ctx = ctx;
2127 
2128 	sm->portControl = Auto;
2129 
2130 	/* Supplicant PAE state machine */
2131 	sm->heldPeriod = 60;
2132 	sm->startPeriod = 30;
2133 	sm->maxStart = 3;
2134 
2135 	/* Supplicant Backend state machine */
2136 	sm->authPeriod = 30;
2137 
2138 	os_memset(&conf, 0, sizeof(conf));
2139 #ifndef CONFIG_OPENSC_ENGINE_PATH
2140 	conf.opensc_engine_path = ctx->opensc_engine_path;
2141 #endif /* CONFIG_OPENSC_ENGINE_PATH */
2142 #ifndef CONFIG_PKCS11_ENGINE_PATH
2143 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
2144 #endif /* CONFIG_PKCS11_ENGINE_PATH */
2145 #ifndef CONFIG_PKCS11_MODULE_PATH
2146 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
2147 #endif /* CONFIG_PKCS11_MODULE_PATH */
2148 	conf.openssl_ciphers = ctx->openssl_ciphers;
2149 	conf.wps = ctx->wps;
2150 	conf.cert_in_cb = ctx->cert_in_cb;
2151 
2152 	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
2153 	if (sm->eap == NULL) {
2154 		os_free(sm);
2155 		return NULL;
2156 	}
2157 
2158 #ifdef CONFIG_EAP_PROXY
2159 	sm->use_eap_proxy = false;
2160 	sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
2161 	if (sm->eap_proxy == NULL) {
2162 		wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
2163 	}
2164 #endif /* CONFIG_EAP_PROXY */
2165 
2166 	/* Initialize EAPOL state machines */
2167 	sm->force_authorized_update = true;
2168 	sm->initialize = true;
2169 	eapol_sm_step(sm);
2170 	sm->initialize = false;
2171 	eapol_sm_step(sm);
2172 
2173 	if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
2174 		sm->timer_tick_enabled = 1;
2175 
2176 	return sm;
2177 }
2178 
2179 
2180 /**
2181  * eapol_sm_deinit - Deinitialize EAPOL state machine
2182  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
2183  *
2184  * Deinitialize and free EAPOL state machine.
2185  */
eapol_sm_deinit(struct eapol_sm * sm)2186 void eapol_sm_deinit(struct eapol_sm *sm)
2187 {
2188 	if (sm == NULL)
2189 		return;
2190 	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
2191 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
2192 	eap_peer_sm_deinit(sm->eap);
2193 #ifdef CONFIG_EAP_PROXY
2194 	eap_proxy_deinit(sm->eap_proxy);
2195 #endif /* CONFIG_EAP_PROXY */
2196 	os_free(sm->last_rx_key);
2197 	wpabuf_free(sm->eapReqData);
2198 	os_free(sm->ctx);
2199 	os_free(sm);
2200 }
2201 
2202 
eapol_sm_set_ext_pw_ctx(struct eapol_sm * sm,struct ext_password_data * ext)2203 void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
2204 			     struct ext_password_data *ext)
2205 {
2206 	if (sm && sm->eap)
2207 		eap_sm_set_ext_pw_ctx(sm->eap, ext);
2208 }
2209 
2210 
eapol_sm_failed(struct eapol_sm * sm)2211 int eapol_sm_failed(struct eapol_sm *sm)
2212 {
2213 	if (sm == NULL)
2214 		return 0;
2215 	return !sm->eapSuccess && sm->eapFail;
2216 }
2217 
2218 
2219 #ifdef CONFIG_EAP_PROXY
eapol_sm_get_eap_proxy_imsi(void * ctx,int sim_num,char * imsi,size_t * len)2220 int eapol_sm_get_eap_proxy_imsi(void *ctx, int sim_num, char *imsi, size_t *len)
2221 {
2222 	struct eapol_sm *sm = ctx;
2223 
2224 	if (sm->eap_proxy == NULL)
2225 		return -1;
2226 	return eap_proxy_get_imsi(sm->eap_proxy, sim_num, imsi, len);
2227 }
2228 #endif /* CONFIG_EAP_PROXY */
2229 
2230 
eapol_sm_erp_flush(struct eapol_sm * sm)2231 void eapol_sm_erp_flush(struct eapol_sm *sm)
2232 {
2233 	if (sm)
2234 		eap_peer_erp_free_keys(sm->eap);
2235 }
2236 
2237 
eapol_sm_build_erp_reauth_start(struct eapol_sm * sm)2238 struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
2239 {
2240 #ifdef CONFIG_ERP
2241 	if (!sm)
2242 		return NULL;
2243 	return eap_peer_build_erp_reauth_start(sm->eap, 0);
2244 #else /* CONFIG_ERP */
2245 	return NULL;
2246 #endif /* CONFIG_ERP */
2247 }
2248 
2249 
eapol_sm_process_erp_finish(struct eapol_sm * sm,const u8 * buf,size_t len)2250 void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
2251 				 size_t len)
2252 {
2253 #ifdef CONFIG_ERP
2254 	if (!sm)
2255 		return;
2256 	eap_peer_finish(sm->eap, (const struct eap_hdr *) buf, len);
2257 #endif /* CONFIG_ERP */
2258 }
2259 
2260 
eapol_sm_update_erp_next_seq_num(struct eapol_sm * sm,u16 next_seq_num)2261 int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num)
2262 {
2263 #ifdef CONFIG_ERP
2264 	if (!sm)
2265 		return -1;
2266 	return eap_peer_update_erp_next_seq_num(sm->eap, next_seq_num);
2267 #else /* CONFIG_ERP */
2268 	return -1;
2269 #endif /* CONFIG_ERP */
2270 }
2271 
2272 
eapol_sm_get_erp_info(struct eapol_sm * sm,struct eap_peer_config * config,const u8 ** username,size_t * username_len,const u8 ** realm,size_t * realm_len,u16 * erp_next_seq_num,const u8 ** rrk,size_t * rrk_len)2273 int eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
2274 			  const u8 **username, size_t *username_len,
2275 			  const u8 **realm, size_t *realm_len,
2276 			  u16 *erp_next_seq_num, const u8 **rrk,
2277 			  size_t *rrk_len)
2278 {
2279 #ifdef CONFIG_ERP
2280 	if (!sm)
2281 		return -1;
2282 	return eap_peer_get_erp_info(sm->eap, config, username, username_len,
2283 				     realm, realm_len, erp_next_seq_num, rrk,
2284 				     rrk_len);
2285 #else /* CONFIG_ERP */
2286 	return -1;
2287 #endif /* CONFIG_ERP */
2288 }
2289