/*
* Received Management frame processing
- * 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.
#include "utils/includes.h"
#include "utils/common.h"
+#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "crypto/aes_wrap.h"
const struct ieee80211_mgmt *mgmt;
struct wlantest_bss *bss;
struct ieee802_11_elems elems;
+ size_t offset;
mgmt = (const struct ieee80211_mgmt *) data;
+ offset = mgmt->u.beacon.variable - data;
+ if (len < offset)
+ return;
bss = bss_get(wt, mgmt->bssid);
if (bss == NULL)
return;
if (bss->proberesp_seen)
return; /* do not override with Beacon data */
bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
- if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
- len - (mgmt->u.beacon.variable - data),
+ if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - offset,
&elems, 0) == ParseFailed) {
if (bss->parse_error_reported)
return;
const struct ieee80211_mgmt *mgmt;
struct wlantest_bss *bss;
struct ieee802_11_elems elems;
+ size_t offset;
mgmt = (const struct ieee80211_mgmt *) data;
+ offset = mgmt->u.probe_resp.variable - data;
+ if (len < offset)
+ return;
bss = bss_get(wt, mgmt->bssid);
if (bss == NULL)
return;
bss->counters[WLANTEST_BSS_COUNTER_PROBE_RESPONSE]++;
bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
- if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
- len - (mgmt->u.probe_resp.variable - data),
+ if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - offset,
&elems, 0) == ParseFailed) {
if (bss->parse_error_reported)
return;
struct wlantest_bss *bss;
struct wlantest_sta *sta;
u16 capab, status, aid;
+ const u8 *ies;
+ size_t ies_len;
+ struct wpa_ft_ies parse;
mgmt = (const struct ieee80211_mgmt *) data;
bss = bss_get(wt, mgmt->bssid);
return;
}
+ ies = mgmt->u.assoc_resp.variable;
+ ies_len = len - (mgmt->u.assoc_resp.variable - data);
+
capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
status = le_to_host16(mgmt->u.assoc_resp.status_code);
aid = le_to_host16(mgmt->u.assoc_resp.aid);
if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
struct ieee802_11_elems elems;
- const u8 *ies = mgmt->u.assoc_resp.variable;
- size_t ies_len = len - (mgmt->u.assoc_resp.variable - data);
if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
ParseFailed) {
add_note(wt, MSG_INFO, "Failed to parse IEs in "
"AssocResp from " MACSTR,
MAC2STR(mgmt->sa));
} else if (elems.timeout_int == NULL ||
- elems.timeout_int_len != 5 ||
elems.timeout_int[0] !=
WLAN_TIMEOUT_ASSOC_COMEBACK) {
add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
MAC2STR(sta->addr), MAC2STR(bss->bssid));
sta->state = STATE3;
}
+
+ if (wpa_ft_parse_ies(ies, ies_len, &parse) == 0) {
+ if (parse.r0kh_id) {
+ os_memcpy(bss->r0kh_id, parse.r0kh_id,
+ parse.r0kh_id_len);
+ bss->r0kh_id_len = parse.r0kh_id_len;
+ }
+ if (parse.r1kh_id)
+ os_memcpy(bss->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
+ }
}
"ReassocResp from " MACSTR,
MAC2STR(mgmt->sa));
} else if (elems.timeout_int == NULL ||
- elems.timeout_int_len != 5 ||
elems.timeout_int[0] !=
WLAN_TIMEOUT_ASSOC_COMEBACK) {
add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
}
-static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
+static int check_mmie_mic(unsigned int mgmt_group_cipher,
+ const u8 *igtk, size_t igtk_len,
+ const u8 *data, size_t len)
{
u8 *buf;
u8 mic[16];
u16 fc;
const struct ieee80211_hdr *hdr;
+ int ret, mic_len;
+
+ if (!mgmt_group_cipher || igtk_len < 16)
+ return -1;
+ mic_len = mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
+
+ if (len < 24 || len - 24 < mic_len)
+ return -1;
buf = os_malloc(len + 20 - 24);
if (buf == NULL)
os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
/* Frame body with MMIE MIC masked to zero */
- os_memcpy(buf + 20, data + 24, len - 24 - 8);
- os_memset(buf + 20 + len - 24 - 8, 0, 8);
+ os_memcpy(buf + 20, data + 24, len - 24 - mic_len);
+ os_memset(buf + 20 + len - 24 - mic_len, 0, mic_len);
wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
/* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
- if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
+ if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ ret = omac1_aes_128(igtk, buf, len + 20 - 24, mic);
+ } else if (mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256) {
+ ret = omac1_aes_256(igtk, buf, len + 20 - 24, mic);
+ } else if (mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
+ mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256) {
+ u8 nonce[12], *npos;
+ const u8 *ipn;
+
+ ipn = data + len - mic_len - 6;
+
+ /* Nonce: A2 | IPN */
+ os_memcpy(nonce, hdr->addr2, ETH_ALEN);
+ npos = nonce + ETH_ALEN;
+ *npos++ = ipn[5];
+ *npos++ = ipn[4];
+ *npos++ = ipn[3];
+ *npos++ = ipn[2];
+ *npos++ = ipn[1];
+ *npos++ = ipn[0];
+
+ ret = aes_gmac(igtk, igtk_len, nonce, sizeof(nonce),
+ buf, len + 20 - 24, mic);
+ } else {
+ ret = -1;
+ }
+ if (ret < 0) {
os_free(buf);
return -1;
}
os_free(buf);
- if (os_memcmp(data + len - 8, mic, 8) != 0)
+ if (os_memcmp(data + len - mic_len, mic, mic_len) != 0)
return -1;
return 0;
const u8 *mmie;
u16 keyid;
struct wlantest_bss *bss;
+ size_t mic_len;
mgmt = (const struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
if (bss == NULL)
return 0; /* No key known yet */
- if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
- data[len - 17] != 16) {
+ mic_len = bss->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
+
+ if (len < 24 + 10 + mic_len ||
+ data[len - (10 + mic_len)] != WLAN_EID_MMIE ||
+ data[len - (10 + mic_len - 1)] != 8 + mic_len) {
/* No MMIE */
if (bss->rsn_capab & WPA_CAPABILITY_MFPC) {
add_note(wt, MSG_INFO, "Robust group-addressed "
return 0;
}
- mmie = data + len - 16;
+ mmie = data + len - (8 + mic_len);
keyid = WPA_GET_LE16(mmie);
if (keyid & 0xf000) {
add_note(wt, MSG_INFO, "MMIE KeyID reserved bits not zero "
}
wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
- wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
+ wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, mic_len);
- if (!bss->igtk_set[keyid]) {
+ if (!bss->igtk_len[keyid]) {
add_note(wt, MSG_DEBUG, "No IGTK known to validate BIP frame");
return 0;
}
wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
}
- if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
+ if (check_mmie_mic(bss->mgmt_group_cipher, bss->igtk[keyid],
+ bss->igtk_len[keyid], data, len) < 0) {
add_note(wt, MSG_INFO, "Invalid MMIE MIC in a frame from "
MACSTR, MAC2STR(mgmt->sa));
bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
}
- decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data + 24, len - 24, dlen);
+ decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data + 24, len - 24, dlen);
if (decrypted) {
os_memcpy(rsc, pn, 6);
frame = os_malloc(24 + *dlen);