]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PASN: Authentication with user-specified network parameters
authorPeddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
Sat, 14 Jun 2025 08:05:34 +0000 (13:35 +0530)
committerJouni Malinen <j@w1.fi>
Tue, 24 Jun 2025 18:09:42 +0000 (21:09 +0300)
Allow PASN Authentication with user requested network parameters such
as AKMP, cipher, and password in driver initiated cases.

These changes will allow user to choose which AKMP and cipher to use
with PASN Authentication and also to specified the password in case of
PASN-SAE. When the password is supplied a temporary network block is
created and used to perform PASN. Any temporary network block that is
created will be destroyed after PASN regardless of whether PASN succeeds
or fails.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
src/drivers/driver.h
wpa_supplicant/pasn_supplicant.c

index 8f6f9d61a87c7bac54298774bc0a760cf9d7b4ae..f4d6e4289ace47b45aee622eb67a9ffbe37b2051 100644 (file)
@@ -3053,6 +3053,8 @@ enum pasn_status {
  * @akmp: Authentication key management protocol type supported.
  * @cipher: Cipher suite.
  * @group: Finite cyclic group. Default group used is 19 (ECC).
+ * @temporary_network: Indicates if a temporary network was created to perform
+ *     PASN authentication.
  * @password: Password of user requested network.
  * @ltf_keyseed_required: Indicates whether LTF keyseed generation is required
  * @status: PASN response status, %PASN_STATUS_SUCCESS for successful
@@ -3067,6 +3069,7 @@ struct pasn_peer {
        int akmp;
        int cipher;
        int group;
+       bool temporary_network;
        char *password;
        bool ltf_keyseed_required;
        enum pasn_status status;
index 6399c58bc7348d2a7e3b931839df2854362f87fb..89a8f17e7591f77c5c7d1835841a3fcf5f06b127 100644 (file)
@@ -151,28 +151,15 @@ static int wpas_pasn_sae_setup_pt(struct wpa_ssid *ssid, int group)
 
 
 static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
-                                        struct pasn_peer *peer)
+                                        struct pasn_peer *peer,
+                                        struct wpa_bss *bss,
+                                        struct wpa_ssid *ssid)
 {
        int ret;
        const u8 *rsne, *rsnxe;
-       struct wpa_bss *bss;
        struct wpa_ie_data rsne_data;
        int sel, key_mgmt, pairwise_cipher;
-       int network_id = 0, group = 19;
-       struct wpa_ssid *ssid = NULL;
-       size_t ssid_str_len = 0;
-       const u8 *ssid_str = NULL;
-       const u8 *peer_addr = peer->peer_addr;
-
-       bss = wpa_bss_get_bssid(wpa_s, peer_addr);
-       if (!bss) {
-               wpa_supplicant_update_scan_results(wpa_s, peer_addr);
-               bss = wpa_bss_get_bssid(wpa_s, peer_addr);
-               if (!bss) {
-                       wpa_printf(MSG_DEBUG, "PASN: BSS not found");
-                       return -1;
-               }
-       }
+       int group = 19;
 
        rsne = wpa_bss_get_rsne(wpa_s, bss, NULL, false);
        if (!rsne) {
@@ -188,22 +175,11 @@ static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
 
        rsnxe = wpa_bss_get_rsnxe(wpa_s, bss, NULL, false);
 
-       ssid_str_len = bss->ssid_len;
-       ssid_str = bss->ssid;
-
-       /* Get the network configuration based on the obtained SSID */
-       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
-               if (!wpas_network_disabled(wpa_s, ssid) &&
-                   ssid_str_len == ssid->ssid_len &&
-                   os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
-                       break;
-       }
-
-       if (ssid)
-               network_id = ssid->id;
 
        sel = rsne_data.pairwise_cipher;
-       if (ssid && ssid->pairwise_cipher)
+       if (peer->cipher && peer->cipher != WPA_CIPHER_NONE)
+               sel &= peer->cipher;
+       else if (ssid && !ssid->temporary && ssid->pairwise_cipher)
                sel &= ssid->pairwise_cipher;
 
        wpa_printf(MSG_DEBUG, "PASN: peer pairwise 0x%x, select 0x%x",
@@ -217,7 +193,9 @@ static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
        }
 
        sel = rsne_data.key_mgmt;
-       if (ssid && ssid->key_mgmt)
+       if (peer->akmp && peer->akmp != WPA_KEY_MGMT_NONE)
+               sel &= peer->akmp;
+       else if (ssid && !ssid->temporary && ssid->key_mgmt)
                sel &= ssid->key_mgmt;
 
        wpa_printf(MSG_DEBUG, "PASN: peer AKMP 0x%x, select 0x%x",
@@ -300,7 +278,8 @@ static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
 
        peer->akmp = key_mgmt;
        peer->cipher = pairwise_cipher;
-       peer->network_id = network_id;
+       if (ssid)
+               peer->network_id = ssid->id;
        peer->group = group;
        return 0;
 }
@@ -339,17 +318,89 @@ static int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s,
 }
 
 
+static struct wpa_ssid *
+wpas_pasn_add_temporary_network(struct wpa_supplicant *wpa_s,
+                               const struct wpa_bss *bss, const char *password)
+{
+       struct wpa_ssid *ssid;
+
+       ssid = wpa_config_add_network(wpa_s->conf);
+       if (!ssid) {
+               wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SSID block");
+               return NULL;
+       }
+
+       ssid->ssid = os_memdup(bss->ssid, bss->ssid_len);
+       if (!ssid->ssid)
+               return NULL;
+
+       ssid->ssid_len = bss->ssid_len;
+       ssid->passphrase = os_strdup(password);
+       if (!ssid->passphrase) {
+               wpa_config_free_ssid(ssid);
+               wpa_printf(MSG_DEBUG, "PASN: Failed to copy password");
+               return NULL;
+       }
+
+       ssid->temporary = true;
+       wpa_printf(MSG_DEBUG, "PASN: Created temporary network block for "
+                  MACSTR, MAC2STR(bss->bssid));
+
+       return ssid;
+}
+
+
+static struct wpa_bss * wpas_pasn_get_bss(struct wpa_supplicant *wpa_s,
+                                         const u8 *peer_addr)
+{
+       struct wpa_bss *bss;
+
+       bss = wpa_bss_get_bssid(wpa_s, peer_addr);
+       if (!bss) {
+               wpa_supplicant_update_scan_results(wpa_s, peer_addr);
+               bss = wpa_bss_get_bssid(wpa_s, peer_addr);
+       }
+
+       return bss;
+}
+
+
+static struct wpa_ssid * wpas_pasn_get_network(struct wpa_supplicant *wpa_s,
+                                              struct wpa_bss *bss)
+{
+       size_t ssid_str_len;
+       const u8 *ssid_str;
+       struct wpa_ssid *ssid;
+
+       ssid_str_len = bss->ssid_len;
+       ssid_str = bss->ssid;
+
+       /* Get the network configuration based on the obtained SSID */
+       for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+               if (ssid_str_len == ssid->ssid_len &&
+                   os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
+                       break;
+       }
+
+       return ssid;
+}
+
+
 static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                                          struct pasn_auth *pasn_params)
 {
        struct pasn_peer *peer;
        u8 comeback_len = 0;
        const u8 *comeback = NULL;
+       struct wpa_ssid *ssid;
 
        if (!pasn_params)
                return;
 
        while (wpa_s->pasn_count < pasn_params->num_peers) {
+               struct wpa_bss *bss;
+               bool check_cache = true;
+
                peer = &pasn_params->peer[wpa_s->pasn_count];
 
                if (ether_addr_equal(wpa_s->bssid, peer->peer_addr)) {
@@ -360,13 +411,39 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                        continue;
                }
 
-               if (wpas_pasn_get_params_from_bss(wpa_s, peer)) {
+               bss = wpas_pasn_get_bss(wpa_s, peer->peer_addr);
+               if (!bss) {
+                       wpa_printf(MSG_DEBUG, "PASN: BSS not found");
+                       peer->status = PASN_STATUS_FAILURE;
+                       wpa_s->pasn_count++;
+                       continue;
+               }
+
+               ssid = wpas_pasn_get_network(wpa_s, bss);
+               if (peer->password && peer->akmp &&
+                   peer->akmp != WPA_KEY_MGMT_NONE) {
+                       ssid = wpas_pasn_add_temporary_network(wpa_s, bss,
+                                                              peer->password);
+
+                       if (!ssid) {
+                               wpa_printf(MSG_DEBUG,
+                                          "PASN: Failed to create temporary network");
+                               return;
+                       }
+                       peer->temporary_network = true;
+               }
+
+               if (ssid && ssid->temporary)
+                       check_cache = false;
+
+               if (wpas_pasn_get_params_from_bss(wpa_s, peer, bss, ssid)) {
                        peer->status = PASN_STATUS_FAILURE;
                        wpa_s->pasn_count++;
                        continue;
                }
 
-               if (wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr,
+               if (check_cache &&
+                   wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr,
                                                  peer->peer_addr,
                                                  peer->cipher,
                                                  peer->akmp) == 0) {
@@ -381,7 +458,14 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                                         peer->network_id,
                                         comeback, comeback_len)) {
                        peer->status = PASN_STATUS_FAILURE;
+                       wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
+                               " akmp=%s, status=%u",
+                               MAC2STR(peer->peer_addr),
+                               wpa_key_mgmt_txt(peer->akmp, WPA_PROTO_RSN),
+                               peer->status);
                        wpa_s->pasn_count++;
+                       str_clear_free(peer->password);
+                       peer->password = NULL;
                        continue;
                }
                wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR,
@@ -390,8 +474,27 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
        }
 
        if (wpa_s->pasn_count == pasn_params->num_peers) {
+               unsigned int i;
+
                wpa_drv_send_pasn_resp(wpa_s, pasn_params);
                wpa_printf(MSG_DEBUG, "PASN: Response sent");
+               for (i = 0; i < pasn_params->num_peers; i++) {
+                       peer = &pasn_params->peer[i];
+                       str_clear_free(peer->password);
+
+                       if (peer->temporary_network) {
+                               ssid = wpa_config_get_network(wpa_s->conf,
+                                                             peer->network_id);
+
+                               if (ssid && ssid->temporary) {
+                                       wpa_config_remove_network(
+                                               wpa_s->conf, peer->network_id);
+                                       wpa_printf(MSG_DEBUG,
+                                                  "PASN: Remove temporary network block of "
+                                                  MACSTR, MAC2STR(peer->peer_addr));
+                               }
+                       }
+               }
                os_free(wpa_s->pasn_params);
                wpa_s->pasn_params = NULL;
        }
@@ -422,6 +525,8 @@ static void wpas_pasn_delete_peers(struct wpa_supplicant *wpa_s,
                peer = &pasn_params->peer[i];
                ptksa_cache_flush(wpa_s->ptksa, peer->peer_addr,
                                  WPA_CIPHER_NONE);
+               str_clear_free(peer->password);
+               peer->password = NULL;
        }
 }
 
@@ -774,15 +879,20 @@ static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
        u16 group = pasn->group;
        u8 own_addr[ETH_ALEN];
        u8 peer_addr[ETH_ALEN];
+       int network_id;
 
        wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
        os_memcpy(own_addr, pasn->own_addr, ETH_ALEN);
        os_memcpy(peer_addr, pasn->peer_addr, ETH_ALEN);
+
+       /* Hold network ID to avoid losing it in wpas_pasn_reset(). */
+       network_id = pasn->network_id;
+
        wpas_pasn_reset(wpa_s);
 
        return wpas_pasn_auth_start(wpa_s, own_addr, peer_addr, akmp, cipher,
-                                   group, pasn->network_id,
-                                   params->comeback, params->comeback_len);
+                                   group, network_id, params->comeback,
+                                   params->comeback_len);
 }
 
 
@@ -877,6 +987,16 @@ void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
                os_memcpy(dst->peer_addr, src->peer_addr, ETH_ALEN);
                dst->ltf_keyseed_required = src->ltf_keyseed_required;
                dst->status = PASN_STATUS_SUCCESS;
+               dst->akmp = src->akmp;
+               dst->cipher = src->cipher;
+               if (src->password) {
+                       dst->password = os_strdup(src->password);
+                       if (!dst->password) {
+                               wpa_printf(MSG_DEBUG,
+                                          "PASN: Mem alloc failed for password");
+                               return;
+                       }
+               }
 
                if (!is_zero_ether_addr(src->own_addr)) {
                        os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN);