From 2b3e64a0fb5fd193ceeebf26aa8b459aa8625080 Mon Sep 17 00:00:00 2001 From: Vinay Gannevaram Date: Thu, 30 Sep 2021 12:48:26 +0530 Subject: [PATCH] Update ciphers to address GTK renewal failures while roaming After roaming from WPA2-AP (group=CCMP) to WPA-AP (group=TKIP) using driver-based SME and roaming trigger, GTK renewal failures are observed for the currently associated WPA-AP because of group cipher mismatch, resulting in deauthentication with the AP. Update the group cipher and pairwise cipher values in wpa_sm from association event received from the driver in case of SME offload to the driver to address GTK renewal failures (and similar issues) that could happen when the driver/firmware roams between APs with different security profiles. Signed-off-by: Jouni Malinen --- wpa_supplicant/events.c | 89 +++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant.c | 75 ++++++++++++++------------ wpa_supplicant/wpa_supplicant_i.h | 2 + 3 files changed, 133 insertions(+), 33 deletions(-) diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 72a2a9c15..878d9bc74 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2680,6 +2680,91 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s, #endif /* CONFIG_FST */ +static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + int sel; + const u8 *p; + int l, len; + bool found = false; + struct wpa_ie_data ie; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + if (!ssid) + return 0; + + p = data->assoc_info.req_ies; + l = data->assoc_info.req_ies_len; + + while (p && l >= 2) { + len = p[1] + 2; + if (len > l) { + wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info", + p, l); + break; + } + if (((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 && + (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) || + (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 && + (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) || + (p[0] == WLAN_EID_RSN && p[1] >= 2))) { + found = true; + break; + } + l -= len; + p += len; + } + + if (!found || wpa_parse_wpa_ie(p, len, &ie) < 0) + return 0; + + wpa_hexdump(MSG_DEBUG, + "WPA: Update cipher suite selection based on IEs in driver-generated WPA/RSNE in AssocReq", + p, l); + + sel = ie.group_cipher; + if (ssid->group_cipher) + sel &= ssid->group_cipher; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP group cipher 0x%x network group cipher 0x%x; available group cipher 0x%x", + ie.group_cipher, ssid->group_cipher, sel); + if (ie.group_cipher && !sel) { + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_GROUP_CIPHER_NOT_VALID); + return -1; + } + + wpa_s->group_cipher = ie.group_cipher; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s", + wpa_cipher_txt(wpa_s->group_cipher)); + + sel = ie.pairwise_cipher; + if (ssid->pairwise_cipher) + sel &= ssid->pairwise_cipher; + + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP pairwise cipher 0x%x network pairwise cipher 0x%x; available pairwise cipher 0x%x", + ie.pairwise_cipher, ssid->pairwise_cipher, sel); + if (ie.pairwise_cipher && !sel) { + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID); + return -1; + } + + wpa_s->pairwise_cipher = ie.pairwise_cipher; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE, + wpa_s->pairwise_cipher); + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s", + wpa_cipher_txt(wpa_s->pairwise_cipher)); + + wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie); + + return 0; +} + + static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -3124,6 +3209,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, } } + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + data && wpa_supplicant_use_own_rsne_params(wpa_s, data) < 0) + return; + multi_ap_set_4addr_mode(wpa_s); if (wpa_s->conf->ap_scan == 1 && diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index c9d53a3d7..0f9db267f 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1297,6 +1297,47 @@ static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie, } +void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_ie_data *ie) +{ + int sel; + + sel = ie->mgmt_group_cipher; + if (ssid->group_mgmt_cipher) + sel &= ssid->group_mgmt_cipher; + if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION || + !(ie->capabilities & WPA_CAPABILITY_MFPC)) + sel = 0; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x", + ie->mgmt_group_cipher, ssid->group_mgmt_cipher, sel); + if (sel & WPA_CIPHER_AES_128_CMAC) { + wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using MGMT group cipher AES-128-CMAC"); + } else if (sel & WPA_CIPHER_BIP_GMAC_128) { + wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using MGMT group cipher BIP-GMAC-128"); + } else if (sel & WPA_CIPHER_BIP_GMAC_256) { + wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using MGMT group cipher BIP-GMAC-256"); + } else if (sel & WPA_CIPHER_BIP_CMAC_256) { + wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using MGMT group cipher BIP-CMAC-256"); + } else { + wpa_s->mgmt_group_cipher = 0; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher"); + } + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, + wpa_s->mgmt_group_cipher); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, + wpas_get_ssid_pmf(wpa_s, ssid)); +} + + /** * wpa_supplicant_set_suites - Set authentication and encryption parameters * @wpa_s: Pointer to wpa_supplicant data @@ -1630,39 +1671,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, return -1; } - sel = ie.mgmt_group_cipher; - if (ssid->group_mgmt_cipher) - sel &= ssid->group_mgmt_cipher; - if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION || - !(ie.capabilities & WPA_CAPABILITY_MFPC)) - sel = 0; - wpa_dbg(wpa_s, MSG_DEBUG, - "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x", - ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel); - if (sel & WPA_CIPHER_AES_128_CMAC) { - wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " - "AES-128-CMAC"); - } else if (sel & WPA_CIPHER_BIP_GMAC_128) { - wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " - "BIP-GMAC-128"); - } else if (sel & WPA_CIPHER_BIP_GMAC_256) { - wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " - "BIP-GMAC-256"); - } else if (sel & WPA_CIPHER_BIP_CMAC_256) { - wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher " - "BIP-CMAC-256"); - } else { - wpa_s->mgmt_group_cipher = 0; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher"); - } - wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, - wpa_s->mgmt_group_cipher); - wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, - wpas_get_ssid_pmf(wpa_s, ssid)); + wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie); #ifdef CONFIG_OCV if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV)) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 47d0cabbe..cbc955159 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1543,6 +1543,8 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s); int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s); int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s, const char *bridge_ifname); +void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, struct wpa_ie_data *ie); int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid, u8 *wpa_ie, size_t *wpa_ie_len);