]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add support for SAE offload for AP interface
authorVinayak Yadawad <vinayak.yadawad@broadcom.com>
Fri, 10 Nov 2023 14:23:06 +0000 (19:53 +0530)
committerJouni Malinen <j@w1.fi>
Sat, 11 Nov 2023 21:44:01 +0000 (23:44 +0200)
The driver advertising SAE AP offload support would take care of SAE
authentication and PMK generation at the driver/firmware. This feature
requires the driver to be supporting 4-way handshake offload to process
the generated PMK at the driver level for 4-way handshake.

Signed-off-by: Vinayak Yadawad <vinayak.yadawad@broadcom.com>
src/ap/beacon.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/wpa_auth.h
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_ie.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211_capa.c

index 2101d4847b7e64e0d791f43b6489aee20a05ff20..1b5cea96b23b816fca4c6bc45a67f9487e30473e 100644 (file)
@@ -2044,6 +2044,33 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                }
        }
 
+#ifdef CONFIG_SAE
+       /* If SAE offload is enabled, provide password to lower layer for
+        * SAE authentication and PMK generation.
+        */
+       if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+           (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
+               if (hostapd_sae_pk_in_use(hapd->conf)) {
+                       wpa_printf(MSG_ERROR,
+                                  "SAE PK not supported with SAE offload");
+                       return -1;
+               }
+
+               if (hostapd_sae_pw_id_in_use(hapd->conf)) {
+                       wpa_printf(MSG_ERROR,
+                                  "SAE Password Identifiers not supported with SAE offload");
+                       return -1;
+               }
+
+               params->sae_password = sae_get_password(hapd, NULL, NULL, NULL,
+                                                       NULL, NULL);
+               if (!params->sae_password) {
+                       wpa_printf(MSG_ERROR, "SAE password not configured for offload");
+                       return -1;
+               }
+       }
+#endif /* CONFIG_SAE */
+
        params->head = (u8 *) head;
        params->head_len = head_len;
        params->tail = tail;
index d48185a17189d9df5f5b10d467be414f329b779d..1f39107d8e0ef31842648ba89f7bddb5882c6584 100644 (file)
@@ -540,12 +540,12 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
 }
 
 
-static const char * sae_get_password(struct hostapd_data *hapd,
-                                    struct sta_info *sta,
-                                    const char *rx_id,
-                                    struct sae_password_entry **pw_entry,
-                                    struct sae_pt **s_pt,
-                                    const struct sae_pk **s_pk)
+const char * sae_get_password(struct hostapd_data *hapd,
+                             struct sta_info *sta,
+                             const char *rx_id,
+                             struct sae_password_entry **pw_entry,
+                             struct sae_pt **s_pt,
+                             const struct sae_pk **s_pk)
 {
        const char *password = NULL;
        struct sae_password_entry *pw;
@@ -555,7 +555,8 @@ static const char * sae_get_password(struct hostapd_data *hapd,
 
        for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
                if (!is_broadcast_ether_addr(pw->peer_addr) &&
-                   os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+                   (!sta ||
+                    os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0))
                        continue;
                if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
                        continue;
@@ -573,7 +574,7 @@ static const char * sae_get_password(struct hostapd_data *hapd,
                pt = hapd->conf->ssid.pt;
        }
 
-       if (!password) {
+       if (!password && sta) {
                for (psk = sta->psk; psk; psk = psk->next) {
                        if (psk->is_passphrase) {
                                password = psk->passphrase;
index 8ffce0bf5bfee04be9fe85598806d6b371463625..4b58fee6243c6e6876da273914b535b68b89bc7a 100644 (file)
@@ -20,6 +20,9 @@ struct radius_sta;
 enum ieee80211_op_mode;
 enum oper_chan_width;
 struct ieee802_11_elems;
+struct sae_pk;
+struct sae_pt;
+struct sae_password_entry;
 
 int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
                    struct hostapd_frame_info *fi);
@@ -238,5 +241,9 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
                            enum oper_chan_width *width, u8 *seg0, u8 *seg1);
 bool hostapd_is_mld_ap(struct hostapd_data *hapd);
+const char * sae_get_password(struct hostapd_data *hapd,
+                             struct sta_info *sta, const char *rx_id,
+                             struct sae_password_entry **pw_entry,
+                             struct sae_pt **s_pt, const struct sae_pk **s_pk);
 
 #endif /* IEEE802_11_H */
index 28eea83d84ff9daa15d5750eefaee7de24565e0f..d6ed6772bb8a61f67d34bb1b393ed8e9d3aa4541 100644 (file)
@@ -395,6 +395,7 @@ struct wpa_auth_callbacks {
        int (*get_ml_rsn_info)(void *ctx, struct wpa_auth_ml_rsn_info *info);
        int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
 #endif /* CONFIG_IEEE80211BE */
+       int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
 };
 
 struct wpa_authenticator * wpa_init(const u8 *addr,
index 30a72b1262fac5c115ab9c63a8b276360cced9a9..fbe82779a5d3748d81042f9bd671f2035a86446c 100644 (file)
@@ -1601,6 +1601,20 @@ static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
 #endif /* CONFIG_IEEE80211BE */
 
 
+static int hostapd_wpa_auth_get_drv_flags(void *ctx,
+                                         u64 *drv_flags, u64 *drv_flags2)
+{
+       struct hostapd_data *hapd = ctx;
+
+       if (drv_flags)
+               *drv_flags = hapd->iface->drv_flags;
+       if (drv_flags2)
+               *drv_flags2 = hapd->iface->drv_flags2;
+
+       return 0;
+}
+
+
 int hostapd_setup_wpa(struct hostapd_data *hapd)
 {
        struct wpa_auth_config _conf;
@@ -1655,6 +1669,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
                .get_ml_rsn_info = hostapd_wpa_auth_get_ml_rsn_info,
                .get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
 #endif /* CONFIG_IEEE80211BE */
+               .get_drv_flags = hostapd_wpa_auth_get_drv_flags,
        };
        const u8 *wpa_ie;
        size_t wpa_ie_len;
index 9b90e0749b84ac7631d4b4b5dff6bb4716407acc..283b9a10f2f62b36d34e0dbcfd970cdaafaaf636 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
@@ -1013,11 +1014,23 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        }
 
 #ifdef CONFIG_SAE
-       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
-           !sm->pmksa) {
-               wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-                                "No PMKSA cache entry found for SAE");
-               return WPA_INVALID_PMKID;
+       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE) {
+               u64 drv_flags = 0;
+               u64 drv_flags2 = 0;
+               bool ap_sae_offload = false;
+
+               if (wpa_auth->cb->get_drv_flags &&
+                   wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, &drv_flags,
+                                               &drv_flags2) == 0)
+                       ap_sae_offload =
+                               !!(drv_flags2 &
+                                  WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
+
+               if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
+                       wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+                                        "No PMKSA cache entry found for SAE");
+                       return WPA_INVALID_PMKID;
+               }
        }
 #endif /* CONFIG_SAE */
 
index d75cf100e3cf45a09d61f8debcce044ba4038f30..d7f4c599dde01981c1708bf26af832ac1b345231 100644 (file)
@@ -1822,6 +1822,11 @@ struct wpa_driver_ap_params {
         * psk_len - PSK length in bytes (0 = not set)
         */
        size_t psk_len;
+
+       /**
+        * sae_password - SAE password for SAE offload
+        */
+       const char *sae_password;
 };
 
 struct wpa_driver_mesh_bss_params {
@@ -2300,6 +2305,8 @@ struct wpa_driver_capa {
 #define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA      0x0000000000040000ULL
 /** Driver supports OWE AP offload */
 #define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP       0x0000000000080000ULL
+/** Driver support AP SAE authentication offload */
+#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP       0x0000000000100000ULL
        u64 flags2;
 
 #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
index 94273bfe2376c88a7682d0cef6db2ab9920038c2..ac63e640542d6403c4025e5ea5901cad7a47931f 100644 (file)
@@ -5116,6 +5116,13 @@ static int wpa_driver_nl80211_set_ap(void *priv,
            nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk))
                goto fail;
 
+       if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
+           (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
+           params->sae_password &&
+           nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
+                   os_strlen(params->sae_password), params->sae_password))
+               goto fail;
+
        if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
            (!params->pairwise_ciphers ||
             params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
index aa5c33fc7eb8dfa813558cdb46d50eade797a8f0..544e54dbc70d366e35d2c3ef46529eaa4a5f769f 100644 (file)
@@ -717,6 +717,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
        if (ext_feature_isset(ext_features, len,
                              NL80211_EXT_FEATURE_OWE_OFFLOAD_AP))
                capa->flags2 |= WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP;
+
+       if (ext_feature_isset(ext_features, len,
+                             NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
+               capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP;
 }