diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index f8b5f7e8a..9e84b8a8e 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -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, - const struct ieee80211_hdr *hdr, +static u8 * try_ptk(struct wlantest *wt, int pairwise_cipher, + struct wpa_ptk *ptk, const struct ieee80211_hdr *hdr, const u8 *data, size_t data_len, size_t *decrypted_len) { u8 *decrypted; @@ -174,8 +174,14 @@ static u8 * try_ptk(int pairwise_cipher, struct wpa_ptk *ptk, data, data_len, decrypted_len); } else if ((pairwise_cipher == WPA_CIPHER_TKIP || pairwise_cipher == 0) && tk_len == 32) { + enum michael_mic_result mic_res; + 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; @@ -192,7 +198,7 @@ static u8 * try_all_ptk(struct wlantest *wt, int pairwise_cipher, wpa_debug_level = MSG_WARNING; 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); if (decrypted) { wpa_debug_level = prev_level; @@ -318,21 +324,28 @@ static void rx_data_bss_prot_group(struct wlantest *wt, } 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, - &dlen); - else if (bss->group_cipher == WPA_CIPHER_WEP40) + &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"); + } else if (bss->group_cipher == WPA_CIPHER_WEP40) { 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, &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, &dlen); - else if (bss->group_cipher == WPA_CIPHER_GCMP || - bss->group_cipher == WPA_CIPHER_GCMP_256) + } else if (bss->group_cipher == WPA_CIPHER_GCMP || + bss->group_cipher == WPA_CIPHER_GCMP_256) { decrypted = gcmp_decrypt(bss->gtk[keyid], bss->gtk_len[keyid], hdr, data, len, &dlen); + } if (decrypted) { char gtk[65]; @@ -603,7 +616,14 @@ skip_replay_det: write_decrypted_note(wt, decrypted, tk, 16, keyid); } } 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); } else if (sta->pairwise_cipher == WPA_CIPHER_WEP40) { decrypted = wep_decrypt(wt, hdr, data, len, &dlen); @@ -631,7 +651,7 @@ check_zero_tk: os_memset(&zero_ptk, 0, sizeof(zero_ptk)); zero_ptk.tk_len = wpa_cipher_key_len(sta->pairwise_cipher); 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); wpa_debug_level = old_debug_level; if (decrypted) { diff --git a/wlantest/test_vectors.c b/wlantest/test_vectors.c index ab9c0a39d..ca0449d31 100644 --- a/wlantest/test_vectors.c +++ b/wlantest/test_vectors.c @@ -63,7 +63,7 @@ static void test_vector_tkip(void) wpa_debug_level = MSG_INFO; 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; os_free(enc); diff --git a/wlantest/tkip.c b/wlantest/tkip.c index d616d4308..613a08aa7 100644 --- a/wlantest/tkip.c +++ b/wlantest/tkip.c @@ -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, - 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; u32 iv32; @@ -303,6 +304,7 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, u8 michael_hdr[16]; u8 mic[8]; u16 fc = le_to_host16(hdr->frame_control); + u16 sc = le_to_host16(hdr->seq_ctrl); if (data_len < 8 + 4) return NULL; @@ -336,6 +338,15 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, plain_len -= 4; /* 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) { 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: Received MIC", plain + plain_len - 8, 8); + if (mic_res) { + *decrypted_len = plain_len - 8; + *mic_res = MICHAEL_MIC_INCORRECT; + return plain; + } os_free(plain); return NULL; + } else if (mic_res) { + *mic_res = MICHAEL_MIC_OK; } *decrypted_len = plain_len - 8; diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index af29f578f..4ea10c9e8 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -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 *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, - 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 *pn, int keyid, size_t *encrypted_len); void tkip_get_pn(u8 *pn, const u8 *data);