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