SSID protection in 4-way handshake on STA
Add support for SSID protection in 4-way handshake based on the mechanism added in IEEE 802.11REVme/D6.0. This is a mitigation against CVE-2023-52424 (a.k.a. the SSID Confusion Attack). This functionality is disabled by default and can be enabled with ssid_protection=1 in the network profile. Once there has been more testing of this to confirm there is no significant interoperability issues, the goal is to be able to change this to be enabled by default. Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
parent
9a022cdc70
commit
dab7549d68
12 changed files with 98 additions and 6 deletions
|
@ -616,6 +616,7 @@
|
||||||
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
|
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
|
||||||
#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
|
#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
|
||||||
#define WLAN_RSNX_CAPAB_URNM_MFPR 15
|
#define WLAN_RSNX_CAPAB_URNM_MFPR 15
|
||||||
|
#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21
|
||||||
|
|
||||||
/* Multiple BSSID element subelements */
|
/* Multiple BSSID element subelements */
|
||||||
#define WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
|
#define WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0
|
||||||
|
|
|
@ -3743,6 +3743,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
|
||||||
ie->supp_oper_classes = pos + 2;
|
ie->supp_oper_classes = pos + 2;
|
||||||
ie->supp_oper_classes_len = pos[1];
|
ie->supp_oper_classes_len = pos[1];
|
||||||
}
|
}
|
||||||
|
} else if (*pos == WLAN_EID_SSID) {
|
||||||
|
ie->ssid = pos + 2;
|
||||||
|
ie->ssid_len = pos[1];
|
||||||
|
wpa_hexdump_ascii(MSG_DEBUG, "RSN: SSID in EAPOL-Key",
|
||||||
|
ie->ssid, ie->ssid_len);
|
||||||
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
|
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
|
||||||
ret = wpa_parse_generic(pos, ie);
|
ret = wpa_parse_generic(pos, ie);
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
|
|
|
@ -698,6 +698,8 @@ struct wpa_eapol_ie_parse {
|
||||||
size_t supp_channels_len;
|
size_t supp_channels_len;
|
||||||
const u8 *supp_oper_classes;
|
const u8 *supp_oper_classes;
|
||||||
size_t supp_oper_classes_len;
|
size_t supp_oper_classes_len;
|
||||||
|
const u8 *ssid;
|
||||||
|
size_t ssid_len;
|
||||||
u8 qosinfo;
|
u8 qosinfo;
|
||||||
u16 aid;
|
u16 aid;
|
||||||
const u8 *wmm;
|
const u8 *wmm;
|
||||||
|
|
|
@ -2542,6 +2542,28 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
|
||||||
if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
|
if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
|
if (sm->ssid_protection) {
|
||||||
|
if (!ie.ssid) {
|
||||||
|
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
|
||||||
|
"RSN: No SSID included in EAPOL-Key msg 3/4");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ie.ssid_len != sm->ssid_len ||
|
||||||
|
os_memcmp(ie.ssid, sm->ssid, sm->ssid_len) != 0) {
|
||||||
|
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
|
||||||
|
"RSN: SSID mismatch in EAPOL-Key msg 3/4");
|
||||||
|
wpa_hexdump_ascii(MSG_DEBUG, "RSN: Received SSID",
|
||||||
|
ie.ssid, ie.ssid_len);
|
||||||
|
wpa_hexdump_ascii(MSG_DEBUG, "RSN: Expected SSID",
|
||||||
|
sm->ssid, sm->ssid_len);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
|
||||||
|
"RSN: SSID matched expected value");
|
||||||
|
}
|
||||||
|
|
||||||
if (mlo && !ie.valid_mlo_gtks) {
|
if (mlo && !ie.valid_mlo_gtks) {
|
||||||
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
|
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
|
||||||
"MLO RSN: No GTK KDE included in EAPOL-Key msg 3/4");
|
"MLO RSN: No GTK KDE included in EAPOL-Key msg 3/4");
|
||||||
|
@ -4460,6 +4482,20 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len)
|
||||||
|
{
|
||||||
|
if (!sm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ssid) {
|
||||||
|
os_memcpy(sm->ssid, ssid, ssid_len);
|
||||||
|
sm->ssid_len = ssid_len;
|
||||||
|
} else {
|
||||||
|
sm->ssid_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
|
int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -4689,6 +4725,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
|
||||||
case WPA_PARAM_FT_PREPEND_PMKID:
|
case WPA_PARAM_FT_PREPEND_PMKID:
|
||||||
sm->ft_prepend_pmkid = value;
|
sm->ft_prepend_pmkid = value;
|
||||||
break;
|
break;
|
||||||
|
case WPA_PARAM_SSID_PROTECTION:
|
||||||
|
sm->ssid_protection = value;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4960,6 +4999,14 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
|
||||||
sm->assoc_rsnxe_len = len;
|
sm->assoc_rsnxe_len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sm->ssid_protection &&
|
||||||
|
!ieee802_11_rsnx_capab(sm->assoc_rsnxe,
|
||||||
|
WLAN_RSNX_CAPAB_SSID_PROTECTION)) {
|
||||||
|
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
|
||||||
|
"RSN: Disabling SSID protection based on own RSNXE update");
|
||||||
|
sm->ssid_protection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,7 @@ enum wpa_sm_conf_params {
|
||||||
WPA_PARAM_ENCRYPT_EAPOL_M2,
|
WPA_PARAM_ENCRYPT_EAPOL_M2,
|
||||||
WPA_PARAM_ENCRYPT_EAPOL_M4,
|
WPA_PARAM_ENCRYPT_EAPOL_M4,
|
||||||
WPA_PARAM_FT_PREPEND_PMKID,
|
WPA_PARAM_FT_PREPEND_PMKID,
|
||||||
|
WPA_PARAM_SSID_PROTECTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rsn_supp_config {
|
struct rsn_supp_config {
|
||||||
|
@ -188,6 +189,7 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
|
||||||
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
|
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
|
||||||
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
|
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
|
||||||
void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config);
|
void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config);
|
||||||
|
void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len);
|
||||||
void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
|
void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
|
||||||
void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
|
void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
|
||||||
const char *bridge_ifname);
|
const char *bridge_ifname);
|
||||||
|
|
|
@ -112,6 +112,7 @@ struct wpa_sm {
|
||||||
unsigned int secure_ltf:1;
|
unsigned int secure_ltf:1;
|
||||||
unsigned int secure_rtt:1;
|
unsigned int secure_rtt:1;
|
||||||
unsigned int prot_range_neg:1;
|
unsigned int prot_range_neg:1;
|
||||||
|
unsigned int ssid_protection:1;
|
||||||
|
|
||||||
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
|
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
|
||||||
size_t assoc_wpa_ie_len;
|
size_t assoc_wpa_ie_len;
|
||||||
|
|
|
@ -366,7 +366,7 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
|
||||||
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
|
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
|
||||||
{
|
{
|
||||||
u8 *pos = rsnxe;
|
u8 *pos = rsnxe;
|
||||||
u16 capab = 0;
|
u32 capab = 0, tmp;
|
||||||
size_t flen;
|
size_t flen;
|
||||||
|
|
||||||
if (wpa_key_mgmt_sae(sm->key_mgmt) &&
|
if (wpa_key_mgmt_sae(sm->key_mgmt) &&
|
||||||
|
@ -385,20 +385,27 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
|
||||||
if (sm->prot_range_neg)
|
if (sm->prot_range_neg)
|
||||||
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
|
||||||
|
if (sm->ssid_protection)
|
||||||
|
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||||
|
|
||||||
flen = (capab & 0xff00) ? 2 : 1;
|
|
||||||
if (!capab)
|
if (!capab)
|
||||||
return 0; /* no supported extended RSN capabilities */
|
return 0; /* no supported extended RSN capabilities */
|
||||||
|
tmp = capab;
|
||||||
|
flen = 0;
|
||||||
|
while (tmp) {
|
||||||
|
flen++;
|
||||||
|
tmp >>= 8;
|
||||||
|
}
|
||||||
if (rsnxe_len < 2 + flen)
|
if (rsnxe_len < 2 + flen)
|
||||||
return -1;
|
return -1;
|
||||||
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
|
||||||
|
|
||||||
*pos++ = WLAN_EID_RSNX;
|
*pos++ = WLAN_EID_RSNX;
|
||||||
*pos++ = flen;
|
*pos++ = flen;
|
||||||
*pos++ = capab & 0x00ff;
|
while (capab) {
|
||||||
capab >>= 8;
|
*pos++ = capab & 0xff;
|
||||||
if (capab)
|
capab >>= 8;
|
||||||
*pos++ = capab;
|
}
|
||||||
|
|
||||||
return pos - rsnxe;
|
return pos - rsnxe;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2755,6 +2755,7 @@ static const struct parse_data ssid_fields[] = {
|
||||||
{ INT_RANGE(disable_eht, 0, 1)},
|
{ INT_RANGE(disable_eht, 0, 1)},
|
||||||
{ INT_RANGE(enable_4addr_mode, 0, 1)},
|
{ INT_RANGE(enable_4addr_mode, 0, 1)},
|
||||||
{ INT_RANGE(max_idle, 0, 65535)},
|
{ INT_RANGE(max_idle, 0, 65535)},
|
||||||
|
{ INT_RANGE(ssid_protection, 0, 1)},
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef OFFSET
|
#undef OFFSET
|
||||||
|
|
|
@ -894,6 +894,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
|
||||||
INT(disable_eht);
|
INT(disable_eht);
|
||||||
INT(enable_4addr_mode);
|
INT(enable_4addr_mode);
|
||||||
INT(max_idle);
|
INT(max_idle);
|
||||||
|
INT(ssid_protection);
|
||||||
|
|
||||||
#undef STR
|
#undef STR
|
||||||
#undef INT
|
#undef INT
|
||||||
|
|
|
@ -1278,6 +1278,11 @@ struct wpa_ssid {
|
||||||
* as the maximum idle period for the STA during association.
|
* as the maximum idle period for the STA during association.
|
||||||
*/
|
*/
|
||||||
int max_idle;
|
int max_idle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssid_protection - Whether to use SSID protection in 4-way handshake
|
||||||
|
*/
|
||||||
|
bool ssid_protection;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_SSID_H */
|
#endif /* CONFIG_SSID_H */
|
||||||
|
|
|
@ -1048,6 +1048,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
old_ssid = wpa_s->current_ssid;
|
old_ssid = wpa_s->current_ssid;
|
||||||
wpa_s->current_ssid = ssid;
|
wpa_s->current_ssid = ssid;
|
||||||
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
|
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
|
||||||
|
wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
|
||||||
wpa_supplicant_initiate_eapol(wpa_s);
|
wpa_supplicant_initiate_eapol(wpa_s);
|
||||||
|
|
||||||
#ifdef CONFIG_FILS
|
#ifdef CONFIG_FILS
|
||||||
|
|
|
@ -443,6 +443,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
|
||||||
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
|
||||||
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
|
||||||
wpa_s->mgmt_group_cipher);
|
wpa_s->mgmt_group_cipher);
|
||||||
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, 0);
|
||||||
|
|
||||||
pmksa_cache_clear_current(wpa_s->wpa);
|
pmksa_cache_clear_current(wpa_s->wpa);
|
||||||
os_memset(&mlo, 0, sizeof(mlo));
|
os_memset(&mlo, 0, sizeof(mlo));
|
||||||
|
@ -2024,6 +2025,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
|
||||||
wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
|
wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE);
|
||||||
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm);
|
||||||
|
|
||||||
|
if (ssid->ssid_protection && proto == WPA_PROTO_RSN) {
|
||||||
|
bool ssid_prot;
|
||||||
|
|
||||||
|
/* Enable SSID protection based on the AP advertising support
|
||||||
|
* for it to avoid potential interoperability issues with
|
||||||
|
* incorrect AP behavior if we were to send an "unexpected"
|
||||||
|
* RSNXE with multiple octets of payload. */
|
||||||
|
ssid_prot = ieee802_11_rsnx_capab(
|
||||||
|
bss_rsnx, WLAN_RSNX_CAPAB_SSID_PROTECTION);
|
||||||
|
if (!skip_default_rsne)
|
||||||
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION,
|
||||||
|
proto == WPA_PROTO_RSN && ssid_prot);
|
||||||
|
} else {
|
||||||
|
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!skip_default_rsne) {
|
if (!skip_default_rsne) {
|
||||||
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
|
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
|
||||||
wpa_ie_len)) {
|
wpa_ie_len)) {
|
||||||
|
@ -4550,6 +4567,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
|
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
|
||||||
|
if (bss)
|
||||||
|
wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
|
||||||
wpa_supplicant_initiate_eapol(wpa_s);
|
wpa_supplicant_initiate_eapol(wpa_s);
|
||||||
if (old_ssid != wpa_s->current_ssid)
|
if (old_ssid != wpa_s->current_ssid)
|
||||||
wpas_notify_network_changed(wpa_s);
|
wpas_notify_network_changed(wpa_s);
|
||||||
|
|
Loading…
Reference in a new issue