diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 5191ae090..1eb8bd500 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2055,6 +2055,43 @@ static int wpa_ft_set_key_mgmt(struct wpa_state_machine *sm, } +static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *r0kh_id, size_t r0kh_id_len, + const u8 *req_pmk_r0_name, + const u8 *req_pmk_r1_name, + u8 *out_pmk_r1, int *out_pairwise) +{ + struct wpa_auth_config *conf = &wpa_auth->conf; + const struct wpa_ft_pmk_r0_sa *r0; + u8 pmk_r1_name[WPA_PMK_NAME_LEN]; + + if (conf->r0_key_holder_len != r0kh_id_len || + os_memcmp(conf->r0_key_holder, r0kh_id, conf->r0_key_holder_len) != + 0) + return -1; /* not our R0KH-ID */ + + wpa_printf(MSG_DEBUG, "FT: STA R0KH-ID matching local configuration"); + if (wpa_ft_fetch_pmk_r0(sm->wpa_auth, sm->addr, req_pmk_r0_name, &r0) < + 0) + return -1; /* no matching PMKR0Name in local cache */ + + wpa_printf(MSG_DEBUG, "FT: Requested PMKR0Name found in local cache"); + + if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_name, conf->r1_key_holder, + sm->addr, out_pmk_r1, pmk_r1_name) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", out_pmk_r1, PMK_LEN); + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); + + wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, pmk_r1_name, + sm->pairwise); + + *out_pairwise = sm->pairwise; + return 0; +} + + static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, const u8 *ies, size_t ies_len, u8 **resp_ies, size_t *resp_ies_len) @@ -2132,8 +2169,22 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise) < 0) return WLAN_STATUS_INVALID_PMKID; + wpa_printf(MSG_DEBUG, + "FT: Generated PMK-R1 for FT-PSK locally"); } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1, &pairwise) < 0) { + wpa_printf(MSG_DEBUG, + "FT: No PMK-R1 available in local cache for the requested PMKR1Name"); + if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm, + parse.r0kh_id, parse.r0kh_id_len, + parse.rsn_pmkid, + pmk_r1_name, pmk_r1, &pairwise) + == 0) { + wpa_printf(MSG_DEBUG, + "FT: Generated PMK-R1 based on local PMK-R0"); + goto pmk_r1_derived; + } + if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) { wpa_printf(MSG_DEBUG, "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH"); @@ -2141,8 +2192,11 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, } return -1; /* Status pending */ + } else { + wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache"); } +pmk_r1_derived: wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN); sm->pmk_r1_name_valid = 1; os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);