Parcourir la source

Merge branch 'bugfix/bdsa_security_issues' into 'master'

wpa_supplicant: BDSA related patch updates

Closes WIFI-4853

See merge request espressif/esp-idf!20535
Nachiket Kukade il y a 3 ans
Parent
commit
3b31370e39

+ 21 - 10
components/wpa_supplicant/esp_supplicant/src/esp_common.c

@@ -23,8 +23,8 @@
 #include "rsn_supp/wpa_i.h"
 #include "rsn_supp/wpa.h"
 
-#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 struct wpa_supplicant g_wpa_supp;
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 
 #ifdef CONFIG_SUPPLICANT_TASK
 static void *s_supplicant_task_hdl = NULL;
@@ -276,6 +276,7 @@ static int handle_assoc_frame(u8 *frame, size_t len,
 	return 0;
 }
 #endif /* CONFIG_IEEE80211R */
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 
 static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
 				   u32 rssi, u8 channel, u64 current_tsf)
@@ -283,19 +284,24 @@ static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
 	int ret = 0;
 
 	switch (type) {
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_WPA_11KV_SUPPORT)
 	case WLAN_FC_STYPE_BEACON:
 	case WLAN_FC_STYPE_PROBE_RESP:
 		ret = esp_handle_beacon_probe(type, frame, len, sender, rssi, channel, current_tsf);
 		break;
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 #ifdef CONFIG_IEEE80211R
 	case WLAN_FC_STYPE_AUTH:
 		ret = handle_auth_frame(frame, len, sender, rssi, channel);
 		break;
+#endif /* CONFIG_IEEE80211R */
 	case WLAN_FC_STYPE_ASSOC_RESP:
 	case WLAN_FC_STYPE_REASSOC_RESP:
+		wpa_sm_notify_assoc(&gWpaSm, sender);
+#ifdef CONFIG_IEEE80211R
 		ret = handle_assoc_frame(frame, len, sender, rssi, channel);
-		break;
 #endif /* CONFIG_IEEE80211R */
+		break;
 #if defined(CONFIG_WPA_11KV_SUPPORT)
 	case WLAN_FC_STYPE_ACTION:
 #ifdef CONFIG_SUPPLICANT_TASK
@@ -313,6 +319,7 @@ static int ieee80211_handle_rx_frm(u8 type, u8 *frame, size_t len, u8 *sender,
 	return ret;
 }
 
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 #ifdef CONFIG_MBO
 bool mbo_bss_profile_match(u8 *bssid)
 {
@@ -338,11 +345,14 @@ bool mbo_bss_profile_match(u8 *bssid)
 }
 #endif /* CONFIG_MBO */
 
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
+
 int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
 {
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
 	int ret = 0;
 
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 #ifdef CONFIG_SUPPLICANT_TASK
 	s_supplicant_api_lock = os_recursive_mutex_create();
 	if (!s_supplicant_api_lock) {
@@ -376,19 +386,21 @@ int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
 	esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
 			&supplicant_sta_disconn_handler, NULL);
 
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 	wpa_s->type = 0;
 	wpa_s->subtype = 0;
-#ifdef CONFIG_IEEE80211R
 	wpa_s->type |= (1 << WLAN_FC_STYPE_ASSOC_RESP) | (1 << WLAN_FC_STYPE_REASSOC_RESP) | (1 << WLAN_FC_STYPE_AUTH);
-#endif /* CONFIG_IEEE80211R */
 	if (esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype) != ESP_OK) {
 		ret = -1;
 		goto err;
 	}
 	wpa_cb->wpa_sta_rx_mgmt = ieee80211_handle_rx_frm;
+
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 #ifdef CONFIG_MBO
 	dl_list_init(&wpa_s->bss_tmp_disallowed);
 #endif /* CONFIG_MBO */
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 	return 0;
 err:
 	esp_supplicant_common_deinit();
