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 <jouni@codeaurora.org>
This commit is contained in:
parent
4ddca8142e
commit
2f37387812
4 changed files with 101 additions and 11 deletions
|
@ -1806,6 +1806,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||||
struct wpa_ft_ies parse;
|
struct wpa_ft_ies parse;
|
||||||
u8 *ric_start;
|
u8 *ric_start;
|
||||||
u8 *anonce, *snonce;
|
u8 *anonce, *snonce;
|
||||||
|
const u8 *kck;
|
||||||
|
size_t kck_len;
|
||||||
|
|
||||||
if (sm == NULL)
|
if (sm == NULL)
|
||||||
return pos;
|
return pos;
|
||||||
|
@ -1898,9 +1900,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||||
if (ric_start == pos)
|
if (ric_start == pos)
|
||||||
ric_start = NULL;
|
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 &&
|
if (auth_alg == WLAN_AUTH_FT &&
|
||||||
wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
|
wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6,
|
||||||
sm->wpa_auth->addr, 6,
|
|
||||||
mdie, mdie_len, ftie, ftie_len,
|
mdie, mdie_len, ftie, ftie_len,
|
||||||
rsnie, rsnie_len,
|
rsnie, rsnie_len,
|
||||||
ric_start, ric_start ? pos - ric_start : 0,
|
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];
|
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
|
||||||
size_t mic_len = 16;
|
size_t mic_len = 16;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
const u8 *kck;
|
||||||
|
size_t kck_len;
|
||||||
|
|
||||||
if (sm == NULL)
|
if (sm == NULL)
|
||||||
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
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;
|
return WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
|
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
|
||||||
sm->wpa_auth->addr, 5,
|
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.mdie - 2, parse.mdie_len + 2,
|
||||||
parse.ftie - 2, parse.ftie_len + 2,
|
parse.ftie - 2, parse.ftie_len + 2,
|
||||||
parse.rsn - 2, parse.rsn_len + 2,
|
parse.rsn - 2, parse.rsn_len + 2,
|
||||||
|
|
|
@ -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)
|
static unsigned int wpa_kek_len(int akmp, size_t pmk_len)
|
||||||
{
|
{
|
||||||
switch (akmp) {
|
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)
|
unsigned int wpa_mic_len(int akmp, size_t pmk_len)
|
||||||
{
|
{
|
||||||
switch (akmp) {
|
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);
|
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);
|
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));
|
os_memset(tmp, 0, sizeof(tmp));
|
||||||
return 0;
|
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);
|
fils_ft, *fils_ft_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptk->kek2_len = 0;
|
||||||
|
ptk->kck2_len = 0;
|
||||||
|
|
||||||
os_memset(tmp, 0, sizeof(tmp));
|
os_memset(tmp, 0, sizeof(tmp));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
err:
|
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];
|
u8 *pos, hash[32];
|
||||||
const u8 *addr[6];
|
const u8 *addr[6];
|
||||||
size_t len[6];
|
size_t len[6];
|
||||||
u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
|
u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
|
||||||
size_t ptk_len;
|
size_t ptk_len, offset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
|
* 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;
|
pos += ETH_ALEN;
|
||||||
|
|
||||||
ptk->kck_len = wpa_kck_len(akmp, PMK_LEN);
|
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->kek_len = wpa_kek_len(akmp, PMK_LEN);
|
||||||
|
ptk->kek2_len = wpa_kek2_len(akmp);
|
||||||
ptk->tk_len = wpa_cipher_key_len(cipher);
|
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,
|
if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
|
||||||
tmp, ptk_len) < 0)
|
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_name, hash, WPA_PMK_NAME_LEN);
|
||||||
|
|
||||||
os_memcpy(ptk->kck, tmp, ptk->kck_len);
|
os_memcpy(ptk->kck, tmp, ptk->kck_len);
|
||||||
os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
|
offset = ptk->kck_len;
|
||||||
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_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: KCK", ptk->kck, ptk->kck_len);
|
||||||
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_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_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
|
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
|
||||||
|
|
||||||
|
|
|
@ -210,9 +210,13 @@ struct wpa_ptk {
|
||||||
u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
|
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 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
|
||||||
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
|
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 kck_len;
|
||||||
size_t kek_len;
|
size_t kek_len;
|
||||||
size_t tk_len;
|
size_t tk_len;
|
||||||
|
size_t kck2_len;
|
||||||
|
size_t kek2_len;
|
||||||
int installed; /* 1 if key has already been installed to driver */
|
int installed; /* 1 if key has already been installed to driver */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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];
|
u8 ptk_name[WPA_PMK_NAME_LEN];
|
||||||
int ret;
|
int ret;
|
||||||
const u8 *bssid;
|
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: Response IEs", ies, ies_len);
|
||||||
wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_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)
|
ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
|
||||||
return -1;
|
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,
|
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
|
||||||
sm->pmk_r1_name,
|
sm->pmk_r1_name,
|
||||||
sm->ptk.kck, sm->ptk.kck_len, bssid,
|
kck, kck_len, bssid,
|
||||||
ric_ies, ric_ies_len,
|
ric_ies, ric_ies_len,
|
||||||
parse.mdie ? parse.mdie - 2 : NULL);
|
parse.mdie ? parse.mdie - 2 : NULL);
|
||||||
if (ft_ies) {
|
if (ft_ies) {
|
||||||
|
@ -679,6 +688,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
||||||
struct rsn_ftie *ftie;
|
struct rsn_ftie *ftie;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
|
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);
|
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;
|
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.mdie - 2, parse.mdie_len + 2,
|
||||||
parse.ftie - 2, parse.ftie_len + 2,
|
parse.ftie - 2, parse.ftie_len + 2,
|
||||||
parse.rsn - 2, parse.rsn_len + 2,
|
parse.rsn - 2, parse.rsn_len + 2,
|
||||||
|
|
Loading…
Reference in a new issue