RSN: Verify RSNXE match between Beacon/ProbeResp and EAPOL-Key msg 3/4

If the AP advertises RSN Extension element, it has to be advertised
consistently in the unprotected (Beacon and Probe Response) and
protected (EAPOL-Key msg 3/4) frames. Verify that this is the case.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2019-09-06 14:51:31 +03:00 committed by Jouni Malinen
parent 3134bb13a8
commit 146889e3ca
9 changed files with 85 additions and 9 deletions

View file

@ -1365,6 +1365,16 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1; return -1;
} }
if ((sm->ap_rsnxe && !ie->rsnxe) ||
(!sm->ap_rsnxe && ie->rsnxe) ||
(sm->ap_rsnxe && ie->rsnxe &&
(sm->ap_rsnxe_len != ie->rsnxe_len ||
os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
return -1;
}
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) && if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0) wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@ -2664,6 +2674,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->assoc_wpa_ie); os_free(sm->assoc_wpa_ie);
os_free(sm->ap_wpa_ie); os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie); os_free(sm->ap_rsn_ie);
os_free(sm->ap_rsnxe);
wpa_sm_drop_sa(sm); wpa_sm_drop_sa(sm);
os_free(sm->ctx); os_free(sm->ctx);
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
@ -3283,6 +3294,39 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
} }
/**
* wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
* @len: IE length
* Returns: 0 on success, -1 on failure
*
* Inform WPA state machine about the RSNXE used in Beacon / Probe Response
* frame.
*/
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
{
if (!sm)
return -1;
os_free(sm->ap_rsnxe);
if (!ie || len == 0) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
sm->ap_rsnxe = NULL;
sm->ap_rsnxe_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
sm->ap_rsnxe = os_memdup(ie, len);
if (!sm->ap_rsnxe)
return -1;
sm->ap_rsnxe_len = len;
}
return 0;
}
/** /**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init() * @sm: Pointer to WPA state machine data from wpa_sm_init()

View file

@ -136,6 +136,7 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len); size_t *wpa_ie_len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len); int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len); int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen); int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@ -260,6 +261,12 @@ static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
return -1; return -1;
} }
static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
size_t len)
{
return -1;
}
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen) static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{ {
return 0; return 0;

View file

@ -88,8 +88,8 @@ struct wpa_sm {
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;
u8 *ap_wpa_ie, *ap_rsn_ie; u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
size_t ap_wpa_ie_len, ap_rsn_ie_len; size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls; struct wpa_tdls_peer *tdls;

View file

@ -506,6 +506,11 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
ie->rsn_ie_len = pos[1] + 2; ie->rsn_ie_len = pos[1] + 2;
wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
ie->rsn_ie, ie->rsn_ie_len); ie->rsn_ie, ie->rsn_ie_len);
} else if (*pos == WLAN_EID_RSNX) {
ie->rsnxe = pos;
ie->rsnxe_len = pos[1] + 2;
wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
ie->rsnxe, ie->rsnxe_len);
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN && } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
pos[1] >= sizeof(struct rsn_mdie)) { pos[1] >= sizeof(struct rsn_mdie)) {
ie->mdie = pos; ie->mdie = pos;

View file

@ -23,6 +23,8 @@ struct wpa_eapol_ie_parse {
size_t mac_addr_len; size_t mac_addr_len;
const u8 *igtk; const u8 *igtk;
size_t igtk_len; size_t igtk_len;
const u8 *rsnxe;
size_t rsnxe_len;
const u8 *mdie; const u8 *mdie;
size_t mdie_len; size_t mdie_len;
const u8 *ftie; const u8 *ftie;

View file

@ -2647,14 +2647,19 @@ no_pfs:
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len); wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
} }
if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
l -= len; l -= len;
p += len; p += len;
} }
if (!wpa_found && data->assoc_info.beacon_ies) if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
if (!rsn_found && data->assoc_info.beacon_ies) if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
}
if (wpa_found || rsn_found) if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1; wpa_s->ap_ies_from_associnfo = 1;
@ -2674,7 +2679,7 @@ no_pfs:
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s) static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{ {
const u8 *bss_wpa = NULL, *bss_rsn = NULL; const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid) if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1; return -1;
@ -2685,11 +2690,14 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss, bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE); WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN); bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) || bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn, wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
bss_rsn ? 2 + bss_rsn[1] : 0)) bss_rsn ? 2 + bss_rsn[1] : 0) ||
wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1; return -1;
return 0; return 0;

View file

@ -111,6 +111,7 @@ static int supp_get_beacon_ie(void *ctx)
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */ /* TODO: get correct RSN IE */
wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp, return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00" (u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04" "\x00\x0f\xac\x04"

View file

@ -402,6 +402,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE; wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0); wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_s->pairwise_cipher = WPA_CIPHER_NONE; wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE; wpa_s->group_cipher = WPA_CIPHER_NONE;
@ -1233,14 +1234,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
{ {
struct wpa_ie_data ie; struct wpa_ie_data ie;
int sel, proto; int sel, proto;
const u8 *bss_wpa, *bss_rsn, *bss_osen; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) { if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
} else } else {
bss_wpa = bss_rsn = bss_osen = NULL; bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
}
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 && wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@ -1371,7 +1374,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa, if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) || bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn, wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
bss_rsn ? 2 + bss_rsn[1] : 0)) bss_rsn ? 2 + bss_rsn[1] : 0) ||
wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1; return -1;
} }

View file

@ -396,6 +396,10 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN); ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1; ret = -1;
ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
} else { } else {
ret = -1; ret = -1;
} }