struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, int force_sha256);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
static const u32 eapol_key_timeout_first = 100; /* ms */
if (sm == NULL)
return;
- sm->PTKRequest = TRUE;
- sm->PTK_valid = 0;
+ if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+ MAC2STR(sm->addr));
+ sm->Disconnect = TRUE;
+ /* Try to encourage the STA to reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ } else {
+ sm->PTKRequest = TRUE;
+ sm->PTK_valid = 0;
+ }
}
pmk_len = sm->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+ 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
sm->Init = FALSE;
sm->AuthenticationRequest = TRUE;
break;
+ } else if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+ wpa_printf(MSG_INFO,
+ "WPA: PTK0 rekey not allowed, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = TRUE;
+ /* Try to encourage the STA reconnect */
+ sm->disconnect_reason =
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+ break;
}
if (sm->GUpdateStationKeys) {
/*
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, unsigned int pmk_len,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
size_t z_len = 0;
+ int akmp;
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
}
#endif /* CONFIG_DPP2 */
+ akmp = sm->wpa_key_mgmt;
+ if (force_sha256)
+ akmp = WPA_KEY_MGMT_PSK_SHA256;
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, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len);
}
size_t gtk_len;
struct wpa_group *gsm;
- plain = wpabuf_alloc(1000);
+ plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm));
if (!plain)
return NULL;
gtk, gtk_len);
wpabuf_put(plain, tmp2 - tmp);
- /* IGTK KDE */
+ /* IGTK KDE and BIGTK KDE */
tmp = wpabuf_put(plain, 0);
tmp2 = ieee80211w_kde_add(sm, tmp);
wpabuf_put(plain, tmp2 - tmp);
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
pmk_len = sm->pmksa->pmk_len;
}
- if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+ owe_ptk_workaround == 2) < 0)
break;
if (mic_len &&
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_OWE
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+ owe_ptk_workaround == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try PTK derivation workaround with SHA256");
+ owe_ptk_workaround = 2;
+ continue;
+ }
+#endif /* CONFIG_OWE */
+
if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
wpa_key_mgmt_sae(sm->wpa_key_mgmt))
break;
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
{
+ size_t len = 0;
+
if (sm->mgmt_frame_prot) {
- size_t len;
- len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
- return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
+ len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+ }
+ if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+ len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+ len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
}
- return 0;
+ return len;
}
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
+ struct wpa_bigtk_kde bigtk;
struct wpa_group *gsm = sm->group;
u8 rsc[WPA_KEY_RSC_LEN];
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ if (!sm->wpa_auth->conf.beacon_prot)
+ return pos;
+
+ bigtk.keyid[0] = gsm->GN_bigtk;
+ bigtk.keyid[1] = 0;
+ if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+ os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+ else
+ os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+ os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+ (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+ NULL, 0);
+
return pos;
}
}
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
struct wpa_group *group)
{
int ret = 0;
+ size_t len;
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
group->GTK[group->GN - 1], group->GTK_len);
if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- size_t len;
len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
group->IGTK[group->GN_igtk - 4], len);
}
+ if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ wpa_auth->conf.beacon_prot) {
+ len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+ os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+ inc_byte_array(group->Counter, WPA_NONCE_LEN);
+ if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion",
+ wpa_auth->addr, group->GNonce,
+ group->BIGTK[group->GN_bigtk - 6], len) < 0)
+ ret = -1;
+ wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+ group->BIGTK[group->GN_bigtk - 6], len);
+ }
+
return ret;
}
group->GM = 2;
group->GN_igtk = 4;
group->GM_igtk = 5;
+ group->GN_bigtk = 6;
+ group->GM_bigtk = 7;
/* GTK[GN] = CalcGTK() */
wpa_gtk_update(wpa_auth, group);
}
return pos - start;
}
+
+int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+ size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+
+ /*
+ * BIGTK subelement:
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+ *pos++ = 2 + 6 + len;
+ WPA_PUT_LE16(pos, gsm->GN_bigtk);
+ pos += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+ return 0;
+ pos += 6;
+
+ os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+ pos += len;
+
+ wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN_bigtk);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+ gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+ return pos - start;
+}
+
#endif /* CONFIG_WNM_AP */
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
/* "GKeyDoneStations = GNoStations" is done in more robust way by
* counting the STAs that are marked with GUpdateStationKeys instead of
* including all STAs that could be in not-yet-completed state. */
group->IGTK[group->GN_igtk - 4], len,
KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
+
+ if (ret == 0 && wpa_auth->conf.beacon_prot &&
+ wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+ broadcast_ether_addr, group->GN_bigtk,
+ group->BIGTK[group->GN_bigtk - 6], len,
+ KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+ ret = -1;
}
return ret;
tmp = group->GM_igtk;
group->GM_igtk = group->GN_igtk;
group->GN_igtk = tmp;
+ tmp = group->GM_bigtk;
+ group->GM_bigtk = group->GN_bigtk;
+ group->GN_bigtk = tmp;
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
}
int wpa_ie_len, secure, gtkidx, encr = 0;
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
- GTK[GN], IGTK, [FTIE], [TIE * 2])
+ GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
*/
/* Use 0 RSC */