From 146889e3ca4353c99fe1677c98fbd1972f9b5eac Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 6 Sep 2019 14:51:31 +0300 Subject: [PATCH] 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 --- src/rsn_supp/wpa.c | 44 +++++++++++++++++++++++++++++++++ src/rsn_supp/wpa.h | 7 ++++++ src/rsn_supp/wpa_i.h | 4 +-- src/rsn_supp/wpa_ie.c | 5 ++++ src/rsn_supp/wpa_ie.h | 2 ++ wpa_supplicant/events.c | 14 ++++++++--- wpa_supplicant/ibss_rsn.c | 1 + wpa_supplicant/wpa_supplicant.c | 13 +++++++--- wpa_supplicant/wpas_glue.c | 4 +++ 9 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 9707ae7ab..f5231c138 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1365,6 +1365,16 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, 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 if (wpa_key_mgmt_ft(sm->key_mgmt) && 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->ap_wpa_ie); os_free(sm->ap_rsn_ie); + os_free(sm->ap_rsnxe); wpa_sm_drop_sa(sm); os_free(sm->ctx); #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 * @sm: Pointer to WPA state machine data from wpa_sm_init() diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index ae9cd6484..125d359ef 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -136,6 +136,7 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie, 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_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_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; } +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) { return 0; diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 129dfb14a..16224c9ef 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -88,8 +88,8 @@ struct wpa_sm { u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ size_t assoc_wpa_ie_len; - u8 *ap_wpa_ie, *ap_rsn_ie; - size_t ap_wpa_ie_len, ap_rsn_ie_len; + u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe; + size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len; #ifdef CONFIG_TDLS struct wpa_tdls_peer *tdls; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 809f208f0..e6af6c10e 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -506,6 +506,11 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ie->rsn_ie_len = pos[1] + 2; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 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 && pos[1] >= sizeof(struct rsn_mdie)) { ie->mdie = pos; diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 77ebe2172..6f18bbe2a 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -23,6 +23,8 @@ struct wpa_eapol_ie_parse { size_t mac_addr_len; const u8 *igtk; size_t igtk_len; + const u8 *rsnxe; + size_t rsnxe_len; const u8 *mdie; size_t mdie_len; const u8 *ftie; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 523b7bd46..c9ead080e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2647,14 +2647,19 @@ no_pfs: 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; p += len; } if (!wpa_found && data->assoc_info.beacon_ies) 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_rsnxe(wpa_s->wpa, NULL, 0); + } if (wpa_found || rsn_found) 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) { - 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) 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, WPA_IE_VENDOR_TYPE); 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, bss_wpa ? 2 + bss_wpa[1] : 0) || 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 0; diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 6934c4725..2bf51c626 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -111,6 +111,7 @@ static int supp_get_beacon_ie(void *ctx) wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); /* TODO: get correct RSN IE */ + wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0); return wpa_sm_set_ap_rsn_ie(peer->supp, (u8 *) "\x30\x14\x01\x00" "\x00\x0f\xac\x04" diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 94cc8c760..ca8e1cc0b 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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_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_rsnxe(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->group_cipher = WPA_CIPHER_NONE; @@ -1233,14 +1234,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, { struct wpa_ie_data ie; int sel, proto; - const u8 *bss_wpa, *bss_rsn, *bss_osen; + const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); 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); - } else - bss_wpa = bss_rsn = bss_osen = NULL; + } else { + bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL; + } if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) && 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, bss_wpa ? 2 + bss_wpa[1] : 0) || 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; } diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 62af7f6b1..d80b8f28d 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -396,6 +396,10 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) 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)) 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 { ret = -1; }