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