]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
SSID verification based on beacon protection
authorJouni Malinen <quic_jouni@quicinc.com>
Thu, 11 Jul 2024 20:52:30 +0000 (23:52 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 11 Jul 2024 20:55:05 +0000 (23:55 +0300)
If SSID was not verified during the initial setup of an association, but
beacon protection was negotiated, try verify the SSID based on Beacon
frames that have been received after the first BIGTK has been
configured.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 3689f203dfdb3c0e43df4ae13961a9eeee5a62fa..b679103c30f58f820be4dac4875a266232212a89 100644 (file)
@@ -125,6 +125,7 @@ const char *const wpa_supplicant_full_license5 =
 
 
 static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx);
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
 static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
 #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
@@ -611,6 +612,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
        eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
 
        wpas_wps_deinit(wpa_s);
 
@@ -927,6 +929,88 @@ void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
 }
 
 
+static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       struct wpa_bss *bss;
+       const u8 *ssid;
+       size_t ssid_len;
+
+       if (!wpa_s->current_ssid || !wpa_s->current_bss)
+               return;
+
+       ssid = wpa_s->current_bss->ssid;
+       ssid_len = wpa_s->current_bss->ssid_len;
+
+       if (wpa_s->current_ssid->ssid_len &&
+           (wpa_s->current_ssid->ssid_len != ssid_len ||
+            os_memcmp(wpa_s->current_ssid->ssid, ssid, ssid_len) != 0))
+               return;
+
+       if (wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
+           !wpa_s->bigtk_set || wpa_s->ssid_verified)
+               return;
+
+       wpa_printf(MSG_DEBUG,
+                  "SSID not yet verified; check if the driver has received a verified Beacon frame");
+       if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
+               return;
+
+       bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
+       if (!bss)
+               return;
+       wpa_printf(MSG_DEBUG, "The current beacon time stamp: 0x%llx",
+                  (long long unsigned int) bss->tsf);
+       if (bss->tsf > wpa_s->first_beacon_tsf) {
+               const u8 *ie;
+
+               wpa_printf(MSG_DEBUG,
+                          "Verified Beacon frame has been received");
+               wpa_s->beacons_checked++;
+
+               ie = wpa_bss_get_ie_beacon(bss, WLAN_EID_SSID);
+               if (ie && ie[1] == ssid_len &&
+                   os_memcmp(&ie[2], ssid, ssid_len) == 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "SSID verified based on a Beacon frame and beacon protection");
+                       wpa_s->ssid_verified = true;
+                       return;
+               }
+
+               /* TODO: Multiple BSSID element */
+       }
+
+       if (wpa_s->beacons_checked < 16)
+               eloop_register_timeout(1, 0, wpas_verify_ssid_beacon,
+                                      wpa_s, NULL);
+}
+
+
+static void wpas_verify_ssid_beacon_prot(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss;
+
+       wpa_printf(MSG_DEBUG,
+                  "SSID not yet verified; try to verify using beacon protection");
+       /* Fetch the current scan result which is likely based on not yet
+        * verified payload since the current BIGTK was just received. Any
+        * newer update in the future with a larger timestamp value is an
+        * indication that a verified Beacon frame has been received. */
+       if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0)
+               return;
+
+       bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid);
+       if (!bss)
+               return;
+       wpa_printf(MSG_DEBUG, "The initial beacon time stamp: 0x%llx",
+                  (long long unsigned int) bss->tsf);
+       wpa_s->first_beacon_tsf = bss->tsf;
+       wpa_s->beacons_checked = 0;
+       eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
+       eloop_register_timeout(1, 0, wpas_verify_ssid_beacon, wpa_s, NULL);
+}
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1100,6 +1184,10 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                if (wpa_s->wpa_state == WPA_COMPLETED)
                        wpas_dpp_connected(wpa_s);
 #endif /* CONFIG_DPP2 */
+
+               if (wpa_s->wpa_state == WPA_COMPLETED &&
+                   wpa_s->bigtk_set && !wpa_s->ssid_verified)
+                       wpas_verify_ssid_beacon_prot(wpa_s);
        }
 #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
        if (update_fils_connect_params)
index 6ebd1846704f86d6793523bfd59f38ae152824d5..de4b1923bc035e645364408376d4098434bcab54 100644 (file)
@@ -1612,6 +1612,8 @@ struct wpa_supplicant {
 
        bool ssid_verified;
        bool bigtk_set;
+       u64 first_beacon_tsf;
+       unsigned int beacons_checked;
 };