diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index 9d439be88..eaa2b8691 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -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); } diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c index b18b3cf36..5fde05a3f 100644 --- a/wlantest/rx_eapol.c +++ b/wlantest/rx_eapol.c @@ -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"); } diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c index 3589d689b..d1b550e8c 100644 --- a/wlantest/wlantest.c +++ b/wlantest/wlantest.c @@ -32,7 +32,7 @@ static void usage(void) "[-P]\n" " [-n]\n" " [-w] [-f]\n" - " [-L]\n"); + " [-L] [-T]\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; diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 6146830e3..60802d53f 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -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;