]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Validate MMIE MIC
authorJouni Malinen <j@w1.fi>
Wed, 10 Nov 2010 00:06:59 +0000 (02:06 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 10 Nov 2010 00:06:59 +0000 (02:06 +0200)
wlantest/rx_mgmt.c
wlantest/wlantest.h

index 5b630c6f30355e6c2e44fdd7d78c393a769547c3..19d478eafa80f3e59ee895782ceead5a4f7cbc43 100644 (file)
@@ -17,6 +17,7 @@
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "crypto/aes_wrap.h"
 #include "wlantest.h"
 
 
@@ -418,6 +419,116 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len)
 }
 
 
+static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
+{
+       u8 *buf;
+       u8 mic[16];
+       u16 fc;
+       const struct ieee80211_hdr *hdr;
+
+       buf = os_malloc(len + 20 - 24);
+       if (buf == NULL)
+               return -1;
+
+       /* BIP AAD: FC(masked) A1 A2 A3 */
+       hdr = (const struct ieee80211_hdr *) data;
+       fc = le_to_host16(hdr->frame_control);
+       fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
+       WPA_PUT_LE16(buf, fc);
+       os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
+
+       /* Frame body with MMIE MIC masked to zero */
+       os_memcpy(buf + 20, data + 24, len - 24 - 8);
+       os_memset(buf + 20 + len - 24 - 8, 0, 8);
+
+       wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
+       /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
+       if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
+               os_free(buf);
+               return -1;
+       }
+
+       os_free(buf);
+
+       if (os_memcmp(data + len - 8, mic, 8) != 0)
+               return -1;
+
+       return 0;
+}
+
+
+static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
+{
+       const struct ieee80211_mgmt *mgmt;
+       u16 fc, stype;
+       const u8 *mmie;
+       int keyid;
+       struct wlantest_bss *bss;
+
+       mgmt = (const struct ieee80211_mgmt *) data;
+       fc = le_to_host16(mgmt->frame_control);
+       stype = WLAN_FC_GET_STYPE(fc);
+
+       if (stype == WLAN_FC_STYPE_ACTION) {
+               if (len < 24 + 1)
+                       return 0;
+               if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
+                       return 0; /* Not a robust management frame */
+       }
+
+       bss = bss_get(wt, mgmt->bssid);
+       if (bss == NULL)
+               return 0; /* No key known yet */
+
+       if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
+           data[len - 17] != 16) {
+               /* No MMIE */
+               /* TODO: use MFPC flag in RSN IE instead of IGTK flags */
+               if (bss->igtk_set[4] || bss->igtk_set[5]) {
+                       wpa_printf(MSG_INFO, "Robust group-addressed "
+                                  "management frame sent without BIP by "
+                                  MACSTR, MAC2STR(mgmt->sa));
+                       return -1;
+               }
+               return 0;
+       }
+
+       mmie = data + len - 16;
+       keyid = WPA_GET_LE16(mmie);
+       if (keyid < 4 || keyid > 5) {
+               wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
+                          keyid, MAC2STR(mgmt->sa));
+               return 0;
+       }
+       wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
+       wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
+       wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
+
+       if (!bss->igtk_set[keyid]) {
+               wpa_printf(MSG_DEBUG, "No IGTK known to validate BIP frame");
+               return 0;
+       }
+
+       if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) >= 0) {
+               wpa_printf(MSG_INFO, "BIP replay detected: SA=" MACSTR,
+                          MAC2STR(mgmt->sa));
+               wpa_hexdump(MSG_INFO, "RX IPN", mmie + 2, 6);
+               wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
+       }
+
+       if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
+               wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from "
+                          MACSTR, MAC2STR(mgmt->sa));
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
+       os_memcpy(bss->ipn[keyid], mmie + 2, 6);
+
+       return 0;
+}
+
+
 void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
 {
        const struct ieee80211_hdr *hdr;
@@ -431,6 +542,12 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
        wt->rx_mgmt++;
        stype = WLAN_FC_GET_STYPE(fc);
 
+       if ((hdr->addr1[0] & 0x01) &&
+           (stype == WLAN_FC_STYPE_DEAUTH ||
+            stype == WLAN_FC_STYPE_DISASSOC ||
+            stype == WLAN_FC_STYPE_ACTION))
+               check_bip(wt, data, len);
+
        wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
                    stype == WLAN_FC_STYPE_PROBE_RESP ||
                    stype == WLAN_FC_STYPE_PROBE_REQ) ?
index fed2e363f9ec8ac60529b6718ef6c5e0bfe8742e..443559a720bce29232bf7df084c6ad8a8f4c4480 100644 (file)
@@ -73,6 +73,7 @@ struct wlantest_bss {
        size_t gtk_len[4];
        u8 igtk[6][16];
        int igtk_set[6];
+       u8 ipn[6][6];
 };
 
 struct wlantest_radius {