]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Allow additional PTKs to be specified from a file
authorJouni Malinen <j@w1.fi>
Sun, 17 Nov 2013 20:52:15 +0000 (22:52 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 17 Nov 2013 21:09:38 +0000 (23:09 +0200)
A text file with a hexdump of PTK (KCK|KEK=TK with 48 octets for CCMP or
64 octets for TKIP or alternative 16 or 32 octet TK for CCMP/TKIP) can
now be read from a file specified with the -T command line argument. If
the current known PTK fails to decrypt a frame (or if no current PTK is
known) all listed PTKs are iterated to see if any of them matches.

Signed-hostap: Jouni Malinen <j@w1.fi>

wlantest/rx_data.c
wlantest/rx_eapol.c
wlantest/wlantest.c
wlantest/wlantest.h

index 9d439be88046330b14eddfe3b91d4e5c28aebb46..eaa2b8691cef85533b8f4c5e95ca98a7247935c9 100644 (file)
@@ -14,6 +14,8 @@
 #include "common/ieee802_11_defs.h"
 #include "wlantest.h"
 
+extern int wpa_debug_level;
+
 
 static const char * data_stype(u16 stype)
 {
@@ -93,6 +95,39 @@ static void rx_data_process(struct wlantest *wt, const u8 *bssid,
 }
 
 
+static u8 * try_all_ptk(struct wlantest *wt, int pairwise_cipher,
+                       const struct ieee80211_hdr *hdr,
+                       const u8 *data, size_t data_len, size_t *decrypted_len)
+{
+       struct wlantest_ptk *ptk;
+       u8 *decrypted;
+       int prev_level = wpa_debug_level;
+
+       wpa_debug_level = MSG_WARNING;
+       dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
+               decrypted = NULL;
+               if ((pairwise_cipher == WPA_CIPHER_CCMP ||
+                    pairwise_cipher == 0) && ptk->ptk_len == 48) {
+                       decrypted = ccmp_decrypt(ptk->ptk.tk1, hdr, data,
+                                                data_len, decrypted_len);
+               }
+               if ((pairwise_cipher == WPA_CIPHER_TKIP ||
+                    pairwise_cipher == 0) && ptk->ptk_len == 64) {
+                       decrypted = tkip_decrypt(ptk->ptk.tk1, hdr, data,
+                                                data_len, decrypted_len);
+               }
+               if (decrypted) {
+                       wpa_debug_level = prev_level;
+                       add_note(wt, MSG_DEBUG, "Found PTK match from list of all known PTKs");
+                       return decrypted;
+               }
+       }
+       wpa_debug_level = prev_level;
+
+       return NULL;
+}
+
+
 static void rx_data_bss_prot_group(struct wlantest *wt,
                                   const struct ieee80211_hdr *hdr,
                                   const u8 *qos, const u8 *dst, const u8 *src,
@@ -204,6 +239,8 @@ static void rx_data_bss_prot(struct wlantest *wt,
        u8 pn[6], *rsc;
        struct wlantest_tdls *tdls = NULL, *found;
        const u8 *tk = NULL;
+       int ptk_iter_done = 0;
+       int try_ptk_iter = 0;
 
        if (hdr->addr1[0] & 0x01) {
                rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len);
@@ -253,7 +290,9 @@ static void rx_data_bss_prot(struct wlantest *wt,
             (!sta->ptk_set && sta->pairwise_cipher != WPA_CIPHER_WEP40)) &&
            tk == NULL) {
                add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
-               return;
+               if (dl_list_empty(&wt->ptk))
+                       return;
+               try_ptk_iter = 1;
        }
 
        if (len < 4) {
@@ -337,8 +376,20 @@ skip_replay_det:
                decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
        else if (sta->pairwise_cipher == WPA_CIPHER_WEP40)
                decrypted = wep_decrypt(wt, hdr, data, len, &dlen);
-       else
+       else if (sta->ptk_set)
                decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
+       else {
+               decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data,
+                                       len, &dlen);
+               ptk_iter_done = 1;
+       }
+       if (!decrypted && !ptk_iter_done) {
+               decrypted = try_all_ptk(wt, sta->pairwise_cipher, hdr, data,
+                                       len, &dlen);
+               if (decrypted) {
+                       add_note(wt, MSG_DEBUG, "Current PTK did not work, but found a match from all known PTKs");
+               }
+       }
        if (decrypted) {
                u16 fc = le_to_host16(hdr->frame_control);
                const u8 *peer_addr = NULL;
@@ -349,7 +400,7 @@ skip_replay_det:
                                dlen, 1, peer_addr);
                write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
                                     decrypted, dlen);
-       } else
+       } else if (!try_ptk_iter)
                add_note(wt, MSG_DEBUG, "Failed to decrypt frame");
        os_free(decrypted);
 }
