2 * EAPOL supplicant state machines
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "state_machine.h"
21 #include "crypto/crypto.h"
22 #include "crypto/md5.h"
23 #include "common/eapol_common.h"
24 #include "eap_peer/eap.h"
25 #include "eapol_supp_sm.h"
27 #define STATE_MACHINE_DATA struct eapol_sm
28 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
31 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
34 * struct eapol_sm - Internal data for EAPOL state machines
38 unsigned int authWhile
;
39 unsigned int heldWhile
;
40 unsigned int startWhen
;
41 unsigned int idleWhile
; /* for EAP state machine */
42 int timer_tick_enabled
;
44 /* Global variables */
51 PortControl portControl
;
53 PortStatus suppPortStatus
; /* dot1xSuppControlledPortStatus */
61 /* Supplicant PAE state machine */
64 SUPP_PAE_DISCONNECTED
= 1,
66 SUPP_PAE_CONNECTING
= 3,
67 SUPP_PAE_AUTHENTICATING
= 4,
68 SUPP_PAE_AUTHENTICATED
= 5,
72 SUPP_PAE_S_FORCE_AUTH
= 9,
73 SUPP_PAE_S_FORCE_UNAUTH
= 10
74 } SUPP_PAE_state
; /* dot1xSuppPaeState */
78 unsigned int startCount
;
80 PortControl sPortMode
;
82 unsigned int heldPeriod
; /* dot1xSuppHeldPeriod */
83 unsigned int startPeriod
; /* dot1xSuppStartPeriod */
84 unsigned int maxStart
; /* dot1xSuppMaxStart */
86 /* Key Receive state machine */
89 KEY_RX_NO_KEY_RECEIVE
, KEY_RX_KEY_RECEIVE
94 /* Supplicant Backend state machine */
97 SUPP_BE_INITIALIZE
= 1,
101 SUPP_BE_RESPONSE
= 5,
105 } SUPP_BE_state
; /* dot1xSuppBackendPaeState */
111 unsigned int authPeriod
; /* dot1xSuppAuthPeriod */
114 unsigned int dot1xSuppEapolFramesRx
;
115 unsigned int dot1xSuppEapolFramesTx
;
116 unsigned int dot1xSuppEapolStartFramesTx
;
117 unsigned int dot1xSuppEapolLogoffFramesTx
;
118 unsigned int dot1xSuppEapolRespFramesTx
;
119 unsigned int dot1xSuppEapolReqIdFramesRx
;
120 unsigned int dot1xSuppEapolReqFramesRx
;
121 unsigned int dot1xSuppInvalidEapolFramesRx
;
122 unsigned int dot1xSuppEapLengthErrorFramesRx
;
123 unsigned int dot1xSuppLastEapolFrameVersion
;
124 unsigned char dot1xSuppLastEapolFrameSource
[6];
126 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
129 struct eap_peer_config
*config
;
132 size_t last_rx_key_len
;
133 struct wpabuf
*eapReqData
; /* for EAP */
134 Boolean altAccept
; /* for EAP */
135 Boolean altReject
; /* for EAP */
136 Boolean replay_counter_valid
;
137 u8 last_replay_counter
[16];
138 struct eapol_config conf
;
139 struct eapol_ctx
*ctx
;
140 enum { EAPOL_CB_IN_PROGRESS
= 0, EAPOL_CB_SUCCESS
, EAPOL_CB_FAILURE
}
144 Boolean unicast_key_received
, broadcast_key_received
;
148 #define IEEE8021X_REPLAY_COUNTER_LEN 8
149 #define IEEE8021X_KEY_SIGN_LEN 16
150 #define IEEE8021X_KEY_IV_LEN 16
152 #define IEEE8021X_KEY_INDEX_FLAG 0x80
153 #define IEEE8021X_KEY_INDEX_MASK 0x03
156 #pragma pack(push, 1)
157 #endif /* _MSC_VER */
159 struct ieee802_1x_eapol_key
{
161 /* Note: key_length is unaligned */
163 /* does not repeat within the life of the keying material used to
164 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
165 u8 replay_counter
[IEEE8021X_REPLAY_COUNTER_LEN
];
166 u8 key_iv
[IEEE8021X_KEY_IV_LEN
]; /* cryptographically random number */
167 u8 key_index
; /* key flag in the most significant bit:
168 * 0 = broadcast (default key),
169 * 1 = unicast (key mapping key); key index is in the
170 * 7 least significant bits */
171 /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
173 u8 key_signature
[IEEE8021X_KEY_SIGN_LEN
];
175 /* followed by key: if packet body length = 44 + key length, then the
176 * key field (of key_length bytes) contains the key in encrypted form;
177 * if packet body length = 44, key field is absent and key_length
178 * represents the number of least significant octets from
179 * MS-MPPE-Send-Key attribute to be used as the keying material;
180 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
185 #endif /* _MSC_VER */
188 static void eapol_sm_txLogoff(struct eapol_sm
*sm
);
189 static void eapol_sm_txStart(struct eapol_sm
*sm
);
190 static void eapol_sm_processKey(struct eapol_sm
*sm
);
191 static void eapol_sm_getSuppRsp(struct eapol_sm
*sm
);
192 static void eapol_sm_txSuppRsp(struct eapol_sm
*sm
);
193 static void eapol_sm_abortSupp(struct eapol_sm
*sm
);
194 static void eapol_sm_abort_cached(struct eapol_sm
*sm
);
195 static void eapol_sm_step_timeout(void *eloop_ctx
, void *timeout_ctx
);
196 static void eapol_sm_set_port_authorized(struct eapol_sm
*sm
);
197 static void eapol_sm_set_port_unauthorized(struct eapol_sm
*sm
);
200 /* Port Timers state machine - implemented as a function that will be called
201 * once a second as a registered event loop timeout */
202 static void eapol_port_timers_tick(void *eloop_ctx
, void *timeout_ctx
)
204 struct eapol_sm
*sm
= timeout_ctx
;
206 if (sm
->authWhile
> 0) {
208 if (sm
->authWhile
== 0)
209 wpa_printf(MSG_DEBUG
, "EAPOL: authWhile --> 0");
211 if (sm
->heldWhile
> 0) {
213 if (sm
->heldWhile
== 0)
214 wpa_printf(MSG_DEBUG
, "EAPOL: heldWhile --> 0");
216 if (sm
->startWhen
> 0) {
218 if (sm
->startWhen
== 0)
219 wpa_printf(MSG_DEBUG
, "EAPOL: startWhen --> 0");
221 if (sm
->idleWhile
> 0) {
223 if (sm
->idleWhile
== 0)
224 wpa_printf(MSG_DEBUG
, "EAPOL: idleWhile --> 0");
227 if (sm
->authWhile
| sm
->heldWhile
| sm
->startWhen
| sm
->idleWhile
) {
228 eloop_register_timeout(1, 0, eapol_port_timers_tick
, eloop_ctx
,
231 wpa_printf(MSG_DEBUG
, "EAPOL: disable timer tick");
232 sm
->timer_tick_enabled
= 0;
238 static void eapol_enable_timer_tick(struct eapol_sm
*sm
)
240 if (sm
->timer_tick_enabled
)
242 wpa_printf(MSG_DEBUG
, "EAPOL: enable timer tick");
243 sm
->timer_tick_enabled
= 1;
244 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
245 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
249 SM_STATE(SUPP_PAE
, LOGOFF
)
251 SM_ENTRY(SUPP_PAE
, LOGOFF
);
252 eapol_sm_txLogoff(sm
);
253 sm
->logoffSent
= TRUE
;
254 sm
->suppPortStatus
= Unauthorized
;
255 eapol_sm_set_port_unauthorized(sm
);
259 SM_STATE(SUPP_PAE
, DISCONNECTED
)
261 SM_ENTRY(SUPP_PAE
, DISCONNECTED
);
262 sm
->sPortMode
= Auto
;
264 sm
->logoffSent
= FALSE
;
265 sm
->suppPortStatus
= Unauthorized
;
266 eapol_sm_set_port_unauthorized(sm
);
267 sm
->suppAbort
= TRUE
;
269 sm
->unicast_key_received
= FALSE
;
270 sm
->broadcast_key_received
= FALSE
;
274 SM_STATE(SUPP_PAE
, CONNECTING
)
276 int send_start
= sm
->SUPP_PAE_state
== SUPP_PAE_CONNECTING
;
277 SM_ENTRY(SUPP_PAE
, CONNECTING
);
279 sm
->startWhen
= sm
->startPeriod
;
283 * Do not send EAPOL-Start immediately since in most cases,
284 * Authenticator is going to start authentication immediately
285 * after association and an extra EAPOL-Start is just going to
286 * delay authentication. Use a short timeout to send the first
287 * EAPOL-Start if Authenticator does not start authentication.
290 /* Reduce latency on starting WPS negotiation. */
292 #else /* CONFIG_WPS */
294 #endif /* CONFIG_WPS */
296 eapol_enable_timer_tick(sm
);
297 sm
->eapolEap
= FALSE
;
299 eapol_sm_txStart(sm
);
303 SM_STATE(SUPP_PAE
, AUTHENTICATING
)
305 SM_ENTRY(SUPP_PAE
, AUTHENTICATING
);
307 sm
->suppSuccess
= FALSE
;
308 sm
->suppFail
= FALSE
;
309 sm
->suppTimeout
= FALSE
;
312 sm
->suppStart
= TRUE
;
316 SM_STATE(SUPP_PAE
, HELD
)
318 SM_ENTRY(SUPP_PAE
, HELD
);
319 sm
->heldWhile
= sm
->heldPeriod
;
320 eapol_enable_timer_tick(sm
);
321 sm
->suppPortStatus
= Unauthorized
;
322 eapol_sm_set_port_unauthorized(sm
);
323 sm
->cb_status
= EAPOL_CB_FAILURE
;
327 SM_STATE(SUPP_PAE
, AUTHENTICATED
)
329 SM_ENTRY(SUPP_PAE
, AUTHENTICATED
);
330 sm
->suppPortStatus
= Authorized
;
331 eapol_sm_set_port_authorized(sm
);
332 sm
->cb_status
= EAPOL_CB_SUCCESS
;
336 SM_STATE(SUPP_PAE
, RESTART
)
338 SM_ENTRY(SUPP_PAE
, RESTART
);
339 sm
->eapRestart
= TRUE
;
343 SM_STATE(SUPP_PAE
, S_FORCE_AUTH
)
345 SM_ENTRY(SUPP_PAE
, S_FORCE_AUTH
);
346 sm
->suppPortStatus
= Authorized
;
347 eapol_sm_set_port_authorized(sm
);
348 sm
->sPortMode
= ForceAuthorized
;
352 SM_STATE(SUPP_PAE
, S_FORCE_UNAUTH
)
354 SM_ENTRY(SUPP_PAE
, S_FORCE_UNAUTH
);
355 sm
->suppPortStatus
= Unauthorized
;
356 eapol_sm_set_port_unauthorized(sm
);
357 sm
->sPortMode
= ForceUnauthorized
;
358 eapol_sm_txLogoff(sm
);
364 if ((sm
->userLogoff
&& !sm
->logoffSent
) &&
365 !(sm
->initialize
|| !sm
->portEnabled
))
366 SM_ENTER_GLOBAL(SUPP_PAE
, LOGOFF
);
367 else if (((sm
->portControl
== Auto
) &&
368 (sm
->sPortMode
!= sm
->portControl
)) ||
369 sm
->initialize
|| !sm
->portEnabled
)
370 SM_ENTER_GLOBAL(SUPP_PAE
, DISCONNECTED
);
371 else if ((sm
->portControl
== ForceAuthorized
) &&
372 (sm
->sPortMode
!= sm
->portControl
) &&
373 !(sm
->initialize
|| !sm
->portEnabled
))
374 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_AUTH
);
375 else if ((sm
->portControl
== ForceUnauthorized
) &&
376 (sm
->sPortMode
!= sm
->portControl
) &&
377 !(sm
->initialize
|| !sm
->portEnabled
))
378 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_UNAUTH
);
379 else switch (sm
->SUPP_PAE_state
) {
380 case SUPP_PAE_UNKNOWN
:
382 case SUPP_PAE_LOGOFF
:
384 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
386 case SUPP_PAE_DISCONNECTED
:
387 SM_ENTER(SUPP_PAE
, CONNECTING
);
389 case SUPP_PAE_CONNECTING
:
390 if (sm
->startWhen
== 0 && sm
->startCount
< sm
->maxStart
)
391 SM_ENTER(SUPP_PAE
, CONNECTING
);
392 else if (sm
->startWhen
== 0 &&
393 sm
->startCount
>= sm
->maxStart
&&
395 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
396 else if (sm
->eapSuccess
|| sm
->eapFail
)
397 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
398 else if (sm
->eapolEap
)
399 SM_ENTER(SUPP_PAE
, RESTART
);
400 else if (sm
->startWhen
== 0 &&
401 sm
->startCount
>= sm
->maxStart
&&
403 SM_ENTER(SUPP_PAE
, HELD
);
405 case SUPP_PAE_AUTHENTICATING
:
406 if (sm
->eapSuccess
&& !sm
->portValid
&&
407 sm
->conf
.accept_802_1x_keys
&&
408 sm
->conf
.required_keys
== 0) {
409 wpa_printf(MSG_DEBUG
, "EAPOL: IEEE 802.1X for "
410 "plaintext connection; no EAPOL-Key frames "
412 sm
->portValid
= TRUE
;
413 if (sm
->ctx
->eapol_done_cb
)
414 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
416 if (sm
->eapSuccess
&& sm
->portValid
)
417 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
418 else if (sm
->eapFail
|| (sm
->keyDone
&& !sm
->portValid
))
419 SM_ENTER(SUPP_PAE
, HELD
);
420 else if (sm
->suppTimeout
)
421 SM_ENTER(SUPP_PAE
, CONNECTING
);
424 if (sm
->heldWhile
== 0)
425 SM_ENTER(SUPP_PAE
, CONNECTING
);
426 else if (sm
->eapolEap
)
427 SM_ENTER(SUPP_PAE
, RESTART
);
429 case SUPP_PAE_AUTHENTICATED
:
430 if (sm
->eapolEap
&& sm
->portValid
)
431 SM_ENTER(SUPP_PAE
, RESTART
);
432 else if (!sm
->portValid
)
433 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
435 case SUPP_PAE_RESTART
:
437 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
439 case SUPP_PAE_S_FORCE_AUTH
:
441 case SUPP_PAE_S_FORCE_UNAUTH
:
447 SM_STATE(KEY_RX
, NO_KEY_RECEIVE
)
449 SM_ENTRY(KEY_RX
, NO_KEY_RECEIVE
);
453 SM_STATE(KEY_RX
, KEY_RECEIVE
)
455 SM_ENTRY(KEY_RX
, KEY_RECEIVE
);
456 eapol_sm_processKey(sm
);
463 if (sm
->initialize
|| !sm
->portEnabled
)
464 SM_ENTER_GLOBAL(KEY_RX
, NO_KEY_RECEIVE
);
465 switch (sm
->KEY_RX_state
) {
468 case KEY_RX_NO_KEY_RECEIVE
:
470 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
472 case KEY_RX_KEY_RECEIVE
:
474 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
480 SM_STATE(SUPP_BE
, REQUEST
)
482 SM_ENTRY(SUPP_BE
, REQUEST
);
485 eapol_sm_getSuppRsp(sm
);
489 SM_STATE(SUPP_BE
, RESPONSE
)
491 SM_ENTRY(SUPP_BE
, RESPONSE
);
492 eapol_sm_txSuppRsp(sm
);
497 SM_STATE(SUPP_BE
, SUCCESS
)
499 SM_ENTRY(SUPP_BE
, SUCCESS
);
501 sm
->suppSuccess
= TRUE
;
503 if (eap_key_available(sm
->eap
)) {
504 /* New key received - clear IEEE 802.1X EAPOL-Key replay
506 sm
->replay_counter_valid
= FALSE
;
511 SM_STATE(SUPP_BE
, FAIL
)
513 SM_ENTRY(SUPP_BE
, FAIL
);
518 SM_STATE(SUPP_BE
, TIMEOUT
)
520 SM_ENTRY(SUPP_BE
, TIMEOUT
);
521 sm
->suppTimeout
= TRUE
;
525 SM_STATE(SUPP_BE
, IDLE
)
527 SM_ENTRY(SUPP_BE
, IDLE
);
528 sm
->suppStart
= FALSE
;
529 sm
->initial_req
= TRUE
;
533 SM_STATE(SUPP_BE
, INITIALIZE
)
535 SM_ENTRY(SUPP_BE
, INITIALIZE
);
536 eapol_sm_abortSupp(sm
);
537 sm
->suppAbort
= FALSE
;
541 SM_STATE(SUPP_BE
, RECEIVE
)
543 SM_ENTRY(SUPP_BE
, RECEIVE
);
544 sm
->authWhile
= sm
->authPeriod
;
545 eapol_enable_timer_tick(sm
);
546 sm
->eapolEap
= FALSE
;
547 sm
->eapNoResp
= FALSE
;
548 sm
->initial_req
= FALSE
;
554 if (sm
->initialize
|| sm
->suppAbort
)
555 SM_ENTER_GLOBAL(SUPP_BE
, INITIALIZE
);
556 else switch (sm
->SUPP_BE_state
) {
557 case SUPP_BE_UNKNOWN
:
559 case SUPP_BE_REQUEST
:
561 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
562 * and SUCCESS based on eapFail and eapSuccess, respectively.
563 * However, IEEE Std 802.1X-2004 is also specifying that
564 * eapNoResp should be set in conjuction with eapSuccess and
565 * eapFail which would mean that more than one of the
566 * transitions here would be activated at the same time.
567 * Skipping RESPONSE and/or RECEIVE states in these cases can
568 * cause problems and the direct transitions to do not seem
569 * correct. Because of this, the conditions for these
570 * transitions are verified only after eapNoResp. They are
571 * unlikely to be used since eapNoResp should always be set if
572 * either of eapSuccess or eapFail is set.
574 if (sm
->eapResp
&& sm
->eapNoResp
) {
575 wpa_printf(MSG_DEBUG
, "EAPOL: SUPP_BE REQUEST: both "
576 "eapResp and eapNoResp set?!");
579 SM_ENTER(SUPP_BE
, RESPONSE
);
580 else if (sm
->eapNoResp
)
581 SM_ENTER(SUPP_BE
, RECEIVE
);
582 else if (sm
->eapFail
)
583 SM_ENTER(SUPP_BE
, FAIL
);
584 else if (sm
->eapSuccess
)
585 SM_ENTER(SUPP_BE
, SUCCESS
);
587 case SUPP_BE_RESPONSE
:
588 SM_ENTER(SUPP_BE
, RECEIVE
);
590 case SUPP_BE_SUCCESS
:
591 SM_ENTER(SUPP_BE
, IDLE
);
594 SM_ENTER(SUPP_BE
, IDLE
);
596 case SUPP_BE_TIMEOUT
:
597 SM_ENTER(SUPP_BE
, IDLE
);
600 if (sm
->eapFail
&& sm
->suppStart
)
601 SM_ENTER(SUPP_BE
, FAIL
);
602 else if (sm
->eapolEap
&& sm
->suppStart
)
603 SM_ENTER(SUPP_BE
, REQUEST
);
604 else if (sm
->eapSuccess
&& sm
->suppStart
)
605 SM_ENTER(SUPP_BE
, SUCCESS
);
607 case SUPP_BE_INITIALIZE
:
608 SM_ENTER(SUPP_BE
, IDLE
);
610 case SUPP_BE_RECEIVE
:
612 SM_ENTER(SUPP_BE
, REQUEST
);
613 else if (sm
->eapFail
)
614 SM_ENTER(SUPP_BE
, FAIL
);
615 else if (sm
->authWhile
== 0)
616 SM_ENTER(SUPP_BE
, TIMEOUT
);
617 else if (sm
->eapSuccess
)
618 SM_ENTER(SUPP_BE
, SUCCESS
);
624 static void eapol_sm_txLogoff(struct eapol_sm
*sm
)
626 wpa_printf(MSG_DEBUG
, "EAPOL: txLogoff");
627 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
628 IEEE802_1X_TYPE_EAPOL_LOGOFF
, (u8
*) "", 0);
629 sm
->dot1xSuppEapolLogoffFramesTx
++;
630 sm
->dot1xSuppEapolFramesTx
++;
634 static void eapol_sm_txStart(struct eapol_sm
*sm
)
636 wpa_printf(MSG_DEBUG
, "EAPOL: txStart");
637 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
638 IEEE802_1X_TYPE_EAPOL_START
, (u8
*) "", 0);
639 sm
->dot1xSuppEapolStartFramesTx
++;
640 sm
->dot1xSuppEapolFramesTx
++;
644 #define IEEE8021X_ENCR_KEY_LEN 32
645 #define IEEE8021X_SIGN_KEY_LEN 32
647 struct eap_key_data
{
648 u8 encr_key
[IEEE8021X_ENCR_KEY_LEN
];
649 u8 sign_key
[IEEE8021X_SIGN_KEY_LEN
];
653 static void eapol_sm_processKey(struct eapol_sm
*sm
)
655 struct ieee802_1x_hdr
*hdr
;
656 struct ieee802_1x_eapol_key
*key
;
657 struct eap_key_data keydata
;
658 u8 orig_key_sign
[IEEE8021X_KEY_SIGN_LEN
], datakey
[32];
659 u8 ekey
[IEEE8021X_KEY_IV_LEN
+ IEEE8021X_ENCR_KEY_LEN
];
660 int key_len
, res
, sign_key_len
, encr_key_len
;
663 wpa_printf(MSG_DEBUG
, "EAPOL: processKey");
664 if (sm
->last_rx_key
== NULL
)
667 if (!sm
->conf
.accept_802_1x_keys
) {
668 wpa_printf(MSG_WARNING
, "EAPOL: Received IEEE 802.1X EAPOL-Key"
669 " even though this was not accepted - "
670 "ignoring this packet");
674 hdr
= (struct ieee802_1x_hdr
*) sm
->last_rx_key
;
675 key
= (struct ieee802_1x_eapol_key
*) (hdr
+ 1);
676 if (sizeof(*hdr
) + be_to_host16(hdr
->length
) > sm
->last_rx_key_len
) {
677 wpa_printf(MSG_WARNING
, "EAPOL: Too short EAPOL-Key frame");
680 rx_key_length
= WPA_GET_BE16(key
->key_length
);
681 wpa_printf(MSG_DEBUG
, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
682 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
683 hdr
->version
, hdr
->type
, be_to_host16(hdr
->length
),
684 key
->type
, rx_key_length
, key
->key_index
);
686 eapol_sm_notify_lower_layer_success(sm
, 1);
687 sign_key_len
= IEEE8021X_SIGN_KEY_LEN
;
688 encr_key_len
= IEEE8021X_ENCR_KEY_LEN
;
689 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, sizeof(keydata
));
691 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get master key for "
692 "decrypting EAPOL-Key keys");
696 /* LEAP derives only 16 bytes of keying material. */
697 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, 16);
699 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get LEAP "
700 "master key for decrypting EAPOL-Key keys");
705 os_memcpy(keydata
.sign_key
, keydata
.encr_key
, 16);
707 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get enough master key "
708 "data for decrypting EAPOL-Key keys (res=%d)", res
);
712 /* The key replay_counter must increase when same master key */
713 if (sm
->replay_counter_valid
&&
714 os_memcmp(sm
->last_replay_counter
, key
->replay_counter
,
715 IEEE8021X_REPLAY_COUNTER_LEN
) >= 0) {
716 wpa_printf(MSG_WARNING
, "EAPOL: EAPOL-Key replay counter did "
717 "not increase - ignoring key");
718 wpa_hexdump(MSG_DEBUG
, "EAPOL: last replay counter",
719 sm
->last_replay_counter
,
720 IEEE8021X_REPLAY_COUNTER_LEN
);
721 wpa_hexdump(MSG_DEBUG
, "EAPOL: received replay counter",
722 key
->replay_counter
, IEEE8021X_REPLAY_COUNTER_LEN
);
726 /* Verify key signature (HMAC-MD5) */
727 os_memcpy(orig_key_sign
, key
->key_signature
, IEEE8021X_KEY_SIGN_LEN
);
728 os_memset(key
->key_signature
, 0, IEEE8021X_KEY_SIGN_LEN
);
729 hmac_md5(keydata
.sign_key
, sign_key_len
,
730 sm
->last_rx_key
, sizeof(*hdr
) + be_to_host16(hdr
->length
),
732 if (os_memcmp(orig_key_sign
, key
->key_signature
,
733 IEEE8021X_KEY_SIGN_LEN
) != 0) {
734 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key signature in "
736 os_memcpy(key
->key_signature
, orig_key_sign
,
737 IEEE8021X_KEY_SIGN_LEN
);
740 wpa_printf(MSG_DEBUG
, "EAPOL: EAPOL-Key key signature verified");
742 key_len
= be_to_host16(hdr
->length
) - sizeof(*key
);
743 if (key_len
> 32 || rx_key_length
> 32) {
744 wpa_printf(MSG_WARNING
, "EAPOL: Too long key data length %d",
745 key_len
? key_len
: rx_key_length
);
748 if (key_len
== rx_key_length
) {
749 os_memcpy(ekey
, key
->key_iv
, IEEE8021X_KEY_IV_LEN
);
750 os_memcpy(ekey
+ IEEE8021X_KEY_IV_LEN
, keydata
.encr_key
,
752 os_memcpy(datakey
, key
+ 1, key_len
);
753 rc4_skip(ekey
, IEEE8021X_KEY_IV_LEN
+ encr_key_len
, 0,
755 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: Decrypted(RC4) key",
757 } else if (key_len
== 0) {
759 * IEEE 802.1X-2004 specifies that least significant Key Length
760 * octets from MS-MPPE-Send-Key are used as the key if the key
761 * data is not present. This seems to be meaning the beginning
762 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
763 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
764 * Anyway, taking the beginning of the keying material from EAP
765 * seems to interoperate with Authenticators.
767 key_len
= rx_key_length
;
768 os_memcpy(datakey
, keydata
.encr_key
, key_len
);
769 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: using part of EAP keying "
770 "material data encryption key",
773 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key data length %d "
774 "(key_length=%d)", key_len
, rx_key_length
);
778 sm
->replay_counter_valid
= TRUE
;
779 os_memcpy(sm
->last_replay_counter
, key
->replay_counter
,
780 IEEE8021X_REPLAY_COUNTER_LEN
);
782 wpa_printf(MSG_DEBUG
, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
784 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
?
785 "unicast" : "broadcast",
786 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
, key_len
);
788 if (sm
->ctx
->set_wep_key
&&
789 sm
->ctx
->set_wep_key(sm
->ctx
->ctx
,
790 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
,
791 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
,
792 datakey
, key_len
) < 0) {
793 wpa_printf(MSG_WARNING
, "EAPOL: Failed to set WEP key to the "
796 if (key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
)
797 sm
->unicast_key_received
= TRUE
;
799 sm
->broadcast_key_received
= TRUE
;
801 if ((sm
->unicast_key_received
||
802 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_UNICAST
)) &&
803 (sm
->broadcast_key_received
||
804 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_BROADCAST
)))
806 wpa_printf(MSG_DEBUG
, "EAPOL: all required EAPOL-Key "
808 sm
->portValid
= TRUE
;
809 if (sm
->ctx
->eapol_done_cb
)
810 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
816 static void eapol_sm_getSuppRsp(struct eapol_sm
*sm
)
818 wpa_printf(MSG_DEBUG
, "EAPOL: getSuppRsp");
819 /* EAP layer processing; no special code is needed, since Supplicant
820 * Backend state machine is waiting for eapNoResp or eapResp to be set
821 * and these are only set in the EAP state machine when the processing
826 static void eapol_sm_txSuppRsp(struct eapol_sm
*sm
)
830 wpa_printf(MSG_DEBUG
, "EAPOL: txSuppRsp");
831 resp
= eap_get_eapRespData(sm
->eap
);
833 wpa_printf(MSG_WARNING
, "EAPOL: txSuppRsp - EAP response data "
838 /* Send EAP-Packet from the EAP layer to the Authenticator */
839 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
840 IEEE802_1X_TYPE_EAP_PACKET
, wpabuf_head(resp
),
843 /* eapRespData is not used anymore, so free it here */
847 sm
->dot1xSuppEapolReqIdFramesRx
++;
849 sm
->dot1xSuppEapolReqFramesRx
++;
850 sm
->dot1xSuppEapolRespFramesTx
++;
851 sm
->dot1xSuppEapolFramesTx
++;
855 static void eapol_sm_abortSupp(struct eapol_sm
*sm
)
857 /* release system resources that may have been allocated for the
858 * authentication session */
859 os_free(sm
->last_rx_key
);
860 sm
->last_rx_key
= NULL
;
861 wpabuf_free(sm
->eapReqData
);
862 sm
->eapReqData
= NULL
;
863 eap_sm_abort(sm
->eap
);
867 static void eapol_sm_step_timeout(void *eloop_ctx
, void *timeout_ctx
)
869 eapol_sm_step(timeout_ctx
);
873 static void eapol_sm_set_port_authorized(struct eapol_sm
*sm
)
875 if (sm
->ctx
->port_cb
)
876 sm
->ctx
->port_cb(sm
->ctx
->ctx
, 1);
880 static void eapol_sm_set_port_unauthorized(struct eapol_sm
*sm
)
882 if (sm
->ctx
->port_cb
)
883 sm
->ctx
->port_cb(sm
->ctx
->ctx
, 0);
888 * eapol_sm_step - EAPOL state machine step function
889 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
891 * This function is called to notify the state machine about changed external
892 * variables. It will step through the EAPOL state machines in loop to process
893 * all triggered state changes.
895 void eapol_sm_step(struct eapol_sm
*sm
)
899 /* In theory, it should be ok to run this in loop until !changed.
900 * However, it is better to use a limit on number of iterations to
901 * allow events (e.g., SIGTERM) to stop the program cleanly if the
902 * state machine were to generate a busy loop. */
903 for (i
= 0; i
< 100; i
++) {
905 SM_STEP_RUN(SUPP_PAE
);
907 SM_STEP_RUN(SUPP_BE
);
908 if (eap_peer_sm_step(sm
->eap
))
915 /* restart EAPOL state machine step from timeout call in order
916 * to allow other events to be processed. */
917 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
918 eloop_register_timeout(0, 0, eapol_sm_step_timeout
, NULL
, sm
);
921 if (sm
->ctx
->cb
&& sm
->cb_status
!= EAPOL_CB_IN_PROGRESS
) {
922 int success
= sm
->cb_status
== EAPOL_CB_SUCCESS
? 1 : 0;
923 sm
->cb_status
= EAPOL_CB_IN_PROGRESS
;
924 sm
->ctx
->cb(sm
, success
, sm
->ctx
->cb_ctx
);
929 #ifdef CONFIG_CTRL_IFACE
930 static const char *eapol_supp_pae_state(int state
)
933 case SUPP_PAE_LOGOFF
:
935 case SUPP_PAE_DISCONNECTED
:
936 return "DISCONNECTED";
937 case SUPP_PAE_CONNECTING
:
939 case SUPP_PAE_AUTHENTICATING
:
940 return "AUTHENTICATING";
943 case SUPP_PAE_AUTHENTICATED
:
944 return "AUTHENTICATED";
945 case SUPP_PAE_RESTART
:
953 static const char *eapol_supp_be_state(int state
)
956 case SUPP_BE_REQUEST
:
958 case SUPP_BE_RESPONSE
:
960 case SUPP_BE_SUCCESS
:
964 case SUPP_BE_TIMEOUT
:
968 case SUPP_BE_INITIALIZE
:
970 case SUPP_BE_RECEIVE
:
978 static const char * eapol_port_status(PortStatus status
)
980 if (status
== Authorized
)
983 return "Unauthorized";
985 #endif /* CONFIG_CTRL_IFACE */
988 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
989 static const char * eapol_port_control(PortControl ctrl
)
994 case ForceUnauthorized
:
995 return "ForceUnauthorized";
996 case ForceAuthorized
:
997 return "ForceAuthorized";
1002 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1006 * eapol_sm_configure - Set EAPOL variables
1007 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1008 * @heldPeriod: dot1xSuppHeldPeriod
1009 * @authPeriod: dot1xSuppAuthPeriod
1010 * @startPeriod: dot1xSuppStartPeriod
1011 * @maxStart: dot1xSuppMaxStart
1013 * Set configurable EAPOL state machine variables. Each variable can be set to
1014 * the given value or ignored if set to -1 (to set only some of the variables).
1016 void eapol_sm_configure(struct eapol_sm
*sm
, int heldPeriod
, int authPeriod
,
1017 int startPeriod
, int maxStart
)
1021 if (heldPeriod
>= 0)
1022 sm
->heldPeriod
= heldPeriod
;
1023 if (authPeriod
>= 0)
1024 sm
->authPeriod
= authPeriod
;
1025 if (startPeriod
>= 0)
1026 sm
->startPeriod
= startPeriod
;
1028 sm
->maxStart
= maxStart
;
1032 #ifdef CONFIG_CTRL_IFACE
1034 * eapol_sm_get_status - Get EAPOL state machine status
1035 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1036 * @buf: Buffer for status information
1037 * @buflen: Maximum buffer length
1038 * @verbose: Whether to include verbose status information
1039 * Returns: Number of bytes written to buf.
1041 * Query EAPOL state machine for status information. This function fills in a
1042 * text area with current status information from the EAPOL state machine. If
1043 * the buffer (buf) is not large enough, status information will be truncated
1044 * to fit the buffer.
1046 int eapol_sm_get_status(struct eapol_sm
*sm
, char *buf
, size_t buflen
,
1053 len
= os_snprintf(buf
, buflen
,
1054 "Supplicant PAE state=%s\n"
1055 "suppPortStatus=%s\n",
1056 eapol_supp_pae_state(sm
->SUPP_PAE_state
),
1057 eapol_port_status(sm
->suppPortStatus
));
1058 if (len
< 0 || (size_t) len
>= buflen
)
1062 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1068 "Supplicant Backend state=%s\n",
1073 eapol_port_control(sm
->portControl
),
1074 eapol_supp_be_state(sm
->SUPP_BE_state
));
1075 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1080 len
+= eap_sm_get_status(sm
->eap
, buf
+ len
, buflen
- len
, verbose
);
1087 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1088 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1089 * @buf: Buffer for MIB information
1090 * @buflen: Maximum buffer length
1091 * Returns: Number of bytes written to buf.
1093 * Query EAPOL state machine for MIB information. This function fills in a
1094 * text area with current MIB information from the EAPOL state machine. If
1095 * the buffer (buf) is not large enough, MIB information will be truncated to
1098 int eapol_sm_get_mib(struct eapol_sm
*sm
, char *buf
, size_t buflen
)
1105 ret
= os_snprintf(buf
, buflen
,
1106 "dot1xSuppPaeState=%d\n"
1107 "dot1xSuppHeldPeriod=%u\n"
1108 "dot1xSuppAuthPeriod=%u\n"
1109 "dot1xSuppStartPeriod=%u\n"
1110 "dot1xSuppMaxStart=%u\n"
1111 "dot1xSuppSuppControlledPortStatus=%s\n"
1112 "dot1xSuppBackendPaeState=%d\n",
1118 sm
->suppPortStatus
== Authorized
?
1119 "Authorized" : "Unauthorized",
1122 if (ret
< 0 || (size_t) ret
>= buflen
)
1126 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1127 "dot1xSuppEapolFramesRx=%u\n"
1128 "dot1xSuppEapolFramesTx=%u\n"
1129 "dot1xSuppEapolStartFramesTx=%u\n"
1130 "dot1xSuppEapolLogoffFramesTx=%u\n"
1131 "dot1xSuppEapolRespFramesTx=%u\n"
1132 "dot1xSuppEapolReqIdFramesRx=%u\n"
1133 "dot1xSuppEapolReqFramesRx=%u\n"
1134 "dot1xSuppInvalidEapolFramesRx=%u\n"
1135 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1136 "dot1xSuppLastEapolFrameVersion=%u\n"
1137 "dot1xSuppLastEapolFrameSource=" MACSTR
"\n",
1138 sm
->dot1xSuppEapolFramesRx
,
1139 sm
->dot1xSuppEapolFramesTx
,
1140 sm
->dot1xSuppEapolStartFramesTx
,
1141 sm
->dot1xSuppEapolLogoffFramesTx
,
1142 sm
->dot1xSuppEapolRespFramesTx
,
1143 sm
->dot1xSuppEapolReqIdFramesRx
,
1144 sm
->dot1xSuppEapolReqFramesRx
,
1145 sm
->dot1xSuppInvalidEapolFramesRx
,
1146 sm
->dot1xSuppEapLengthErrorFramesRx
,
1147 sm
->dot1xSuppLastEapolFrameVersion
,
1148 MAC2STR(sm
->dot1xSuppLastEapolFrameSource
));
1150 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1156 #endif /* CONFIG_CTRL_IFACE */
1160 * eapol_sm_rx_eapol - Process received EAPOL frames
1161 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1162 * @src: Source MAC address of the EAPOL packet
1163 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1164 * @len: Length of the EAPOL frame
1165 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1168 int eapol_sm_rx_eapol(struct eapol_sm
*sm
, const u8
*src
, const u8
*buf
,
1171 const struct ieee802_1x_hdr
*hdr
;
1172 const struct ieee802_1x_eapol_key
*key
;
1179 sm
->dot1xSuppEapolFramesRx
++;
1180 if (len
< sizeof(*hdr
)) {
1181 sm
->dot1xSuppInvalidEapolFramesRx
++;
1184 hdr
= (const struct ieee802_1x_hdr
*) buf
;
1185 sm
->dot1xSuppLastEapolFrameVersion
= hdr
->version
;
1186 os_memcpy(sm
->dot1xSuppLastEapolFrameSource
, src
, ETH_ALEN
);
1187 if (hdr
->version
< EAPOL_VERSION
) {
1188 /* TODO: backwards compatibility */
1190 plen
= be_to_host16(hdr
->length
);
1191 if (plen
> len
- sizeof(*hdr
)) {
1192 sm
->dot1xSuppEapLengthErrorFramesRx
++;
1196 if (sm
->conf
.workaround
&&
1197 plen
< len
- sizeof(*hdr
) &&
1198 hdr
->type
== IEEE802_1X_TYPE_EAP_PACKET
&&
1199 len
- sizeof(*hdr
) > sizeof(struct eap_hdr
)) {
1200 const struct eap_hdr
*ehdr
=
1201 (const struct eap_hdr
*) (hdr
+ 1);
1204 elen
= be_to_host16(ehdr
->length
);
1205 if (elen
> plen
&& elen
<= len
- sizeof(*hdr
)) {
1207 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1208 * packets with too short EAPOL header length field
1209 * (14 octets). This is fixed in firmware Ver.1.49.
1210 * As a workaround, fix the EAPOL header based on the
1211 * correct length in the EAP packet.
1213 wpa_printf(MSG_DEBUG
, "EAPOL: Workaround - fix EAPOL "
1214 "payload length based on EAP header: "
1215 "%d -> %d", (int) plen
, elen
);
1219 #endif /* CONFIG_WPS */
1220 data_len
= plen
+ sizeof(*hdr
);
1222 switch (hdr
->type
) {
1223 case IEEE802_1X_TYPE_EAP_PACKET
:
1224 if (sm
->cached_pmk
) {
1225 /* Trying to use PMKSA caching, but Authenticator did
1226 * not seem to have a matching entry. Need to restart
1227 * EAPOL state machines.
1229 eapol_sm_abort_cached(sm
);
1231 wpabuf_free(sm
->eapReqData
);
1232 sm
->eapReqData
= wpabuf_alloc_copy(hdr
+ 1, plen
);
1233 if (sm
->eapReqData
) {
1234 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAP-Packet "
1236 sm
->eapolEap
= TRUE
;
1240 case IEEE802_1X_TYPE_EAPOL_KEY
:
1241 if (plen
< sizeof(*key
)) {
1242 wpa_printf(MSG_DEBUG
, "EAPOL: Too short EAPOL-Key "
1246 key
= (const struct ieee802_1x_eapol_key
*) (hdr
+ 1);
1247 if (key
->type
== EAPOL_KEY_TYPE_WPA
||
1248 key
->type
== EAPOL_KEY_TYPE_RSN
) {
1249 /* WPA Supplicant takes care of this frame. */
1250 wpa_printf(MSG_DEBUG
, "EAPOL: Ignoring WPA EAPOL-Key "
1251 "frame in EAPOL state machines");
1255 if (key
->type
!= EAPOL_KEY_TYPE_RC4
) {
1256 wpa_printf(MSG_DEBUG
, "EAPOL: Ignored unknown "
1257 "EAPOL-Key type %d", key
->type
);
1260 os_free(sm
->last_rx_key
);
1261 sm
->last_rx_key
= os_malloc(data_len
);
1262 if (sm
->last_rx_key
) {
1263 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAPOL-Key "
1265 os_memcpy(sm
->last_rx_key
, buf
, data_len
);
1266 sm
->last_rx_key_len
= data_len
;
1272 wpa_printf(MSG_DEBUG
, "EAPOL: Received unknown EAPOL type %d",
1274 sm
->dot1xSuppInvalidEapolFramesRx
++;
1283 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1284 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1286 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1287 * component, e.g., WPA. This will update the statistics.
1289 void eapol_sm_notify_tx_eapol_key(struct eapol_sm
*sm
)
1292 sm
->dot1xSuppEapolFramesTx
++;
1297 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1298 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1299 * @enabled: New portEnabled value
1301 * Notify EAPOL state machine about new portEnabled value.
1303 void eapol_sm_notify_portEnabled(struct eapol_sm
*sm
, Boolean enabled
)
1307 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1308 "portEnabled=%d", enabled
);
1309 sm
->portEnabled
= enabled
;
1315 * eapol_sm_notify_portValid - Notification about portValid change
1316 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1317 * @valid: New portValid value
1319 * Notify EAPOL state machine about new portValid value.
1321 void eapol_sm_notify_portValid(struct eapol_sm
*sm
, Boolean valid
)
1325 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1326 "portValid=%d", valid
);
1327 sm
->portValid
= valid
;
1333 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1334 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1335 * @success: %TRUE = set success, %FALSE = clear success
1337 * Notify the EAPOL state machine that external event has forced EAP state to
1338 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1340 * This function is called to update EAP state when WPA-PSK key handshake has
1341 * been completed successfully since WPA-PSK does not use EAP state machine.
1343 void eapol_sm_notify_eap_success(struct eapol_sm
*sm
, Boolean success
)
1347 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1348 "EAP success=%d", success
);
1349 sm
->eapSuccess
= success
;
1350 sm
->altAccept
= success
;
1352 eap_notify_success(sm
->eap
);
1358 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1359 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1360 * @fail: %TRUE = set failure, %FALSE = clear failure
1362 * Notify EAPOL state machine that external event has forced EAP state to
1363 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1365 void eapol_sm_notify_eap_fail(struct eapol_sm
*sm
, Boolean fail
)
1369 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1370 "EAP fail=%d", fail
);
1372 sm
->altReject
= fail
;
1378 * eapol_sm_notify_config - Notification of EAPOL configuration change
1379 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1380 * @config: Pointer to current network EAP configuration
1381 * @conf: Pointer to EAPOL configuration data
1383 * Notify EAPOL state machine that configuration has changed. config will be
1384 * stored as a backpointer to network configuration. This can be %NULL to clear
1385 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1386 * data. If conf is %NULL, this part of the configuration change will be
1389 void eapol_sm_notify_config(struct eapol_sm
*sm
,
1390 struct eap_peer_config
*config
,
1391 const struct eapol_config
*conf
)
1396 sm
->config
= config
;
1401 sm
->conf
.accept_802_1x_keys
= conf
->accept_802_1x_keys
;
1402 sm
->conf
.required_keys
= conf
->required_keys
;
1403 sm
->conf
.fast_reauth
= conf
->fast_reauth
;
1404 sm
->conf
.workaround
= conf
->workaround
;
1406 eap_set_fast_reauth(sm
->eap
, conf
->fast_reauth
);
1407 eap_set_workaround(sm
->eap
, conf
->workaround
);
1408 eap_set_force_disabled(sm
->eap
, conf
->eap_disabled
);
1414 * eapol_sm_get_key - Get master session key (MSK) from EAP
1415 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1416 * @key: Pointer for key buffer
1417 * @len: Number of bytes to copy to key
1418 * Returns: 0 on success (len of key available), maximum available key len
1419 * (>0) if key is available but it is shorter than len, or -1 on failure.
1421 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1422 * is available only after a successful authentication.
1424 int eapol_sm_get_key(struct eapol_sm
*sm
, u8
*key
, size_t len
)
1429 if (sm
== NULL
|| !eap_key_available(sm
->eap
)) {
1430 wpa_printf(MSG_DEBUG
, "EAPOL: EAP key not available");
1433 eap_key
= eap_get_eapKeyData(sm
->eap
, &eap_len
);
1434 if (eap_key
== NULL
) {
1435 wpa_printf(MSG_DEBUG
, "EAPOL: Failed to get eapKeyData");
1438 if (len
> eap_len
) {
1439 wpa_printf(MSG_DEBUG
, "EAPOL: Requested key length (%lu) not "
1440 "available (len=%lu)",
1441 (unsigned long) len
, (unsigned long) eap_len
);
1444 os_memcpy(key
, eap_key
, len
);
1445 wpa_printf(MSG_DEBUG
, "EAPOL: Successfully fetched key (len=%lu)",
1446 (unsigned long) len
);
1452 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1453 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1454 * @logoff: Whether command was logoff
1456 * Notify EAPOL state machines that user requested logon/logoff.
1458 void eapol_sm_notify_logoff(struct eapol_sm
*sm
, Boolean logoff
)
1461 sm
->userLogoff
= logoff
;
1468 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1469 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1471 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1472 * to move EAPOL and EAP state machines into authenticated/successful state.
1474 void eapol_sm_notify_cached(struct eapol_sm
*sm
)
1478 wpa_printf(MSG_DEBUG
, "EAPOL: PMKSA caching was used - skip EAPOL");
1479 sm
->SUPP_PAE_state
= SUPP_PAE_AUTHENTICATED
;
1480 sm
->suppPortStatus
= Authorized
;
1481 eapol_sm_set_port_authorized(sm
);
1482 sm
->portValid
= TRUE
;
1483 eap_notify_success(sm
->eap
);
1489 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1490 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1491 * @attempt: Whether PMKSA caching is tried
1493 * Notify EAPOL state machines whether PMKSA caching is used.
1495 void eapol_sm_notify_pmkid_attempt(struct eapol_sm
*sm
, int attempt
)
1500 wpa_printf(MSG_DEBUG
, "RSN: Trying to use cached PMKSA");
1501 sm
->cached_pmk
= TRUE
;
1503 wpa_printf(MSG_DEBUG
, "RSN: Do not try to use cached PMKSA");
1504 sm
->cached_pmk
= FALSE
;
1509 static void eapol_sm_abort_cached(struct eapol_sm
*sm
)
1511 wpa_printf(MSG_DEBUG
, "RSN: Authenticator did not accept PMKID, "
1512 "doing full EAP authentication");
1515 sm
->cached_pmk
= FALSE
;
1516 sm
->SUPP_PAE_state
= SUPP_PAE_CONNECTING
;
1517 sm
->suppPortStatus
= Unauthorized
;
1518 eapol_sm_set_port_unauthorized(sm
);
1520 /* Make sure we do not start sending EAPOL-Start frames first, but
1521 * instead move to RESTART state to start EAPOL authentication. */
1523 eapol_enable_timer_tick(sm
);
1525 if (sm
->ctx
->aborted_cached
)
1526 sm
->ctx
->aborted_cached(sm
->ctx
->ctx
);
1531 * eapol_sm_register_scard_ctx - Notification of smart card context
1532 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1533 * @ctx: Context data for smart card operations
1535 * Notify EAPOL state machines of context data for smart card operations. This
1536 * context data will be used as a parameter for scard_*() functions.
1538 void eapol_sm_register_scard_ctx(struct eapol_sm
*sm
, void *ctx
)
1541 sm
->ctx
->scard_ctx
= ctx
;
1542 eap_register_scard_ctx(sm
->eap
, ctx
);
1548 * eapol_sm_notify_portControl - Notification of portControl changes
1549 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1550 * @portControl: New value for portControl variable
1552 * Notify EAPOL state machines that portControl variable has changed.
1554 void eapol_sm_notify_portControl(struct eapol_sm
*sm
, PortControl portControl
)
1558 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1559 "portControl=%s", eapol_port_control(portControl
));
1560 sm
->portControl
= portControl
;
1566 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1567 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1569 * Notify EAPOL state machines that a monitor was attached to the control
1570 * interface to trigger re-sending of pending requests for user input.
1572 void eapol_sm_notify_ctrl_attached(struct eapol_sm
*sm
)
1576 eap_sm_notify_ctrl_attached(sm
->eap
);
1581 * eapol_sm_notify_ctrl_response - Notification of received user input
1582 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1584 * Notify EAPOL state machines that a control response, i.e., user
1585 * input, was received in order to trigger retrying of a pending EAP request.
1587 void eapol_sm_notify_ctrl_response(struct eapol_sm
*sm
)
1591 if (sm
->eapReqData
&& !sm
->eapReq
) {
1592 wpa_printf(MSG_DEBUG
, "EAPOL: received control response (user "
1593 "input) notification - retrying pending EAP "
1595 sm
->eapolEap
= TRUE
;
1603 * eapol_sm_request_reauth - Request reauthentication
1604 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1606 * This function can be used to request EAPOL reauthentication, e.g., when the
1607 * current PMKSA entry is nearing expiration.
1609 void eapol_sm_request_reauth(struct eapol_sm
*sm
)
1611 if (sm
== NULL
|| sm
->SUPP_PAE_state
!= SUPP_PAE_AUTHENTICATED
)
1613 eapol_sm_txStart(sm
);
1618 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1619 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1620 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1621 * machine loop (eapol_sm_step())
1623 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1624 * successful authentication. This is used to recover from dropped EAP-Success
1627 void eapol_sm_notify_lower_layer_success(struct eapol_sm
*sm
, int in_eapol_sm
)
1631 eap_notify_lower_layer_success(sm
->eap
);
1638 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1639 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1641 void eapol_sm_invalidate_cached_session(struct eapol_sm
*sm
)
1644 eap_invalidate_cached_session(sm
->eap
);
1648 static struct eap_peer_config
* eapol_sm_get_config(void *ctx
)
1650 struct eapol_sm
*sm
= ctx
;
1651 return sm
? sm
->config
: NULL
;
1655 static struct wpabuf
* eapol_sm_get_eapReqData(void *ctx
)
1657 struct eapol_sm
*sm
= ctx
;
1658 if (sm
== NULL
|| sm
->eapReqData
== NULL
)
1661 return sm
->eapReqData
;
1665 static Boolean
eapol_sm_get_bool(void *ctx
, enum eapol_bool_var variable
)
1667 struct eapol_sm
*sm
= ctx
;
1671 case EAPOL_eapSuccess
:
1672 return sm
->eapSuccess
;
1673 case EAPOL_eapRestart
:
1674 return sm
->eapRestart
;
1679 case EAPOL_eapNoResp
:
1680 return sm
->eapNoResp
;
1683 case EAPOL_portEnabled
:
1684 return sm
->portEnabled
;
1685 case EAPOL_altAccept
:
1686 return sm
->altAccept
;
1687 case EAPOL_altReject
:
1688 return sm
->altReject
;
1694 static void eapol_sm_set_bool(void *ctx
, enum eapol_bool_var variable
,
1697 struct eapol_sm
*sm
= ctx
;
1701 case EAPOL_eapSuccess
:
1702 sm
->eapSuccess
= value
;
1704 case EAPOL_eapRestart
:
1705 sm
->eapRestart
= value
;
1708 sm
->eapFail
= value
;
1711 sm
->eapResp
= value
;
1713 case EAPOL_eapNoResp
:
1714 sm
->eapNoResp
= value
;
1719 case EAPOL_portEnabled
:
1720 sm
->portEnabled
= value
;
1722 case EAPOL_altAccept
:
1723 sm
->altAccept
= value
;
1725 case EAPOL_altReject
:
1726 sm
->altReject
= value
;
1732 static unsigned int eapol_sm_get_int(void *ctx
, enum eapol_int_var variable
)
1734 struct eapol_sm
*sm
= ctx
;
1738 case EAPOL_idleWhile
:
1739 return sm
->idleWhile
;
1745 static void eapol_sm_set_int(void *ctx
, enum eapol_int_var variable
,
1748 struct eapol_sm
*sm
= ctx
;
1752 case EAPOL_idleWhile
:
1753 sm
->idleWhile
= value
;
1754 eapol_enable_timer_tick(sm
);
1760 static void eapol_sm_set_config_blob(void *ctx
, struct wpa_config_blob
*blob
)
1762 #ifndef CONFIG_NO_CONFIG_BLOBS
1763 struct eapol_sm
*sm
= ctx
;
1764 if (sm
&& sm
->ctx
&& sm
->ctx
->set_config_blob
)
1765 sm
->ctx
->set_config_blob(sm
->ctx
->ctx
, blob
);
1766 #endif /* CONFIG_NO_CONFIG_BLOBS */
1770 static const struct wpa_config_blob
*
1771 eapol_sm_get_config_blob(void *ctx
, const char *name
)
1773 #ifndef CONFIG_NO_CONFIG_BLOBS
1774 struct eapol_sm
*sm
= ctx
;
1775 if (sm
&& sm
->ctx
&& sm
->ctx
->get_config_blob
)
1776 return sm
->ctx
->get_config_blob(sm
->ctx
->ctx
, name
);
1779 #else /* CONFIG_NO_CONFIG_BLOBS */
1781 #endif /* CONFIG_NO_CONFIG_BLOBS */
1785 static void eapol_sm_notify_pending(void *ctx
)
1787 struct eapol_sm
*sm
= ctx
;
1790 if (sm
->eapReqData
&& !sm
->eapReq
) {
1791 wpa_printf(MSG_DEBUG
, "EAPOL: received notification from EAP "
1792 "state machine - retrying pending EAP Request");
1793 sm
->eapolEap
= TRUE
;
1800 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1801 static void eapol_sm_eap_param_needed(void *ctx
, const char *field
,
1804 struct eapol_sm
*sm
= ctx
;
1805 wpa_printf(MSG_DEBUG
, "EAPOL: EAP parameter needed");
1806 if (sm
->ctx
->eap_param_needed
)
1807 sm
->ctx
->eap_param_needed(sm
->ctx
->ctx
, field
, txt
);
1809 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1810 #define eapol_sm_eap_param_needed NULL
1811 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1814 static struct eapol_callbacks eapol_cb
=
1816 eapol_sm_get_config
,
1821 eapol_sm_get_eapReqData
,
1822 eapol_sm_set_config_blob
,
1823 eapol_sm_get_config_blob
,
1824 eapol_sm_notify_pending
,
1825 eapol_sm_eap_param_needed
1830 * eapol_sm_init - Initialize EAPOL state machine
1831 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1832 * and EAPOL state machine will free it in eapol_sm_deinit()
1833 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1835 * Allocate and initialize an EAPOL state machine.
1837 struct eapol_sm
*eapol_sm_init(struct eapol_ctx
*ctx
)
1839 struct eapol_sm
*sm
;
1840 struct eap_config conf
;
1841 sm
= os_zalloc(sizeof(*sm
));
1846 sm
->portControl
= Auto
;
1848 /* Supplicant PAE state machine */
1849 sm
->heldPeriod
= 60;
1850 sm
->startPeriod
= 30;
1853 /* Supplicant Backend state machine */
1854 sm
->authPeriod
= 30;
1856 os_memset(&conf
, 0, sizeof(conf
));
1857 conf
.opensc_engine_path
= ctx
->opensc_engine_path
;
1858 conf
.pkcs11_engine_path
= ctx
->pkcs11_engine_path
;
1859 conf
.pkcs11_module_path
= ctx
->pkcs11_module_path
;
1860 conf
.wps
= ctx
->wps
;
1862 sm
->eap
= eap_peer_sm_init(sm
, &eapol_cb
, sm
->ctx
->msg_ctx
, &conf
);
1863 if (sm
->eap
== NULL
) {
1868 /* Initialize EAPOL state machines */
1869 sm
->initialize
= TRUE
;
1871 sm
->initialize
= FALSE
;
1874 sm
->timer_tick_enabled
= 1;
1875 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
1882 * eapol_sm_deinit - Deinitialize EAPOL state machine
1883 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1885 * Deinitialize and free EAPOL state machine.
1887 void eapol_sm_deinit(struct eapol_sm
*sm
)
1891 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
1892 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
1893 eap_peer_sm_deinit(sm
->eap
);
1894 os_free(sm
->last_rx_key
);
1895 wpabuf_free(sm
->eapReqData
);