]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Report decrypted TKIP frames even if cannot check Michael MIC
authorJouni Malinen <jouni@codeaurora.org>
Sat, 30 Jan 2021 15:28:49 +0000 (17:28 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 11 May 2021 18:13:56 +0000 (21:13 +0300)
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>
wlantest/rx_data.c
wlantest/test_vectors.c
wlantest/tkip.c
wlantest/wlantest.h

index f8b5f7e8a73566a7227a5754afa401211a7de0f0..9e84b8a8e9ce4d53816903982d8c216b1faf2346 100644 (file)
@@ -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) {
index ab9c0a39d37a02f05a5a170048736369c8f6fd04..ca0449d318c50bccc93f89ce828d763e8d3d74ba 100644 (file)
@@ -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);
 
index d616d4308ccd7632c430ca0db4247951eebde9c3..613a08aa770a615fdbf23e2668b2191ada47cfc9 100644 (file)
@@ -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;
index af29f578f0e55264397e2cb157f5bac20d06f854..4ea10c9e8782291383ac31a436e3659a575499fd 100644 (file)
@@ -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);