Browse Source

wlantest: Validate MMIE MIC

Jouni Malinen 14 years ago
parent
commit
bacc31286c
2 changed files with 118 additions and 0 deletions
  1. 117 0
      wlantest/rx_mgmt.c
  2. 1 0
      wlantest/wlantest.h

+ 117 - 0
wlantest/rx_mgmt.c

@@ -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) ?

+ 1 - 0
wlantest/wlantest.h

@@ -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 {