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