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