index b18b3cf36f6e715e288e05b877042f869825d418..5fde05a3f9bcbb15e8219151695dda88a00fd3d0 100644 (file)
@@ -19,6 +19,8 @@
 #include "rsn_supp/wpa_ie.h"
 #include "wlantest.h"
 
+extern int wpa_debug_level;
+
 
 static int is_zero(const u8 *buf, size_t len)
 {
@@ -157,6 +159,33 @@ static void derive_ptk(struct wlantest *wt, struct wlantest_bss *bss,
                if (try_pmk(wt, bss, sta, ver, data, len, pmk) == 0)
                        return;
        }
+
+       if (!sta->ptk_set) {
+               struct wlantest_ptk *ptk;
+               int prev_level = wpa_debug_level;
+
+               wpa_debug_level = MSG_WARNING;
+               dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
+                       if (check_mic(ptk->ptk.kck, ver, data, len) < 0)
+                               continue;
+                       wpa_printf(MSG_INFO, "Pre-set PTK matches for STA "
+                                  MACSTR " BSSID " MACSTR,
+                                  MAC2STR(sta->addr), MAC2STR(bss->bssid));
+                       add_note(wt, MSG_DEBUG, "Using pre-set PTK");
+                       os_memcpy(&sta->ptk, &ptk->ptk, sizeof(ptk->ptk));
+                       wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
+                       wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
+                       wpa_hexdump(MSG_DEBUG, "PTK:TK1", sta->ptk.tk1, 16);
+                       if (ptk->ptk_len > 48)
+                               wpa_hexdump(MSG_DEBUG, "PTK:TK2",
+                                           sta->ptk.u.tk2, 16);
+                       sta->ptk_set = 1;
+                       os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
+                       os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
+               }
+               wpa_debug_level = prev_level;
+       }
+
        add_note(wt, MSG_DEBUG, "No matching PMK found to derive PTK");
 }
 
index 3589d689bbae35464f66f27c22767722b1dcf93f..d1b550e8ca2cf69d80361e84d318120b3bd19891 100644 (file)
@@ -32,7 +32,7 @@ static void usage(void)
               "[-P<RADIUS shared secret>]\n"
               "         [-n<write pcapng file>]\n"
               "         [-w<write pcap file>] [-f<MSK/PMK file>]\n"
-              "         [-L<log file>]\n");
+              "         [-L<log file>] [-T<PTK file>]\n");
 }
 
 
@@ -63,6 +63,7 @@ static void wlantest_init(struct wlantest *wt)
        dl_list_init(&wt->secret);
        dl_list_init(&wt->radius);
        dl_list_init(&wt->pmk);
+       dl_list_init(&wt->ptk);
        dl_list_init(&wt->wep);
 }
 
@@ -74,12 +75,20 @@ void radius_deinit(struct wlantest_radius *r)
 }
 
 
+static void ptk_deinit(struct wlantest_ptk *ptk)
+{
+       dl_list_del(&ptk->list);
+       os_free(ptk);
+}
+
+
 static void wlantest_deinit(struct wlantest *wt)
 {
        struct wlantest_passphrase *p, *pn;
        struct wlantest_radius_secret *s, *sn;
        struct wlantest_radius *r, *rn;
        struct wlantest_pmk *pmk, *np;
+       struct wlantest_ptk *ptk, *npt;
        struct wlantest_wep *wep, *nw;
 
        if (wt->ctrl_sock >= 0)
@@ -97,6 +106,8 @@ static void wlantest_deinit(struct wlantest *wt)
                radius_deinit(r);
        dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list)
                pmk_deinit(pmk);
