aboutsummaryrefslogtreecommitdiffstats
path: root/wlantest
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-11-07 17:43:10 (GMT)
committerJouni Malinen <j@w1.fi>2010-11-07 21:29:02 (GMT)
commitd06df64d14e591140ba8f0bef17947b3183a14e0 (patch)
tree783eeabde423c1b96233823398d13bd7b8b9f75f /wlantest
parent3215df77eeaf4fee01d03b1a164b1329cfdcfb52 (diff)
downloadhostap-d06df64d14e591140ba8f0bef17947b3183a14e0.zip
hostap-d06df64d14e591140ba8f0bef17947b3183a14e0.tar.gz
hostap-d06df64d14e591140ba8f0bef17947b3183a14e0.tar.bz2
wlantest: Derive PMK from RADIUS exchange
Decrypt MPPE keys and derive PMK from RADIUS exchange if RADIUS shared secret is known. Use the derived PMK when trying to derive PTK during 4-Way Handshake.
Diffstat (limited to 'wlantest')
-rw-r--r--wlantest/bss.c2
-rw-r--r--wlantest/rx_data.c56
-rw-r--r--wlantest/wired.c85
-rw-r--r--wlantest/wlantest.c51
-rw-r--r--wlantest/wlantest.h18
5 files changed, 188 insertions, 24 deletions
diff --git a/wlantest/bss.c b/wlantest/bss.c
index 156d8b3..2435dce 100644
--- a/wlantest/bss.c
+++ b/wlantest/bss.c
@@ -45,7 +45,7 @@ struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid)
}
-static void pmk_deinit(struct wlantest_pmk *pmk)
+void pmk_deinit(struct wlantest_pmk *pmk)
{
dl_list_del(&pmk->list);
os_free(pmk);
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
index 0320144..b9a12c9 100644
--- a/wlantest/rx_data.c
+++ b/wlantest/rx_data.c
@@ -110,29 +110,43 @@ static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
}
-static void derive_ptk(struct wlantest_bss *bss, struct wlantest_sta *sta,
- u16 ver, const u8 *data, size_t len)
+static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta,
+ u16 ver, const u8 *data, size_t len,
+ struct wlantest_pmk *pmk)
+{
+ struct wpa_ptk ptk;
+ size_t ptk_len = 48; /* FIX: 64 for TKIP */
+ wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
+ "Pairwise key expansion",
+ bss->bssid, sta->addr, sta->anonce, sta->snonce,
+ (u8 *) &ptk, ptk_len,
+ 0 /* FIX: SHA256 based on AKM */);
+ if (check_mic(ptk.kck, ver,
+ data, len) < 0)
+ return -1;
+
+ wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR
+ ")", MAC2STR(sta->addr), MAC2STR(bss->bssid));
+ os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
+ sta->ptk_set = 1;
+ return 0;
+}
+
+
+static void derive_ptk(struct wlantest *wt, struct wlantest_bss *bss,
+ struct wlantest_sta *sta, u16 ver,
+ const u8 *data, size_t len)
{
struct wlantest_pmk *pmk;
dl_list_for_each(pmk, &bss->pmk, struct wlantest_pmk, list) {
- struct wpa_ptk ptk;
- size_t ptk_len = 48; /* FIX: 64 for TKIP */
- wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
- "Pairwise key expansion",
- bss->bssid, sta->addr, sta->anonce, sta->snonce,
- (u8 *) &ptk, ptk_len,
- 0 /* FIX: SHA256 based on AKM */);
- if (check_mic(ptk.kck, ver,
- data, len) < 0)
- continue;
-
- wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID "
- MACSTR ")",
- MAC2STR(sta->addr), MAC2STR(bss->bssid));
- os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
- sta->ptk_set = 1;
- break;
+ if (try_pmk(bss, sta, ver, data, len, pmk) == 0)
+ return;
+ }
+
+ dl_list_for_each(pmk, &wt->pmk, struct wlantest_pmk, list) {
+ if (try_pmk(bss, sta, ver, data, len, pmk) == 0)
+ return;
}
}
@@ -159,7 +173,7 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
hdr = (const struct wpa_eapol_key *) (eapol + 1);
os_memcpy(sta->snonce, hdr->key_nonce, WPA_NONCE_LEN);
key_info = WPA_GET_BE16(hdr->key_info);
- derive_ptk(bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
+ derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
}
@@ -192,7 +206,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
}
os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN);
if (recalc) {
- derive_ptk(bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK,
+ derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK,
data, len);
}
diff --git a/wlantest/wired.c b/wlantest/wired.c
index fe64d45..bf9f163 100644
--- a/wlantest/wired.c
+++ b/wlantest/wired.c
@@ -22,6 +22,28 @@
#include "wlantest.h"
+static struct wlantest_radius * radius_get(struct wlantest *wt, u32 srv,
+ u32 cli)
+{
+ struct wlantest_radius *r;
+
+ dl_list_for_each(r, &wt->radius, struct wlantest_radius, list) {
+ if (r->srv == srv && r->cli == cli)
+ return r;
+ }
+
+ r = os_zalloc(sizeof(*r));
+ if (r == NULL)
+ return NULL;
+
+ r->srv = srv;
+ r->cli = cli;
+ dl_list_add(&wt->radius, &r->list);
+
+ return r;
+}
+
+
static const char * radius_code_string(u8 code)
{
switch (code) {
@@ -53,6 +75,7 @@ static void process_radius_access_request(struct wlantest *wt, u32 dst,
u32 src, const u8 *data, size_t len)
{
struct radius_msg *msg;
+ struct wlantest_radius *r;
msg = radius_msg_parse(data, len);
if (msg == NULL) {
@@ -60,14 +83,43 @@ static void process_radius_access_request(struct wlantest *wt, u32 dst,
return;
}
+ r = radius_get(wt, dst, src);
+ if (r) {
+ radius_msg_free(r->last_req);
+ r->last_req = msg;
+ return;
+ }
radius_msg_free(msg);
}
+static void wlantest_add_pmk(struct wlantest *wt, const u8 *pmk)
+{
+ struct wlantest_pmk *p;
+
+ p = os_zalloc(sizeof(*p));
+ if (p == NULL)
+ return;
+ os_memcpy(p->pmk, pmk, 32);
+ dl_list_add(&wt->pmk, &p->list);
+ wpa_hexdump(MSG_INFO, "Add PMK", pmk, 32);
+}
+
+
static void process_radius_access_accept(struct wlantest *wt, u32 dst, u32 src,
const u8 *data, size_t len)
{
struct radius_msg *msg;
+ struct wlantest_radius *r;
+ struct radius_ms_mppe_keys *keys;
+ struct wlantest_radius_secret *s;
+
+ r = radius_get(wt, src, dst);
+ if (r == NULL || r->last_req == NULL) {
+ wpa_printf(MSG_DEBUG, "No RADIUS Access-Challenge found for "
+ "decrypting Access-Accept keys");
+ return;
+ }
msg = radius_msg_parse(data, len);
if (msg == NULL) {
@@ -75,6 +127,39 @@ static void process_radius_access_accept(struct wlantest *wt, u32 dst, u32 src,
return;
}
+ dl_list_for_each(s, &wt->secret, struct wlantest_radius_secret, list) {
+ int found = 0;
+ keys = radius_msg_get_ms_keys(msg, r->last_req,
+ (u8 *) s->secret,
+ os_strlen(s->secret));
+ if (keys && keys->send && keys->recv) {
+ u8 pmk[32];
+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+ keys->send, keys->send_len);
+ wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+ keys->recv, keys->recv_len);
+ os_memcpy(pmk, keys->recv,
+ keys->recv_len > 32 ? 32 : keys->recv_len);
+ if (keys->recv_len < 32) {
+ os_memcpy(pmk + keys->recv_len,
+ keys->send,
+ keys->recv_len + keys->send_len > 32
+ ? 32 : 32 - keys->recv_len);
+ }
+ wlantest_add_pmk(wt, pmk);
+ found = 1;
+ }
+
+ if (keys) {
+ os_free(keys->send);
+ os_free(keys->recv);
+ os_free(keys);
+ }
+
+ if (found)
+ break;
+ }
+
radius_msg_free(msg);
}
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
index b28f43d..fc1d408 100644
--- a/wlantest/wlantest.c
+++ b/wlantest/wlantest.c
@@ -33,7 +33,8 @@ static void usage(void)
{
printf("wlantest [-ddhqq] [-i<ifname>] [-r<pcap file>] "
"[-p<passphrase>]\n"
- " [-I<wired ifname>] [-R<wired pcap file>]\n");
+ " [-I<wired ifname>] [-R<wired pcap file>] "
+ "[-P<RADIUS shared secret>]\n");
}
@@ -44,12 +45,29 @@ static void passphrase_deinit(struct wlantest_passphrase *p)
}
+static void secret_deinit(struct wlantest_radius_secret *r)
+{
+ dl_list_del(&r->list);
+ os_free(r);
+}
+
+
static void wlantest_init(struct wlantest *wt)
{
os_memset(wt, 0, sizeof(*wt));
wt->monitor_sock = -1;
dl_list_init(&wt->passphrase);
dl_list_init(&wt->bss);
+ dl_list_init(&wt->secret);
+ dl_list_init(&wt->radius);
+ dl_list_init(&wt->pmk);
+}
+
+
+void radius_deinit(struct wlantest_radius *r)
+{
+ dl_list_del(&r->list);
+ os_free(r);
}
@@ -57,6 +75,10 @@ static void wlantest_deinit(struct wlantest *wt)
{
struct wlantest_bss *bss, *n;
struct wlantest_passphrase *p, *pn;
+ struct wlantest_radius_secret *s, *sn;
+ struct wlantest_radius *r, *rn;
+ struct wlantest_pmk *pmk, *np;
+
if (wt->monitor_sock >= 0)
monitor_deinit(wt);
dl_list_for_each_safe(bss, n, &wt->bss, struct wlantest_bss, list)
@@ -64,6 +86,13 @@ static void wlantest_deinit(struct wlantest *wt)
dl_list_for_each_safe(p, pn, &wt->passphrase,
struct wlantest_passphrase, list)
passphrase_deinit(p);
+ dl_list_for_each_safe(s, sn, &wt->secret,
+ struct wlantest_radius_secret, list)
+ secret_deinit(s);
+ dl_list_for_each_safe(r, rn, &wt->radius, struct wlantest_radius, list)
+ radius_deinit(r);
+ dl_list_for_each_safe(pmk, np, &wt->pmk, struct wlantest_pmk, list)
+ pmk_deinit(pmk);
}
@@ -82,6 +111,21 @@ static void add_passphrase(struct wlantest *wt, const char *passphrase)
}
+static void add_secret(struct wlantest *wt, const char *secret)
+{
+ struct wlantest_radius_secret *s;
+ size_t len = os_strlen(secret);
+
+ if (len >= MAX_RADIUS_SECRET_LEN)
+ return;
+ s = os_zalloc(sizeof(*s));
+ if (s == NULL)
+ return;
+ os_memcpy(s->secret, secret, len);
+ dl_list_add(&wt->secret, &s->list);
+}
+
+
int main(int argc, char *argv[])
{
int c;
@@ -100,7 +144,7 @@ int main(int argc, char *argv[])
wlantest_init(&wt);
for (;;) {
- c = getopt(argc, argv, "dhi:I:p:qr:R:");
+ c = getopt(argc, argv, "dhi:I:p:P:qr:R:");
if (c < 0)
break;
switch (c) {
@@ -120,6 +164,9 @@ int main(int argc, char *argv[])
case 'p':
add_passphrase(&wt, optarg);
break;
+ case 'P':
+ add_secret(&wt, optarg);
+ break;
case 'q':
wpa_debug_level++;
break;
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index 203044a..71eea52 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -19,7 +19,14 @@
#include "common/wpa_common.h"
struct ieee802_11_elems;
+struct radius_msg;
+#define MAX_RADIUS_SECRET_LEN 128
+
+struct wlantest_radius_secret {
+ struct dl_list list;
+ char secret[MAX_RADIUS_SECRET_LEN];
+};
struct wlantest_passphrase {
struct dl_list list;
@@ -64,12 +71,22 @@ struct wlantest_bss {
struct dl_list pmk; /* struct wlantest_pmk */
};
+struct wlantest_radius {
+ struct dl_list list;
+ u32 srv;
+ u32 cli;
+ struct radius_msg *last_req;
+};
+
struct wlantest {
int monitor_sock;
int monitor_wired;
struct dl_list passphrase; /* struct wlantest_passphrase */
struct dl_list bss; /* struct wlantest_bss */
+ struct dl_list secret; /* struct wlantest_radius_secret */
+ struct dl_list radius; /* struct wlantest_radius */
+ struct dl_list pmk; /* struct wlantest_pmk */
unsigned int rx_mgmt;
unsigned int rx_ctrl;
@@ -92,6 +109,7 @@ struct wlantest_bss * bss_get(struct wlantest *wt, const u8 *bssid);
void bss_deinit(struct wlantest_bss *bss);
void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
struct ieee802_11_elems *elems);
+void pmk_deinit(struct wlantest_pmk *pmk);
struct wlantest_sta * sta_get(struct wlantest_bss *bss, const u8 *addr);
void sta_deinit(struct wlantest_sta *sta);