SecureLTF: Work around misbehaving STAs for PTK derivation without KDK
Some deployed STAs that advertise SecureLTF support in the RSNXE in (Re)Association Request frames, do not derive KDK during PTK generation. Since the correct key calculations in the AP includes an additional KDK generation in such cases, this causes different PTK-KCK being derived and the AP ultimately discarding EAPOL-Key message 2/4 due to MIC validation failure. Try to derive a PTK without KDK as a workaround in such cases and allow the 4-way handshake to continue if this results in a matching MIC. Signed-off-by: Sai Pratyusha Magam <quic_smagam@quicinc.com>
This commit is contained in:
parent
438a27b369
commit
8f69e538a9
1 changed files with 34 additions and 7 deletions
|
@ -62,7 +62,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, unsigned int pmk_len,
|
const u8 *pmk, unsigned int pmk_len,
|
||||||
struct wpa_ptk *ptk, int force_sha256,
|
struct wpa_ptk *ptk, int force_sha256,
|
||||||
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
|
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
|
||||||
size_t *key_len);
|
size_t *key_len, bool no_kdk);
|
||||||
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_group *group);
|
struct wpa_group *group);
|
||||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
||||||
|
@ -1323,7 +1323,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0,
|
if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0,
|
||||||
pmk_r0, pmk_r1, pmk_r0_name, &key_len) < 0)
|
pmk_r0, pmk_r1, pmk_r0_name, &key_len,
|
||||||
|
false) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
|
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
|
||||||
|
@ -2859,7 +2860,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, unsigned int pmk_len,
|
const u8 *pmk, unsigned int pmk_len,
|
||||||
struct wpa_ptk *ptk, int force_sha256,
|
struct wpa_ptk *ptk, int force_sha256,
|
||||||
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
|
u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
|
||||||
size_t *key_len)
|
size_t *key_len, bool no_kdk)
|
||||||
{
|
{
|
||||||
const u8 *z = NULL;
|
const u8 *z = NULL;
|
||||||
size_t z_len = 0, kdk_len;
|
size_t z_len = 0, kdk_len;
|
||||||
|
@ -2867,7 +2868,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (sm->wpa_auth->conf.force_kdk_derivation ||
|
if (sm->wpa_auth->conf.force_kdk_derivation ||
|
||||||
(sm->wpa_auth->conf.secure_ltf &&
|
(!no_kdk && sm->wpa_auth->conf.secure_ltf &&
|
||||||
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
|
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
|
||||||
kdk_len = WPA_KDK_MAX_LEN;
|
kdk_len = WPA_KDK_MAX_LEN;
|
||||||
else
|
else
|
||||||
|
@ -2896,7 +2897,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PASN
|
#ifdef CONFIG_PASN
|
||||||
if (sm->wpa_auth->conf.secure_ltf &&
|
if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
|
||||||
ieee802_11_rsnx_capab(sm->rsnxe,
|
ieee802_11_rsnx_capab(sm->rsnxe,
|
||||||
WLAN_RSNX_CAPAB_SECURE_LTF)) {
|
WLAN_RSNX_CAPAB_SECURE_LTF)) {
|
||||||
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt,
|
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt,
|
||||||
|
@ -2932,7 +2933,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PASN
|
#ifdef CONFIG_PASN
|
||||||
if (sm->wpa_auth->conf.secure_ltf &&
|
if (!no_kdk && sm->wpa_auth->conf.secure_ltf &&
|
||||||
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
|
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) {
|
||||||
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise);
|
ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -3643,6 +3644,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
size_t key_len;
|
size_t key_len;
|
||||||
u8 *key_data_buf = NULL;
|
u8 *key_data_buf = NULL;
|
||||||
size_t key_data_buf_len = 0;
|
size_t key_data_buf_len = 0;
|
||||||
|
bool derive_kdk, no_kdk = false;
|
||||||
|
|
||||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||||
sm->EAPOLKeyReceived = false;
|
sm->EAPOLKeyReceived = false;
|
||||||
|
@ -3651,6 +3653,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
|
|
||||||
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
|
mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
|
||||||
|
|
||||||
|
derive_kdk = sm->wpa_auth->conf.secure_ltf &&
|
||||||
|
ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF);
|
||||||
|
|
||||||
/* WPA with IEEE 802.1X: use the derived PMK from EAP
|
/* WPA with IEEE 802.1X: use the derived PMK from EAP
|
||||||
* WPA-PSK: iterate through possible PSKs and select the one matching
|
* WPA-PSK: iterate through possible PSKs and select the one matching
|
||||||
* the packet */
|
* the packet */
|
||||||
|
@ -3680,9 +3685,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
pmk_len = sm->pmksa->pmk_len;
|
pmk_len = sm->pmksa->pmk_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_kdk = false;
|
||||||
|
try_without_kdk:
|
||||||
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
|
if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
|
||||||
owe_ptk_workaround == 2, pmk_r0, pmk_r1,
|
owe_ptk_workaround == 2, pmk_r0, pmk_r1,
|
||||||
pmk_r0_name, &key_len) < 0)
|
pmk_r0_name, &key_len, no_kdk) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (mic_len &&
|
if (mic_len &&
|
||||||
|
@ -3716,11 +3723,31 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OWE */
|
#endif /* CONFIG_OWE */
|
||||||
|
|
||||||
|
/* Some deployed STAs that advertise SecureLTF support in the
|
||||||
|
* RSNXE in (Re)Association Request frames, do not derive KDK
|
||||||
|
* during PTK generation. Try to work around this by checking if
|
||||||
|
* a PTK derived without KDK would result in a matching MIC. */
|
||||||
|
if (!sm->wpa_auth->conf.force_kdk_derivation &&
|
||||||
|
derive_kdk && !no_kdk) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Try new PTK derivation without KDK as a workaround");
|
||||||
|
no_kdk = true;
|
||||||
|
goto try_without_kdk;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
|
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
|
||||||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
|
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (no_kdk && ok) {
|
||||||
|
/* The workaround worked, so allow the 4-way handshake to be
|
||||||
|
* completed with the PTK that was derived without the KDK. */
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"PTK without KDK worked - misbehaving STA "
|
||||||
|
MACSTR, MAC2STR(sm->addr));
|
||||||
|
}
|
||||||
|
|
||||||
if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
|
if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
|
||||||
wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
|
wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
|
||||||
!sm->waiting_radius_psk) {
|
!sm->waiting_radius_psk) {
|
||||||
|
|
Loading…
Reference in a new issue