+       dl_list_for_each_safe(ptk, npt, &wt->ptk, struct wlantest_ptk, list)
+               ptk_deinit(ptk);
        dl_list_for_each_safe(wep, nw, &wt->wep, struct wlantest_wep, list)
                os_free(wep);
        write_pcap_deinit(wt);
@@ -172,6 +183,53 @@ static int add_pmk_file(struct wlantest *wt, const char *pmk_file)
 }
 
 
+static int add_ptk_file(struct wlantest *wt, const char *ptk_file)
+{
+       FILE *f;
+       u8 ptk[64];
+       size_t ptk_len;
+       char buf[300], *pos;
+       struct wlantest_ptk *p;
+
+       f = fopen(ptk_file, "r");
+       if (f == NULL) {
+               wpa_printf(MSG_ERROR, "Could not open '%s'", ptk_file);
+               return -1;
+       }
+
+       while (fgets(buf, sizeof(buf), f)) {
+               pos = buf;
+               while (*pos && *pos != '\r' && *pos != '\n')
+                       pos++;
+               *pos = '\0';
+               ptk_len = pos - buf;
+               if (ptk_len & 1)
+                       continue;
+               ptk_len /= 2;
+               if (ptk_len != 16 && ptk_len != 32 &&
+                   ptk_len != 48 && ptk_len != 64)
+                       continue;
+               if (hexstr2bin(buf, ptk, ptk_len) < 0)
+                       continue;
+               p = os_zalloc(sizeof(*p));
+               if (p == NULL)
+                       break;
+               if (ptk_len < 48) {
+                       os_memcpy(p->ptk.tk1, ptk, ptk_len);
+                       p->ptk_len = 32 + ptk_len;
+               } else {
+                       os_memcpy(&p->ptk, ptk, ptk_len);
+                       p->ptk_len = ptk_len;
+               }
+               dl_list_add(&wt->ptk, &p->list);
+               wpa_hexdump(MSG_DEBUG, "Added PTK from file", ptk, ptk_len);
+       }
+
+       fclose(f);
+       return 0;
+}
+
+
 int add_wep(struct wlantest *wt, const char *key)
 {
        struct wlantest_wep *w;
@@ -291,7 +349,7 @@ int main(int argc, char *argv[])
        wlantest_init(&wt);
 
        for (;;) {
-               c = getopt(argc, argv, "cdf:Fhi:I:L:n:p:P:qr:R:tw:W:");
+               c = getopt(argc, argv, "cdf:Fhi:I:L:n:p:P:qr:R:tT:w:W:");
                if (c < 0)
                        break;
                switch (c) {
@@ -342,6 +400,10 @@ int main(int argc, char *argv[])
                case 't':
                        wpa_debug_timestamp = 1;
                        break;
+               case 'T':
+                       if (add_ptk_file(&wt, optarg) < 0)
+                               return -1;
+                       break;
                case 'w':
                        wt.write_file = optarg;
                        break;
index 6146830e30dc55f2cb827b00fd35d9ab2ef1d485..60802d53ffd230bdf684bb5c0293547fa4707b71 100644 (file)
@@ -38,6 +38,12 @@ struct wlantest_pmk {
        u8 pmk[32];
 };
 
+struct wlantest_ptk {
+       struct dl_list list;
+       struct wpa_ptk ptk;
+       size_t ptk_len;
+};
+
 struct wlantest_wep {
        struct dl_list list;
        size_t key_len;
@@ -164,6 +170,7 @@ struct wlantest {
        struct dl_list secret; /* struct wlantest_radius_secret */
        struct dl_list radius; /* struct wlantest_radius */
        struct dl_list pmk; /* struct wlantest_pmk */
+       struct dl_list ptk; /* struct wlantest_ptk */
        struct dl_list wep; /* struct wlantest_wep */
 
        unsigned int rx_mgmt;