wlantest: Extend Management frame decryption to support GCMP and CCMP-256
Data frame processing had already been extended to support additional cipher suites, but Robust Management frame processing was still using a hardcoded cipher suite (CCMP-128). Extend it to support GCMP-128, GCMP-256, and CCMP-256 as well. Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
parent
cc046a1ff8
commit
ce7bdb54e5
1 changed files with 48 additions and 20 deletions
|
@ -2266,14 +2266,28 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u8 * try_tk(struct wpa_ptk *ptk, const u8 *data, size_t len,
|
static u8 * try_tk(struct wpa_ptk *ptk, size_t ptk_len,
|
||||||
size_t *dlen)
|
const u8 *data, size_t len, size_t *dlen)
|
||||||
{
|
{
|
||||||
const struct ieee80211_hdr *hdr;
|
const struct ieee80211_hdr *hdr;
|
||||||
u8 *decrypted, *frame;
|
u8 *decrypted, *frame;
|
||||||
|
|
||||||
hdr = (const struct ieee80211_hdr *) data;
|
hdr = (const struct ieee80211_hdr *) data;
|
||||||
decrypted = ccmp_decrypt(ptk->tk, hdr, data + 24, len - 24, dlen);
|
if (ptk_len == 16) {
|
||||||
|
decrypted = ccmp_decrypt(ptk->tk, hdr, data + 24, len - 24,
|
||||||
|
dlen);
|
||||||
|
if (!decrypted)
|
||||||
|
decrypted = gcmp_decrypt(ptk->tk, 16, hdr, data + 24,
|
||||||
|
len - 24, dlen);
|
||||||
|
} else if (ptk_len == 32) {
|
||||||
|
decrypted = ccmp_256_decrypt(ptk->tk, hdr, data + 24, len - 24,
|
||||||
|
dlen);
|
||||||
|
if (!decrypted)
|
||||||
|
decrypted = gcmp_decrypt(ptk->tk, 32, hdr, data + 24,
|
||||||
|
len - 24, dlen);
|
||||||
|
} else {
|
||||||
|
decrypted = NULL;
|
||||||
|
}
|
||||||
if (!decrypted)
|
if (!decrypted)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2288,8 +2302,8 @@ static u8 * try_tk(struct wpa_ptk *ptk, const u8 *data, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u8 * mgmt_ccmp_decrypt_tk(struct wlantest *wt, const u8 *data,
|
static u8 * mgmt_decrypt_tk(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
size_t len, size_t *dlen)
|
size_t *dlen)
|
||||||
{
|
{
|
||||||
struct wlantest_ptk *ptk;
|
struct wlantest_ptk *ptk;
|
||||||
u8 *decrypted;
|
u8 *decrypted;
|
||||||
|
@ -2300,7 +2314,7 @@ static u8 * mgmt_ccmp_decrypt_tk(struct wlantest *wt, const u8 *data,
|
||||||
|
|
||||||
wpa_debug_level = MSG_WARNING;
|
wpa_debug_level = MSG_WARNING;
|
||||||
dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
|
dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
|
||||||
decrypted = try_tk(&ptk->ptk, data, len, dlen);
|
decrypted = try_tk(&ptk->ptk, ptk->ptk_len, data, len, dlen);
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
wpa_debug_level = prev_level;
|
wpa_debug_level = prev_level;
|
||||||
add_note(wt, MSG_DEBUG,
|
add_note(wt, MSG_DEBUG,
|
||||||
|
@ -2316,7 +2330,7 @@ static u8 * mgmt_ccmp_decrypt_tk(struct wlantest *wt, const u8 *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
static u8 * mgmt_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
size_t *dlen)
|
size_t *dlen)
|
||||||
{
|
{
|
||||||
struct wlantest_bss *bss;
|
struct wlantest_bss *bss;
|
||||||
|
@ -2335,7 +2349,7 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!(data[24 + 3] & 0x20)) {
|
if (!(data[24 + 3] & 0x20)) {
|
||||||
add_note(wt, MSG_INFO, "Expected CCMP frame from " MACSTR
|
add_note(wt, MSG_INFO, "Expected CCMP/GCMP frame from " MACSTR
|
||||||
" did not have ExtIV bit set to 1",
|
" did not have ExtIV bit set to 1",
|
||||||
MAC2STR(hdr->addr2));
|
MAC2STR(hdr->addr2));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2346,8 +2360,8 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)
|
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)
|
||||||
mask &= ~0x10; /* FTM */
|
mask &= ~0x10; /* FTM */
|
||||||
if (data[24 + 2] != 0 || (data[24 + 3] & mask) != 0) {
|
if (data[24 + 2] != 0 || (data[24 + 3] & mask) != 0) {
|
||||||
add_note(wt, MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
|
add_note(wt, MSG_INFO, "CCMP/GCMP mgmt frame from " MACSTR
|
||||||
"non-zero reserved bit", MAC2STR(hdr->addr2));
|
" used non-zero reserved bit", MAC2STR(hdr->addr2));
|
||||||
}
|
}
|
||||||
|
|
||||||
keyid = data[24 + 3] >> 6;
|
keyid = data[24 + 3] >> 6;
|
||||||
|
@ -2359,13 +2373,13 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
|
|
||||||
bss = bss_get(wt, hdr->addr3);
|
bss = bss_get(wt, hdr->addr3);
|
||||||
if (bss == NULL)
|
if (bss == NULL)
|
||||||
return mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
|
return mgmt_decrypt_tk(wt, data, len, dlen);
|
||||||
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
|
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
|
||||||
sta = sta_get(bss, hdr->addr2);
|
sta = sta_get(bss, hdr->addr2);
|
||||||
else
|
else
|
||||||
sta = sta_get(bss, hdr->addr1);
|
sta = sta_get(bss, hdr->addr1);
|
||||||
if (sta == NULL || !sta->ptk_set) {
|
if (sta == NULL || !sta->ptk_set) {
|
||||||
decrypted = mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
|
decrypted = mgmt_decrypt_tk(wt, data, len, dlen);
|
||||||
if (!decrypted)
|
if (!decrypted)
|
||||||
add_note(wt, MSG_MSGDUMP,
|
add_note(wt, MSG_MSGDUMP,
|
||||||
"No PTK known to decrypt the frame");
|
"No PTK known to decrypt the frame");
|
||||||
|
@ -2380,7 +2394,7 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
ccmp_get_pn(pn, data + 24);
|
ccmp_get_pn(pn, data + 24);
|
||||||
if (os_memcmp(pn, rsc, 6) <= 0) {
|
if (os_memcmp(pn, rsc, 6) <= 0) {
|
||||||
u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
|
u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
|
||||||
add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
|
add_note(wt, MSG_INFO, "replay detected: A1=" MACSTR
|
||||||
" A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u%s",
|
" A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u%s",
|
||||||
MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
|
MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
|
||||||
MAC2STR(hdr->addr3),
|
MAC2STR(hdr->addr3),
|
||||||
|
@ -2392,7 +2406,21 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
|
wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data + 24, len - 24, dlen);
|
if (sta->pairwise_cipher == WPA_CIPHER_CCMP_256) {
|
||||||
|
decrypted = ccmp_256_decrypt(sta->ptk.tk, hdr, data + 24,
|
||||||
|
len - 24, dlen);
|
||||||
|
write_decrypted_note(wt, decrypted, sta->ptk.tk, 32, keyid);
|
||||||
|
} else if (sta->pairwise_cipher == WPA_CIPHER_GCMP ||
|
||||||
|
sta->pairwise_cipher == WPA_CIPHER_GCMP_256) {
|
||||||
|
decrypted = gcmp_decrypt(sta->ptk.tk, sta->ptk.tk_len, hdr,
|
||||||
|
data + 24, len - 24, dlen);
|
||||||
|
write_decrypted_note(wt, decrypted, sta->ptk.tk,
|
||||||
|
sta->ptk.tk_len, keyid);
|
||||||
|
} else {
|
||||||
|
decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data + 24, len - 24,
|
||||||
|
dlen);
|
||||||
|
write_decrypted_note(wt, decrypted, sta->ptk.tk, 16, keyid);
|
||||||
|
}
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
os_memcpy(rsc, pn, 6);
|
os_memcpy(rsc, pn, 6);
|
||||||
frame = os_malloc(24 + *dlen);
|
frame = os_malloc(24 + *dlen);
|
||||||
|
@ -2415,7 +2443,7 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
|
static int check_mgmt_ccmp_gcmp(struct wlantest *wt, const u8 *data, size_t len)
|
||||||
{
|
{
|
||||||
const struct ieee80211_mgmt *mgmt;
|
const struct ieee80211_mgmt *mgmt;
|
||||||
u16 fc;
|
u16 fc;
|
||||||
|
@ -2447,8 +2475,8 @@ static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
|
||||||
(sta->state == STATE3 ||
|
(sta->state == STATE3 ||
|
||||||
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION ||
|
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION ||
|
||||||
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
||||||
add_note(wt, MSG_INFO, "Robust individually-addressed "
|
add_note(wt, MSG_INFO,
|
||||||
"management frame sent without CCMP by "
|
"Robust individually-addressed management frame sent without CCMP/GCMP by "
|
||||||
MACSTR, MAC2STR(mgmt->sa));
|
MACSTR, MAC2STR(mgmt->sa));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -2499,7 +2527,7 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
|
||||||
stype == WLAN_FC_STYPE_DISASSOC ||
|
stype == WLAN_FC_STYPE_DISASSOC ||
|
||||||
stype == WLAN_FC_STYPE_ACTION ||
|
stype == WLAN_FC_STYPE_ACTION ||
|
||||||
stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
||||||
decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
|
decrypted = mgmt_decrypt(wt, data, len, &dlen);
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
|
write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
|
||||||
data = decrypted;
|
data = decrypted;
|
||||||
|
@ -2514,7 +2542,7 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
|
||||||
stype == WLAN_FC_STYPE_DISASSOC ||
|
stype == WLAN_FC_STYPE_DISASSOC ||
|
||||||
stype == WLAN_FC_STYPE_ACTION ||
|
stype == WLAN_FC_STYPE_ACTION ||
|
||||||
stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
|
||||||
if (check_mgmt_ccmp(wt, data, len) < 0)
|
if (check_mgmt_ccmp_gcmp(wt, data, len) < 0)
|
||||||
valid = 0;
|
valid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue