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:
parent
2d4c78aef7
commit
faf6894f35
3 changed files with 132 additions and 3 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Loading…
Reference in a new issue