/*
* Received Data frame processing for EAPOL messages
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
}
-static int check_mic(const u8 *kck, int ver, const u8 *data, size_t len)
+static int check_mic(const u8 *kck, size_t kck_len, int akmp, int ver,
+ const u8 *data, size_t len)
{
u8 *buf;
int ret = -1;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- u8 rx_mic[16];
+ u8 rx_mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = wpa_mic_len(akmp, PMK_LEN);
- buf = os_malloc(len);
+ buf = os_memdup(data, len);
if (buf == NULL)
return -1;
- os_memcpy(buf, data, len);
hdr = (struct ieee802_1x_hdr *) buf;
key = (struct wpa_eapol_key *) (hdr + 1);
- os_memcpy(rx_mic, key->key_mic, 16);
- os_memset(key->key_mic, 0, 16);
+ os_memcpy(rx_mic, key + 1, mic_len);
+ os_memset(key + 1, 0, mic_len);
- if (wpa_eapol_key_mic(kck, ver, buf, len, key->key_mic) == 0 &&
- os_memcmp(rx_mic, key->key_mic, 16) == 0)
+ if (wpa_eapol_key_mic(kck, kck_len, akmp, ver, buf, len,
+ (u8 *) (key + 1)) == 0 &&
+ os_memcmp(rx_mic, key + 1, mic_len) == 0)
ret = 0;
os_free(buf);
struct wlantest_pmk *pmk)
{
struct wpa_ptk ptk;
- size_t ptk_len = sta->pairwise_cipher == WPA_CIPHER_TKIP ? 64 : 48;
- wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk),
- "Pairwise key expansion",
- bss->bssid, sta->addr, sta->anonce, sta->snonce,
- (u8 *) &ptk, ptk_len,
- wpa_key_mgmt_sha256(sta->key_mgmt));
- if (check_mic(ptk.kck, ver, data, len) < 0)
+
+ if (wpa_key_mgmt_ft(sta->key_mgmt)) {
+ u8 pmk_r1[PMK_LEN];
+ u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+ u8 ptk_name[WPA_PMK_NAME_LEN];
+
+ if (wpa_derive_pmk_r0(pmk->pmk, PMK_LEN,
+ bss->ssid, bss->ssid_len, bss->mdid,
+ bss->r0kh_id, bss->r0kh_id_len,
+ sta->addr, sta->pmk_r0, sta->pmk_r0_name,
+ 0) < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "FT: PMK-R0", sta->pmk_r0, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", sta->pmk_r0_name,
+ WPA_PMK_NAME_LEN);
+ if (wpa_derive_pmk_r1(sta->pmk_r0, PMK_LEN, sta->pmk_r0_name,
+ bss->r1kh_id, sta->addr,
+ pmk_r1, pmk_r1_name) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+ wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(pmk_r1, PMK_LEN, sta->snonce, sta->anonce,
+ sta->addr,
+ bss->bssid, pmk_r1_name, &ptk, ptk_name,
+ sta->key_mgmt,
+ sta->pairwise_cipher) < 0 ||
+ check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
+ len) < 0)
+ return -1;
+ } else if (wpa_pmk_to_ptk(pmk->pmk, PMK_LEN,
+ "Pairwise key expansion",
+ bss->bssid, sta->addr, sta->anonce,
+ sta->snonce, &ptk, sta->key_mgmt,
+ sta->pairwise_cipher, NULL, 0) < 0 ||
+ check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
+ len) < 0) {
return -1;
+ }
wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR,
MAC2STR(sta->addr), MAC2STR(bss->bssid));
*/
add_note(wt, MSG_DEBUG, "Derived PTK during rekeying");
os_memcpy(&sta->tptk, &ptk, sizeof(ptk));
- wpa_hexdump(MSG_DEBUG, "TPTK:KCK", sta->tptk.kck, 16);
- wpa_hexdump(MSG_DEBUG, "TPTK:KEK", sta->tptk.kek, 16);
- wpa_hexdump(MSG_DEBUG, "TPTK:TK1", sta->tptk.tk1, 16);
- if (ptk_len > 48)
- wpa_hexdump(MSG_DEBUG, "TPTK:TK2", sta->tptk.u.tk2,
- 16);
+ wpa_hexdump(MSG_DEBUG, "TPTK:KCK",
+ sta->tptk.kck, sta->tptk.kck_len);
+ wpa_hexdump(MSG_DEBUG, "TPTK:KEK",
+ sta->tptk.kek, sta->tptk.kek_len);
+ wpa_hexdump(MSG_DEBUG, "TPTK:TK",
+ sta->tptk.tk, sta->tptk.tk_len);
sta->tptk_set = 1;
return 0;
}
add_note(wt, MSG_DEBUG, "Derived new PTK");
os_memcpy(&sta->ptk, &ptk, sizeof(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_len > 48)
- wpa_hexdump(MSG_DEBUG, "PTK:TK2", sta->ptk.u.tk2, 16);
+ wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, sta->ptk.kck_len);
+ wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, sta->ptk.kek_len);
+ wpa_hexdump(MSG_DEBUG, "PTK:TK", sta->ptk.tk, sta->ptk.tk_len);
sta->ptk_set = 1;
os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
{
struct wlantest_pmk *pmk;
- wpa_printf(MSG_DEBUG, "Trying to derive PTK for " MACSTR,
- MAC2STR(sta->addr));
+ wpa_printf(MSG_DEBUG, "Trying to derive PTK for " MACSTR " (ver %u)",
+ MAC2STR(sta->addr), ver);
dl_list_for_each(pmk, &bss->pmk, struct wlantest_pmk, list) {
wpa_printf(MSG_DEBUG, "Try per-BSS PMK");
if (try_pmk(wt, bss, sta, ver, data, len, pmk) == 0)
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)
+ if (check_mic(ptk->ptk.kck, ptk->ptk.kck_len,
+ sta->key_mgmt, 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");
+ ptk->ptk_len = 32 +
+ wpa_cipher_key_len(sta->pairwise_cipher);
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);
+ wpa_hexdump(MSG_DEBUG, "PTK:KCK",
+ sta->ptk.kck, sta->ptk.kck_len);
+ wpa_hexdump(MSG_DEBUG, "PTK:KEK",
+ sta->ptk.kek, sta->ptk.kek_len);
+ wpa_hexdump(MSG_DEBUG, "PTK:TK",
+ sta->ptk.tk, sta->ptk.tk_len);
sta->ptk_set = 1;
os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
}
+static void elems_from_eapol_ie(struct ieee802_11_elems *elems,
+ struct wpa_eapol_ie_parse *ie)
+{
+ os_memset(elems, 0, sizeof(*elems));
+ if (ie->wpa_ie) {
+ elems->wpa_ie = ie->wpa_ie + 2;
+ elems->wpa_ie_len = ie->wpa_ie_len - 2;
+ }
+ if (ie->rsn_ie) {
+ elems->rsn_ie = ie->rsn_ie + 2;
+ elems->rsn_ie_len = ie->rsn_ie_len - 2;
+ }
+ if (ie->osen) {
+ elems->osen = ie->osen + 2;
+ elems->osen_len = ie->osen_len - 2;
+ }
+}
+
+
static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
const u8 *src, const u8 *data, size_t len)
{
struct wlantest_sta *sta;
const struct ieee802_1x_hdr *eapol;
const struct wpa_eapol_key *hdr;
- const u8 *key_data, *kck;
+ const u8 *key_data, *kck, *mic;
+ size_t kck_len, mic_len;
u16 key_info, key_data_len;
struct wpa_eapol_ie_parse ie;
eapol = (const struct ieee802_1x_hdr *) data;
hdr = (const struct wpa_eapol_key *) (eapol + 1);
+ mic_len = wpa_mic_len(sta->key_mgmt, PMK_LEN);
+ mic = (const u8 *) (hdr + 1);
if (is_zero(hdr->key_nonce, WPA_NONCE_LEN)) {
add_note(wt, MSG_INFO, "EAPOL-Key 2/4 from " MACSTR
" used zero nonce", MAC2STR(src));
}
os_memcpy(sta->snonce, hdr->key_nonce, WPA_NONCE_LEN);
key_info = WPA_GET_BE16(hdr->key_info);
- key_data_len = WPA_GET_BE16(hdr->key_data_length);
+ key_data = mic + mic_len + 2;
+ key_data_len = WPA_GET_BE16(mic + mic_len);
+
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) {
+ add_note(wt, MSG_INFO, "Failed to parse EAPOL-Key Key Data");
+ return;
+ }
+
+ if (!sta->assocreq_seen) {
+ struct ieee802_11_elems elems;
+
+ elems_from_eapol_ie(&elems, &ie);
+ wpa_printf(MSG_DEBUG,
+ "Update STA data based on IEs in EAPOL-Key 2/4");
+ sta_update_assoc(sta, &elems);
+ }
+
derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
if (!sta->ptk_set && !sta->tptk_set) {
}
kck = sta->ptk.kck;
+ kck_len = sta->ptk.kck_len;
if (sta->tptk_set) {
add_note(wt, MSG_DEBUG,
"Use TPTK for validation EAPOL-Key MIC");
kck = sta->tptk.kck;
+ kck_len = sta->tptk.kck_len;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, kck_len, sta->key_mgmt,
+ key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
return;
}
add_note(wt, MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/4");
- key_data = (const u8 *) (hdr + 1);
-
- if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) {
- add_note(wt, MSG_INFO, "Failed to parse EAPOL-Key Key Data");
- return;
- }
-
if (ie.wpa_ie) {
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE",
ie.wpa_ie, ie.wpa_ie_len);
if (os_memcmp(ie.wpa_ie, sta->rsnie, ie.wpa_ie_len) != 0) {
- struct ieee802_11_elems elems;
add_note(wt, MSG_INFO,
"Mismatch in WPA IE between EAPOL-Key 2/4 "
"and (Re)Association Request from " MACSTR,
"Request",
sta->rsnie,
sta->rsnie[0] ? 2 + sta->rsnie[1] : 0);
- /*
- * The sniffer may have missed (Re)Association
- * Request, so try to survive with the information from
- * EAPOL-Key.
- */
- os_memset(&elems, 0, sizeof(elems));
- elems.wpa_ie = ie.wpa_ie + 2;
- elems.wpa_ie_len = ie.wpa_ie_len - 2;
- wpa_printf(MSG_DEBUG, "Update STA data based on WPA "
- "IE in EAPOL-Key 2/4");
- sta_update_assoc(sta, &elems);
}
}
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE",
ie.rsn_ie, ie.rsn_ie_len);
if (os_memcmp(ie.rsn_ie, sta->rsnie, ie.rsn_ie_len) != 0) {
- struct ieee802_11_elems elems;
add_note(wt, MSG_INFO,
"Mismatch in RSN IE between EAPOL-Key 2/4 "
"and (Re)Association Request from " MACSTR,
"Request",
sta->rsnie,
sta->rsnie[0] ? 2 + sta->rsnie[1] : 0);
- /*
- * The sniffer may have missed (Re)Association
- * Request, so try to survive with the information from
- * EAPOL-Key.
- */
- os_memset(&elems, 0, sizeof(elems));
- elems.rsn_ie = ie.rsn_ie + 2;
- elems.rsn_ie_len = ie.rsn_ie_len - 2;
- wpa_printf(MSG_DEBUG, "Update STA data based on RSN "
- "IE in EAPOL-Key 2/4");
- sta_update_assoc(sta, &elems);
}
}
}
static u8 * decrypt_eapol_key_data_rc4(struct wlantest *wt, const u8 *kek,
const struct wpa_eapol_key *hdr,
+ const u8 *keydata, u16 keydatalen,
size_t *len)
{
u8 ek[32], *buf;
- u16 keydatalen = WPA_GET_BE16(hdr->key_data_length);
- buf = os_malloc(keydatalen);
+ buf = os_memdup(keydata, keydatalen);
if (buf == NULL)
return NULL;
os_memcpy(ek, hdr->key_iv, 16);
os_memcpy(ek + 16, kek, 16);
- os_memcpy(buf, hdr + 1, keydatalen);
if (rc4_skip(ek, 32, 256, buf, keydatalen)) {
add_note(wt, MSG_INFO, "RC4 failed");
os_free(buf);
static u8 * decrypt_eapol_key_data_aes(struct wlantest *wt, const u8 *kek,
const struct wpa_eapol_key *hdr,
+ const u8 *keydata, u16 keydatalen,
size_t *len)
{
u8 *buf;
- u16 keydatalen = WPA_GET_BE16(hdr->key_data_length);
if (keydatalen % 8) {
add_note(wt, MSG_INFO, "Unsupported AES-WRAP len %d",
buf = os_malloc(keydatalen);
if (buf == NULL)
return NULL;
- if (aes_unwrap(kek, keydatalen / 8, (u8 *) (hdr + 1), buf)) {
+ if (aes_unwrap(kek, 16, keydatalen / 8, keydata, buf)) {
os_free(buf);
add_note(wt, MSG_INFO,
"AES unwrap failed - could not decrypt EAPOL-Key "
}
-static u8 * decrypt_eapol_key_data(struct wlantest *wt, const u8 *kek, u16 ver,
+static u8 * decrypt_eapol_key_data(struct wlantest *wt, int akmp, const u8 *kek,
+ size_t kek_len, u16 ver,
const struct wpa_eapol_key *hdr,
size_t *len)
{
+ size_t mic_len;
+ u16 keydatalen;
+ const u8 *mic, *keydata;
+
+ if (kek_len != 16)
+ return NULL;
+
+ mic = (const u8 *) (hdr + 1);
+ mic_len = wpa_mic_len(akmp, PMK_LEN);
+ keydata = mic + mic_len + 2;
+ keydatalen = WPA_GET_BE16(mic + mic_len);
+
switch (ver) {
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
- return decrypt_eapol_key_data_rc4(wt, kek, hdr, len);
+ return decrypt_eapol_key_data_rc4(wt, kek, hdr, keydata,
+ keydatalen, len);
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
- return decrypt_eapol_key_data_aes(wt, kek, hdr, len);
+ return decrypt_eapol_key_data_aes(wt, kek, hdr, keydata,
+ keydatalen, len);
+ case WPA_KEY_INFO_TYPE_AKM_DEFINED:
+ /* For now, assume this is OSEN */
+ return decrypt_eapol_key_data_aes(wt, kek, hdr, keydata,
+ keydatalen, len);
default:
add_note(wt, MSG_INFO,
"Unsupported EAPOL-Key Key Descriptor Version %u",
ie.rsn_ie, ie.rsn_ie_len);
}
+ if (ie.key_id)
+ add_note(wt, MSG_DEBUG, "KeyID %u", ie.key_id[0]);
+
if (ie.gtk) {
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - GTK KDE",
ie.gtk, ie.gtk_len);
wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8,
16);
os_memcpy(bss->igtk[id], ie.igtk + 8, 16);
- bss->igtk_set[id] = 1;
+ bss->igtk_len[id] = 16;
+ ipn = ie.igtk + 2;
+ bss->ipn[id][0] = ipn[5];
+ bss->ipn[id][1] = ipn[4];
+ bss->ipn[id][2] = ipn[3];
+ bss->ipn[id][3] = ipn[2];
+ bss->ipn[id][4] = ipn[1];
+ bss->ipn[id][5] = ipn[0];
+ bss->igtk_idx = id;
+ }
+ } else if (ie.igtk_len == 40) {
+ u16 id;
+ id = WPA_GET_LE16(ie.igtk);
+ if (id > 5) {
+ add_note(wt, MSG_INFO,
+ "Unexpected IGTK KeyID %u", id);
+ } else {
+ const u8 *ipn;
+ add_note(wt, MSG_DEBUG, "IGTK KeyID %u", id);
+ wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6);
+ wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8,
+ 32);
+ os_memcpy(bss->igtk[id], ie.igtk + 8, 32);
+ bss->igtk_len[id] = 32;
ipn = ie.igtk + 2;
bss->ipn[id][0] = ipn[5];
bss->ipn[id][1] = ipn[4];
(unsigned) ie.igtk_len);
}
}
+
+ if (ie.bigtk) {
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - BIGTK KDE",
+ ie.bigtk, ie.bigtk_len);
+ if (ie.bigtk_len == 24) {
+ u16 id;
+
+ id = WPA_GET_LE16(ie.bigtk);
+ if (id < 6 || id > 7) {
+ add_note(wt, MSG_INFO,
+ "Unexpected BIGTK KeyID %u", id);
+ } else {
+ const u8 *ipn;
+
+ add_note(wt, MSG_DEBUG, "BIGTK KeyID %u", id);
+ wpa_hexdump(MSG_DEBUG, "BIPN", ie.bigtk + 2, 6);
+ wpa_hexdump(MSG_DEBUG, "BIGTK", ie.bigtk + 8,
+ 16);
+ os_memcpy(bss->igtk[id], ie.bigtk + 8, 16);
+ bss->igtk_len[id] = 16;
+ ipn = ie.bigtk + 2;
+ bss->ipn[id][0] = ipn[5];
+ bss->ipn[id][1] = ipn[4];
+ bss->ipn[id][2] = ipn[3];
+ bss->ipn[id][3] = ipn[2];
+ bss->ipn[id][4] = ipn[1];
+ bss->ipn[id][5] = ipn[0];
+ bss->bigtk_idx = id;
+ }
+ } else if (ie.bigtk_len == 40) {
+ u16 id;
+
+ id = WPA_GET_LE16(ie.bigtk);
+ if (id < 6 || id > 7) {
+ add_note(wt, MSG_INFO,
+ "Unexpected BIGTK KeyID %u", id);
+ } else {
+ const u8 *ipn;
+
+ add_note(wt, MSG_DEBUG, "BIGTK KeyID %u", id);
+ wpa_hexdump(MSG_DEBUG, "BIPN", ie.bigtk + 2, 6);
+ wpa_hexdump(MSG_DEBUG, "BIGTK", ie.bigtk + 8,
+ 32);
+ os_memcpy(bss->igtk[id], ie.bigtk + 8, 32);
+ bss->igtk_len[id] = 32;
+ ipn = ie.bigtk + 2;
+ bss->ipn[id][0] = ipn[5];
+ bss->ipn[id][1] = ipn[4];
+ bss->ipn[id][2] = ipn[3];
+ bss->ipn[id][3] = ipn[2];
+ bss->ipn[id][4] = ipn[1];
+ bss->ipn[id][5] = ipn[0];
+ bss->bigtk_idx = id;
+ }
+ } else {
+ add_note(wt, MSG_INFO, "Invalid BIGTK KDE length %u",
+ (unsigned) ie.bigtk_len);
+ }
+ }
}
struct wlantest_sta *sta;
const struct ieee802_1x_hdr *eapol;
const struct wpa_eapol_key *hdr;
- const u8 *key_data, *kck, *kek;
+ const u8 *key_data, *kck, *kek, *mic;
+ size_t kck_len, kek_len, mic_len;
int recalc = 0;
u16 key_info, ver;
u8 *decrypted_buf = NULL;
sta = sta_get(bss, dst);
if (sta == NULL)
return;
+ mic_len = wpa_mic_len(sta->key_mgmt, PMK_LEN);
eapol = (const struct ieee802_1x_hdr *) data;
hdr = (const struct wpa_eapol_key *) (eapol + 1);
+ mic = (const u8 *) (hdr + 1);
key_info = WPA_GET_BE16(hdr->key_info);
if (os_memcmp(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN) != 0) {
}
kek = sta->ptk.kek;
+ kek_len = sta->ptk.kek_len;
kck = sta->ptk.kck;
+ kck_len = sta->ptk.kck_len;
if (sta->tptk_set) {
add_note(wt, MSG_DEBUG,
"Use TPTK for validation EAPOL-Key MIC");
kck = sta->tptk.kck;
+ kck_len = sta->tptk.kck_len;
kek = sta->tptk.kek;
+ kek_len = sta->tptk.kek_len;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, kck_len, sta->key_mgmt,
+ key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
return;
}
add_note(wt, MSG_DEBUG, "Valid MIC found in EAPOL-Key 3/4");
- key_data = (const u8 *) (hdr + 1);
+ key_data = mic + mic_len + 2;
if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
if (sta->proto & WPA_PROTO_RSN)
add_note(wt, MSG_INFO,
"EAPOL-Key 3/4 without EncrKeyData bit");
decrypted = key_data;
- decrypted_len = WPA_GET_BE16(hdr->key_data_length);
+ decrypted_len = WPA_GET_BE16(mic + mic_len);
} else {
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
- decrypted_buf = decrypt_eapol_key_data(wt, kek, ver, hdr,
- &decrypted_len);
+ decrypted_buf = decrypt_eapol_key_data(wt, sta->key_mgmt,
+ kek, kek_len, ver,
+ hdr, &decrypted_len);
if (decrypted_buf == NULL) {
add_note(wt, MSG_INFO,
"Failed to decrypt EAPOL-Key Key Data");
wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
decrypted, decrypted_len);
}
- if (wt->write_pcap_dumper && decrypted != key_data) {
+ if ((wt->write_pcap_dumper || wt->pcapng) && decrypted != key_data) {
/* Fill in a dummy Data frame header */
- u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr)];
+ u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr) + 64];
struct ieee80211_hdr *h;
struct wpa_eapol_key *k;
const u8 *p;
if (p[0] == 0xdd && p[1] == 0x00) {
/* Remove padding */
plain_len = p - decrypted;
+ p = NULL;
break;
}
p += 2 + p[1];
}
+ if (p && p > decrypted && *p == 0xdd &&
+ p + 1 == decrypted + decrypted_len) {
+ /* Remove padding */
+ p--;
+ plain_len = p - decrypted;
+ }
os_memset(buf, 0, sizeof(buf));
h = (struct ieee80211_hdr *) buf;
pos += 8;
os_memcpy(pos, eapol, sizeof(*eapol));
pos += sizeof(*eapol);
- os_memcpy(pos, hdr, sizeof(*hdr));
+ os_memcpy(pos, hdr, sizeof(*hdr) + mic_len);
k = (struct wpa_eapol_key *) pos;
+ pos += sizeof(struct wpa_eapol_key) + mic_len;
WPA_PUT_BE16(k->key_info,
key_info & ~WPA_KEY_INFO_ENCR_KEY_DATA);
- WPA_PUT_BE16(k->key_data_length, plain_len);
- write_pcap_decrypted(wt, buf, sizeof(buf),
+ WPA_PUT_BE16(pos, plain_len);
+ write_pcap_decrypted(wt, buf, 24 + 8 + sizeof(*eapol) +
+ sizeof(*hdr) + mic_len + 2,
decrypted, plain_len);
}
return;
}
+ if (!bss->ies_set) {
+ struct ieee802_11_elems elems;
+
+ elems_from_eapol_ie(&elems, &ie);
+ wpa_printf(MSG_DEBUG,
+ "Update BSS data based on IEs in EAPOL-Key 3/4");
+ bss_update(wt, bss, &elems, 0);
+ }
+
if ((ie.wpa_ie &&
os_memcmp(ie.wpa_ie, bss->wpaie, ie.wpa_ie_len) != 0) ||
(ie.wpa_ie == NULL && bss->wpaie[0])) {
MAC2STR(bss->bssid));
wpa_hexdump(MSG_INFO, "RSN IE in EAPOL-Key",
ie.rsn_ie, ie.rsn_ie_len);
- wpa_hexdump(MSG_INFO, "RSN IE in (Re)Association "
- "Request",
+ wpa_hexdump(MSG_INFO, "RSN IE in Beacon/Probe Response",
bss->rsnie,
bss->rsnie[0] ? 2 + bss->rsnie[1] : 0);
}
const struct wpa_eapol_key *hdr;
u16 key_info;
const u8 *kck;
+ size_t kck_len;
wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
MAC2STR(src), MAC2STR(dst));
}
kck = sta->ptk.kck;
+ kck_len = sta->ptk.kck_len;
if (sta->tptk_set) {
add_note(wt, MSG_DEBUG,
"Use TPTK for validation EAPOL-Key MIC");
kck = sta->tptk.kck;
+ kck_len = sta->tptk.kck_len;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, kck_len, sta->key_mgmt,
+ key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC");
return;
}
u16 key_info, ver;
u8 *decrypted;
size_t decrypted_len = 0;
+ size_t mic_len;
wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
MAC2STR(src), MAC2STR(dst));
sta = sta_get(bss, dst);
if (sta == NULL)
return;
+ mic_len = wpa_mic_len(sta->key_mgmt, PMK_LEN);
eapol = (const struct ieee802_1x_hdr *) data;
hdr = (const struct wpa_eapol_key *) (eapol + 1);
}
if (sta->ptk_set &&
- check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ check_mic(sta->ptk.kck, sta->ptk.kck_len, sta->key_mgmt,
+ key_info & WPA_KEY_INFO_TYPE_MASK,
data, len) < 0) {
add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 1/2 MIC");
return;
return;
}
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
- decrypted = decrypt_eapol_key_data(wt, sta->ptk.kek, ver, hdr,
- &decrypted_len);
+ decrypted = decrypt_eapol_key_data(wt, sta->key_mgmt,
+ sta->ptk.kek, sta->ptk.kek_len,
+ ver, hdr, &decrypted_len);
if (decrypted == NULL) {
add_note(wt, MSG_INFO, "Failed to decrypt EAPOL-Key Key Data");
return;
}
wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
decrypted, decrypted_len);
- if (wt->write_pcap_dumper) {
+ if (wt->write_pcap_dumper || wt->pcapng) {
/* Fill in a dummy Data frame header */
- u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr)];
+ u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr) + 64];
struct ieee80211_hdr *h;
struct wpa_eapol_key *k;
u8 *pos;
pos += 8;
os_memcpy(pos, eapol, sizeof(*eapol));
pos += sizeof(*eapol);
- os_memcpy(pos, hdr, sizeof(*hdr));
+ os_memcpy(pos, hdr, sizeof(*hdr) + mic_len);
k = (struct wpa_eapol_key *) pos;
+ pos += sizeof(struct wpa_eapol_key) + mic_len;
WPA_PUT_BE16(k->key_info,
key_info & ~WPA_KEY_INFO_ENCR_KEY_DATA);
- WPA_PUT_BE16(k->key_data_length, plain_len);
- write_pcap_decrypted(wt, buf, sizeof(buf),
+ WPA_PUT_BE16(pos, plain_len);
+ write_pcap_decrypted(wt, buf, 24 + 8 + sizeof(*eapol) +
+ sizeof(*hdr) + mic_len + 2,
decrypted, plain_len);
}
if (sta->proto & WPA_PROTO_RSN)
}
if (sta->ptk_set &&
- check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ check_mic(sta->ptk.kck, sta->ptk.kck_len, sta->key_mgmt,
+ key_info & WPA_KEY_INFO_TYPE_MASK,
data, len) < 0) {
add_note(wt, MSG_INFO, "Mismatch in EAPOL-Key 2/2 MIC");
return;
}
-static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
+static void rx_data_eapol_key(struct wlantest *wt, const u8 *bssid,
+ const u8 *sta_addr, const u8 *dst,
const u8 *src, const u8 *data, size_t len,
int prot)
{
const struct wpa_eapol_key *hdr;
const u8 *key_data;
u16 key_info, key_length, ver, key_data_length;
+ size_t mic_len = 16;
+ const u8 *mic;
+ struct wlantest_bss *bss;
+ struct wlantest_sta *sta;
+
+ bss = bss_get(wt, bssid);
+ if (bss) {
+ sta = sta_get(bss, sta_addr);
+ if (sta)
+ mic_len = wpa_mic_len(sta->key_mgmt, PMK_LEN);
+ }
eapol = (const struct ieee802_1x_hdr *) data;
hdr = (const struct wpa_eapol_key *) (eapol + 1);
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key",
(const u8 *) hdr, len - sizeof(*eapol));
- if (len < sizeof(*hdr)) {
+ if (len < sizeof(*hdr) + mic_len + 2) {
add_note(wt, MSG_INFO, "Too short EAPOL-Key frame from " MACSTR,
MAC2STR(src));
return;
}
+ mic = (const u8 *) (hdr + 1);
if (hdr->type == EAPOL_KEY_TYPE_RC4) {
/* TODO: EAPOL-Key RC4 for WEP */
key_info = WPA_GET_BE16(hdr->key_info);
key_length = WPA_GET_BE16(hdr->key_length);
- key_data_length = WPA_GET_BE16(hdr->key_data_length);
- key_data = (const u8 *) (hdr + 1);
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ key_data = mic + mic_len + 2;
if (key_data + key_data_length > data + len) {
add_note(wt, MSG_INFO, "Truncated EAPOL-Key from " MACSTR,
MAC2STR(src));
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
- ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
wpa_printf(MSG_INFO, "Unsupported EAPOL-Key Key Descriptor "
"Version %u from " MACSTR, ver, MAC2STR(src));
return;
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC",
hdr->key_rsc, WPA_KEY_RSC_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC",
- hdr->key_mic, 16);
+ mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data",
key_data, key_data_length);
break;
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
+ case WPA_KEY_INFO_SECURE |
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
break;
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+ case WPA_KEY_INFO_SECURE:
if (key_data_length == 0)
rx_data_eapol_key_4_of_4(wt, dst, src, data,
len);
WPA_KEY_INFO_ACK)) {
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK:
+ case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ACK:
rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
break;
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+ case WPA_KEY_INFO_SECURE:
rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
break;
default:
}
-void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
+void rx_data_eapol(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
+ const u8 *dst, const u8 *src,
const u8 *data, size_t len, int prot)
{
const struct ieee802_1x_hdr *hdr;
wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
break;
case IEEE802_1X_TYPE_EAPOL_KEY:
- rx_data_eapol_key(wt, dst, src, data, sizeof(*hdr) + length,
- prot);
+ rx_data_eapol_key(wt, bssid, sta_addr, dst, src, data,
+ sizeof(*hdr) + length, prot);
break;
case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",