wlantest: Support TK list for Management frame decryption

Use the TKs from the PTK file (-T command line argument) to try to
decrypt encrypted Management frames if no BSS/STA key can be found based
on addresses.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2021-02-07 11:37:58 +02:00
parent fce6fb0ec2
commit 56a04ae1a1
4 changed files with 80 additions and 24 deletions

View file

@ -119,19 +119,6 @@ static void rx_data_process(struct wlantest *wt, const u8 *bssid,
}
static void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
const u8 *tk, size_t tk_len, int keyid)
{
char tk_hex[65];
if (!decrypted)
return;
wpa_snprintf_hex(tk_hex, sizeof(tk_hex), tk, tk_len);
add_note(wt, MSG_EXCESSIVE, "TK[%d] %s", keyid, tk_hex);
}
static u8 * try_ptk(int pairwise_cipher, struct wpa_ptk *ptk,
const struct ieee80211_hdr *hdr,
const u8 *data, size_t data_len, size_t *decrypted_len)

View file

@ -2139,6 +2139,56 @@ 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,
size_t *dlen)
{
const struct ieee80211_hdr *hdr;
u8 *decrypted, *frame;
hdr = (const struct ieee80211_hdr *) data;
decrypted = ccmp_decrypt(ptk->tk, hdr, data + 24, len - 24, dlen);
if (!decrypted)
return NULL;
frame = os_malloc(24 + *dlen);
if (frame) {
os_memcpy(frame, data, 24);
os_memcpy(frame + 24, decrypted, *dlen);
*dlen += 24;
}
os_free(decrypted);
return frame;
}
static u8 * mgmt_ccmp_decrypt_tk(struct wlantest *wt, const u8 *data,
size_t len, size_t *dlen)
{
struct wlantest_ptk *ptk;
u8 *decrypted;
int prev_level = wpa_debug_level;
int keyid;
keyid = data[24 + 3] >> 6;
wpa_debug_level = MSG_WARNING;
dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
decrypted = try_tk(&ptk->ptk, data, len, dlen);
if (decrypted) {
wpa_debug_level = prev_level;
add_note(wt, MSG_DEBUG,
"Found TK match from the list of all known TKs");
write_decrypted_note(wt, decrypted, ptk->ptk.tk,
ptk->ptk.tk_len, keyid);
return decrypted;
}
}
wpa_debug_level = prev_level;
return NULL;
}
static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
size_t *dlen)
{
@ -2150,17 +2200,6 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
u8 pn[6], *rsc;
hdr = (const struct ieee80211_hdr *) data;
bss = bss_get(wt, hdr->addr3);
if (bss == NULL)
return NULL;
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
sta = sta_get(bss, hdr->addr2);
else
sta = sta_get(bss, hdr->addr1);
if (sta == NULL || !sta->ptk_set) {
add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
return NULL;
}
if (len < 24 + 4)
return NULL;
@ -2184,6 +2223,21 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
MACSTR, keyid, MAC2STR(hdr->addr2));
}
bss = bss_get(wt, hdr->addr3);
if (bss == NULL)
return mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
sta = sta_get(bss, hdr->addr2);
else
sta = sta_get(bss, hdr->addr1);
if (sta == NULL || !sta->ptk_set) {
decrypted = mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
if (!decrypted)
add_note(wt, MSG_MSGDUMP,
"No PTK known to decrypt the frame");
return decrypted;
}
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
rsc = sta->rsc_tods[16];
else

View file

@ -323,6 +323,19 @@ size_t notes_len(struct wlantest *wt, size_t hdrlen)
}
void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
const u8 *tk, size_t tk_len, int keyid)
{
char tk_hex[65];
if (!decrypted)
return;
wpa_snprintf_hex(tk_hex, sizeof(tk_hex), tk, tk_len);
add_note(wt, MSG_EXCESSIVE, "TK[%d] %s", keyid, tk_hex);
}
int wlantest_relog(struct wlantest *wt)
{
int ret = 0;

View file

@ -232,6 +232,8 @@ void add_note(struct wlantest *wt, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
void clear_notes(struct wlantest *wt);
size_t notes_len(struct wlantest *wt, size_t hdrlen);
void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
const u8 *tk, size_t tk_len, int keyid);
int add_wep(struct wlantest *wt, const char *key);
int read_cap_file(struct wlantest *wt, const char *fname);