]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FILS: Fix PMK and PMKID derivation from ERP
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 13 Jan 2017 19:06:21 +0000 (21:06 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 13 Jan 2017 19:07:40 +0000 (21:07 +0200)
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>
src/ap/ieee802_11.c
src/common/wpa_common.c
src/common/wpa_common.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa_i.h

index fdc2bac3c4db9838e69e42b54ed5949a7d196188..060b6351751ed14aff2c3118a71cd08d27bfea62 100644 (file)
@@ -1166,6 +1166,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
        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;
@@ -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_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;
index 6eb1e6631e2d4d5eb86697144158a7584550e86f..c9cdc698441dd5e4b8bbb328ab5b46353daca854 100644 (file)
@@ -230,6 +230,78 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 
 #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)
index 4e952c1f8869cd73afe5dc6f2dc9fefec48a7570..3288a029b9039745d4291152d25d7ac4d8b5f761 100644 (file)
@@ -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 *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);
index 365845f7cba8cda72aaed4a039c3a8c8c4e3881a..b2fc0ba7d149625c0a0f70e3cfd8c355e59ca244 100644 (file)
@@ -17,6 +17,7 @@
 #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"
@@ -3302,12 +3303,19 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm)
        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",
@@ -3407,6 +3415,9 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t len)
 
        /* 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);
@@ -3415,14 +3426,30 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *data, size_t 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);
        }
 
index 180d4680ad510d1f18cd9adf5eecac62b36cbb23..491fc986a995cae05502f3f30f8b350661985e0b 100644 (file)
@@ -147,6 +147,8 @@ struct wpa_sm {
        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 */
 };