u8 *ie_buf = NULL;
const u8 *pmk = NULL;
size_t pmk_len = 0;
+ u8 pmk_buf[PMK_LEN_MAX];
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA);
wpabuf_put_buf(data, erp_resp);
- pmk = msk;
- pmk_len = msk_len > PMK_LEN ? PMK_LEN : msk_len;
+ if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
+ 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) {
pmk = pmksa->pmk;
pmk_len = pmksa->pmk_len;
#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,
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher)
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
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,
const u8 *snonce, const u8 *anonce, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher);
#include "crypto/aes_siv.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "eap_common/eap_defs.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "wpa.h"
#include "eloop.h"
wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN);
/* FILS Wrapped Data */
+ sm->fils_erp_pmkid_set = 0;
if (erp_msg) {
wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */
wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */
/* Element ID Extension */
wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA);
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",
/* 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",
elems.fils_wrapped_data,
elems.fils_wrapped_data_len);
if (eapol_sm_failed(sm->eapol))
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)
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");
- sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, PMK_LEN,
- NULL, NULL, 0, sm->bssid,
- sm->own_addr,
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->fils_erp_pmkid, NULL, 0,
+ sm->bssid, sm->own_addr,
sm->network_ctx, sm->key_mgmt);
}
u8 fils_key_auth_sta[FILS_MAX_KEY_AUTH_LEN];
size_t fils_key_auth_len;
unsigned int fils_completed:1;
+ unsigned int fils_erp_pmkid_set:1;
+ u8 fils_erp_pmkid[PMKID_LEN];
#endif /* CONFIG_FILS */
};