RSNO: Use SNonce cookie to indicate support for RSN overriding

This provides an implicitly protected (SNonce is used as an input to PTK
derivation) mechanism for a STA to indicate support for RSN overriding
in a manner that does not cause interopability issues with deployed APs.

In addition, update sm->SNonce on the Authenticator only based on
message 2/4 since that is the only EAPOL-Key message that is defined to
provide the actual SNonce value. While clearing of this internal buffer
on message 4/4 might not cause issues, it is better to keep the actual
SNonce value here since the SNonce cookie can be used at a later point
in the sequence.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2024-07-29 16:43:50 +03:00 committed by Jouni Malinen
parent 62ca121f96
commit 6f522baa1b
4 changed files with 34 additions and 2 deletions

View file

@ -1887,6 +1887,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
sm->EAPOLKeyReceived = true; sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
if (msg == PAIRWISE_2)
os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
wpa_sm_step(sm); wpa_sm_step(sm);
@ -3922,7 +3923,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
/* Verify RSN Selection element for RSN overriding */ /* Verify RSN Selection element for RSN overriding */
if ((sm->rsn_selection && !kde.rsn_selection) || if ((rsn_is_snonce_cookie(sm->SNonce) && !kde.rsn_selection) ||
(!rsn_is_snonce_cookie(sm->SNonce) && kde.rsn_selection) ||
(sm->rsn_selection && !kde.rsn_selection) ||
(!sm->rsn_selection && kde.rsn_selection) || (!sm->rsn_selection && kde.rsn_selection) ||
(sm->rsn_selection && kde.rsn_selection && (sm->rsn_selection && kde.rsn_selection &&
(sm->rsn_selection_len != kde.rsn_selection_len || (sm->rsn_selection_len != kde.rsn_selection_len ||
@ -3930,6 +3933,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->rsn_selection_len) != 0))) { sm->rsn_selection_len) != 0))) {
wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
"RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4"); "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
wpa_printf(MSG_DEBUG,
"SNonce cookie for RSN overriding %sused",
rsn_is_snonce_cookie(sm->SNonce) ? "" : "not ");
wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq", wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
sm->rsn_selection, sm->rsn_selection_len); sm->rsn_selection, sm->rsn_selection_len);
wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4", wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",

View file

@ -4274,3 +4274,24 @@ int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len)
} }
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
void rsn_set_snonce_cookie(u8 *snonce)
{
u8 *pos;
pos = snonce + WPA_NONCE_LEN - 6;
WPA_PUT_BE24(pos, OUI_WFA);
pos += 3;
WPA_PUT_BE24(pos, 0x000029);
}
bool rsn_is_snonce_cookie(const u8 *snonce)
{
const u8 *pos;
pos = snonce + WPA_NONCE_LEN - 6;
return WPA_GET_BE24(pos) == OUI_WFA &&
WPA_GET_BE24(pos + 3) == 0x000029;
}

View file

@ -797,4 +797,7 @@ int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab); void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len); int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len);
void rsn_set_snonce_cookie(u8 *snonce);
bool rsn_is_snonce_cookie(const u8 *snonce);
#endif /* WPA_COMMON_H */ #endif /* WPA_COMMON_H */

View file

@ -1023,6 +1023,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
"WPA: Failed to get random data for SNonce"); "WPA: Failed to get random data for SNonce");
goto failed; goto failed;
} }
if (sm->rsn_override != RSN_OVERRIDE_NOT_USED)
rsn_set_snonce_cookie(sm->snonce);
sm->renew_snonce = 0; sm->renew_snonce = 0;
wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
sm->snonce, WPA_NONCE_LEN); sm->snonce, WPA_NONCE_LEN);