From 5de45546d565e0c0f2953c278a81e8a7a1f01971 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Sun, 20 Feb 2022 07:21:56 +0530 Subject: [PATCH] Add support to send multi AKM connect request when driver's SME in use Add support to configure SAE, PSK, and PSK-SHA256 AKMs in connect request when driver's SME in use. This is needed for implementing WPA3-Personal transition mode correctly with any driver that handles roaming internally. Send additional AKMs configured in network block to driver based on the maximum number of AKMs allowed by driver in connect request. Keep first AKM in the list AKMs in the connect request as AKM selected by wpa_supplicant to maintain backwards compatibility. Signed-off-by: Veerendranath Jakkam --- src/common/defs.h | 7 ++ src/drivers/driver.h | 11 +++ src/drivers/driver_nl80211.c | 107 ++++++++++++++++++-------- wpa_supplicant/events.c | 1 + wpa_supplicant/wpa_supplicant.c | 120 +++++++++++++++++++++++++++++- wpa_supplicant/wpa_supplicant_i.h | 5 ++ 6 files changed, 217 insertions(+), 34 deletions(-) diff --git a/src/common/defs.h b/src/common/defs.h index 3c21ab4c1..e3d02f810 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -181,6 +181,13 @@ static inline int wpa_key_mgmt_cckm(int akm) return akm == WPA_KEY_MGMT_CCKM; } +static inline int wpa_key_mgmt_cross_akm(int akm) +{ + return !!(akm & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_SAE_EXT_KEY)); +} #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 48b4bb4a1..ccbae59a3 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -999,6 +999,17 @@ struct wpa_driver_associate_params { */ unsigned int key_mgmt_suite; + /** + * allowed_key_mgmts - Bitfield of allowed key management suites + * (WPA_KEY_MGMT_*) other than @key_mgmt_suite for the current + * connection + * + * SME in the driver may choose key_mgmt from this list for the initial + * connection or roaming. The driver which doesn't support this + * ignores this parameter. + */ + unsigned int allowed_key_mgmts; + /** * auth_alg - Allowed authentication algorithms * Bit field of WPA_AUTH_ALG_* diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b52a4800e..3df5dfb0b 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -6137,6 +6137,17 @@ static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv, } +static unsigned int num_bits_set(u32 val) +{ + unsigned int c; + + for (c = 0; val; c++) + val &= val - 1; + + return c; +} + + static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, struct nl_msg *msg) @@ -6268,77 +6279,111 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 || params->key_mgmt_suite == WPA_KEY_MGMT_OWE || params->key_mgmt_suite == WPA_KEY_MGMT_DPP) { - int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + u32 *mgmt; + unsigned int akm_count = 1, i; + + /* + * Make sure the driver has capability to handle default AKM in + * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts. + */ + if (drv->capa.max_num_akms <= + num_bits_set(params->allowed_key_mgmts)) { + wpa_printf(MSG_INFO, + "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)", + drv->capa.max_num_akms, + num_bits_set(params->allowed_key_mgmts)); + return -1; + } + + mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms); + if (!mgmt) + return -1; + + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; switch (params->key_mgmt_suite) { case WPA_KEY_MGMT_CCKM: - mgmt = RSN_AUTH_KEY_MGMT_CCKM; + mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM; break; case WPA_KEY_MGMT_IEEE8021X: - mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; break; case WPA_KEY_MGMT_FT_IEEE8021X: - mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X; break; case WPA_KEY_MGMT_FT_PSK: - mgmt = RSN_AUTH_KEY_MGMT_FT_PSK; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK; break; case WPA_KEY_MGMT_IEEE8021X_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256; break; case WPA_KEY_MGMT_PSK_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256; break; case WPA_KEY_MGMT_OSEN: - mgmt = RSN_AUTH_KEY_MGMT_OSEN; + mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN; break; case WPA_KEY_MGMT_SAE: - mgmt = RSN_AUTH_KEY_MGMT_SAE; + mgmt[0] = RSN_AUTH_KEY_MGMT_SAE; break; case WPA_KEY_MGMT_SAE_EXT_KEY: - mgmt = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; + mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; break; case WPA_KEY_MGMT_FT_SAE: - mgmt = RSN_AUTH_KEY_MGMT_FT_SAE; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE; break; case WPA_KEY_MGMT_FT_SAE_EXT_KEY: - mgmt = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; break; case WPA_KEY_MGMT_IEEE8021X_SUITE_B: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; break; case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; break; case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; break; case WPA_KEY_MGMT_FILS_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256; break; case WPA_KEY_MGMT_FILS_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384; break; case WPA_KEY_MGMT_FT_FILS_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; break; case WPA_KEY_MGMT_FT_FILS_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; break; case WPA_KEY_MGMT_OWE: - mgmt = RSN_AUTH_KEY_MGMT_OWE; + mgmt[0] = RSN_AUTH_KEY_MGMT_OWE; break; case WPA_KEY_MGMT_DPP: - mgmt = RSN_AUTH_KEY_MGMT_DPP; + mgmt[0] = RSN_AUTH_KEY_MGMT_DPP; break; case WPA_KEY_MGMT_PSK: default: - mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; break; } - wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt); - if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt)) + + if (drv->capa.max_num_akms > 1) { + akm_count += wpa_key_mgmt_to_suites( + params->allowed_key_mgmts, &mgmt[1], + drv->capa.max_num_akms - 1); + } + + for (i = 0; i < akm_count; i++) + wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]); + + if (nla_put(msg, NL80211_ATTR_AKM_SUITES, + akm_count * sizeof(u32), mgmt)) { + os_free(mgmt); return -1; + } + + os_free(mgmt); } if (params->req_handshake_offload && @@ -6403,7 +6448,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, nl80211_put_fils_connect_params(drv, params, msg) != 0) return -1; - if (wpa_key_mgmt_sae(params->key_mgmt_suite) && + if ((wpa_key_mgmt_sae(params->key_mgmt_suite) || + wpa_key_mgmt_sae(params->allowed_key_mgmts)) && (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) && nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) return -1; @@ -6424,9 +6470,8 @@ static int wpa_driver_nl80211_try_connect( #ifdef CONFIG_DRIVER_NL80211_QCA if (params->req_key_mgmt_offload && params->psk && - (params->key_mgmt_suite == WPA_KEY_MGMT_PSK || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || - params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { + (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) || + wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) { wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK"); ret = issue_key_mgmt_set_key(drv, params->psk, 32); if (ret) @@ -6453,7 +6498,8 @@ static int wpa_driver_nl80211_try_connect( goto fail; #ifdef CONFIG_SAE - if (wpa_key_mgmt_sae(params->key_mgmt_suite) && + if ((wpa_key_mgmt_sae(params->key_mgmt_suite) || + wpa_key_mgmt_sae(params->allowed_key_mgmts)) && nl80211_put_sae_pwe(msg, params->sae_pwe) < 0) goto fail; #endif /* CONFIG_SAE */ @@ -6561,7 +6607,8 @@ static int wpa_driver_nl80211_associate( if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; - if (wpa_key_mgmt_sae(params->key_mgmt_suite)) + if (wpa_key_mgmt_sae(params->key_mgmt_suite) || + wpa_key_mgmt_sae(params->allowed_key_mgmts)) bss->use_nl_connect = 1; else bss->use_nl_connect = 0; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 5ddee6717..6d8be2a78 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -337,6 +337,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_s->current_ssid = NULL; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->key_mgmt = 0; + wpa_s->allowed_key_mgmts = 0; wpas_rrm_reset(wpa_s); wpa_s->wnmsleep_used = 0; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 096e2ad27..f91609bd7 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1119,6 +1119,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s) wpa_s->group_cipher = 0; wpa_s->mgmt_group_cipher = 0; wpa_s->key_mgmt = 0; + wpa_s->allowed_key_mgmts = 0; if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) wpa_supplicant_set_state(wpa_s, new_state); @@ -1339,6 +1340,111 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, } +static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + int akm_count = wpa_s->max_num_akms; + u8 capab = 0; + + if (akm_count < 2) + return; + + akm_count--; + wpa_s->allowed_key_mgmts = 0; + switch (wpa_s->key_mgmt) { + case WPA_KEY_MGMT_PSK: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + case WPA_KEY_MGMT_PSK_SHA256: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + break; + case WPA_KEY_MGMT_SAE: + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + case WPA_KEY_MGMT_SAE_EXT_KEY: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + default: + return; + } + + if (wpa_s->conf->sae_pwe) + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); +#ifdef CONFIG_SAE_PK + if (ssid->sae_pk) + capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK); +#endif /* CONFIG_SAE_PK */ + + if (!((wpa_s->allowed_key_mgmts & + (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab)) + return; + + if (!wpa_s->rsnxe_len) { + wpa_s->rsnxe_len = 3; + wpa_s->rsnxe[0] = WLAN_EID_RSNX; + wpa_s->rsnxe[1] = 1; + wpa_s->rsnxe[2] = 0; + } + + wpa_s->rsnxe[2] |= capab; +} + + /** * wpa_supplicant_set_suites - Set authentication and encryption parameters * @wpa_s: Pointer to wpa_supplicant data @@ -1902,6 +2008,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0); } + if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) + wpas_update_allowed_key_mgmt(wpa_s, ssid); + return 0; } @@ -3903,6 +4013,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.group_suite = cipher_group; params.mgmt_group_suite = cipher_group_mgmt; params.key_mgmt_suite = wpa_s->key_mgmt; + params.allowed_key_mgmts = wpa_s->allowed_key_mgmts; params.wpa_proto = wpa_s->wpa_proto; wpa_s->auth_alg = params.auth_alg; params.mode = ssid->mode; @@ -3922,7 +4033,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || - params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { + params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK || + (params.allowed_key_mgmts & + (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) { params.passphrase = ssid->passphrase; if (ssid->psk_set) params.psk = ssid->psk; @@ -3946,9 +4059,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) else params.req_key_mgmt_offload = 1; - if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK || - params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || - params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) && + if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) || + wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) && ssid->psk_set) params.psk = ssid->psk; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index eb9855c23..c8d023680 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -747,6 +747,11 @@ struct wpa_supplicant { int key_mgmt; int wpa_proto; int mgmt_group_cipher; + /* + * Allowed key management suites for roaming/initial connection + * when the driver's SME is in use. + */ + int allowed_key_mgmts; void *drv_priv; /* private data used by driver_ops */ void *global_drv_priv;