static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+ size_t data_len);
static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
return;
}
}
+
+ if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+ "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
+ return;
+ }
}
if (key_info & WPA_KEY_INFO_REQUEST) {
sm->MICVerified = FALSE;
if (sm->PTK_valid && !sm->update_snonce) {
- if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
+ data_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
return;
if (force_version)
version = force_version;
- else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+ else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
pad_len = key_data_len % 8;
if (pad_len)
buf, key_data_len);
if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
if (aes_wrap(sm->PTK.kek, 16,
(key_data_len - 8) / 8, buf,
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
- key->key_mic);
+ wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key->key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
}
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+ size_t data_len)
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
key_info = WPA_GET_BE16(key->key_info);
os_memcpy(mic, key->key_mic, 16);
os_memset(key->key_mic, 0, 16);
- if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ if (wpa_eapol_key_mic(PTK->kck, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
data, data_len, key->key_mic) ||
os_memcmp_const(mic, key->key_mic, 16) != 0)
ret = -1;
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
- if (sm->pmksa)
+ if (sm->pmksa) {
os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
sm->pmksa->pmkid, PMKID_LEN);
- else {
+ } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
+ /* No KCK available to derive PMKID */
+ pmkid = NULL;
+ } else {
/*
* Calculate PMKID since no PMKSA cache entry was
* available with pre-calculated PMKID.
wpa_derive_ptk(sm, pmk, &PTK);
- if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+ if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+ sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
ok = 1;
break;
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
+ size_t len, u8 *mic)
{
- u8 hash[SHA1_MAC_LEN];
+ u8 hash[SHA256_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
-#ifdef CONFIG_HS20
case WPA_KEY_INFO_TYPE_AKM_DEFINED:
- /* FIX: This should be based on negotiated AKM */
- return omac1_aes_128(key, buf, len, mic);
+ switch (akmp) {
+#ifdef CONFIG_HS20
+ case WPA_KEY_MGMT_OSEN:
+ return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ if (hmac_sha256(key, 16, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, MD5_MAC_LEN);
+ break;
+#endif /* CONFIG_SUITEB */
+ default:
+ return -1;
+ }
+ break;
default:
return -1;
}
#endif /* _MSC_VER */
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
- u8 *mic);
+int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
+ size_t len, u8 *mic);
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
os_memcpy(mic, key->key_mic, 16);
if (peerkey->tstk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
- key->key_mic);
+ wpa_eapol_key_mic(peerkey->tstk.kck, sm->key_mgmt, ver, buf,
+ len, key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
if (!ok && peerkey->stk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+ wpa_eapol_key_mic(peerkey->stk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+ wpa_eapol_key_mic(kck, sm->key_mgmt, ver, msg, msg_len, key_mic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key "
- "version %d MIC", ver);
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
goto out;
}
wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf;
- if (sm->key_mgmt == WPA_KEY_MGMT_OSEN)
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
wpa_key_mgmt_sha256(sm->key_mgmt))
os_memcpy(mic, key->key_mic, 16);
if (sm->tptk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
+ wpa_eapol_key_mic(sm->tptk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
if (!ok && sm->ptk_set) {
os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
+ wpa_eapol_key_mic(sm->ptk.kck, sm->key_mgmt, ver, buf, len,
key->key_mic);
if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
- sm->key_mgmt == WPA_KEY_MGMT_OSEN) {
+ sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt)) {
u8 *buf;
if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
goto out;
}
+ if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
+ ver);
+ goto out;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
- sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
} else
goto out;
} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
}
-static int check_mic(const u8 *kck, int ver, const u8 *data, size_t len)
+static int check_mic(const u8 *kck, int akmp, int ver, const u8 *data,
+ size_t len)
{
u8 *buf;
int ret = -1;
os_memcpy(rx_mic, key->key_mic, 16);
os_memset(key->key_mic, 0, 16);
- if (wpa_eapol_key_mic(kck, ver, buf, len, key->key_mic) == 0 &&
+ if (wpa_eapol_key_mic(kck, akmp, ver, buf, len, key->key_mic) == 0 &&
os_memcmp(rx_mic, key->key_mic, 16) == 0)
ret = 0;
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 (check_mic(ptk.kck, sta->key_mgmt, ver, data, len) < 0)
return -1;
sta->tk_len = wpa_cipher_key_len(sta->pairwise_cipher);
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, sta->key_mgmt, ver, data,
+ len) < 0)
continue;
wpa_printf(MSG_INFO, "Pre-set PTK matches for STA "
MACSTR " BSSID " MACSTR,
"Use TPTK for validation EAPOL-Key MIC");
kck = sta->tptk.kck;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, 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;
}
kck = sta->tptk.kck;
kek = sta->tptk.kek;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, 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;
}
"Use TPTK for validation EAPOL-Key MIC");
kck = sta->tptk.kck;
}
- if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
+ if (check_mic(kck, 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;
}
}
if (sta->ptk_set &&
- check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ check_mic(sta->ptk.kck, 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;
}
if (sta->ptk_set &&
- check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+ check_mic(sta->ptk.kck, 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;