]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add testing functionality for resetting PN/IPN for configured keys
authorJouni Malinen <j@w1.fi>
Sat, 14 Oct 2017 10:41:08 +0000 (13:41 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 16 Oct 2017 14:43:10 +0000 (17:43 +0300)
This can be used to test replay protection. The "RESET_PN" command in
wpa_supplicant and "RESET_PN <addr>" command in hostapd resets the local
counters to zero for the last configured key. For hostapd, the address
parameter specifies which STA this operation is for or selects GTK
("ff:ff:ff:ff:ff:ff") or IGTK ("ff:ff:ff:ff:ff:ff IGTK").

This functionality is for testing purposes and included only in builds
with CONFIG_TESTING_OPTIONS=y.

Signed-off-by: Jouni Malinen <j@w1.fi>
hostapd/ctrl_iface.c
src/ap/hostapd.h
src/ap/sta_info.h
src/ap/wpa_auth_glue.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant_i.h
wpa_supplicant/wpas_glue.c

index 9aba5416dd899cc63dc3b959b78b4ae8f9213185..12978f79f7abe8f1573002e9733b772dc7dce4f7 100644 (file)
@@ -1949,6 +1949,90 @@ static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
 #endif /* WPA_TRACE_BFD */
 }
 
+
+static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
+{
+       struct sta_info *sta;
+       u8 addr[ETH_ALEN];
+       u8 zero[WPA_TK_MAX_LEN];
+
+       os_memset(zero, 0, sizeof(zero));
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+#ifdef CONFIG_IEEE80211W
+       if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) {
+               if (hapd->last_igtk_alg == WPA_ALG_NONE)
+                       return -1;
+
+               wpa_printf(MSG_INFO, "TESTING: Reset IPN for IGTK");
+
+               /* First, use a zero key to avoid any possible duplicate key
+                * avoidance in the driver. */
+               if (hostapd_drv_set_key(hapd->conf->iface, hapd,
+                                       hapd->last_igtk_alg,
+                                       broadcast_ether_addr,
+                                       hapd->last_igtk_key_idx, 1, NULL, 0,
+                                       zero, hapd->last_igtk_len) < 0)
+                       return -1;
+
+               /* Set the previously configured key to reset its TSC */
+               return hostapd_drv_set_key(hapd->conf->iface, hapd,
+                                          hapd->last_igtk_alg,
+                                          broadcast_ether_addr,
+                                          hapd->last_igtk_key_idx, 1, NULL, 0,
+                                          hapd->last_igtk,
+                                          hapd->last_igtk_len);
+       }
+#endif /* CONFIG_IEEE80211W */
+
+       if (is_broadcast_ether_addr(addr)) {
+               if (hapd->last_gtk_alg == WPA_ALG_NONE)
+                       return -1;
+
+               wpa_printf(MSG_INFO, "TESTING: Reset PN for GTK");
+
+               /* First, use a zero key to avoid any possible duplicate key
+                * avoidance in the driver. */
+               if (hostapd_drv_set_key(hapd->conf->iface, hapd,
+                                       hapd->last_gtk_alg,
+                                       broadcast_ether_addr,
+                                       hapd->last_gtk_key_idx, 1, NULL, 0,
+                                       zero, hapd->last_gtk_len) < 0)
+                       return -1;
+
+               /* Set the previously configured key to reset its TSC */
+               return hostapd_drv_set_key(hapd->conf->iface, hapd,
+                                          hapd->last_gtk_alg,
+                                          broadcast_ether_addr,
+                                          hapd->last_gtk_key_idx, 1, NULL, 0,
+                                          hapd->last_gtk, hapd->last_gtk_len);
+       }
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta)
+               return -1;
+
+       if (sta->last_tk_alg == WPA_ALG_NONE)
+               return -1;
+
+       wpa_printf(MSG_INFO, "TESTING: Reset PN for " MACSTR,
+                  MAC2STR(sta->addr));
+
+       /* First, use a zero key to avoid any possible duplicate key avoidance
+        * in the driver. */
+       if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
+                               sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
+                               zero, sta->last_tk_len) < 0)
+               return -1;
+
+       /* Set the previously configured key to reset its TSC/RSC */
+       return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
+                                  sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
+                                  sta->last_tk, sta->last_tk_len);
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -2665,6 +2749,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
                        reply_len = -1;
        } else if (os_strcmp(buf, "GET_FAIL") == 0) {
                reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
+       } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
+               if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
+                       reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
        } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
                if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
