Skip to content

Instantly share code, notes, and snippets.

@zekica
Last active June 21, 2023 15:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zekica/bee8df4144d097f2e07bcaaca96de4b8 to your computer and use it in GitHub Desktop.
Save zekica/bee8df4144d097f2e07bcaaca96de4b8 to your computer and use it in GitHub Desktop.
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index cb6595f..571a483 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -56,7 +56,9 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
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,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
@@ -879,6 +881,10 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
const u8 *pmk = NULL;
size_t pmk_len;
int vlan_id = 0;
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t key_len;
+ int ret = -1;
os_memset(&PTK, 0, sizeof(PTK));
for (;;) {
@@ -900,7 +906,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
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,
+ pmk_r0, pmk_r1, pmk_r0_name, &key_len) < 0)
break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
@@ -921,7 +928,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
if (!ok) {
wpa_printf(MSG_DEBUG,
"WPA: Earlier SNonce did not result in matching MIC");
- return -1;
+ goto fail;
}
wpa_printf(MSG_DEBUG,
@@ -930,14 +937,26 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
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;
+ goto fail;
+
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
+ wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
+ wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
+ key_len);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
- return 0;
+ ret = 0;
+fail:
+ forced_memzero(pmk_r0, sizeof(pmk_r0));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
+ return ret;
}
@@ -2208,7 +2227,9 @@ SM_STATE(WPA_PTK, PTKSTART)
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,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len)
{
const u8 *z = NULL;
size_t z_len = 0;
@@ -2226,7 +2247,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
sm->wpa_key_mgmt,
sm->pairwise);
}
- return wpa_auth_derive_ptk_ft(sm, ptk);
+ return wpa_auth_derive_ptk_ft(sm, ptk, pmk_r0, pmk_r1,
+ pmk_r0_name, key_len);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -2819,6 +2841,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
struct wpa_eapol_key *key;
struct wpa_eapol_ie_parse kde;
int vlan_id = 0;
+ u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t key_len;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
@@ -2856,7 +2881,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
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, pmk_r0, pmk_r1,
+ pmk_r0_name, &key_len) < 0)
break;
if (mic_len &&
@@ -2890,7 +2916,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
"invalid MIC in msg 2/4 of 4-Way Handshake");
if (psk_found)
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
- return;
+ goto out;
}
/*
@@ -2904,12 +2930,12 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
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;
+ goto out;
if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key msg 2/4 with invalid Key Data contents");
- return;
+ goto out;
}
if (kde.rsn_ie) {
eapol_key_ie = kde.rsn_ie;
@@ -2936,7 +2962,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
/* MLME-DEAUTHENTICATE.request */
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
@@ -2947,20 +2973,20 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
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;
+ goto out;
}
if (get_sta_tx_parameters(sm,
channel_width_to_int(ci.chanwidth),
ci.seg1_idx, &tx_chanwidth,
&tx_seg1_idx) < 0)
- return;
+ goto out;
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;
+ goto out;
}
}
#endif /* CONFIG_OCV */
@@ -2968,7 +2994,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
wpa_sta_disconnect(wpa_auth, sm->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- return;
+ goto out;
}
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P
@@ -3016,7 +3042,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
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;
+ goto out;
}
sm->pending_1_of_4_timeout = 0;
@@ -3031,10 +3057,20 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
}
sm->MICVerified = TRUE;
+#ifdef CONFIG_IEEE80211R_AP
+ if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) {
+ wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1");
+ wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name,
+ key_len);
+ }
+#endif /* CONFIG_IEEE80211R_AP */
os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
forced_memzero(&PTK, sizeof(PTK));
sm->PTK_valid = TRUE;
+out:
+ forced_memzero(pmk_r0, sizeof(pmk_r0));
+ forced_memzero(pmk_r1, sizeof(pmk_r1));
}
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 696f8d5..71b3599 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2075,13 +2075,14 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm,
}
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len)
{
- u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN];
size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ?
SHA384_MAC_LEN : PMK_LEN;
size_t pmk_r1_len = pmk_r0_len;
- u8 pmk_r1[PMK_LEN_MAX];
+ *key_len = pmk_r1_len;
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
@@ -2089,12 +2090,6 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
- int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
- int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
- struct vlan_description vlan;
- const u8 *identity, *radius_cui;
- size_t identity_len, radius_cui_len;
- int session_timeout;
const u8 *mpmk;
size_t mpmk_len;
@@ -2109,11 +2104,39 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
"derivation");
return -1;
}
+ if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name,
+ wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, sm->pmk_r1_name) < 0)
+ return -1;
+
+ return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
+ sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
+}
+
+
+void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r1, const u8 *pmk_r0_name,
+ size_t key_len)
+{
+ int psk_local = sm->wpa_auth->conf.ft_psk_generate_local;
+ int expires_in = sm->wpa_auth->conf.r0_key_lifetime;
+ struct vlan_description vlan;
+ const u8 *identity, *radius_cui;
+ size_t identity_len, radius_cui_len;
+ int session_timeout;
+
+ if (psk_local && wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
+ return;
+
if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR,
MAC2STR(sm->addr));
- return -1;
+ return;
}
identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity);
@@ -2121,35 +2144,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
&radius_cui);
session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr);
- if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid,
- r0kh, r0kh_len, sm->addr,
- pmk_r0, pmk_r0_name,
- wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
- if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
- wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_len,
- pmk_r0_name,
- sm->pairwise, &vlan, expires_in,
- session_timeout, identity, identity_len,
- radius_cui, radius_cui_len);
-
- if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, sm->pmk_r1_name) < 0)
- return -1;
- wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len);
- wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
- WPA_PMK_NAME_LEN);
- if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
- wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_len,
- sm->pmk_r1_name, sm->pairwise, &vlan,
- expires_in, session_timeout, identity,
- identity_len, radius_cui, radius_cui_len);
+ wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, key_len,
+ pmk_r0_name,
+ sm->pairwise, &vlan, expires_in,
+ session_timeout, identity, identity_len,
+ radius_cui, radius_cui_len);
+ wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, key_len,
+ sm->pmk_r1_name, sm->pairwise, &vlan,
+ expires_in, session_timeout, identity,
+ identity_len, radius_cui, radius_cui_len);
- return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
- sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
- ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 4babd0c..2bc1674 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -292,7 +292,12 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
-int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
+ u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name,
+ size_t *key_len);
+void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0,
+ const u8 *pmk_r1, const u8 *pmk_r0_name,
+ size_t key_len);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment