aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@codeaurora.org>2020-02-21 17:40:32 (GMT)
committerJouni Malinen <j@w1.fi>2020-02-21 17:41:36 (GMT)
commitfaf6894f35f6f2592ff05324db9e6e6184ebc041 (patch)
tree991d1220d5655ad8c2221b7d78aaa1a7201d0f11
parent2d4c78aef718b9a3e5947c4fad4bbd634b6eab9d (diff)
downloadhostap-faf6894f35f6f2592ff05324db9e6e6184ebc041.zip
hostap-faf6894f35f6f2592ff05324db9e6e6184ebc041.tar.gz
hostap-faf6894f35f6f2592ff05324db9e6e6184ebc041.tar.bz2
wlantest: BIGTK fetching and Beacon protection validation
Fetch the BIGTK from EAPOL-Key msg 3/4 and use it to validate MME in Beacon frames when the AP uses Beacon protection. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--wlantest/rx_eapol.c59
-rw-r--r--wlantest/rx_mgmt.c69
-rw-r--r--wlantest/wlantest.h7
3 files changed, 132 insertions, 3 deletions
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index e184495..e4fe7e2 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -548,6 +548,65 @@ static void learn_kde_keys(struct wlantest *wt, struct wlantest_bss *bss,
(unsigned) ie.igtk_len);
}
}
+
+ if (ie.bigtk) {
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - BIGTK KDE",
+ ie.bigtk, ie.bigtk_len);
+ if (ie.bigtk_len == 24) {
+ u16 id;
+
+ id = WPA_GET_LE16(ie.bigtk);
+ if (id < 6 || id > 7) {
+ add_note(wt, MSG_INFO,
+ "Unexpected BIGTK KeyID %u", id);
+ } else {
+ const u8 *ipn;
+
+ add_note(wt, MSG_DEBUG, "BIGTK KeyID %u", id);
+ wpa_hexdump(MSG_DEBUG, "BIPN", ie.bigtk + 2, 6);
+ wpa_hexdump(MSG_DEBUG, "BIGTK", ie.bigtk + 8,
+ 16);
+ os_memcpy(bss->igtk[id], ie.bigtk + 8, 16);
+ bss->igtk_len[id] = 16;
+ ipn = ie.bigtk + 2;
+ bss->ipn[id][0] = ipn[5];
+ bss->ipn[id][1] = ipn[4];
+ bss->ipn[id][2] = ipn[3];
+ bss->ipn[id][3] = ipn[2];
+ bss->ipn[id][4] = ipn[1];
+ bss->ipn[id][5] = ipn[0];
+ bss->bigtk_idx = id;
+ }
+ } else if (ie.bigtk_len == 40) {
+ u16 id;
+
+ id = WPA_GET_LE16(ie.bigtk);
+ if (id < 6 || id > 7) {
+ add_note(wt, MSG_INFO,
+ "Unexpected BIGTK KeyID %u", id);
+ } else {
+ const u8 *ipn;
+
+ add_note(wt, MSG_DEBUG, "BIGTK KeyID %u", id);
+ wpa_hexdump(MSG_DEBUG, "BIPN", ie.bigtk + 2, 6);
+ wpa_hexdump(MSG_DEBUG, "BIGTK", ie.bigtk + 8,
+ 32);
+ os_memcpy(bss->igtk[id], ie.bigtk + 8, 32);
+ bss->igtk_len[id] = 32;
+ ipn = ie.bigtk + 2;
+ bss->ipn[id][0] = ipn[5];
+ bss->ipn[id][1] = ipn[4];
+ bss->ipn[id][2] = ipn[3];
+ bss->ipn[id][3] = ipn[2];
+ bss->ipn[id][4] = ipn[1];
+ bss->ipn[id][5] = ipn[0];
+ bss->bigtk_idx = id;
+ }
+ } else {
+ add_note(wt, MSG_INFO, "Invalid BIGTK KDE length %u",
+ (unsigned) ie.bigtk_len);
+ }
+ }
}
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
index 39b23b2..92762b8 100644
--- a/wlantest/rx_mgmt.c
+++ b/wlantest/rx_mgmt.c
@@ -19,6 +19,11 @@
#include "wlantest.h"
+static int check_mmie_mic(unsigned int mgmt_group_cipher,
+ const u8 *igtk, size_t igtk_len,
+ const u8 *data, size_t len);
+
+
static const char * mgmt_stype(u16 stype)
{
switch (stype) {
@@ -57,6 +62,9 @@ static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
struct wlantest_bss *bss;
struct ieee802_11_elems elems;
size_t offset;
+ const u8 *mme;
+ size_t mic_len;
+ u16 keyid;
mgmt = (const struct ieee80211_mgmt *) data;
offset = mgmt->u.beacon.variable - data;
@@ -79,6 +87,62 @@ static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
}
bss_update(wt, bss, &elems);
+
+ mme = get_ie(mgmt->u.beacon.variable, len - offset, WLAN_EID_MMIE);
+ if (!mme) {
+ if (bss->bigtk_idx) {
+ add_note(wt, MSG_INFO,
+ "Unexpected unprotected Beacon frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
+ }
+ return;
+ }
+
+ mic_len = bss->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
+ if (len < 24 + 10 + mic_len ||
+ data[len - (10 + mic_len)] != WLAN_EID_MMIE ||
+ data[len - (10 + mic_len - 1)] != 8 + mic_len) {
+ add_note(wt, MSG_INFO, "Invalid MME in a Beacon frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ mme += 2;
+ keyid = WPA_GET_LE16(mme);
+ if (keyid < 6 || keyid > 7) {
+ add_note(wt, MSG_INFO, "Unexpected MME KeyID %u from " MACSTR,
+ keyid, MAC2STR(mgmt->sa));
+ bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Beacon frame MME KeyID %u", keyid);
+ wpa_hexdump(MSG_MSGDUMP, "MME IPN", mme + 2, 6);
+ wpa_hexdump(MSG_MSGDUMP, "MME MIC", mme + 8, mic_len);
+
+ if (!bss->igtk_len[keyid]) {
+ add_note(wt, MSG_DEBUG, "No BIGTK known to validate BIP frame");
+ return;
+ }
+
+ if (os_memcmp(mme + 2, bss->ipn[keyid], 6) <= 0) {
+ add_note(wt, MSG_INFO, "BIP replay detected: SA=" MACSTR,
+ MAC2STR(mgmt->sa));
+ wpa_hexdump(MSG_INFO, "RX IPN", mme + 2, 6);
+ wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
+ }
+
+ if (check_mmie_mic(bss->mgmt_group_cipher, bss->igtk[keyid],
+ bss->igtk_len[keyid], data, len) < 0) {
+ add_note(wt, MSG_INFO, "Invalid MME MIC in a Beacon frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
+ return;
+ }
+
+ add_note(wt, MSG_DEBUG, "Valid MME MIC in Beacon frame");
+ os_memcpy(bss->ipn[keyid], mme + 2, 6);
}
@@ -1329,6 +1393,11 @@ static int check_mmie_mic(unsigned int mgmt_group_cipher,
os_memcpy(buf + 20, data + 24, len - 24 - mic_len);
os_memset(buf + 20 + len - 24 - mic_len, 0, mic_len);
+ if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
+ /* Timestamp field masked to zero */
+ os_memset(buf + 20, 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 (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index 4f90b20..82eddc1 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -150,10 +150,11 @@ struct wlantest_bss {
size_t gtk_len[4];
int gtk_idx;
u8 rsc[4][6];
- u8 igtk[6][32];
- size_t igtk_len[6];
+ u8 igtk[8][32];
+ size_t igtk_len[8];
int igtk_idx;
- u8 ipn[6][6];
+ u8 ipn[8][6];
+ int bigtk_idx;
u32 counters[NUM_WLANTEST_BSS_COUNTER];
struct dl_list tdls; /* struct wlantest_tdls */
u8 mdid[2];