]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Prevent reinstallation of an already in-use group key
authorMathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
Wed, 12 Jul 2017 14:03:24 +0000 (16:03 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 15 Oct 2017 23:03:47 +0000 (02:03 +0300)
Track the current GTK and IGTK that is in use and when receiving a
(possibly retransmitted) Group Message 1 or WNM-Sleep Mode Response, do
not install the given key if it is already in use. This prevents an
attacker from trying to trick the client into resetting or lowering the
sequence counter associated to the group key.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
src/common/wpa_common.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa_i.h

index cc8edf82d29f2ace7370ebf80c7e0cdc0ddd056c..0872b1216fc559c0513a9b3edca0bde7d6ebffa7 100644 (file)
@@ -221,6 +221,17 @@ struct wpa_ptk {
        size_t tk_len;
 };
 
+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 */
 
 /* WPA IE version 1
  * 00-50-f2:1 (OUI:OUI type)
index 0e9f05d3e79baaa763b16ded2646a6997218b41f..22e8661f6493621913019c42787d953fa863f239 100644 (file)
@@ -802,6 +802,15 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
        const u8 *_gtk = gd->gtk;
        u8 gtk_buf[32];
 
+       /* Detect possible key reinstallation */
+       if (sm->gtk.gtk_len == (size_t) gd->gtk_len &&
+           os_memcmp(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len) == 0) {
+               wpa_dbg(sm->ctx->msg_ctx, 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);
+               return 0;
+       }
+
        wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                "WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
@@ -836,6 +845,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
        }
        os_memset(gtk_buf, 0, sizeof(gtk_buf));
 
+       sm->gtk.gtk_len = gd->gtk_len;
+       os_memcpy(sm->gtk.gtk, gd->gtk, sm->gtk.gtk_len);
+
        return 0;
 }
 
@@ -942,6 +954,48 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
 }
 
 
+#ifdef CONFIG_IEEE80211W
+static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
+                                      const struct wpa_igtk_kde *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_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                       "WPA: Not reinstalling already in-use IGTK to the driver (keyidx=%d)",
+                       keyidx);
+               return  0;
+       }
+
+       wpa_dbg(sm->ctx->msg_ctx, 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_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                       "WPA: Invalid IGTK KeyID %d", keyidx);
+               return -1;
+       }
+       if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+                          broadcast_ether_addr,
+                          keyidx, 0, igtk->pn, sizeof(igtk->pn),
+                          igtk->igtk, len) < 0) {
+               wpa_msg(sm->ctx->msg_ctx, 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 */
+
+
 static int ieee80211w_set_keys(struct wpa_sm *sm,
                               struct wpa_eapol_ie_parse *ie)
 {
@@ -952,30 +1006,14 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
        if (ie->igtk) {
                size_t len;
                const struct wpa_igtk_kde *igtk;
-               u16 keyidx;
+
                len = wpa_cipher_key_len(sm->mgmt_group_cipher);
                if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
                        return -1;
+
                igtk = (const struct wpa_igtk_kde *) ie->igtk;
-               keyidx = WPA_GET_LE16(igtk->keyid);
-               wpa_dbg(sm->ctx->msg_ctx, 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_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: Invalid IGTK KeyID %d", keyidx);
-                       return -1;
-               }
-               if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
-                                  broadcast_ether_addr,
-                                  keyidx, 0, igtk->pn, sizeof(igtk->pn),
-                                  igtk->igtk, len) < 0) {
-                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "WPA: Failed to configure IGTK to the driver");
+               if (wpa_supplicant_install_igtk(sm, igtk) < 0)
                        return -1;
-               }
        }
 
        return 0;
@@ -2493,7 +2531,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
  */
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
 {
-       int clear_ptk = 1;
+       int clear_keys = 1;
 
        if (sm == NULL)
                return;
@@ -2519,7 +2557,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
                /* Prepare for the next transition */
                wpa_ft_prepare_auth_request(sm, NULL);
 
-               clear_ptk = 0;
+               clear_keys = 0;
        }
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_FILS
@@ -2529,11 +2567,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
                 * AUTHENTICATED state to get the EAPOL port Authorized.
                 */
                wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
-               clear_ptk = 0;
+               clear_keys = 0;
        }
 #endif /* CONFIG_FILS */
 
-       if (clear_ptk) {
+       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.
@@ -2543,6 +2581,10 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
                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));
+#ifdef CONFIG_IEEE80211W
+               os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+#endif /* CONFIG_IEEE80211W */
        }
 
 #ifdef CONFIG_TDLS
@@ -3119,6 +3161,10 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
        os_memset(sm->pmk, 0, sizeof(sm->pmk));
        os_memset(&sm->ptk, 0, sizeof(sm->ptk));
        os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+       os_memset(&sm->gtk, 0, sizeof(sm->gtk));
+#ifdef CONFIG_IEEE80211W
+       os_memset(&sm->igtk, 0, sizeof(sm->igtk));
+#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
        os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
        os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
@@ -3191,29 +3237,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
                os_memset(&gd, 0, sizeof(gd));
 #ifdef CONFIG_IEEE80211W
        } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
-               struct wpa_igtk_kde igd;
-               u16 keyidx;
-
-               os_memset(&igd, 0, sizeof(igd));
-               keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
-               os_memcpy(igd.keyid, buf + 2, 2);
-               os_memcpy(igd.pn, buf + 4, 6);
-
-               keyidx = WPA_GET_LE16(igd.keyid);
-               os_memcpy(igd.igtk, buf + 10, keylen);
-
-               wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
-                               igd.igtk, keylen);
-               if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
-                                  broadcast_ether_addr,
-                                  keyidx, 0, igd.pn, sizeof(igd.pn),
-                                  igd.igtk, keylen) < 0) {
-                       wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
-                                  "WNM mode");
-                       os_memset(&igd, 0, sizeof(igd));
+               const struct wpa_igtk_kde *igtk;
+
+               igtk = (const struct wpa_igtk_kde *) (buf + 2);
+               if (wpa_supplicant_install_igtk(sm, igtk) < 0)
                        return -1;
-               }
-               os_memset(&igd, 0, sizeof(igd));
 #endif /* CONFIG_IEEE80211W */
        } else {
                wpa_printf(MSG_DEBUG, "Unknown element id");
index ab8411e8b79735edd8cbf40af266137b2fb7e660..89e1d34d2f6ab74d95c897968db5fdb1f06469f7 100644 (file)
@@ -31,6 +31,10 @@ 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 eapol_sm *eapol; /* EAPOL state machine from upper level code */