index fee413469712995db6299564b00070d7a125c209..f77e6ec7f703cdedf301bfb1a54f188c3bf98e21 100644 (file)
@@ -304,6 +304,18 @@ struct hostapd_data {
        unsigned int ext_eapol_frame_io:1;
 
        struct l2_packet_data *l2_test;
+
+       enum wpa_alg last_gtk_alg;
+       int last_gtk_key_idx;
+       u8 last_gtk[WPA_GTK_MAX_LEN];
+       size_t last_gtk_len;
+
+#ifdef CONFIG_IEEE80211W
+       enum wpa_alg last_igtk_alg;
+       int last_igtk_key_idx;
+       u8 last_igtk[WPA_IGTK_MAX_LEN];
+       size_t last_igtk_len;
+#endif /* CONFIG_IEEE80211W */
 #endif /* CONFIG_TESTING_OPTIONS */
 
 #ifdef CONFIG_MBO
index efbbcebb36b4dd06f5a808473fa46678b91a4e40..3fb60f69fbed8c27de98c7bcc571ce281d8f261e 100644 (file)
@@ -250,6 +250,13 @@ struct sta_info {
        struct crypto_ecdh *owe_ecdh;
        u16 owe_group;
 #endif /* CONFIG_OWE */
+
+#ifdef CONFIG_TESTING_OPTIONS
+       enum wpa_alg last_tk_alg;
+       int last_tk_key_idx;
+       u8 last_tk[WPA_TK_MAX_LEN];
+       size_t last_tk_len;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
index 10394c9b78cff8ad0c0eb7f683836b4743c58671..d9f917e4a528eafffd478ac73a31d9e56a08a246 100644 (file)
@@ -349,6 +349,37 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
                        return -1;
        }
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (addr && !is_broadcast_ether_addr(addr)) {
+               struct sta_info *sta;
+
+               sta = ap_get_sta(hapd, addr);
+               if (sta) {
+                       sta->last_tk_alg = alg;
+                       sta->last_tk_key_idx = idx;
+                       if (key)
+                               os_memcpy(sta->last_tk, key, key_len);
+                       sta->last_tk_len = key_len;
+               }
+#ifdef CONFIG_IEEE80211W
+       } else if (alg == WPA_CIPHER_AES_128_CMAC ||
+                  alg == WPA_CIPHER_BIP_GMAC_128 ||
+                  alg == WPA_CIPHER_BIP_GMAC_256 ||
+                  alg == WPA_CIPHER_BIP_CMAC_256) {
+               hapd->last_igtk_alg = alg;
+               hapd->last_igtk_key_idx = idx;
+               if (key)
+                       os_memcpy(hapd->last_igtk, key, key_len);
+               hapd->last_igtk_len = key_len;
+#endif /* CONFIG_IEEE80211W */
+       } else {
+               hapd->last_gtk_alg = alg;
+               hapd->last_gtk_key_idx = idx;
+               if (key)
+                       os_memcpy(hapd->last_gtk, key, key_len);
+               hapd->last_gtk_len = key_len;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
        return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
                                   key, key_len);
 }
index 89cacc649e0ce5a479651574b7f1fa4f1c574bec..8e50d013309f3659da5767c3c0488a3f9bfe0b33 100644 (file)
@@ -8907,6 +8907,30 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
        return 0;
 }
 
+
+static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
+{
+       u8 zero[WPA_TK_MAX_LEN];
+
+       if (wpa_s->last_tk_alg == WPA_ALG_NONE)
+               return -1;
+
+       wpa_printf(MSG_INFO, "TESTING: Reset PN");
+       os_memset(zero, 0, sizeof(zero));
+
+       /* First, use a zero key to avoid any possible duplicate key avoidance
+        * in the driver. */
+       if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+                           wpa_s->last_tk_key_idx, 1, zero, 6,
+                           zero, wpa_s->last_tk_len) < 0)
+               return -1;
+
+       /* Set the previously configured key to reset its TSC/RSC */
+       return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+                              wpa_s->last_tk_key_idx, 1, zero, 6,
+                              wpa_s->last_tk, wpa_s->last_tk_len);
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -10278,6 +10302,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
        } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
                if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
                        reply_len = -1;
+       } else if (os_strcmp(buf, "RESET_PN") == 0) {
+               if (wpas_ctrl_reset_pn(wpa_s) < 0)
+                       reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
        } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
                if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
index 06678626be0c4687cb30eeeec46d26db64f65c09..6e4a9f6d312af784b56bee1d9ae34a2d180d44a2 100644 (file)
@@ -314,6 +314,11 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 
        wpas_rrm_reset(wpa_s);
        wpa_s->wnmsleep_used = 0;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       wpa_s->last_tk_alg = WPA_ALG_NONE;
+       os_memset(wpa_s->last_tk, 0, sizeof(wpa_s->last_tk));
+#endif /* CONFIG_TESTING_OPTIONS */
 }
 
 
index 13eab2f407d4fbaef40b5ee9c70f42baf0581f79..8ce7085bc3a4e9dfb279bd89dd31346c8aed92fe 100644 (file)
@@ -1077,6 +1077,11 @@ struct wpa_supplicant {
        unsigned int ignore_auth_resp:1;
        unsigned int ignore_assoc_disallow:1;
        struct wpabuf *sae_commit_override;
+       enum wpa_alg last_tk_alg;
+       u8 last_tk_addr[ETH_ALEN];
+       int last_tk_key_idx;
+       u8 last_tk[WPA_TK_MAX_LEN];
+       size_t last_tk_len;
 #endif /* CONFIG_TESTING_OPTIONS */
 
        struct wmm_ac_assoc_data *wmm_ac_assoc_info;
index 961123727c893571c0d0632a4f9e397d9c9acee5..e44f6afad5ff9b0ee9ace86f2bd6d6154c0b041c 100644 (file)
@@ -502,6 +502,16 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
                wpa_s->last_gtk_len = key_len;
        }
 #endif /* CONFIG_TESTING_GET_GTK */
+#ifdef CONFIG_TESTING_OPTIONS
+       if (addr && !is_broadcast_ether_addr(addr)) {
+               wpa_s->last_tk_alg = alg;
+               os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN);
+               wpa_s->last_tk_key_idx = key_idx;
+               if (key)
+                       os_memcpy(wpa_s->last_tk, key, key_len);
+               wpa_s->last_tk_len = key_len;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
        return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
                               key, key_len);
 }