Work around SNonce updates on EAPOL-Key 1/4 retransmission
Some deployed supplicants update their SNonce for every receive EAPOL-Key message 1/4 even when these messages happen during the same 4-way handshake. Furthermore, some of these supplicants fail to use the first SNonce that they sent and derive an incorrect PTK using another SNonce that does not match with what the authenticator is using from the first received message 2/4. This results in failed 4-way handshake whenever the EAPOL-Key 1/4 retransmission timeout is reached. The timeout for the first retry is fixed to 100 ms in the IEEE 802.11 standard and that seems to be short enough to make it difficult for some stations to get the response out before retransmission. Work around this issue by increasing the initial EAPOL-Key 1/4 timeout by 1000 ms (i.e., total timeout of 1100 ms) if the station acknowledges reception of the EAPOL-Key frame. If the driver does not indicate TX status for EAPOL frames, use longer initial timeout (1000 ms) unconditionally.
This commit is contained in:
parent
2fee890af7
commit
e4bf4db907
5 changed files with 56 additions and 1 deletions
|
@ -1770,6 +1770,16 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
MAC2STR(sta->addr), xhdr->version, xhdr->type,
|
MAC2STR(sta->addr), xhdr->version, xhdr->type,
|
||||||
be_to_host16(xhdr->length), ack);
|
be_to_host16(xhdr->length), ack);
|
||||||
|
|
||||||
|
if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
|
||||||
|
pos + sizeof(struct wpa_eapol_key) <= buf + len) {
|
||||||
|
const struct wpa_eapol_key *wpa;
|
||||||
|
wpa = (const struct wpa_eapol_key *) pos;
|
||||||
|
if (wpa->type == EAPOL_KEY_TYPE_RSN ||
|
||||||
|
wpa->type == EAPOL_KEY_TYPE_WPA)
|
||||||
|
wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
|
||||||
|
sta->wpa_sm, ack);
|
||||||
|
}
|
||||||
|
|
||||||
/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
|
/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
|
||||||
* or Authenticator state machines, but EAPOL-Key packets are not
|
* or Authenticator state machines, but EAPOL-Key packets are not
|
||||||
* retransmitted in case of failure. Try to re-sent failed EAPOL-Key
|
* retransmitted in case of failure. Try to re-sent failed EAPOL-Key
|
||||||
|
|
|
@ -602,6 +602,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
|
||||||
}
|
}
|
||||||
|
|
||||||
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
||||||
|
sm->pending_1_of_4_timeout = 0;
|
||||||
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
|
eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
|
||||||
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
|
||||||
if (sm->in_step_loop) {
|
if (sm->in_step_loop) {
|
||||||
|
@ -969,6 +970,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
|
||||||
}
|
}
|
||||||
sm->MICVerified = TRUE;
|
sm->MICVerified = TRUE;
|
||||||
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
|
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
|
||||||
|
sm->pending_1_of_4_timeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key_info & WPA_KEY_INFO_REQUEST) {
|
if (key_info & WPA_KEY_INFO_REQUEST) {
|
||||||
|
@ -1098,6 +1100,7 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
struct wpa_authenticator *wpa_auth = eloop_ctx;
|
||||||
struct wpa_state_machine *sm = timeout_ctx;
|
struct wpa_state_machine *sm = timeout_ctx;
|
||||||
|
|
||||||
|
sm->pending_1_of_4_timeout = 0;
|
||||||
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
|
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
|
||||||
sm->TimeoutEvt = TRUE;
|
sm->TimeoutEvt = TRUE;
|
||||||
wpa_sm_step(sm);
|
wpa_sm_step(sm);
|
||||||
|
@ -1285,10 +1288,14 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
|
||||||
keyidx, encr, 0);
|
keyidx, encr, 0);
|
||||||
|
|
||||||
ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
|
ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
|
||||||
if (ctr == 1)
|
if (ctr == 1 && wpa_auth->conf.tx_status)
|
||||||
timeout_ms = eapol_key_timeout_first;
|
timeout_ms = eapol_key_timeout_first;
|
||||||
else
|
else
|
||||||
timeout_ms = eapol_key_timeout_subseq;
|
timeout_ms = eapol_key_timeout_subseq;
|
||||||
|
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
|
||||||
|
sm->pending_1_of_4_timeout = 1;
|
||||||
|
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
|
||||||
|
"counter %d)", timeout_ms, ctr);
|
||||||
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
|
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
|
||||||
wpa_send_eapol_timeout, wpa_auth, sm);
|
wpa_send_eapol_timeout, wpa_auth, sm);
|
||||||
}
|
}
|
||||||
|
@ -1711,6 +1718,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
|
||||||
|
sm->pending_1_of_4_timeout = 0;
|
||||||
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
|
||||||
|
|
||||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
||||||
|
@ -2798,3 +2806,33 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
|
||||||
sm->group = group;
|
sm->group = group;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, int ack)
|
||||||
|
{
|
||||||
|
if (wpa_auth == NULL || sm == NULL)
|
||||||
|
return;
|
||||||
|
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
|
||||||
|
" ack=%d", MAC2STR(sm->addr), ack);
|
||||||
|
if (sm->pending_1_of_4_timeout && ack) {
|
||||||
|
/*
|
||||||
|
* Some deployed supplicant implementations update their SNonce
|
||||||
|
* for each EAPOL-Key 2/4 message even within the same 4-way
|
||||||
|
* handshake and then fail to use the first SNonce when
|
||||||
|
* deriving the PTK. This results in unsuccessful 4-way
|
||||||
|
* handshake whenever the relatively short initial timeout is
|
||||||
|
* reached and EAPOL-Key 1/4 is retransmitted. Try to work
|
||||||
|
* around this by increasing the timeout now that we know that
|
||||||
|
* the station has received the frame.
|
||||||
|
*/
|
||||||
|
int timeout_ms = eapol_key_timeout_subseq;
|
||||||
|
wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
|
||||||
|
"timeout by %u ms because of acknowledged frame",
|
||||||
|
timeout_ms);
|
||||||
|
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
|
||||||
|
eloop_register_timeout(timeout_ms / 1000,
|
||||||
|
(timeout_ms % 1000) * 1000,
|
||||||
|
wpa_send_eapol_timeout, wpa_auth, sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -144,6 +144,7 @@ struct wpa_auth_config {
|
||||||
int wmm_enabled;
|
int wmm_enabled;
|
||||||
int wmm_uapsd;
|
int wmm_uapsd;
|
||||||
int okc;
|
int okc;
|
||||||
|
int tx_status;
|
||||||
#ifdef CONFIG_IEEE80211W
|
#ifdef CONFIG_IEEE80211W
|
||||||
enum mfp_options ieee80211w;
|
enum mfp_options ieee80211w;
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
@ -260,6 +261,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||||
int session_timeout,
|
int session_timeout,
|
||||||
struct eapol_state_machine *eapol);
|
struct eapol_state_machine *eapol);
|
||||||
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
|
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
|
||||||
|
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
|
||||||
|
struct wpa_state_machine *sm, int ack);
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||||
|
|
|
@ -462,6 +462,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
|
||||||
size_t wpa_ie_len;
|
size_t wpa_ie_len;
|
||||||
|
|
||||||
hostapd_wpa_auth_conf(hapd->conf, &_conf);
|
hostapd_wpa_auth_conf(hapd->conf, &_conf);
|
||||||
|
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
|
||||||
|
_conf.tx_status = 1;
|
||||||
os_memset(&cb, 0, sizeof(cb));
|
os_memset(&cb, 0, sizeof(cb));
|
||||||
cb.ctx = hapd;
|
cb.ctx = hapd;
|
||||||
cb.logger = hostapd_wpa_auth_logger;
|
cb.logger = hostapd_wpa_auth_logger;
|
||||||
|
|
|
@ -120,6 +120,8 @@ struct wpa_state_machine {
|
||||||
* message 2/4 */
|
* message 2/4 */
|
||||||
u8 *assoc_resp_ftie;
|
u8 *assoc_resp_ftie;
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
|
||||||
|
int pending_1_of_4_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue