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