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>
This commit is contained in:
Jouni Malinen 2020-02-21 19:40:32 +02:00 committed by Jouni Malinen
parent 2d4c78aef7
commit faf6894f35
3 changed files with 132 additions and 3 deletions

View File

@ -548,6 +548,65 @@ static void learn_kde_keys(struct wlantest *wt, struct wlantest_bss *bss,
(unsigned) ie.igtk_len); (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);
}
}
} }

View File

@ -19,6 +19,11 @@
#include "wlantest.h" #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) static const char * mgmt_stype(u16 stype)
{ {
switch (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 wlantest_bss *bss;
struct ieee802_11_elems elems; struct ieee802_11_elems elems;
size_t offset; size_t offset;
const u8 *mme;
size_t mic_len;
u16 keyid;
mgmt = (const struct ieee80211_mgmt *) data; mgmt = (const struct ieee80211_mgmt *) data;
offset = mgmt->u.beacon.variable - 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); 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_memcpy(buf + 20, data + 24, len - 24 - mic_len);
os_memset(buf + 20 + len - 24 - mic_len, 0, 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); wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
/* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */ /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {

View File

@ -150,10 +150,11 @@ struct wlantest_bss {
size_t gtk_len[4]; size_t gtk_len[4];
int gtk_idx; int gtk_idx;
u8 rsc[4][6]; u8 rsc[4][6];
u8 igtk[6][32]; u8 igtk[8][32];
size_t igtk_len[6]; size_t igtk_len[8];
int igtk_idx; int igtk_idx;
u8 ipn[6][6]; u8 ipn[8][6];
int bigtk_idx;
u32 counters[NUM_WLANTEST_BSS_COUNTER]; u32 counters[NUM_WLANTEST_BSS_COUNTER];
struct dl_list tdls; /* struct wlantest_tdls */ struct dl_list tdls; /* struct wlantest_tdls */
u8 mdid[2]; u8 mdid[2];