wlantest: Report decrypted TKIP frames even if cannot check Michael MIC
This can be useful for debugging, so return successfully decrypted TKIP frame even if the Michael MIC cannot be verified (fragment reassembly not yet supported) or if the Michael MIC value is incorrect. Add a note in the frame to point out that the Michael MIC was not verified or is incorrect. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
81169ebc48
commit
3332657d69
4 changed files with 60 additions and 16 deletions
|
@ -150,8 +150,8 @@ static void rx_data_process(struct wlantest *wt, struct wlantest_bss *bss,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u8 * try_ptk(int pairwise_cipher, struct wpa_ptk *ptk,
|
static u8 * try_ptk(struct wlantest *wt, int pairwise_cipher,
|
||||||
const struct ieee80211_hdr *hdr,
|
struct wpa_ptk *ptk, const struct ieee80211_hdr *hdr,
|
||||||
const u8 *data, size_t data_len, size_t *decrypted_len)
|
const u8 *data, size_t data_len, size_t *decrypted_len)
|
||||||
{
|
{
|
||||||
u8 *decrypted;
|
u8 *decrypted;
|
||||||
|
@ -174,8 +174,14 @@ static u8 * try_ptk(int pairwise_cipher, struct wpa_ptk *ptk,
|
||||||
data, data_len, decrypted_len);
|
data, data_len, decrypted_len);
|
||||||
} else if ((pairwise_cipher == WPA_CIPHER_TKIP ||
|
} else if ((pairwise_cipher == WPA_CIPHER_TKIP ||
|
||||||
pairwise_cipher == 0) && tk_len == 32) {
|
pairwise_cipher == 0) && tk_len == 32) {
|
||||||
|
enum michael_mic_result mic_res;
|
||||||
|
|
||||||
decrypted = tkip_decrypt(ptk->tk, hdr, data, data_len,
|
decrypted = tkip_decrypt(ptk->tk, hdr, data, data_len,
|
||||||
decrypted_len);
|
decrypted_len, &mic_res);
|
||||||
|
if (decrypted && mic_res == MICHAEL_MIC_INCORRECT)
|
||||||
|
add_note(wt, MSG_INFO, "Invalid Michael MIC");
|
||||||
|
else if (decrypted && mic_res == MICHAEL_MIC_NOT_VERIFIED)
|
||||||
|
add_note(wt, MSG_DEBUG, "Michael MIC not verified");
|
||||||
}
|
}
|
||||||
|
|
||||||
return decrypted;
|
return decrypted;
|
||||||
|
@ -192,7 +198,7 @@ static u8 * try_all_ptk(struct wlantest *wt, int pairwise_cipher,
|
||||||
|
|
||||||
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_ptk(pairwise_cipher, &ptk->ptk, hdr,
|
decrypted = try_ptk(wt, pairwise_cipher, &ptk->ptk, hdr,
|
||||||
data, data_len, decrypted_len);
|
data, data_len, decrypted_len);
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
wpa_debug_level = prev_level;
|
wpa_debug_level = prev_level;
|
||||||
|
@ -318,21 +324,28 @@ static void rx_data_bss_prot_group(struct wlantest *wt,
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_replay_det:
|
skip_replay_det:
|
||||||
if (bss->group_cipher == WPA_CIPHER_TKIP)
|
if (bss->group_cipher == WPA_CIPHER_TKIP) {
|
||||||
|
enum michael_mic_result mic_res;
|
||||||
|
|
||||||
decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len,
|
decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len,
|
||||||
&dlen);
|
&dlen, &mic_res);
|
||||||
else if (bss->group_cipher == WPA_CIPHER_WEP40)
|
if (decrypted && mic_res == MICHAEL_MIC_INCORRECT)
|
||||||
|
add_note(wt, MSG_INFO, "Invalid Michael MIC");
|
||||||
|
else if (decrypted && mic_res == MICHAEL_MIC_NOT_VERIFIED)
|
||||||
|
add_note(wt, MSG_DEBUG, "Michael MIC not verified");
|
||||||
|
} else if (bss->group_cipher == WPA_CIPHER_WEP40) {
|
||||||
decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
|
decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
|
||||||
else if (bss->group_cipher == WPA_CIPHER_CCMP)
|
} else if (bss->group_cipher == WPA_CIPHER_CCMP) {
|
||||||
decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len,
|
decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len,
|
||||||
&dlen);
|
&dlen);
|
||||||
else if (bss->group_cipher == WPA_CIPHER_CCMP_256)
|
} else if (bss->group_cipher == WPA_CIPHER_CCMP_256) {
|
||||||
decrypted = ccmp_256_decrypt(bss->gtk[keyid], hdr, data, len,
|
decrypted = ccmp_256_decrypt(bss->gtk[keyid], hdr, data, len,
|
||||||
&dlen);
|
&dlen);
|
||||||
else if (bss->group_cipher == WPA_CIPHER_GCMP ||
|
} else if (bss->group_cipher == WPA_CIPHER_GCMP ||
|
||||||
bss->group_cipher == WPA_CIPHER_GCMP_256)
|
bss->group_cipher == WPA_CIPHER_GCMP_256) {
|
||||||
decrypted = gcmp_decrypt(bss->gtk[keyid], bss->gtk_len[keyid],
|
decrypted = gcmp_decrypt(bss->gtk[keyid], bss->gtk_len[keyid],
|
||||||
hdr, data, len, &dlen);
|
hdr, data, len, &dlen);
|
||||||
|
}
|
||||||
|
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
char gtk[65];
|
char gtk[65];
|
||||||
|
@ -603,7 +616,14 @@ skip_replay_det:
|
||||||
write_decrypted_note(wt, decrypted, tk, 16, keyid);
|
write_decrypted_note(wt, decrypted, tk, 16, keyid);
|
||||||
}
|
}
|
||||||
} else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) {
|
} else if (sta->pairwise_cipher == WPA_CIPHER_TKIP) {
|
||||||
decrypted = tkip_decrypt(sta->ptk.tk, hdr, data, len, &dlen);
|
enum michael_mic_result mic_res;
|
||||||
|
|
||||||
|
decrypted = tkip_decrypt(sta->ptk.tk, hdr, data, len, &dlen,
|
||||||
|
&mic_res);
|
||||||
|
if (decrypted && mic_res == MICHAEL_MIC_INCORRECT)
|
||||||
|
add_note(wt, MSG_INFO, "Invalid Michael MIC");
|
||||||
|
else if (decrypted && mic_res == MICHAEL_MIC_NOT_VERIFIED)
|
||||||
|
add_note(wt, MSG_DEBUG, "Michael MIC not verified");
|
||||||
write_decrypted_note(wt, decrypted, sta->ptk.tk, 32, keyid);
|
write_decrypted_note(wt, decrypted, sta->ptk.tk, 32, keyid);
|
||||||
} else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) {
|
} else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) {
|
||||||
decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
|
decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
|
||||||
|
@ -631,7 +651,7 @@ check_zero_tk:
|
||||||
os_memset(&zero_ptk, 0, sizeof(zero_ptk));
|
os_memset(&zero_ptk, 0, sizeof(zero_ptk));
|
||||||
zero_ptk.tk_len = wpa_cipher_key_len(sta->pairwise_cipher);
|
zero_ptk.tk_len = wpa_cipher_key_len(sta->pairwise_cipher);
|
||||||
wpa_debug_level = MSG_ERROR;
|
wpa_debug_level = MSG_ERROR;
|
||||||
decrypted = try_ptk(sta->pairwise_cipher, &zero_ptk, hdr,
|
decrypted = try_ptk(wt, sta->pairwise_cipher, &zero_ptk, hdr,
|
||||||
data, len, &dlen);
|
data, len, &dlen);
|
||||||
wpa_debug_level = old_debug_level;
|
wpa_debug_level = old_debug_level;
|
||||||
if (decrypted) {
|
if (decrypted) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ static void test_vector_tkip(void)
|
||||||
|
|
||||||
wpa_debug_level = MSG_INFO;
|
wpa_debug_level = MSG_INFO;
|
||||||
plain = tkip_decrypt(tk, (const struct ieee80211_hdr *) enc,
|
plain = tkip_decrypt(tk, (const struct ieee80211_hdr *) enc,
|
||||||
enc + 24, enc_len - 24, &plain_len);
|
enc + 24, enc_len - 24, &plain_len, NULL);
|
||||||
wpa_debug_level = MSG_EXCESSIVE;
|
wpa_debug_level = MSG_EXCESSIVE;
|
||||||
os_free(enc);
|
os_free(enc);
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,8 @@ static void michael_mic_hdr(const struct ieee80211_hdr *hdr11, u8 *hdr)
|
||||||
|
|
||||||
|
|
||||||
u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
const u8 *data, size_t data_len, size_t *decrypted_len)
|
const u8 *data, size_t data_len, size_t *decrypted_len,
|
||||||
|
enum michael_mic_result *mic_res)
|
||||||
{
|
{
|
||||||
u16 iv16;
|
u16 iv16;
|
||||||
u32 iv32;
|
u32 iv32;
|
||||||
|
@ -303,6 +304,7 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
u8 michael_hdr[16];
|
u8 michael_hdr[16];
|
||||||
u8 mic[8];
|
u8 mic[8];
|
||||||
u16 fc = le_to_host16(hdr->frame_control);
|
u16 fc = le_to_host16(hdr->frame_control);
|
||||||
|
u16 sc = le_to_host16(hdr->seq_ctrl);
|
||||||
|
|
||||||
if (data_len < 8 + 4)
|
if (data_len < 8 + 4)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -336,6 +338,15 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
plain_len -= 4;
|
plain_len -= 4;
|
||||||
|
|
||||||
/* TODO: MSDU reassembly */
|
/* TODO: MSDU reassembly */
|
||||||
|
if ((fc & WLAN_FC_MOREFRAG) || WLAN_GET_SEQ_FRAG(sc) > 0) {
|
||||||
|
/* For now, return the decrypted fragment and do not check the
|
||||||
|
* Michael MIC value in the last fragment */
|
||||||
|
*decrypted_len = plain_len;
|
||||||
|
if (mic_res) {
|
||||||
|
*mic_res = MICHAEL_MIC_NOT_VERIFIED;
|
||||||
|
return plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (plain_len < 8) {
|
if (plain_len < 8) {
|
||||||
wpa_printf(MSG_INFO, "TKIP: Not enough room for Michael MIC "
|
wpa_printf(MSG_INFO, "TKIP: Not enough room for Michael MIC "
|
||||||
|
@ -353,8 +364,15 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
wpa_hexdump(MSG_DEBUG, "TKIP: Calculated MIC", mic, 8);
|
wpa_hexdump(MSG_DEBUG, "TKIP: Calculated MIC", mic, 8);
|
||||||
wpa_hexdump(MSG_DEBUG, "TKIP: Received MIC",
|
wpa_hexdump(MSG_DEBUG, "TKIP: Received MIC",
|
||||||
plain + plain_len - 8, 8);
|
plain + plain_len - 8, 8);
|
||||||
|
if (mic_res) {
|
||||||
|
*decrypted_len = plain_len - 8;
|
||||||
|
*mic_res = MICHAEL_MIC_INCORRECT;
|
||||||
|
return plain;
|
||||||
|
}
|
||||||
os_free(plain);
|
os_free(plain);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else if (mic_res) {
|
||||||
|
*mic_res = MICHAEL_MIC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
*decrypted_len = plain_len - 8;
|
*decrypted_len = plain_len - 8;
|
||||||
|
|
|
@ -304,8 +304,14 @@ u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
|
u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen,
|
||||||
u8 *qos, u8 *pn, int keyid, size_t *encrypted_len);
|
u8 *qos, u8 *pn, int keyid, size_t *encrypted_len);
|
||||||
|
|
||||||
|
enum michael_mic_result {
|
||||||
|
MICHAEL_MIC_OK,
|
||||||
|
MICHAEL_MIC_INCORRECT,
|
||||||
|
MICHAEL_MIC_NOT_VERIFIED
|
||||||
|
};
|
||||||
u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
|
||||||
const u8 *data, size_t data_len, size_t *decrypted_len);
|
const u8 *data, size_t data_len, size_t *decrypted_len,
|
||||||
|
enum michael_mic_result *mic_res);
|
||||||
u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
|
u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
|
||||||
u8 *pn, int keyid, size_t *encrypted_len);
|
u8 *pn, int keyid, size_t *encrypted_len);
|
||||||
void tkip_get_pn(u8 *pn, const u8 *data);
|
void tkip_get_pn(u8 *pn, const u8 *data);
|
||||||
|
|
Loading…
Reference in a new issue