2 * EAPOL supplicant state machines
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "state_machine.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 "eapol_supp_sm.h"
21 #define STATE_MACHINE_DATA struct eapol_sm
22 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
25 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
28 * struct eapol_sm - Internal data for EAPOL state machines
32 unsigned int authWhile;
33 unsigned int heldWhile;
34 unsigned int startWhen;
35 unsigned int idleWhile; /* for EAP state machine */
36 int timer_tick_enabled;
38 /* Global variables */
45 PortControl portControl;
47 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
55 /* Supplicant PAE state machine */
58 SUPP_PAE_DISCONNECTED = 1,
60 SUPP_PAE_CONNECTING = 3,
61 SUPP_PAE_AUTHENTICATING = 4,
62 SUPP_PAE_AUTHENTICATED = 5,
66 SUPP_PAE_S_FORCE_AUTH = 9,
67 SUPP_PAE_S_FORCE_UNAUTH = 10
68 } SUPP_PAE_state; /* dot1xSuppPaeState */
72 unsigned int startCount;
74 PortControl sPortMode;
76 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
77 unsigned int startPeriod; /* dot1xSuppStartPeriod */
78 unsigned int maxStart; /* dot1xSuppMaxStart */
80 /* Key Receive state machine */
83 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
88 /* Supplicant Backend state machine */
91 SUPP_BE_INITIALIZE = 1,
99 } SUPP_BE_state; /* dot1xSuppBackendPaeState */
105 unsigned int authPeriod; /* dot1xSuppAuthPeriod */
108 unsigned int dot1xSuppEapolFramesRx;
109 unsigned int dot1xSuppEapolFramesTx;
110 unsigned int dot1xSuppEapolStartFramesTx;
111 unsigned int dot1xSuppEapolLogoffFramesTx;
112 unsigned int dot1xSuppEapolRespFramesTx;
113 unsigned int dot1xSuppEapolReqIdFramesRx;
114 unsigned int dot1xSuppEapolReqFramesRx;
115 unsigned int dot1xSuppInvalidEapolFramesRx;
116 unsigned int dot1xSuppEapLengthErrorFramesRx;
117 unsigned int dot1xSuppLastEapolFrameVersion;
118 unsigned char dot1xSuppLastEapolFrameSource[6];
120 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
123 struct eap_peer_config *config;
126 size_t last_rx_key_len;
127 struct wpabuf *eapReqData; /* for EAP */
128 Boolean altAccept; /* for EAP */
129 Boolean altReject; /* for EAP */
130 Boolean replay_counter_valid;
131 u8 last_replay_counter[16];
132 struct eapol_config conf;
133 struct eapol_ctx *ctx;
134 enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
138 Boolean unicast_key_received, broadcast_key_received;
142 #define IEEE8021X_REPLAY_COUNTER_LEN 8
143 #define IEEE8021X_KEY_SIGN_LEN 16
144 #define IEEE8021X_KEY_IV_LEN 16
146 #define IEEE8021X_KEY_INDEX_FLAG 0x80
147 #define IEEE8021X_KEY_INDEX_MASK 0x03
150 #pragma pack(push, 1)
151 #endif /* _MSC_VER */
153 struct ieee802_1x_eapol_key {
155 /* Note: key_length is unaligned */
157 /* does not repeat within the life of the keying material used to
158 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
159 u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
160 u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
161 u8 key_index; /* key flag in the most significant bit:
162 * 0 = broadcast (default key),
163 * 1 = unicast (key mapping key); key index is in the
164 * 7 least significant bits */
165 /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
167 u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
169 /* followed by key: if packet body length = 44 + key length, then the
170 * key field (of key_length bytes) contains the key in encrypted form;
171 * if packet body length = 44, key field is absent and key_length
172 * represents the number of least significant octets from
173 * MS-MPPE-Send-Key attribute to be used as the keying material;
174 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
179 #endif /* _MSC_VER */
182 static void eapol_sm_txLogoff(struct eapol_sm *sm);
183 static void eapol_sm_txStart(struct eapol_sm *sm);
184 static void eapol_sm_processKey(struct eapol_sm *sm);
185 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
186 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
187 static void eapol_sm_abortSupp(struct eapol_sm *sm);
188 static void eapol_sm_abort_cached(struct eapol_sm *sm);
189 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
190 static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
191 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
194 /* Port Timers state machine - implemented as a function that will be called
195 * once a second as a registered event loop timeout */
196 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
198 struct eapol_sm *sm = timeout_ctx;
200 if (sm->authWhile > 0) {
202 if (sm->authWhile == 0)
203 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
205 if (sm->heldWhile > 0) {
207 if (sm->heldWhile == 0)
208 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
210 if (sm->startWhen > 0) {
212 if (sm->startWhen == 0)
213 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
215 if (sm->idleWhile > 0) {
217 if (sm->idleWhile == 0)
218 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
221 if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
222 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
225 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
226 sm->timer_tick_enabled = 0;
232 static void eapol_enable_timer_tick(struct eapol_sm *sm)
234 if (sm->timer_tick_enabled)
236 wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
237 sm->timer_tick_enabled = 1;
238 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
239 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
243 SM_STATE(SUPP_PAE, LOGOFF)
245 SM_ENTRY(SUPP_PAE, LOGOFF);
246 eapol_sm_txLogoff(sm);
247 sm->logoffSent = TRUE;
248 sm->suppPortStatus = Unauthorized;
249 eapol_sm_set_port_unauthorized(sm);
253 SM_STATE(SUPP_PAE, DISCONNECTED)
255 SM_ENTRY(SUPP_PAE, DISCONNECTED);
256 sm->sPortMode = Auto;
258 sm->logoffSent = FALSE;
259 sm->suppPortStatus = Unauthorized;
260 eapol_sm_set_port_unauthorized(sm);
261 sm->suppAbort = TRUE;
263 sm->unicast_key_received = FALSE;
264 sm->broadcast_key_received = FALSE;
267 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
268 * allows the timer tick to be stopped more quickly when the port is
269 * not enabled. Since this variable is used only within HELD state,
270 * clearing it on initialization does not change actual state machine
277 SM_STATE(SUPP_PAE, CONNECTING)
279 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
280 SM_ENTRY(SUPP_PAE, CONNECTING);
282 sm->startWhen = sm->startPeriod;
286 * Do not send EAPOL-Start immediately since in most cases,
287 * Authenticator is going to start authentication immediately
288 * after association and an extra EAPOL-Start is just going to
289 * delay authentication. Use a short timeout to send the first
290 * EAPOL-Start if Authenticator does not start authentication.
293 /* Reduce latency on starting WPS negotiation. */
295 #else /* CONFIG_WPS */
297 #endif /* CONFIG_WPS */
299 eapol_enable_timer_tick(sm);
300 sm->eapolEap = FALSE;
302 eapol_sm_txStart(sm);
306 SM_STATE(SUPP_PAE, AUTHENTICATING)
308 SM_ENTRY(SUPP_PAE, AUTHENTICATING);
310 sm->suppSuccess = FALSE;
311 sm->suppFail = FALSE;
312 sm->suppTimeout = FALSE;
315 sm->suppStart = TRUE;
319 SM_STATE(SUPP_PAE, HELD)
321 SM_ENTRY(SUPP_PAE, HELD);
322 sm->heldWhile = sm->heldPeriod;
323 eapol_enable_timer_tick(sm);
324 sm->suppPortStatus = Unauthorized;
325 eapol_sm_set_port_unauthorized(sm);
326 sm->cb_status = EAPOL_CB_FAILURE;
330 SM_STATE(SUPP_PAE, AUTHENTICATED)
332 SM_ENTRY(SUPP_PAE, AUTHENTICATED);
333 sm->suppPortStatus = Authorized;
334 eapol_sm_set_port_authorized(sm);
335 sm->cb_status = EAPOL_CB_SUCCESS;
339 SM_STATE(SUPP_PAE, RESTART)
341 SM_ENTRY(SUPP_PAE, RESTART);
342 sm->eapRestart = TRUE;
346 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
348 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
349 sm->suppPortStatus = Authorized;
350 eapol_sm_set_port_authorized(sm);
351 sm->sPortMode = ForceAuthorized;
355 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
357 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
358 sm->suppPortStatus = Unauthorized;
359 eapol_sm_set_port_unauthorized(sm);
360 sm->sPortMode = ForceUnauthorized;
361 eapol_sm_txLogoff(sm);
367 if ((sm->userLogoff && !sm->logoffSent) &&
368 !(sm->initialize || !sm->portEnabled))
369 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
370 else if (((sm->portControl == Auto) &&
371 (sm->sPortMode != sm->portControl)) ||
372 sm->initialize || !sm->portEnabled)
373 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
374 else if ((sm->portControl == ForceAuthorized) &&
375 (sm->sPortMode != sm->portControl) &&
376 !(sm->initialize || !sm->portEnabled))
377 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
378 else if ((sm->portControl == ForceUnauthorized) &&
379 (sm->sPortMode != sm->portControl) &&
380 !(sm->initialize || !sm->portEnabled))
381 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
382 else switch (sm->SUPP_PAE_state) {
383 case SUPP_PAE_UNKNOWN:
385 case SUPP_PAE_LOGOFF:
387 SM_ENTER(SUPP_PAE, DISCONNECTED);
389 case SUPP_PAE_DISCONNECTED:
390 SM_ENTER(SUPP_PAE, CONNECTING);
392 case SUPP_PAE_CONNECTING:
393 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
394 SM_ENTER(SUPP_PAE, CONNECTING);
395 else if (sm->startWhen == 0 &&
396 sm->startCount >= sm->maxStart &&
398 SM_ENTER(SUPP_PAE, AUTHENTICATED);
399 else if (sm->eapSuccess || sm->eapFail)
400 SM_ENTER(SUPP_PAE, AUTHENTICATING);
401 else if (sm->eapolEap)
402 SM_ENTER(SUPP_PAE, RESTART);
403 else if (sm->startWhen == 0 &&
404 sm->startCount >= sm->maxStart &&
406 SM_ENTER(SUPP_PAE, HELD);
408 case SUPP_PAE_AUTHENTICATING:
409 if (sm->eapSuccess && !sm->portValid &&
410 sm->conf.accept_802_1x_keys &&
411 sm->conf.required_keys == 0) {
412 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
413 "plaintext connection; no EAPOL-Key frames "
415 sm->portValid = TRUE;
416 if (sm->ctx->eapol_done_cb)
417 sm->ctx->eapol_done_cb(sm->ctx->ctx);
419 if (sm->eapSuccess && sm->portValid)
420 SM_ENTER(SUPP_PAE, AUTHENTICATED);
421 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
422 SM_ENTER(SUPP_PAE, HELD);
423 else if (sm->suppTimeout)
424 SM_ENTER(SUPP_PAE, CONNECTING);
427 if (sm->heldWhile == 0)
428 SM_ENTER(SUPP_PAE, CONNECTING);
429 else if (sm->eapolEap)
430 SM_ENTER(SUPP_PAE, RESTART);
432 case SUPP_PAE_AUTHENTICATED:
433 if (sm->eapolEap && sm->portValid)
434 SM_ENTER(SUPP_PAE, RESTART);
435 else if (!sm->portValid)
436 SM_ENTER(SUPP_PAE, DISCONNECTED);
438 case SUPP_PAE_RESTART:
440 SM_ENTER(SUPP_PAE, AUTHENTICATING);
442 case SUPP_PAE_S_FORCE_AUTH:
444 case SUPP_PAE_S_FORCE_UNAUTH:
450 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
452 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
456 SM_STATE(KEY_RX, KEY_RECEIVE)
458 SM_ENTRY(KEY_RX, KEY_RECEIVE);
459 eapol_sm_processKey(sm);
466 if (sm->initialize || !sm->portEnabled)
467 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
468 switch (sm->KEY_RX_state) {
471 case KEY_RX_NO_KEY_RECEIVE:
473 SM_ENTER(KEY_RX, KEY_RECEIVE);
475 case KEY_RX_KEY_RECEIVE:
477 SM_ENTER(KEY_RX, KEY_RECEIVE);
483 SM_STATE(SUPP_BE, REQUEST)
485 SM_ENTRY(SUPP_BE, REQUEST);
488 eapol_sm_getSuppRsp(sm);
492 SM_STATE(SUPP_BE, RESPONSE)
494 SM_ENTRY(SUPP_BE, RESPONSE);
495 eapol_sm_txSuppRsp(sm);
500 SM_STATE(SUPP_BE, SUCCESS)
502 SM_ENTRY(SUPP_BE, SUCCESS);
504 sm->suppSuccess = TRUE;
506 if (eap_key_available(sm->eap)) {
507 /* New key received - clear IEEE 802.1X EAPOL-Key replay
509 sm->replay_counter_valid = FALSE;
514 SM_STATE(SUPP_BE, FAIL)
516 SM_ENTRY(SUPP_BE, FAIL);
521 SM_STATE(SUPP_BE, TIMEOUT)
523 SM_ENTRY(SUPP_BE, TIMEOUT);
524 sm->suppTimeout = TRUE;
528 SM_STATE(SUPP_BE, IDLE)
530 SM_ENTRY(SUPP_BE, IDLE);
531 sm->suppStart = FALSE;
532 sm->initial_req = TRUE;
536 SM_STATE(SUPP_BE, INITIALIZE)
538 SM_ENTRY(SUPP_BE, INITIALIZE);
539 eapol_sm_abortSupp(sm);
540 sm->suppAbort = FALSE;
543 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
544 * allows the timer tick to be stopped more quickly when the port is
545 * not enabled. Since this variable is used only within RECEIVE state,
546 * clearing it on initialization does not change actual state machine
553 SM_STATE(SUPP_BE, RECEIVE)
555 SM_ENTRY(SUPP_BE, RECEIVE);
556 sm->authWhile = sm->authPeriod;
557 eapol_enable_timer_tick(sm);
558 sm->eapolEap = FALSE;
559 sm->eapNoResp = FALSE;
560 sm->initial_req = FALSE;
566 if (sm->initialize || sm->suppAbort)
567 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
568 else switch (sm->SUPP_BE_state) {
569 case SUPP_BE_UNKNOWN:
571 case SUPP_BE_REQUEST:
573 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
574 * and SUCCESS based on eapFail and eapSuccess, respectively.
575 * However, IEEE Std 802.1X-2004 is also specifying that
576 * eapNoResp should be set in conjunction with eapSuccess and
577 * eapFail which would mean that more than one of the
578 * transitions here would be activated at the same time.
579 * Skipping RESPONSE and/or RECEIVE states in these cases can
580 * cause problems and the direct transitions to do not seem
581 * correct. Because of this, the conditions for these
582 * transitions are verified only after eapNoResp. They are
583 * unlikely to be used since eapNoResp should always be set if
584 * either of eapSuccess or eapFail is set.
586 if (sm->eapResp && sm->eapNoResp) {
587 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
588 "eapResp and eapNoResp set?!");
591 SM_ENTER(SUPP_BE, RESPONSE);
592 else if (sm->eapNoResp)
593 SM_ENTER(SUPP_BE, RECEIVE);
594 else if (sm->eapFail)
595 SM_ENTER(SUPP_BE, FAIL);
596 else if (sm->eapSuccess)
597 SM_ENTER(SUPP_BE, SUCCESS);
599 case SUPP_BE_RESPONSE:
600 SM_ENTER(SUPP_BE, RECEIVE);
602 case SUPP_BE_SUCCESS:
603 SM_ENTER(SUPP_BE, IDLE);
606 SM_ENTER(SUPP_BE, IDLE);
608 case SUPP_BE_TIMEOUT:
609 SM_ENTER(SUPP_BE, IDLE);
612 if (sm->eapFail && sm->suppStart)
613 SM_ENTER(SUPP_BE, FAIL);
614 else if (sm->eapolEap && sm->suppStart)
615 SM_ENTER(SUPP_BE, REQUEST);
616 else if (sm->eapSuccess && sm->suppStart)
617 SM_ENTER(SUPP_BE, SUCCESS);
619 case SUPP_BE_INITIALIZE:
620 SM_ENTER(SUPP_BE, IDLE);
622 case SUPP_BE_RECEIVE:
624 SM_ENTER(SUPP_BE, REQUEST);
625 else if (sm->eapFail)
626 SM_ENTER(SUPP_BE, FAIL);
627 else if (sm->authWhile == 0)
628 SM_ENTER(SUPP_BE, TIMEOUT);
629 else if (sm->eapSuccess)
630 SM_ENTER(SUPP_BE, SUCCESS);
636 static void eapol_sm_txLogoff(struct eapol_sm *sm)
638 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
639 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
640 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
641 sm->dot1xSuppEapolLogoffFramesTx++;
642 sm->dot1xSuppEapolFramesTx++;
646 static void eapol_sm_txStart(struct eapol_sm *sm)
648 wpa_printf(MSG_DEBUG, "EAPOL: txStart");
649 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
650 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
651 sm->dot1xSuppEapolStartFramesTx++;
652 sm->dot1xSuppEapolFramesTx++;
656 #define IEEE8021X_ENCR_KEY_LEN 32
657 #define IEEE8021X_SIGN_KEY_LEN 32
659 struct eap_key_data {
660 u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
661 u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
665 static void eapol_sm_processKey(struct eapol_sm *sm)
667 struct ieee802_1x_hdr *hdr;
668 struct ieee802_1x_eapol_key *key;
669 struct eap_key_data keydata;
670 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
671 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
672 int key_len, res, sign_key_len, encr_key_len;
675 wpa_printf(MSG_DEBUG, "EAPOL: processKey");
676 if (sm->last_rx_key == NULL)
679 if (!sm->conf.accept_802_1x_keys) {
680 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
681 " even though this was not accepted - "
682 "ignoring this packet");
686 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
687 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
688 if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
689 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
692 rx_key_length = WPA_GET_BE16(key->key_length);
693 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
694 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
695 hdr->version, hdr->type, be_to_host16(hdr->length),
696 key->type, rx_key_length, key->key_index);
698 eapol_sm_notify_lower_layer_success(sm, 1);
699 sign_key_len = IEEE8021X_SIGN_KEY_LEN;
700 encr_key_len = IEEE8021X_ENCR_KEY_LEN;
701 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
703 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
704 "decrypting EAPOL-Key keys");
708 /* LEAP derives only 16 bytes of keying material. */
709 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
711 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
712 "master key for decrypting EAPOL-Key keys");
717 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
719 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
720 "data for decrypting EAPOL-Key keys (res=%d)", res);
724 /* The key replay_counter must increase when same master key */
725 if (sm->replay_counter_valid &&
726 os_memcmp(sm->last_replay_counter, key->replay_counter,
727 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
728 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
729 "not increase - ignoring key");
730 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
731 sm->last_replay_counter,
732 IEEE8021X_REPLAY_COUNTER_LEN);
733 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
734 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
738 /* Verify key signature (HMAC-MD5) */
739 os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
740 os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
741 hmac_md5(keydata.sign_key, sign_key_len,
742 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
744 if (os_memcmp(orig_key_sign, key->key_signature,
745 IEEE8021X_KEY_SIGN_LEN) != 0) {
746 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
748 os_memcpy(key->key_signature, orig_key_sign,
749 IEEE8021X_KEY_SIGN_LEN);
752 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
754 key_len = be_to_host16(hdr->length) - sizeof(*key);
755 if (key_len > 32 || rx_key_length > 32) {
756 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
757 key_len ? key_len : rx_key_length);
760 if (key_len == rx_key_length) {
761 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
762 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
764 os_memcpy(datakey, key + 1, key_len);
765 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
767 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
769 } else if (key_len == 0) {
771 * IEEE 802.1X-2004 specifies that least significant Key Length
772 * octets from MS-MPPE-Send-Key are used as the key if the key
773 * data is not present. This seems to be meaning the beginning
774 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
775 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
776 * Anyway, taking the beginning of the keying material from EAP
777 * seems to interoperate with Authenticators.
779 key_len = rx_key_length;
780 os_memcpy(datakey, keydata.encr_key, key_len);
781 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
782 "material data encryption key",
785 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
786 "(key_length=%d)", key_len, rx_key_length);
790 sm->replay_counter_valid = TRUE;
791 os_memcpy(sm->last_replay_counter, key->replay_counter,
792 IEEE8021X_REPLAY_COUNTER_LEN);
794 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
796 key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
797 "unicast" : "broadcast",
798 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
800 if (sm->ctx->set_wep_key &&
801 sm->ctx->set_wep_key(sm->ctx->ctx,
802 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
803 key->key_index & IEEE8021X_KEY_INDEX_MASK,
804 datakey, key_len) < 0) {
805 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
808 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
809 sm->unicast_key_received = TRUE;
811 sm->broadcast_key_received = TRUE;
813 if ((sm->unicast_key_received ||
814 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
815 (sm->broadcast_key_received ||
816 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
818 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
820 sm->portValid = TRUE;
821 if (sm->ctx->eapol_done_cb)
822 sm->ctx->eapol_done_cb(sm->ctx->ctx);
828 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
830 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
831 /* EAP layer processing; no special code is needed, since Supplicant
832 * Backend state machine is waiting for eapNoResp or eapResp to be set
833 * and these are only set in the EAP state machine when the processing
838 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
842 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
843 resp = eap_get_eapRespData(sm->eap);
845 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
850 /* Send EAP-Packet from the EAP layer to the Authenticator */
851 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
852 IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
855 /* eapRespData is not used anymore, so free it here */
859 sm->dot1xSuppEapolReqIdFramesRx++;
861 sm->dot1xSuppEapolReqFramesRx++;
862 sm->dot1xSuppEapolRespFramesTx++;
863 sm->dot1xSuppEapolFramesTx++;
867 static void eapol_sm_abortSupp(struct eapol_sm *sm)
869 /* release system resources that may have been allocated for the
870 * authentication session */
871 os_free(sm->last_rx_key);
872 sm->last_rx_key = NULL;
873 wpabuf_free(sm->eapReqData);
874 sm->eapReqData = NULL;
875 eap_sm_abort(sm->eap);
879 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
881 eapol_sm_step(timeout_ctx);
885 static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
887 if (sm->ctx->port_cb)
888 sm->ctx->port_cb(sm->ctx->ctx, 1);
892 static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
894 if (sm->ctx->port_cb)
895 sm->ctx->port_cb(sm->ctx->ctx, 0);
900 * eapol_sm_step - EAPOL state machine step function
901 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
903 * This function is called to notify the state machine about changed external
904 * variables. It will step through the EAPOL state machines in loop to process
905 * all triggered state changes.
907 void eapol_sm_step(struct eapol_sm *sm)
911 /* In theory, it should be ok to run this in loop until !changed.
912 * However, it is better to use a limit on number of iterations to
913 * allow events (e.g., SIGTERM) to stop the program cleanly if the
914 * state machine were to generate a busy loop. */
915 for (i = 0; i < 100; i++) {
917 SM_STEP_RUN(SUPP_PAE);
919 SM_STEP_RUN(SUPP_BE);
920 if (eap_peer_sm_step(sm->eap))
927 /* restart EAPOL state machine step from timeout call in order
928 * to allow other events to be processed. */
929 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
930 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
933 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
934 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
935 sm->cb_status = EAPOL_CB_IN_PROGRESS;
936 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
941 #ifdef CONFIG_CTRL_IFACE
942 static const char *eapol_supp_pae_state(int state)
945 case SUPP_PAE_LOGOFF:
947 case SUPP_PAE_DISCONNECTED:
948 return "DISCONNECTED";
949 case SUPP_PAE_CONNECTING:
951 case SUPP_PAE_AUTHENTICATING:
952 return "AUTHENTICATING";
955 case SUPP_PAE_AUTHENTICATED:
956 return "AUTHENTICATED";
957 case SUPP_PAE_RESTART:
965 static const char *eapol_supp_be_state(int state)
968 case SUPP_BE_REQUEST:
970 case SUPP_BE_RESPONSE:
972 case SUPP_BE_SUCCESS:
976 case SUPP_BE_TIMEOUT:
980 case SUPP_BE_INITIALIZE:
982 case SUPP_BE_RECEIVE:
990 static const char * eapol_port_status(PortStatus status)
992 if (status == Authorized)
995 return "Unauthorized";
997 #endif /* CONFIG_CTRL_IFACE */
1000 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1001 static const char * eapol_port_control(PortControl ctrl)
1006 case ForceUnauthorized:
1007 return "ForceUnauthorized";
1008 case ForceAuthorized:
1009 return "ForceAuthorized";
1014 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1018 * eapol_sm_configure - Set EAPOL variables
1019 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1020 * @heldPeriod: dot1xSuppHeldPeriod
1021 * @authPeriod: dot1xSuppAuthPeriod
1022 * @startPeriod: dot1xSuppStartPeriod
1023 * @maxStart: dot1xSuppMaxStart
1025 * Set configurable EAPOL state machine variables. Each variable can be set to
1026 * the given value or ignored if set to -1 (to set only some of the variables).
1028 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
1029 int startPeriod, int maxStart)
1033 if (heldPeriod >= 0)
1034 sm->heldPeriod = heldPeriod;
1035 if (authPeriod >= 0)
1036 sm->authPeriod = authPeriod;
1037 if (startPeriod >= 0)
1038 sm->startPeriod = startPeriod;
1040 sm->maxStart = maxStart;
1045 * eapol_sm_get_method_name - Get EAPOL method name
1046 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1047 * Returns: Static string containing name of current eap method or NULL
1049 const char * eapol_sm_get_method_name(struct eapol_sm *sm)
1051 if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
1052 sm->suppPortStatus != Authorized)
1055 return eap_sm_get_method_name(sm->eap);
1059 #ifdef CONFIG_CTRL_IFACE
1061 * eapol_sm_get_status - Get EAPOL state machine status
1062 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1063 * @buf: Buffer for status information
1064 * @buflen: Maximum buffer length
1065 * @verbose: Whether to include verbose status information
1066 * Returns: Number of bytes written to buf.
1068 * Query EAPOL state machine for status information. This function fills in a
1069 * text area with current status information from the EAPOL state machine. If
1070 * the buffer (buf) is not large enough, status information will be truncated
1071 * to fit the buffer.
1073 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1080 len = os_snprintf(buf, buflen,
1081 "Supplicant PAE state=%s\n"
1082 "suppPortStatus=%s\n",
1083 eapol_supp_pae_state(sm->SUPP_PAE_state),
1084 eapol_port_status(sm->suppPortStatus));
1085 if (len < 0 || (size_t) len >= buflen)
1089 ret = os_snprintf(buf + len, buflen - len,
1095 "Supplicant Backend state=%s\n",
1100 eapol_port_control(sm->portControl),
1101 eapol_supp_be_state(sm->SUPP_BE_state));
1102 if (ret < 0 || (size_t) ret >= buflen - len)
1107 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1114 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1115 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1116 * @buf: Buffer for MIB information
1117 * @buflen: Maximum buffer length
1118 * Returns: Number of bytes written to buf.
1120 * Query EAPOL state machine for MIB information. This function fills in a
1121 * text area with current MIB information from the EAPOL state machine. If
1122 * the buffer (buf) is not large enough, MIB information will be truncated to
1125 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1132 ret = os_snprintf(buf, buflen,
1133 "dot1xSuppPaeState=%d\n"
1134 "dot1xSuppHeldPeriod=%u\n"
1135 "dot1xSuppAuthPeriod=%u\n"
1136 "dot1xSuppStartPeriod=%u\n"
1137 "dot1xSuppMaxStart=%u\n"
1138 "dot1xSuppSuppControlledPortStatus=%s\n"
1139 "dot1xSuppBackendPaeState=%d\n",
1145 sm->suppPortStatus == Authorized ?
1146 "Authorized" : "Unauthorized",
1149 if (ret < 0 || (size_t) ret >= buflen)
1153 ret = os_snprintf(buf + len, buflen - len,
1154 "dot1xSuppEapolFramesRx=%u\n"
1155 "dot1xSuppEapolFramesTx=%u\n"
1156 "dot1xSuppEapolStartFramesTx=%u\n"
1157 "dot1xSuppEapolLogoffFramesTx=%u\n"
1158 "dot1xSuppEapolRespFramesTx=%u\n"
1159 "dot1xSuppEapolReqIdFramesRx=%u\n"
1160 "dot1xSuppEapolReqFramesRx=%u\n"
1161 "dot1xSuppInvalidEapolFramesRx=%u\n"
1162 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1163 "dot1xSuppLastEapolFrameVersion=%u\n"
1164 "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1165 sm->dot1xSuppEapolFramesRx,
1166 sm->dot1xSuppEapolFramesTx,
1167 sm->dot1xSuppEapolStartFramesTx,
1168 sm->dot1xSuppEapolLogoffFramesTx,
1169 sm->dot1xSuppEapolRespFramesTx,
1170 sm->dot1xSuppEapolReqIdFramesRx,
1171 sm->dot1xSuppEapolReqFramesRx,
1172 sm->dot1xSuppInvalidEapolFramesRx,
1173 sm->dot1xSuppEapLengthErrorFramesRx,
1174 sm->dot1xSuppLastEapolFrameVersion,
1175 MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1177 if (ret < 0 || (size_t) ret >= buflen - len)
1183 #endif /* CONFIG_CTRL_IFACE */
1187 * eapol_sm_rx_eapol - Process received EAPOL frames
1188 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1189 * @src: Source MAC address of the EAPOL packet
1190 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1191 * @len: Length of the EAPOL frame
1192 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1195 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1198 const struct ieee802_1x_hdr *hdr;
1199 const struct ieee802_1x_eapol_key *key;
1206 sm->dot1xSuppEapolFramesRx++;
1207 if (len < sizeof(*hdr)) {
1208 sm->dot1xSuppInvalidEapolFramesRx++;
1211 hdr = (const struct ieee802_1x_hdr *) buf;
1212 sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1213 os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1214 if (hdr->version < EAPOL_VERSION) {
1215 /* TODO: backwards compatibility */
1217 plen = be_to_host16(hdr->length);
1218 if (plen > len - sizeof(*hdr)) {
1219 sm->dot1xSuppEapLengthErrorFramesRx++;
1223 if (sm->conf.workaround &&
1224 plen < len - sizeof(*hdr) &&
1225 hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1226 len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1227 const struct eap_hdr *ehdr =
1228 (const struct eap_hdr *) (hdr + 1);
1231 elen = be_to_host16(ehdr->length);
1232 if (elen > plen && elen <= len - sizeof(*hdr)) {
1234 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1235 * packets with too short EAPOL header length field
1236 * (14 octets). This is fixed in firmware Ver.1.49.
1237 * As a workaround, fix the EAPOL header based on the
1238 * correct length in the EAP packet.
1240 wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1241 "payload length based on EAP header: "
1242 "%d -> %d", (int) plen, elen);
1246 #endif /* CONFIG_WPS */
1247 data_len = plen + sizeof(*hdr);
1249 switch (hdr->type) {
1250 case IEEE802_1X_TYPE_EAP_PACKET:
1251 if (sm->cached_pmk) {
1252 /* Trying to use PMKSA caching, but Authenticator did
1253 * not seem to have a matching entry. Need to restart
1254 * EAPOL state machines.
1256 eapol_sm_abort_cached(sm);
1258 wpabuf_free(sm->eapReqData);
1259 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1260 if (sm->eapReqData) {
1261 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1263 sm->eapolEap = TRUE;
1267 case IEEE802_1X_TYPE_EAPOL_KEY:
1268 if (plen < sizeof(*key)) {
1269 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1273 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1274 if (key->type == EAPOL_KEY_TYPE_WPA ||
1275 key->type == EAPOL_KEY_TYPE_RSN) {
1276 /* WPA Supplicant takes care of this frame. */
1277 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1278 "frame in EAPOL state machines");
1282 if (key->type != EAPOL_KEY_TYPE_RC4) {
1283 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1284 "EAPOL-Key type %d", key->type);
1287 os_free(sm->last_rx_key);
1288 sm->last_rx_key = os_malloc(data_len);
1289 if (sm->last_rx_key) {
1290 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1292 os_memcpy(sm->last_rx_key, buf, data_len);
1293 sm->last_rx_key_len = data_len;
1299 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1301 sm->dot1xSuppInvalidEapolFramesRx++;
1310 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1311 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1313 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1314 * component, e.g., WPA. This will update the statistics.
1316 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1319 sm->dot1xSuppEapolFramesTx++;
1324 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1325 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1326 * @enabled: New portEnabled value
1328 * Notify EAPOL state machine about new portEnabled value.
1330 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1334 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1335 "portEnabled=%d", enabled);
1336 sm->portEnabled = enabled;
1342 * eapol_sm_notify_portValid - Notification about portValid change
1343 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1344 * @valid: New portValid value
1346 * Notify EAPOL state machine about new portValid value.
1348 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1352 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1353 "portValid=%d", valid);
1354 sm->portValid = valid;
1360 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1361 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1362 * @success: %TRUE = set success, %FALSE = clear success
1364 * Notify the EAPOL state machine that external event has forced EAP state to
1365 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1367 * This function is called to update EAP state when WPA-PSK key handshake has
1368 * been completed successfully since WPA-PSK does not use EAP state machine.
1370 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1374 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1375 "EAP success=%d", success);
1376 sm->eapSuccess = success;
1377 sm->altAccept = success;
1379 eap_notify_success(sm->eap);
1385 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1386 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1387 * @fail: %TRUE = set failure, %FALSE = clear failure
1389 * Notify EAPOL state machine that external event has forced EAP state to
1390 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1392 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1396 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1397 "EAP fail=%d", fail);
1399 sm->altReject = fail;
1405 * eapol_sm_notify_config - Notification of EAPOL configuration change
1406 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1407 * @config: Pointer to current network EAP configuration
1408 * @conf: Pointer to EAPOL configuration data
1410 * Notify EAPOL state machine that configuration has changed. config will be
1411 * stored as a backpointer to network configuration. This can be %NULL to clear
1412 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1413 * data. If conf is %NULL, this part of the configuration change will be
1416 void eapol_sm_notify_config(struct eapol_sm *sm,
1417 struct eap_peer_config *config,
1418 const struct eapol_config *conf)
1423 sm->config = config;
1428 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1429 sm->conf.required_keys = conf->required_keys;
1430 sm->conf.fast_reauth = conf->fast_reauth;
1431 sm->conf.workaround = conf->workaround;
1433 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1434 eap_set_workaround(sm->eap, conf->workaround);
1435 eap_set_force_disabled(sm->eap, conf->eap_disabled);
1441 * eapol_sm_get_key - Get master session key (MSK) from EAP
1442 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1443 * @key: Pointer for key buffer
1444 * @len: Number of bytes to copy to key
1445 * Returns: 0 on success (len of key available), maximum available key len
1446 * (>0) if key is available but it is shorter than len, or -1 on failure.
1448 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1449 * is available only after a successful authentication.
1451 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1456 if (sm == NULL || !eap_key_available(sm->eap)) {
1457 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1460 eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1461 if (eap_key == NULL) {
1462 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1465 if (len > eap_len) {
1466 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1467 "available (len=%lu)",
1468 (unsigned long) len, (unsigned long) eap_len);
1471 os_memcpy(key, eap_key, len);
1472 wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1473 (unsigned long) len);
1479 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1480 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1481 * @logoff: Whether command was logoff
1483 * Notify EAPOL state machines that user requested logon/logoff.
1485 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1488 sm->userLogoff = logoff;
1495 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1496 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1498 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1499 * to move EAPOL and EAP state machines into authenticated/successful state.
1501 void eapol_sm_notify_cached(struct eapol_sm *sm)
1505 wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1506 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1507 sm->suppPortStatus = Authorized;
1508 eapol_sm_set_port_authorized(sm);
1509 sm->portValid = TRUE;
1510 eap_notify_success(sm->eap);
1516 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1517 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1518 * @attempt: Whether PMKSA caching is tried
1520 * Notify EAPOL state machines whether PMKSA caching is used.
1522 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1527 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1528 sm->cached_pmk = TRUE;
1530 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1531 sm->cached_pmk = FALSE;
1536 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1538 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1539 "doing full EAP authentication");
1542 sm->cached_pmk = FALSE;
1543 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1544 sm->suppPortStatus = Unauthorized;
1545 eapol_sm_set_port_unauthorized(sm);
1547 /* Make sure we do not start sending EAPOL-Start frames first, but
1548 * instead move to RESTART state to start EAPOL authentication. */
1550 eapol_enable_timer_tick(sm);
1552 if (sm->ctx->aborted_cached)
1553 sm->ctx->aborted_cached(sm->ctx->ctx);
1558 * eapol_sm_register_scard_ctx - Notification of smart card context
1559 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1560 * @ctx: Context data for smart card operations
1562 * Notify EAPOL state machines of context data for smart card operations. This
1563 * context data will be used as a parameter for scard_*() functions.
1565 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1568 sm->ctx->scard_ctx = ctx;
1569 eap_register_scard_ctx(sm->eap, ctx);
1575 * eapol_sm_notify_portControl - Notification of portControl changes
1576 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1577 * @portControl: New value for portControl variable
1579 * Notify EAPOL state machines that portControl variable has changed.
1581 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1585 wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1586 "portControl=%s", eapol_port_control(portControl));
1587 sm->portControl = portControl;
1593 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1594 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1596 * Notify EAPOL state machines that a monitor was attached to the control
1597 * interface to trigger re-sending of pending requests for user input.
1599 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1603 eap_sm_notify_ctrl_attached(sm->eap);
1608 * eapol_sm_notify_ctrl_response - Notification of received user input
1609 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1611 * Notify EAPOL state machines that a control response, i.e., user
1612 * input, was received in order to trigger retrying of a pending EAP request.
1614 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1618 if (sm->eapReqData && !sm->eapReq) {
1619 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1620 "input) notification - retrying pending EAP "
1622 sm->eapolEap = TRUE;
1630 * eapol_sm_request_reauth - Request reauthentication
1631 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1633 * This function can be used to request EAPOL reauthentication, e.g., when the
1634 * current PMKSA entry is nearing expiration.
1636 void eapol_sm_request_reauth(struct eapol_sm *sm)
1638 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1640 eapol_sm_txStart(sm);
1645 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1646 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1647 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1648 * machine loop (eapol_sm_step())
1650 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1651 * successful authentication. This is used to recover from dropped EAP-Success
1654 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1658 eap_notify_lower_layer_success(sm->eap);
1665 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1666 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1668 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1671 eap_invalidate_cached_session(sm->eap);
1675 static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1677 struct eapol_sm *sm = ctx;
1678 return sm ? sm->config : NULL;
1682 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1684 struct eapol_sm *sm = ctx;
1685 if (sm == NULL || sm->eapReqData == NULL)
1688 return sm->eapReqData;
1692 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1694 struct eapol_sm *sm = ctx;
1698 case EAPOL_eapSuccess:
1699 return sm->eapSuccess;
1700 case EAPOL_eapRestart:
1701 return sm->eapRestart;
1706 case EAPOL_eapNoResp:
1707 return sm->eapNoResp;
1710 case EAPOL_portEnabled:
1711 return sm->portEnabled;
1712 case EAPOL_altAccept:
1713 return sm->altAccept;
1714 case EAPOL_altReject:
1715 return sm->altReject;
1721 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1724 struct eapol_sm *sm = ctx;
1728 case EAPOL_eapSuccess:
1729 sm->eapSuccess = value;
1731 case EAPOL_eapRestart:
1732 sm->eapRestart = value;
1735 sm->eapFail = value;
1738 sm->eapResp = value;
1740 case EAPOL_eapNoResp:
1741 sm->eapNoResp = value;
1746 case EAPOL_portEnabled:
1747 sm->portEnabled = value;
1749 case EAPOL_altAccept:
1750 sm->altAccept = value;
1752 case EAPOL_altReject:
1753 sm->altReject = value;
1759 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1761 struct eapol_sm *sm = ctx;
1765 case EAPOL_idleWhile:
1766 return sm->idleWhile;
1772 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1775 struct eapol_sm *sm = ctx;
1779 case EAPOL_idleWhile:
1780 sm->idleWhile = value;
1781 eapol_enable_timer_tick(sm);
1787 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1789 #ifndef CONFIG_NO_CONFIG_BLOBS
1790 struct eapol_sm *sm = ctx;
1791 if (sm && sm->ctx && sm->ctx->set_config_blob)
1792 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1793 #endif /* CONFIG_NO_CONFIG_BLOBS */
1797 static const struct wpa_config_blob *
1798 eapol_sm_get_config_blob(void *ctx, const char *name)
1800 #ifndef CONFIG_NO_CONFIG_BLOBS
1801 struct eapol_sm *sm = ctx;
1802 if (sm && sm->ctx && sm->ctx->get_config_blob)
1803 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1806 #else /* CONFIG_NO_CONFIG_BLOBS */
1808 #endif /* CONFIG_NO_CONFIG_BLOBS */
1812 static void eapol_sm_notify_pending(void *ctx)
1814 struct eapol_sm *sm = ctx;
1817 if (sm->eapReqData && !sm->eapReq) {
1818 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1819 "state machine - retrying pending EAP Request");
1820 sm->eapolEap = TRUE;
1827 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1828 static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
1831 struct eapol_sm *sm = ctx;
1832 wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1833 if (sm->ctx->eap_param_needed)
1834 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1836 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1837 #define eapol_sm_eap_param_needed NULL
1838 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1840 static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
1841 const char *cert_hash,
1842 const struct wpabuf *cert)
1844 struct eapol_sm *sm = ctx;
1845 if (sm->ctx->cert_cb)
1846 sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
1851 static void eapol_sm_notify_status(void *ctx, const char *status,
1852 const char *parameter)
1854 struct eapol_sm *sm = ctx;
1856 if (sm->ctx->status_cb)
1857 sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
1861 static struct eapol_callbacks eapol_cb =
1863 eapol_sm_get_config,
1868 eapol_sm_get_eapReqData,
1869 eapol_sm_set_config_blob,
1870 eapol_sm_get_config_blob,
1871 eapol_sm_notify_pending,
1872 eapol_sm_eap_param_needed,
1873 eapol_sm_notify_cert,
1874 eapol_sm_notify_status
1879 * eapol_sm_init - Initialize EAPOL state machine
1880 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1881 * and EAPOL state machine will free it in eapol_sm_deinit()
1882 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1884 * Allocate and initialize an EAPOL state machine.
1886 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1888 struct eapol_sm *sm;
1889 struct eap_config conf;
1890 sm = os_zalloc(sizeof(*sm));
1895 sm->portControl = Auto;
1897 /* Supplicant PAE state machine */
1898 sm->heldPeriod = 60;
1899 sm->startPeriod = 30;
1902 /* Supplicant Backend state machine */
1903 sm->authPeriod = 30;
1905 os_memset(&conf, 0, sizeof(conf));
1906 conf.opensc_engine_path = ctx->opensc_engine_path;
1907 conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1908 conf.pkcs11_module_path = ctx->pkcs11_module_path;
1909 conf.wps = ctx->wps;
1910 conf.cert_in_cb = ctx->cert_in_cb;
1912 sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1913 if (sm->eap == NULL) {
1918 /* Initialize EAPOL state machines */
1919 sm->initialize = TRUE;
1921 sm->initialize = FALSE;
1924 sm->timer_tick_enabled = 1;
1925 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1932 * eapol_sm_deinit - Deinitialize EAPOL state machine
1933 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1935 * Deinitialize and free EAPOL state machine.
1937 void eapol_sm_deinit(struct eapol_sm *sm)
1941 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1942 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1943 eap_peer_sm_deinit(sm->eap);
1944 os_free(sm->last_rx_key);
1945 wpabuf_free(sm->eapReqData);