]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add support to send multi AKM connect request when driver's SME in use
authorVeerendranath Jakkam <quic_vjakkam@quicinc.com>
Sun, 20 Feb 2022 01:51:56 +0000 (07:21 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 26 Aug 2022 14:54:12 +0000 (17:54 +0300)
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 <quic_vjakkam@quicinc.com>
src/common/defs.h
src/drivers/driver.h
src/drivers/driver_nl80211.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 3c21ab4c1c5055b7909c0292ff1065b2b60c4e69..e3d02f810b71c25cea1329270fbe5a9fb5bbdfa7 100644 (file)
@@ -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)
index 48b4bb4a17682fc1828e3151ef11dcacbce05b53..ccbae59a34d358b342875e8e5e9b262e66fab560 100644 (file)
@@ -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_*
index b52a4800e03c08f174abbb7abde5d55ac1d459e8..3df5dfb0b44f316db8c5ce610f656d479effe4d1 100644 (file)
@@ -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;
index 5ddee6717bc25a410ddf5ce51d8b97d0dc2e15e2..6d8be2a78545079d8cfeac0cd106759d1772dd02 100644 (file)
@@ -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;
index 096e2ad273003ecacde839de6df503b19fef90af..f91609bd70fbf033c1c6c29b16e674e8e68e7903 100644 (file)
@@ -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;
        }
index eb9855c23c82447e9b34e01ecbd9630e726ec124..c8d0236803145e24ff7f30c4d71200540d9542c5 100644 (file)
@@ -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;