FT: Derive PMK-R1 locally if requested PMKR0Name is found

Derive PMK-R1 locally if the derived PMKR1Name is not found from the
local cache, but the request is for a key that was originally generated
locally (R0KH-ID matches) and the PMKR0Name is found in the local cache.
This was apparently not hit in the previously used FT sequences, but
this is useful to have available if a PMK-R1 entry is dropped from the
local cache before PMK-R0.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2018-03-24 18:45:42 +02:00 committed by Jouni Malinen
parent 1dc0945cc9
commit 4ddca8142e

View file

@ -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);