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