FILS: Fix PMK and PMKID derivation from ERP
This adds helper functions for deriving PMK and PMKID from ERP exchange in FILS shared key authentication as defined in IEEE Std 802.11ai-2016, 12.12.2.5.2 (PMKSA key derivation with FILS authentication). These functions is used to fix PMK and PMKID derivation which were previously using the rMSK directly as PMK instead of following the FILS protocol to derive PMK with HMAC from nonces and rMSK. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
ef495c78dd
commit
fcd3d6ce32
5 changed files with 121 additions and 6 deletions
|
@ -1166,6 +1166,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
||||||
u8 *ie_buf = NULL;
|
u8 *ie_buf = NULL;
|
||||||
const u8 *pmk = NULL;
|
const u8 *pmk = NULL;
|
||||||
size_t pmk_len = 0;
|
size_t pmk_len = 0;
|
||||||
|
u8 pmk_buf[PMK_LEN_MAX];
|
||||||
|
|
||||||
if (resp != WLAN_STATUS_SUCCESS)
|
if (resp != WLAN_STATUS_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1234,8 +1235,16 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
|
||||||
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
|
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
|
||||||
wpabuf_put_buf(data, erp_resp);
|
wpabuf_put_buf(data, erp_resp);
|
||||||
|
|
||||||
pmk = msk;
|
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
|
||||||
pmk_len = msk_len > PMK_LEN ? PMK_LEN : msk_len;
|
msk, msk_len, sta->fils_snonce, fils_nonce,
|
||||||
|
NULL, 0, pmk_buf, &pmk_len)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
|
||||||
|
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
|
||||||
|
wpabuf_free(data);
|
||||||
|
data = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
pmk = pmk_buf;
|
||||||
} else if (pmksa) {
|
} else if (pmksa) {
|
||||||
pmk = pmksa->pmk;
|
pmk = pmksa->pmk;
|
||||||
pmk_len = pmksa->pmk_len;
|
pmk_len = pmksa->pmk_len;
|
||||||
|
|
|
@ -230,6 +230,78 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||||
|
|
||||||
#ifdef CONFIG_FILS
|
#ifdef CONFIG_FILS
|
||||||
|
|
||||||
|
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
|
||||||
|
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
|
||||||
|
size_t dh_ss_len, u8 *pmk, size_t *pmk_len)
|
||||||
|
{
|
||||||
|
u8 nonces[2 * FILS_NONCE_LEN];
|
||||||
|
const u8 *addr[2];
|
||||||
|
size_t len[2];
|
||||||
|
size_t num_elem;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) */
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: rMSK to PMK derivation");
|
||||||
|
|
||||||
|
if (wpa_key_mgmt_sha384(akmp))
|
||||||
|
*pmk_len = SHA384_MAC_LEN;
|
||||||
|
else if (wpa_key_mgmt_sha256(akmp))
|
||||||
|
*pmk_len = SHA256_MAC_LEN;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FILS: rMSK", rmsk, rmsk_len);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: SNonce", snonce, FILS_NONCE_LEN);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: ANonce", anonce, FILS_NONCE_LEN);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: DHss", dh_ss, dh_ss_len);
|
||||||
|
|
||||||
|
os_memcpy(nonces, snonce, FILS_NONCE_LEN);
|
||||||
|
os_memcpy(&nonces[FILS_NONCE_LEN], anonce, FILS_NONCE_LEN);
|
||||||
|
addr[0] = rmsk;
|
||||||
|
len[0] = rmsk_len;
|
||||||
|
num_elem = 1;
|
||||||
|
if (dh_ss) {
|
||||||
|
addr[1] = dh_ss;
|
||||||
|
len[1] = dh_ss_len;
|
||||||
|
num_elem++;
|
||||||
|
}
|
||||||
|
if (wpa_key_mgmt_sha384(akmp))
|
||||||
|
res = hmac_sha384_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
|
||||||
|
addr, len, pmk);
|
||||||
|
else
|
||||||
|
res = hmac_sha256_vector(nonces, 2 * FILS_NONCE_LEN, num_elem,
|
||||||
|
addr, len, pmk);
|
||||||
|
if (res == 0)
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FILS: PMK", pmk, *pmk_len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
|
||||||
|
u8 *pmkid)
|
||||||
|
{
|
||||||
|
const u8 *addr[1];
|
||||||
|
size_t len[1];
|
||||||
|
u8 hash[SHA384_MAC_LEN];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) */
|
||||||
|
addr[0] = reauth;
|
||||||
|
len[0] = reauth_len;
|
||||||
|
if (wpa_key_mgmt_sha384(akmp))
|
||||||
|
res = sha384_vector(1, addr, len, hash);
|
||||||
|
else if (wpa_key_mgmt_sha256(akmp))
|
||||||
|
res = sha256_vector(1, addr, len, hash);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
os_memcpy(pmkid, hash, PMKID_LEN);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
|
int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
|
||||||
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
|
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
|
||||||
u8 *ick, size_t *ick_len, int akmp, int cipher)
|
u8 *ick, size_t *ick_len, int akmp, int cipher)
|
||||||
|
|
|
@ -330,6 +330,11 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
|
||||||
const u8 *addr1, const u8 *addr2,
|
const u8 *addr1, const u8 *addr2,
|
||||||
const u8 *nonce1, const u8 *nonce2,
|
const u8 *nonce1, const u8 *nonce2,
|
||||||
struct wpa_ptk *ptk, int akmp, int cipher);
|
struct wpa_ptk *ptk, int akmp, int cipher);
|
||||||
|
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
|
||||||
|
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
|
||||||
|
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
|
||||||
|
int fils_pmkid_erp(int akmp, const u8 *reauth, size_t reauth_len,
|
||||||
|
u8 *pmkid);
|
||||||
int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
|
int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
|
||||||
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
|
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
|
||||||
u8 *ick, size_t *ick_len, int akmp, int cipher);
|
u8 *ick, size_t *ick_len, int akmp, int cipher);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "crypto/aes_siv.h"
|
#include "crypto/aes_siv.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "common/ieee802_11_common.h"
|
#include "common/ieee802_11_common.h"
|
||||||
|
#include "eap_common/eap_defs.h"
|
||||||
#include "eapol_supp/eapol_supp_sm.h"
|
#include "eapol_supp/eapol_supp_sm.h"
|
||||||
#include "wpa.h"
|
#include "wpa.h"
|
||||||
#include "eloop.h"
|
#include "eloop.h"
|
||||||
|
@ -3302,12 +3303,19 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm)
|
||||||
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
|
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
|
||||||
|
|
||||||
/* FILS Wrapped Data */
|
/* FILS Wrapped Data */
|
||||||
|
sm->fils_erp_pmkid_set = 0;
|
||||||
if (erp_msg) {
|
if (erp_msg) {
|
||||||
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
|
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
|
||||||
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
|
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
|
||||||
/* Element ID Extension */
|
/* Element ID Extension */
|
||||||
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
|
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
|
||||||
wpabuf_put_buf(buf, erp_msg);
|
wpabuf_put_buf(buf, erp_msg);
|
||||||
|
/* Calculate pending PMKID here so that we do not need to
|
||||||
|
* maintain a copy of the EAP-Initiate/Reauth message. */
|
||||||
|
if (fils_pmkid_erp(sm->key_mgmt, wpabuf_head(erp_msg),
|
||||||
|
wpabuf_len(erp_msg),
|
||||||
|
sm->fils_erp_pmkid) == 0)
|
||||||
|
sm->fils_erp_pmkid_set = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wpa_hexdump_buf(MSG_DEBUG, "RSN: FILS fields for Authentication frame",
|
wpa_hexdump_buf(MSG_DEBUG, "RSN: FILS fields for Authentication frame",
|
||||||
|
@ -3407,6 +3415,9 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len)
|
||||||
|
|
||||||
/* FILS Wrapped Data */
|
/* FILS Wrapped Data */
|
||||||
if (!sm->cur_pmksa && elems.fils_wrapped_data) {
|
if (!sm->cur_pmksa && elems.fils_wrapped_data) {
|
||||||
|
u8 rmsk[ERP_MAX_KEY_LEN];
|
||||||
|
size_t rmsk_len;
|
||||||
|
|
||||||
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
|
wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data",
|
||||||
elems.fils_wrapped_data,
|
elems.fils_wrapped_data,
|
||||||
elems.fils_wrapped_data_len);
|
elems.fils_wrapped_data_len);
|
||||||
|
@ -3415,14 +3426,30 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len)
|
||||||
if (eapol_sm_failed(sm->eapol))
|
if (eapol_sm_failed(sm->eapol))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
|
rmsk_len = ERP_MAX_KEY_LEN;
|
||||||
|
res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
|
||||||
|
if (res == PMK_LEN) {
|
||||||
|
rmsk_len = PMK_LEN;
|
||||||
|
res = eapol_sm_get_key(sm->eapol, rmsk, rmsk_len);
|
||||||
|
}
|
||||||
if (res)
|
if (res)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
res = fils_rmsk_to_pmk(sm->key_mgmt, rmsk, rmsk_len,
|
||||||
|
sm->fils_nonce, sm->fils_anonce, NULL, 0,
|
||||||
|
sm->pmk, &sm->pmk_len);
|
||||||
|
os_memset(rmsk, 0, sizeof(rmsk));
|
||||||
|
|
||||||
|
if (!sm->fils_erp_pmkid_set) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_hexdump(MSG_DEBUG, "FILS: PMKID", sm->fils_erp_pmkid,
|
||||||
|
PMKID_LEN);
|
||||||
wpa_printf(MSG_DEBUG, "FILS: ERP processing succeeded - add PMKSA cache entry for the result");
|
wpa_printf(MSG_DEBUG, "FILS: ERP processing succeeded - add PMKSA cache entry for the result");
|
||||||
sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, PMK_LEN,
|
sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
|
||||||
NULL, NULL, 0, sm->bssid,
|
sm->fils_erp_pmkid, NULL, 0,
|
||||||
sm->own_addr,
|
sm->bssid, sm->own_addr,
|
||||||
sm->network_ctx, sm->key_mgmt);
|
sm->network_ctx, sm->key_mgmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,8 @@ struct wpa_sm {
|
||||||
u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
|
u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
|
||||||
size_t fils_key_auth_len;
|
size_t fils_key_auth_len;
|
||||||
unsigned int fils_completed:1;
|
unsigned int fils_completed:1;
|
||||||
|
unsigned int fils_erp_pmkid_set:1;
|
||||||
|
u8 fils_erp_pmkid[PMKID_LEN];
|
||||||
#endif /* CONFIG_FILS */
|
#endif /* CONFIG_FILS */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue