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