/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
const u8 *addr,
const u8 *p2p_dev_addr,
- const u8 *prev_psk, size_t *psk_len)
+ const u8 *prev_psk, size_t *psk_len,
+ int *vlan_id)
{
if (wpa_auth->cb->get_psk == NULL)
return NULL;
return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
- prev_psk, psk_len);
+ prev_psk, psk_len, vlan_id);
}
#endif /* CONFIG_OCV */
+static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int vlan_id)
+{
+ if (!wpa_auth->cb->update_vlan)
+ return -1;
+ return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
+}
+
+
static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
wpa_get_ntp_timestamp(buf + ETH_ALEN);
ptr = (unsigned long) group;
os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
+#ifdef TEST_FUZZ
+ os_memset(buf + ETH_ALEN, 0xab, 8);
+ os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
+#endif /* TEST_FUZZ */
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
wpa_group_put(sm->wpa_auth, sm->group);
+#ifdef CONFIG_DPP2
+ wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
os_free(sm);
}
int ok = 0;
const u8 *pmk = NULL;
size_t pmk_len;
+ int vlan_id = 0;
os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk, &pmk_len);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
data, data_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
ok = 1;
break;
}
wpa_printf(MSG_DEBUG,
"WPA: Earlier SNonce resulted in matching MIC");
sm->alt_snonce_valid = 0;
+
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
+ return -1;
+
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
wpa_try_alt_snonce(sm, data, data_len))) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#ifdef CONFIG_FILS
&key_data_length) < 0) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+ wpa_printf(MSG_INFO,
+ "TEST: Ignore Key MIC failure for fuzz testing");
+ goto continue_fuzz;
+#endif /* TEST_FUZZ */
return;
}
#endif /* CONFIG_FILS */
+#ifdef TEST_FUZZ
+ continue_fuzz:
+#endif /* TEST_FUZZ */
sm->MICVerified = TRUE;
eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
sm->pending_1_of_4_timeout = 0;
os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
pos = data + ETH_ALEN + WPA_NONCE_LEN;
wpa_get_ntp_timestamp(pos);
+#ifdef TEST_FUZZ
+ os_memset(pos, 0xef, 8);
+#endif /* TEST_FUZZ */
pos += 8;
if (random_get_bytes(pos, gtk_len) < 0)
ret = -1;
timeout_ms = eapol_key_timeout_no_retrans;
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
+#ifdef TEST_FUZZ
+ timeout_ms = 1;
+#endif /* TEST_FUZZ */
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
"counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
- &psk_len);
+ &psk_len, NULL);
if (psk) {
os_memcpy(sm->PMK, psk, psk_len);
sm->pmk_len = psk_len;
const u8 *pmk, unsigned int pmk_len,
struct wpa_ptk *ptk)
{
+ const u8 *z = NULL;
+ size_t z_len = 0;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_DPP2
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+ z = wpabuf_head(sm->dpp_z);
+ z_len = wpabuf_len(sm->dpp_z);
+ }
+#endif /* CONFIG_DPP2 */
+
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len);
}
pmk_r0_name, WPA_PMK_NAME_LEN);
wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
os_memset(fils_ft, 0, sizeof(fils_ft));
+
+ res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
+ sm->addr, sm->pmk_r1_name,
+ use_sha384);
+ os_memset(pmk_r0, 0, PMK_LEN_MAX);
+ if (res < 0)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+ sm->pmk_r1_name_valid = 1;
}
#endif /* CONFIG_IEEE80211R_AP */
wpabuf_put(plain, tmp2 - tmp);
*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ u8 *pos;
+
+ if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+ wpa_printf(MSG_WARNING,
+ "FILS: Failed to get channel info for OCI element");
+ wpabuf_free(plain);
+ return NULL;
+ }
+
+ pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
+ if (ocv_insert_extended_oci(&ci, pos) < 0) {
+ wpabuf_free(plain);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_OCV */
+
return plain;
}
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
+ int vlan_id = 0;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
!wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
- sm->p2p_dev_addr, pmk, &pmk_len);
+ sm->p2p_dev_addr, pmk, &pmk_len,
+ &vlan_id);
if (pmk == NULL)
break;
psk_found = 1;
wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
sm->last_rx_eapol_key,
sm->last_rx_eapol_key_len) == 0) {
+ if (sm->PMK != pmk) {
+ os_memcpy(sm->PMK, pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ }
ok = 1;
break;
}
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+#ifdef CONFIG_OCV
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
#ifdef CONFIG_IEEE80211R_AP
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
}
#endif /* CONFIG_IEEE80211R_AP */
+ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+ wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
+
sm->pending_1_of_4_timeout = 0;
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
break;
case WPA_PTK_INITPSK:
if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
- NULL, NULL)) {
+ NULL, NULL, NULL)) {
SM_ENTER(WPA_PTK, PTKSTART);
#ifdef CONFIG_SAE
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
{
+#ifdef CONFIG_OCV
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ const u8 *key_data, *mic;
+ struct ieee802_1x_hdr *hdr;
+ struct wpa_eapol_key *key;
+ struct wpa_eapol_ie_parse kde;
+ size_t mic_len;
+ u16 key_data_length;
+#endif /* CONFIG_OCV */
+
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
sm->EAPOLKeyReceived = FALSE;
+
+#ifdef CONFIG_OCV
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+
+ /*
+ * Note: last_rx_eapol_key length fields have already been validated in
+ * wpa_receive().
+ */
+ hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+ key = (struct wpa_eapol_key *) (hdr + 1);
+ mic = (u8 *) (key + 1);
+ key_data = mic + mic_len + 2;
+ key_data_length = WPA_GET_BE16(mic + mic_len);
+ if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+ sizeof(*key) - mic_len - 2)
+ return;
+
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+ "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
+ return;
+ }
+
+ if (wpa_auth_uses_ocv(sm)) {
+ struct wpa_channel_info ci;
+ int tx_chanwidth;
+ int tx_seg1_idx;
+
+ if (wpa_channel_info(wpa_auth, &ci) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+ return;
+ }
+
+ if (get_sta_tx_parameters(sm,
+ channel_width_to_int(ci.chanwidth),
+ ci.seg1_idx, &tx_chanwidth,
+ &tx_seg1_idx) < 0)
+ return;
+
+ if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+ tx_chanwidth, tx_seg1_idx) != 0) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ ocv_errorstr);
+ return;
+ }
+ }
+#endif /* CONFIG_OCV */
+
if (sm->GUpdateStationKeys)
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
}
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
+{
+ if (!sm)
+ return NULL;
+ *len = sm->pmk_len;
+ return sm->PMK;
+}
+
+
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{
if (sm == NULL)
#endif /* CONFIG_FILS */
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
+{
+ if (sm)
+ sm->auth_alg = auth_alg;
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
+{
+ if (sm) {
+ wpabuf_clear_free(sm->dpp_z);
+ sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+ }
+}
+#endif /* CONFIG_DPP2 */
+
+
#ifdef CONFIG_TESTING_OPTIONS
int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,