From 2f37387812a5afc73c3aedaed7d5a5009e391475 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 24 Mar 2018 11:24:18 +0200 Subject: [PATCH] FILS: Add more complete support for FT-FILS use cases This extends the original IEEE Std 802.11ai-2016 functionality with the changes added in REVmd to describe how additional keys are derived to protect the FT protocol using keys derived through FILS authentication. This allows key_mgmt=FT-FILS-SHA256 to be used with FT protocol since the FTE MIC can now be calculated following the changes in REVmd. The FT-FILS-SHA384 case is still unsupported (it needs support for variable length MIC field in FTE). Signed-off-by: Jouni Malinen --- src/ap/wpa_auth_ft.c | 24 +++++++++++++--- src/common/wpa_common.c | 61 +++++++++++++++++++++++++++++++++++++---- src/common/wpa_common.h | 4 +++ src/rsn_supp/wpa_ft.c | 23 ++++++++++++++-- 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 1eb8bd500..8086ee2e0 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -1806,6 +1806,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, struct wpa_ft_ies parse; u8 *ric_start; u8 *anonce, *snonce; + const u8 *kck; + size_t kck_len; if (sm == NULL) return pos; @@ -1898,9 +1900,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, if (ric_start == pos) ric_start = NULL; + if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { + kck = sm->PTK.kck2; + kck_len = sm->PTK.kck2_len; + } else { + kck = sm->PTK.kck; + kck_len = sm->PTK.kck_len; + } if (auth_alg == WLAN_AUTH_FT && - wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr, - sm->wpa_auth->addr, 6, + wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6, mdie, mdie_len, ftie, ftie_len, rsnie, rsnie_len, ric_start, ric_start ? pos - ric_start : 0, @@ -2310,6 +2318,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; size_t mic_len = 16; unsigned int count; + const u8 *kck; + size_t kck_len; if (sm == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -2423,8 +2433,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr, - sm->wpa_auth->addr, 5, + if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { + kck = sm->PTK.kck2; + kck_len = sm->PTK.kck2_len; + } else { + kck = sm->PTK.kck; + kck_len = sm->PTK.kck_len; + } + if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, parse.rsn - 2, parse.rsn_len + 2, diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index f689fe83a..71f2968d5 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -41,6 +41,21 @@ static unsigned int wpa_kck_len(int akmp, size_t pmk_len) } +#ifdef CONFIG_IEEE80211R +static unsigned int wpa_kck2_len(int akmp) +{ + switch (akmp) { + case WPA_KEY_MGMT_FT_FILS_SHA256: + return 16; + case WPA_KEY_MGMT_FT_FILS_SHA384: + return 24; + default: + return 0; + } +} +#endif /* CONFIG_IEEE80211R */ + + static unsigned int wpa_kek_len(int akmp, size_t pmk_len) { switch (akmp) { @@ -61,6 +76,21 @@ static unsigned int wpa_kek_len(int akmp, size_t pmk_len) } +#ifdef CONFIG_IEEE80211R +static unsigned int wpa_kek2_len(int akmp) +{ + switch (akmp) { + case WPA_KEY_MGMT_FT_FILS_SHA256: + return 16; + case WPA_KEY_MGMT_FT_FILS_SHA384: + return 32; + default: + return 0; + } +} +#endif /* CONFIG_IEEE80211R */ + + unsigned int wpa_mic_len(int akmp, size_t pmk_len) { switch (akmp) { @@ -404,6 +434,9 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len); + ptk->kek2_len = 0; + ptk->kck2_len = 0; + os_memset(tmp, 0, sizeof(tmp)); return 0; } @@ -582,6 +615,9 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa, fils_ft, *fils_ft_len); } + ptk->kek2_len = 0; + ptk->kck2_len = 0; + os_memset(tmp, 0, sizeof(tmp)); ret = 0; err: @@ -1470,8 +1506,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, u8 *pos, hash[32]; const u8 *addr[6]; size_t len[6]; - u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; - size_t ptk_len; + u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; + size_t ptk_len, offset; /* * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || @@ -1488,9 +1524,12 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, pos += ETH_ALEN; ptk->kck_len = wpa_kck_len(akmp, PMK_LEN); + ptk->kck2_len = wpa_kck2_len(akmp); ptk->kek_len = wpa_kek_len(akmp, PMK_LEN); + ptk->kek2_len = wpa_kek2_len(akmp); ptk->tk_len = wpa_cipher_key_len(cipher); - ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len; + ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + + ptk->kck2_len + ptk->kek2_len; if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len) < 0) @@ -1518,11 +1557,23 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN); os_memcpy(ptk->kck, tmp, ptk->kck_len); - os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len); - os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len); + offset = ptk->kck_len; + os_memcpy(ptk->kek, tmp + offset, ptk->kek_len); + offset += ptk->kek_len; + os_memcpy(ptk->tk, tmp + offset, ptk->tk_len); + offset += ptk->tk_len; + os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len); + offset = ptk->kck2_len; + os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len); wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len); wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len); + if (ptk->kck2_len) + wpa_hexdump_key(MSG_DEBUG, "FT: KCK2", + ptk->kck2, ptk->kck2_len); + if (ptk->kek2_len) + wpa_hexdump_key(MSG_DEBUG, "FT: KEK2", + ptk->kek2, ptk->kek2_len); wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 5c918a4e6..cb56c0c11 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -210,9 +210,13 @@ struct wpa_ptk { u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */ u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */ u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */ + u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */ + u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */ size_t kck_len; size_t kek_len; size_t tk_len; + size_t kck2_len; + size_t kek2_len; int installed; /* 1 if key has already been installed to driver */ }; diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 1ff7afe2f..a543b7c73 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -385,6 +385,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, u8 ptk_name[WPA_PMK_NAME_LEN]; int ret; const u8 *bssid; + const u8 *kck; + size_t kck_len; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); @@ -485,9 +487,16 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0) return -1; + if (wpa_key_mgmt_fils(sm->key_mgmt)) { + kck = sm->ptk.kck2; + kck_len = sm->ptk.kck2_len; + } else { + kck = sm->ptk.kck; + kck_len = sm->ptk.kck_len; + } ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, sm->pmk_r1_name, - sm->ptk.kck, sm->ptk.kck_len, bssid, + kck, kck_len, bssid, ric_ies, ric_ies_len, parse.mdie ? parse.mdie - 2 : NULL); if (ft_ies) { @@ -679,6 +688,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, struct rsn_ftie *ftie; unsigned int count; u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; + const u8 *kck; + size_t kck_len; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); @@ -776,7 +787,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; } - if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6, + if (wpa_key_mgmt_fils(sm->key_mgmt)) { + kck = sm->ptk.kck2; + kck_len = sm->ptk.kck2_len; + } else { + kck = sm->ptk.kck; + kck_len = sm->ptk.kck_len; + } + + if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, parse.rsn - 2, parse.rsn_len + 2,