@@ -399,6 +411,7 @@ void esp_supplicant_common_deinit(void)
 {
 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
 
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 	esp_scan_deinit(wpa_s);
 #ifdef CONFIG_WPA_11KV_SUPPORT
 	wpas_rrm_reset(wpa_s);
@@ -408,10 +421,12 @@ void esp_supplicant_common_deinit(void)
 			&supplicant_sta_conn_handler);
 	esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED,
 			&supplicant_sta_disconn_handler);
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 	if (wpa_s->type) {
 		wpa_s->type = 0;
 		esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
 	}
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 #ifdef CONFIG_SUPPLICANT_TASK
 	if (!s_supplicant_task_hdl && esp_supplicant_post_evt(SIG_SUPPLICANT_DEL_TASK, 0) != 0) {
 		if (s_supplicant_evt_queue) {
@@ -424,8 +439,10 @@ void esp_supplicant_common_deinit(void)
 		}
 	}
 #endif /* CONFIG_SUPPLICANT_TASK */
+#endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 }
 
+#if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R)
 #ifdef CONFIG_WPA_11KV_SUPPORT
 bool esp_rrm_is_rrm_supported_connection(void)
 {
@@ -817,12 +834,6 @@ int esp_mbo_update_non_pref_chan(struct non_pref_chan_s *non_pref_chan)
 	return -1;
 }
 void esp_set_scan_ie(void) { }
-int esp_supplicant_common_init(struct wpa_funcs *wpa_cb)
-{
-	wpa_cb->wpa_sta_rx_mgmt = NULL;
-	return 0;
-}
-void esp_supplicant_common_deinit(void) { }
 #endif /* defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) */
 
 #if defined(CONFIG_WPA_11KV_SUPPORT) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WPA3_SAE)

+ 1 - 1
components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c

@@ -239,7 +239,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code)
         case WIFI_REASON_CONNECTION_FAIL:
         case WIFI_REASON_HANDSHAKE_TIMEOUT:
             esp_wpa3_free_sae_data();
-            wpa_sta_clear_curr_pmksa();
+            wpa_sm_notify_disassoc(&gWpaSm);
             break;
         default:
             break;

+ 21 - 3
components/wpa_supplicant/src/ap/wpa_auth.c

@@ -1359,6 +1359,21 @@ SM_STATE(WPA_PTK, AUTHENTICATION2)
 }
 
 
+static int wpa_auth_sm_ptk_update(struct wpa_state_machine *sm)
+{
+   if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+       wpa_printf(MSG_ERROR,
+              "WPA: Failed to get random data for ANonce");
+       sm->Disconnect = TRUE;
+       return -1;
+   }
+   wpa_hexdump(MSG_DEBUG, "WPA: Assign new ANonce", sm->ANonce,
+           WPA_NONCE_LEN);
+   sm->TimeoutCtr = 0;
+   return 0;
+}
+
+
 SM_STATE(WPA_PTK, INITPMK)
 {
     u8 msk[2 * PMK_LEN];
@@ -1838,9 +1853,12 @@ SM_STEP(WPA_PTK)
         SM_ENTER(WPA_PTK, AUTHENTICATION);
     else if (sm->ReAuthenticationRequest)
         SM_ENTER(WPA_PTK, AUTHENTICATION2);
-    else if (sm->PTKRequest)
-        SM_ENTER(WPA_PTK, PTKSTART);
-    else switch (sm->wpa_ptk_state) {
+    else if (sm->PTKRequest) {
+        if (wpa_auth_sm_ptk_update(sm) < 0)
+            SM_ENTER(WPA_PTK, DISCONNECTED);
+        else
+            SM_ENTER(WPA_PTK, PTKSTART);
+    } else switch (sm->wpa_ptk_state) {
     case WPA_PTK_INITIALIZE:
         break;
     case WPA_PTK_DISCONNECT:

+ 13 - 0
components/wpa_supplicant/src/common/wpa_common.h

@@ -202,8 +202,21 @@ struct wpa_ptk {
 	size_t kck_len;
 	size_t kek_len;
 	size_t tk_len;
+	int installed; /* 1 if key has already been installed to driver */
 };
 
+struct wpa_gtk {
+	u8 gtk[WPA_GTK_MAX_LEN];
+	size_t gtk_len;
+};
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk {
+	u8 igtk[WPA_IGTK_MAX_LEN];
+	size_t igtk_len;
+};
+#endif /* CONFIG_IEEE80211W */
+
 struct wpa_gtk_data {
 	enum wpa_alg alg;
 	int tx, key_rsc_len, keyidx;

+ 151 - 6
components/wpa_supplicant/src/rsn_supp/wpa.c

@@ -750,8 +750,22 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, enum key_flag key_flag)
     int keylen;
     enum wpa_alg alg;
 
+    if (sm->ptk.installed) {
+        wpa_printf(MSG_DEBUG, "WPA: Do not re-install same PTK to the driver");
+        return 0;
+    }
     wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.\n");
 
+    if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+        wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: NONE - do not use pairwise keys");
+        return 0;
+    }
+
+    if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+        wpa_printf(MSG_DEBUG, "WPA: Unsupported pairwise cipher %d", sm->pairwise_cipher);
+        return -1;
+    }
+
     alg = wpa_cipher_to_alg(sm->pairwise_cipher);
     keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
@@ -770,6 +784,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, enum key_flag key_flag)
         return -1;
     }
 
+    sm->ptk.installed = 1;
+
     if (sm->wpa_ptk_rekey) {
         eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
         eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -856,7 +872,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
     wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
 
     /* Detect possible key reinstallation */
-    if (wpa_supplicant_gtk_in_use(sm, &(sm->gd))) {
+    if ((sm->gtk.gtk_len == (size_t) gd->gtk_len &&
+            os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) ||
+            wpa_supplicant_gtk_in_use(sm, &(sm->gd))) {
             wpa_printf(MSG_DEBUG,
                     "WPA: Not reinstalling already in-use GTK to the driver (keyidx=%d tx=%d len=%d)",
                     gd->keyidx, gd->tx, gd->gtk_len);
@@ -892,6 +910,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
                gd->alg, gd->gtk_len, gd->keyidx);
         return -1;
     }
+    sm->gtk.gtk_len = gd->gtk_len;
+    os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
 
     return 0;
 }
@@ -988,6 +1008,44 @@ int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
     return 0;
 }
 
+#ifdef CONFIG_IEEE80211W
+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
+                      const wifi_wpa_igtk_t *igtk)
+{
+   size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+   u16 keyidx = WPA_GET_LE16(igtk->keyid);
+
+   /* Detect possible key reinstallation */
+   if (sm->igtk.igtk_len == len &&
+       os_memcmp(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len) == 0) {
+       wpa_printf(MSG_DEBUG,
+           "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
+           keyidx);
+       return  0;
+   }
+
+   wpa_printf(MSG_DEBUG,
+       "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+       keyidx, MAC2STR(igtk->pn));
+   wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
+   if (keyidx > 4095) {
+       wpa_printf(MSG_WARNING,
+           "WPA: Invalid IGTK KeyID %d", keyidx);
+       return -1;
+   }
+   if (esp_wifi_set_igtk_internal(WIFI_IF_STA, igtk) < 0) {
+       wpa_printf(MSG_WARNING,
+           "WPA: Failed to configure IGTK to the driver");
+           return -1;
+   }
+
+   sm->igtk.igtk_len = len;
+   os_memcpy(sm->igtk.igtk, igtk->igtk, sm->igtk.igtk_len);
+
+   return 0;
+}
+#endif /* CONFIG_IEEE80211W */
+
 #ifdef DEBUG_PRINT
 void wpa_report_ie_mismatch(struct wpa_sm *sm,
                    const char *reason, const u8 *src_addr,
@@ -1047,7 +1105,6 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
 
     if (ie->igtk) {
         const wifi_wpa_igtk_t *igtk;
-        uint16_t keyidx;
 #define WPA_IGTK_KDE_PREFIX_LEN (2 + 6)
         len = wpa_cipher_key_len(sm->mgmt_group_cipher);
         if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) {
@@ -1055,12 +1112,9 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
         }
 
         igtk = (const wifi_wpa_igtk_t*)ie->igtk;
-        keyidx = WPA_GET_LE16(igtk->keyid);
-        if (keyidx > 4095) {
+        if (wpa_supplicant_install_igtk(sm, igtk) < 0) {
             return -1;
         }
-        wpa_printf(MSG_DEBUG, "WPA: Installing IGTK to the driver.\n");
-        return esp_wifi_set_igtk_internal(WIFI_IF_STA, igtk);
     }
 #endif
     return 0;
@@ -2237,11 +2291,90 @@ void wpa_sm_deinit(void)
     os_free(sm->ap_rsnxe);
     sm->ap_rsnxe = NULL;
     os_free(sm->assoc_rsnxe);
+    wpa_sm_drop_sa(sm);
     sm->assoc_rsnxe = NULL;
 }
 
 
 #ifdef ESP_SUPPLICANT
+/**
+ * wpa_sm_notify_assoc - Notify WPA state machine about association
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: The BSSID of the new association
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was established.
+ */
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+    int clear_keys = 1;
+
+    if (sm == NULL)
+        return;
+
+    wpa_printf(MSG_DEBUG,
+        "WPA: Association event - clear replay counter");
+    os_memcpy(sm->bssid, bssid, ETH_ALEN);
+    os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+    sm->rx_replay_counter_set = 0;
+    sm->renew_snonce = 1;
+
+#ifdef CONFIG_IEEE80211R
+    if (wpa_ft_is_completed(sm)) {
+        /*
+         * Clear portValid to kick EAPOL state machine to re-enter
+         * AUTHENTICATED state to get the EAPOL port Authorized.
+         */
+        wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
+
+        /* Prepare for the next transition */
+        wpa_ft_prepare_auth_request(sm, NULL);
+
+        clear_keys = 0;
+        sm->ft_protocol = 1;
+    } else {
+        sm->ft_protocol = 0;
+    }
+#endif /* CONFIG_IEEE80211R */
+    if (clear_keys) {
+        /*
+         * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
+         * this is not part of a Fast BSS Transition.
+         */
+        wpa_printf(MSG_DEBUG, "WPA: Clear old PTK");
+        sm->ptk_set = 0;
+        os_memset(&sm->ptk, 0, sizeof(sm->ptk));
+        sm->tptk_set = 0;
+        os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+        os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+        os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+    }
+}
+
+
+/**
+ * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was lost. This will abort any existing pre-authentication session.
+ */
+void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+    eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+    pmksa_cache_clear_current(sm);
+#ifdef CONFIG_IEEE80211R
+    sm->ft_reassoc_completed = 0;
+    sm->ft_protocol = 0;
+#endif /* CONFIG_IEEE80211R */
+
+    /* Keys are not needed in the WPA state machine anymore */
+    wpa_sm_drop_sa(sm);
+
+    os_memset(sm->bssid, 0, ETH_ALEN);
+}
+
+
 void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
 {
     struct wpa_sm *sm = &gWpaSm;
@@ -2702,6 +2835,18 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
     return 0;
 }
 
+void wpa_sm_drop_sa(struct wpa_sm *sm)
+{
+    wpa_printf(MSG_DEBUG, "WPA: Clear old PMK and PTK");
+    sm->ptk_set = 0;
+    sm->tptk_set = 0;
+    sm->pmk_len = 0;
+    os_memset(&sm->ptk, 0, sizeof(sm->ptk));
+    os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+    os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+    os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+}
+
 #ifdef CONFIG_OWE_STA
 struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group)
 {

+ 6 - 0
components/wpa_supplicant/src/rsn_supp/wpa.h

@@ -58,6 +58,8 @@ int wpa_sm_set_ap_rsnxe(const u8 *ie, size_t len);
 
 int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
 
+void wpa_sm_drop_sa(struct wpa_sm *sm);
+
 #ifdef CONFIG_IEEE80211R
 
 int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
@@ -123,6 +125,10 @@ struct wpa_sm * get_wpa_sm(void);
 
 void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
 
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
+
+void wpa_sm_notify_disassoc(struct wpa_sm *sm);
+
 int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len);
 
 struct wpabuf *owe_build_assoc_req(struct wpa_sm *sm, u16 group);

+ 5 - 0
components/wpa_supplicant/src/rsn_supp/wpa_i.h

@@ -36,6 +36,11 @@ struct wpa_sm {
     u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
     int rx_replay_counter_set;
     u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+    struct wpa_gtk gtk;
+#ifdef CONFIG_IEEE80211W
+    struct wpa_igtk igtk;
+#endif /* CONFIG_IEEE80211W */
+
     struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
     struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
     u8 ssid[32];