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