]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/rsn_supp/wpa.c
RSN: Report completion only after IGTK configuration
[thirdparty/hostap.git] / src / rsn_supp / wpa.c
index 12e068ac15f6a99a279a03bfda339c7a4b3ab645..eabe88bc07b26440d565d13c123ea04b87e41f4f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2018, Jouni Malinen <j@w1.fi>
  * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This software may be distributed under the terms of the BSD license.
 #include "crypto/sha512.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/ocv.h"
 #include "eap_common/eap_defs.h"
 #include "eapol_supp/eapol_supp_sm.h"
+#include "drivers/driver.h"
 #include "wpa.h"
 #include "eloop.h"
 #include "preauth.h"
 #include "pmksa_cache.h"
 #include "wpa_i.h"
 #include "wpa_ie.h"
-#include "peerkey.h"
 
 
 static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -182,8 +183,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
        int key_info, ver;
        u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
 
-       if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
-           wpa_key_mgmt_suite_b(sm->key_mgmt))
+       if (wpa_use_akm_defined(sm->key_mgmt))
                ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
        else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
                 wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -270,7 +270,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                 * event before receiving this 1/4 message, so try to find a
                 * matching PMKSA cache entry here. */
                sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
-                                               NULL);
+                                               NULL, 0);
                if (sm->cur_pmksa) {
                        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                                "RSN: found matching PMKID from PMKSA cache");
@@ -290,6 +290,18 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                eapol_sm_notify_cached(sm->eapol);
 #ifdef CONFIG_IEEE80211R
                sm->xxkey_len = 0;
+#ifdef CONFIG_SAE
+               if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE &&
+                   sm->pmk_len == PMK_LEN) {
+                       /* Need to allow FT key derivation to proceed with
+                        * PMK from SAE being used as the XXKey in cases where
+                        * the PMKID in msg 1/4 matches the PMKSA entry that was
+                        * just added based on SAE authentication for the
+                        * initial mobility domain association. */
+                       os_memcpy(sm->xxkey, sm->pmk, sm->pmk_len);
+                       sm->xxkey_len = sm->pmk_len;
+               }
+#endif /* CONFIG_SAE */
 #endif /* CONFIG_IEEE80211R */
        } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
                int res, pmk_len;
@@ -313,8 +325,15 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                        u8 buf[2 * PMK_LEN];
                        if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
                        {
-                               os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
-                               sm->xxkey_len = PMK_LEN;
+                               if (wpa_key_mgmt_sha384(sm->key_mgmt)) {
+                                       os_memcpy(sm->xxkey, buf,
+                                                 SHA384_MAC_LEN);
+                                       sm->xxkey_len = SHA384_MAC_LEN;
+                               } else {
+                                       os_memcpy(sm->xxkey, buf + PMK_LEN,
+                                                 PMK_LEN);
+                                       sm->xxkey_len = PMK_LEN;
+                               }
                                os_memset(buf, 0, sizeof(buf));
                        }
 #endif /* CONFIG_IEEE80211R */
@@ -344,8 +363,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                                                     fils_cache_id);
                        }
                        if (!sm->cur_pmksa && pmkid &&
-                           pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
-                       {
+                           pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL,
+                                   0)) {
                                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                                        "RSN: the new PMK matches with the "
                                        "PMKID");
@@ -515,15 +534,25 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
 static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
                          const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
 {
+       const u8 *z = NULL;
+       size_t z_len = 0;
+
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->key_mgmt))
                return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_DPP2
+       if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+               z = wpabuf_head(sm->dpp_z);
+               z_len = wpabuf_len(sm->dpp_z);
+       }
+#endif /* CONFIG_DPP2 */
+
        return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
                              sm->own_addr, sm->bssid, sm->snonce,
                              key->key_nonce, ptk, sm->key_mgmt,
-                             sm->pairwise_cipher);
+                             sm->pairwise_cipher, z, z_len);
 }
 
 
@@ -586,7 +615,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
        /* Calculate PTK which will be stored as a temporary PTK until it has
         * been verified when processing message 3/4. */
        ptk = &sm->tptk;
-       wpa_derive_ptk(sm, src_addr, key, ptk);
+       if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0)
+               goto failed;
        if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
                u8 buf[8];
                /* Supplicant: swap tx/rx Mic keys */
@@ -600,6 +630,33 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
        kde = sm->assoc_wpa_ie;
        kde_len = sm->assoc_wpa_ie_len;
 
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+               u8 *pos;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info for OCI element in EAPOL-Key 2/4");
+                       goto failed;
+               }
+
+               kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
+               if (!kde_buf) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
+                       goto failed;
+               }
+
+               os_memcpy(kde_buf, kde, kde_len);
+               kde = kde_buf;
+               pos = kde + kde_len;
+               if (ocv_insert_oci_kde(&ci, &pos) < 0)
+                       goto failed;
+               kde_len = pos - kde;
+       }
+#endif /* CONFIG_OCV */
+
 #ifdef CONFIG_P2P
        if (sm->p2p) {
                kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
@@ -668,7 +725,9 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
                 * likelihood of the first preauth EAPOL-Start frame getting to
                 * the target AP.
                 */
-               eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+               if (!dl_list_empty(&sm->pmksa_candidates))
+                       eloop_register_timeout(1, 0, wpa_sm_start_preauth,
+                                              sm, NULL);
        }
 
        if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
@@ -726,6 +785,11 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 
        alg = wpa_cipher_to_alg(sm->pairwise_cipher);
        keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+       if (keylen <= 0 || (unsigned int) keylen != sm->ptk.tk_len) {
+               wpa_printf(MSG_DEBUG, "WPA: TK length mismatch: %d != %lu",
+                          keylen, (long unsigned int) sm->ptk.tk_len);
+               return -1;
+       }
        rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
 
        if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
@@ -746,6 +810,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 
        /* TK is not needed anymore in supplicant */
        os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+       sm->ptk.tk_len = 0;
        sm->ptk.installed = 1;
 
        if (sm->wpa_ptk_rekey) {
@@ -956,8 +1021,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
        }
        os_memset(&gd, 0, sizeof(gd));
 
-       wpa_supplicant_key_neg_complete(sm, sm->bssid,
-                                       key_info & WPA_KEY_INFO_SECURE);
        return 0;
 }
 
@@ -983,7 +1046,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
        }
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
-               "WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x",
+               "WPA: IGTK keyid %d pn " COMPACT_MACSTR,
                keyidx, MAC2STR(igtk->pn));
        wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, len);
        if (keyidx > 4095) {
@@ -1394,6 +1457,26 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "Failed to get channel info to validate received OCI in EAPOL-Key 3/4");
+                       return;
+               }
+
+               if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+                                        channel_width_to_int(ci.chanwidth),
+                                        ci.seg1_idx) != 0) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+                               ocv_errorstr);
+                       return;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
                                       &sm->ptk) < 0) {
                goto failed;
@@ -1418,8 +1501,11 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
        wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
 
        if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
-               wpa_supplicant_key_neg_complete(sm, sm->bssid,
-                                               key_info & WPA_KEY_INFO_SECURE);
+               /* No GTK to be set to the driver */
+       } else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "RSN: No GTK KDE included in EAPOL-Key msg 3/4");
+               goto failed;
        } else if (ie.gtk &&
            wpa_supplicant_pairwise_gtk(sm, key,
                                        ie.gtk, ie.gtk_len, key_info) < 0) {
@@ -1434,10 +1520,20 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
                goto failed;
        }
 
+       if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk)
+               wpa_supplicant_key_neg_complete(sm, sm->bssid,
+                                               key_info & WPA_KEY_INFO_SECURE);
+
        if (ie.gtk)
                wpa_sm_set_rekey_offload(sm);
 
-       if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+       /* Add PMKSA cache entry for Suite B AKMs here since PMKID can be
+        * calculated only after KCK has been derived. Though, do not replace an
+        * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID)
+        * to avoid unnecessary changes of PMKID while continuing to use the
+        * same PMK. */
+       if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+           !sm->cur_pmksa) {
                struct rsn_pmksa_cache_entry *sa;
 
                sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL,
@@ -1481,6 +1577,26 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
        }
        maxkeylen = gd->gtk_len = ie.gtk_len - 2;
 
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2");
+                       return -1;
+               }
+
+               if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci,
+                                        channel_width_to_int(ci.chanwidth),
+                                        ci.seg1_idx) != 0) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "%s",
+                               ocv_errorstr);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
                                              gd->gtk_len, maxkeylen,
                                              &gd->key_rsc_len, &gd->alg))
@@ -1601,11 +1717,17 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
        size_t mic_len, hdrlen, rlen;
        struct wpa_eapol_key *reply;
        u8 *rbuf, *key_mic;
+       size_t kde_len = 0;
+
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm))
+               kde_len = OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
 
        mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len);
        hdrlen = sizeof(*reply) + mic_len + 2;
        rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
-                                 hdrlen, &rlen, (void *) &reply);
+                                 hdrlen + kde_len, &rlen, (void *) &reply);
        if (rbuf == NULL)
                return -1;
 
@@ -1627,7 +1749,27 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
                  WPA_REPLAY_COUNTER_LEN);
 
        key_mic = (u8 *) (reply + 1);
-       WPA_PUT_BE16(key_mic + mic_len, 0);
+       WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */
+
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+               u8 *pos;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info for OCI element in EAPOL-Key 2/2");
+                       os_free(rbuf);
+                       return -1;
+               }
+
+               pos = key_mic + mic_len + 2; /* Key Data */
+               if (ocv_insert_oci_kde(&ci, &pos) < 0) {
+                       os_free(rbuf);
+                       return -1;
+               }
+       }
+#endif /* CONFIG_OCV */
 
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
        return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL,
@@ -1718,31 +1860,57 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
        os_memcpy(mic, key + 1, mic_len);
        if (sm->tptk_set) {
                os_memset(key + 1, 0, mic_len);
-               wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
-                                 ver, buf, len, (u8 *) (key + 1));
-               if (os_memcmp_const(mic, key + 1, mic_len) != 0) {
+               if (wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len,
+                                     sm->key_mgmt,
+                                     ver, buf, len, (u8 *) (key + 1)) < 0 ||
+                   os_memcmp_const(mic, key + 1, mic_len) != 0) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Invalid EAPOL-Key MIC "
                                "when using TPTK - ignoring TPTK");
+#ifdef TEST_FUZZ
+                       wpa_printf(MSG_INFO,
+                                  "TEST: Ignore Key MIC failure for fuzz testing");
+                       goto continue_fuzz;
+#endif /* TEST_FUZZ */
                } else {
+#ifdef TEST_FUZZ
+               continue_fuzz:
+#endif /* TEST_FUZZ */
                        ok = 1;
                        sm->tptk_set = 0;
                        sm->ptk_set = 1;
                        os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
                        os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+                       /*
+                        * This assures the same TPTK in sm->tptk can never be
+                        * copied twice to sm->ptk as the new PTK. In
+                        * combination with the installed flag in the wpa_ptk
+                        * struct, this assures the same PTK is only installed
+                        * once.
+                        */
+                       sm->renew_snonce = 1;
                }
        }
 
        if (!ok && sm->ptk_set) {
                os_memset(key + 1, 0, mic_len);
-               wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
-                                 ver, buf, len, (u8 *) (key + 1));
-               if (os_memcmp_const(mic, key + 1, mic_len) != 0) {
+               if (wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len,
+                                     sm->key_mgmt,
+                                     ver, buf, len, (u8 *) (key + 1)) < 0 ||
+                   os_memcmp_const(mic, key + 1, mic_len) != 0) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Invalid EAPOL-Key MIC - "
                                "dropping packet");
+#ifdef TEST_FUZZ
+                       wpa_printf(MSG_INFO,
+                                  "TEST: Ignore Key MIC failure for fuzz testing");
+                       goto continue_fuzz2;
+#endif /* TEST_FUZZ */
                        return -1;
                }
+#ifdef TEST_FUZZ
+       continue_fuzz2:
+#endif /* TEST_FUZZ */
                ok = 1;
        }
 
@@ -1798,10 +1966,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
 #endif /* CONFIG_NO_RC4 */
        } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
                   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
-                  sm->key_mgmt == WPA_KEY_MGMT_OWE ||
-                  sm->key_mgmt == WPA_KEY_MGMT_DPP ||
-                  sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
-                  wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+                  wpa_use_aes_key_wrap(sm->key_mgmt)) {
                u8 *buf;
 
                wpa_printf(MSG_DEBUG,
@@ -1820,14 +1985,25 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
                                "WPA: No memory for AES-UNWRAP buffer");
                        return -1;
                }
+#ifdef TEST_FUZZ
+               os_memset(buf, 0x11, *key_data_len);
+#endif /* TEST_FUZZ */
                if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
                               key_data, buf)) {
+#ifdef TEST_FUZZ
+                       wpa_printf(MSG_INFO,
+                                  "TEST: Ignore AES unwrap failure for fuzz testing");
+                       goto continue_fuzz;
+#endif /* TEST_FUZZ */
                        bin_clear_free(buf, *key_data_len);
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: AES unwrap failed - "
                                "could not decrypt EAPOL-Key key data");
                        return -1;
                }
+#ifdef TEST_FUZZ
+       continue_fuzz:
+#endif /* TEST_FUZZ */
                os_memcpy(key_data, buf, *key_data_len);
                bin_clear_free(buf, *key_data_len);
                WPA_PUT_BE16(((u8 *) (key + 1)) + mic_len, *key_data_len);
@@ -1988,7 +2164,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        u16 key_info, ver;
        u8 *tmp = NULL;
        int ret = -1;
-       struct wpa_peerkey *peerkey = NULL;
        u8 *mic, *key_data;
        size_t mic_len, keyhdrlen;
 
@@ -2079,29 +2254,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
            ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
            ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
-           !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
-           !wpa_key_mgmt_fils(sm->key_mgmt) &&
-           sm->key_mgmt != WPA_KEY_MGMT_OWE &&
-           sm->key_mgmt != WPA_KEY_MGMT_DPP &&
-           sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+           !wpa_use_akm_defined(sm->key_mgmt)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                        "WPA: Unsupported EAPOL-Key descriptor version %d",
                        ver);
                goto out;
        }
 
-       if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
-           ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "OSEN: Unsupported EAPOL-Key descriptor version %d",
-                       ver);
-               goto out;
-       }
-
-       if ((wpa_key_mgmt_suite_b(sm->key_mgmt) ||
-            wpa_key_mgmt_fils(sm->key_mgmt) ||
-            sm->key_mgmt == WPA_KEY_MGMT_DPP ||
-            sm->key_mgmt == WPA_KEY_MGMT_OWE) &&
+       if (wpa_use_akm_defined(sm->key_mgmt) &&
            ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                        "RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
@@ -2112,7 +2272,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->key_mgmt)) {
                /* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
-               if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+               if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+                   !wpa_use_akm_defined(sm->key_mgmt)) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                                "FT: AP did not use AES-128-CMAC");
                        goto out;
@@ -2122,9 +2283,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 #ifdef CONFIG_IEEE80211W
        if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
                if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-                   sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
-                   !wpa_key_mgmt_fils(sm->key_mgmt) &&
-                   !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+                   !wpa_use_akm_defined(sm->key_mgmt)) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                                "WPA: AP did not use the "
                                "negotiated AES-128-CMAC");
@@ -2133,10 +2292,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
        } else
 #endif /* CONFIG_IEEE80211W */
        if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
-           !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
-           !wpa_key_mgmt_fils(sm->key_mgmt) &&
-           sm->key_mgmt != WPA_KEY_MGMT_OWE &&
-           sm->key_mgmt != WPA_KEY_MGMT_DPP &&
+           !wpa_use_akm_defined(sm->key_mgmt) &&
            ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                        "WPA: CCMP is used, but EAPOL-Key "
@@ -2156,7 +2312,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                } else
                        goto out;
        } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
-                  !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+                  !wpa_use_akm_defined(sm->key_mgmt) &&
                   ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                        "WPA: GCMP is used, but EAPOL-Key "
@@ -2164,44 +2320,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                goto out;
        }
 
-#ifdef CONFIG_PEERKEY
-       for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
-               if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
-                       break;
-       }
-
-       if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
-               if (!peerkey->initiator && peerkey->replay_counter_set &&
-                   os_memcmp(key->replay_counter, peerkey->replay_counter,
-                             WPA_REPLAY_COUNTER_LEN) <= 0) {
-                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
-                               "RSN: EAPOL-Key Replay Counter did not "
-                               "increase (STK) - dropping packet");
-                       goto out;
-               } else if (peerkey->initiator) {
-                       u8 _tmp[WPA_REPLAY_COUNTER_LEN];
-                       os_memcpy(_tmp, key->replay_counter,
-                                 WPA_REPLAY_COUNTER_LEN);
-                       inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
-                       if (os_memcmp(_tmp, peerkey->replay_counter,
-                                     WPA_REPLAY_COUNTER_LEN) != 0) {
-                               wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
-                                       "RSN: EAPOL-Key Replay "
-                                       "Counter did not match (STK) - "
-                                       "dropping packet");
-                               goto out;
-                       }
-               }
-       }
-
-       if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
-               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
-                       "RSN: Ack bit in key_info from STK peer");
-               goto out;
-       }
-#endif /* CONFIG_PEERKEY */
-
-       if (!peerkey && sm->rx_replay_counter_set &&
+       if (sm->rx_replay_counter_set &&
            os_memcmp(key->replay_counter, sm->rx_replay_counter,
                      WPA_REPLAY_COUNTER_LEN) <= 0) {
                wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -2210,11 +2329,13 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                goto out;
        }
 
-       if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
-#ifdef CONFIG_PEERKEY
-           && (peerkey == NULL || !peerkey->initiator)
-#endif /* CONFIG_PEERKEY */
-               ) {
+       if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+               wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                       "WPA: Unsupported SMK bit in key_info");
+               goto out;
+       }
+
+       if (!(key_info & WPA_KEY_INFO_ACK)) {
                wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                        "WPA: No Ack bit in key_info");
                goto out;
@@ -2226,17 +2347,10 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                goto out;
        }
 
-       if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
+       if ((key_info & WPA_KEY_INFO_MIC) &&
            wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
                goto out;
 
-#ifdef CONFIG_PEERKEY
-       if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
-           peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp,
-                                        data_len))
-               goto out;
-#endif /* CONFIG_PEERKEY */
-
 #ifdef CONFIG_FILS
        if (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
                if (wpa_supp_aead_decrypt(sm, tmp, data_len, &key_data_len))
@@ -2246,6 +2360,17 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 
        if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
            (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
+               /*
+                * Only decrypt the Key Data field if the frame's authenticity
+                * was verified. When using AES-SIV (FILS), the MIC flag is not
+                * set, so this check should only be performed if mic_len != 0
+                * which is the case in this code branch.
+                */
+               if (!(key_info & WPA_KEY_INFO_MIC)) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+                               "WPA: Ignore EAPOL-Key with encrypted but unauthenticated data");
+                       goto out;
+               }
                if (wpa_supplicant_decrypt_key_data(sm, key, mic_len,
                                                    ver, key_data,
                                                    &key_data_len))
@@ -2259,12 +2384,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                                "non-zero key index");
                        goto out;
                }
-               if (peerkey) {
-                       /* PeerKey 4-Way Handshake */
-                       peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
-                                             key_data, key_data_len);
-               } else if (key_info & (WPA_KEY_INFO_MIC |
-                                      WPA_KEY_INFO_ENCR_KEY_DATA)) {
+               if (key_info & (WPA_KEY_INFO_MIC |
+                               WPA_KEY_INFO_ENCR_KEY_DATA)) {
                        /* 3/4 4-Way Handshake */
                        wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
                                                      key_data_len);
@@ -2274,10 +2395,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                                                      ver, key_data,
                                                      key_data_len);
                }
-       } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
-               /* PeerKey SMK Handshake */
-               peerkey_rx_eapol_smk(sm, src_addr, key, key_data, key_data_len,
-                                    key_info, ver);
        } else {
                if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) ||
                    (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) {
@@ -2462,6 +2579,7 @@ static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
        }
 
        if (deauth) {
+               sm->pmk_len = 0;
                os_memset(sm->pmk, 0, sizeof(sm->pmk));
                wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
        }
@@ -2519,7 +2637,6 @@ void wpa_sm_deinit(struct wpa_sm *sm)
        os_free(sm->ap_rsn_ie);
        wpa_sm_drop_sa(sm);
        os_free(sm->ctx);
-       peerkey_deinit(sm);
 #ifdef CONFIG_IEEE80211R
        os_free(sm->assoc_resp_ies);
 #endif /* CONFIG_IEEE80211R */
@@ -2535,6 +2652,9 @@ void wpa_sm_deinit(struct wpa_sm *sm)
 #ifdef CONFIG_OWE
        crypto_ecdh_deinit(sm->owe_ecdh);
 #endif /* CONFIG_OWE */
+#ifdef CONFIG_DPP2
+       wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
        os_free(sm);
 }
 
@@ -2628,7 +2748,6 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 {
        eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
        eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
-       peerkey_deinit(sm);
        rsn_preauth_deinit(sm);
        pmksa_cache_clear_current(sm);
        if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
@@ -2639,11 +2758,15 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
 #ifdef CONFIG_FILS
        sm->fils_completed = 0;
 #endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+       sm->ft_reassoc_completed = 0;
+#endif /* CONFIG_IEEE80211R */
 
        /* Keys are not needed in the WPA state machine anymore */
        wpa_sm_drop_sa(sm);
 
        sm->msg_3_of_4_ok = 0;
+       os_memset(sm->bssid, 0, ETH_ALEN);
 }
 
 
@@ -2663,6 +2786,8 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
        if (sm == NULL)
                return;
 
+       wpa_hexdump_key(MSG_DEBUG, "WPA: Set PMK based on external data",
+                       pmk, pmk_len);
        sm->pmk_len = pmk_len;
        os_memcpy(sm->pmk, pmk, pmk_len);
 
@@ -2693,11 +2818,15 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
                return;
 
        if (sm->cur_pmksa) {
+               wpa_hexdump_key(MSG_DEBUG,
+                               "WPA: Set PMK based on current PMKSA",
+                               sm->cur_pmksa->pmk, sm->cur_pmksa->pmk_len);
                sm->pmk_len = sm->cur_pmksa->pmk_len;
                os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
        } else {
-               sm->pmk_len = PMK_LEN;
-               os_memset(sm->pmk, 0, PMK_LEN);
+               wpa_printf(MSG_DEBUG, "WPA: No current PMKSA - clear PMK");
+               sm->pmk_len = 0;
+               os_memset(sm->pmk, 0, PMK_LEN_MAX);
        }
 }
 
@@ -2745,7 +2874,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
 
        if (config) {
                sm->network_ctx = config->network_ctx;
-               sm->peerkey_enabled = config->peerkey_enabled;
                sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
                sm->proactive_key_caching = config->proactive_key_caching;
                sm->eap_workaround = config->eap_workaround;
@@ -2769,7 +2897,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
 #endif /* CONFIG_FILS */
        } else {
                sm->network_ctx = NULL;
-               sm->peerkey_enabled = 0;
                sm->allowed_pairwise_cipher = 0;
                sm->proactive_key_caching = 0;
                sm->eap_workaround = 0;
@@ -2879,6 +3006,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
        case WPA_PARAM_MFP:
                sm->mfp = value;
                break;
+       case WPA_PARAM_OCV:
+               sm->ocv = value;
+               break;
        default:
                break;
        }
@@ -2953,6 +3083,19 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
 }
 
 
+int wpa_sm_ocv_enabled(struct wpa_sm *sm)
+{
+       struct wpa_ie_data rsn;
+
+       if (!sm->ocv || !sm->ap_rsn_ie)
+               return 0;
+
+       return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+                                   &rsn) >= 0 &&
+               (rsn.capabilities & WPA_CAPABILITY_OCVC);
+}
+
+
 /**
  * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -3169,7 +3312,7 @@ void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
 int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
                        const void *network_ctx)
 {
-       return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx) != NULL;
+       return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL;
 }
 
 
@@ -3178,6 +3321,7 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
        wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
        sm->ptk_set = 0;
        sm->tptk_set = 0;
+       sm->pmk_len = 0;
        os_memset(sm->pmk, 0, sizeof(sm->pmk));
        os_memset(&sm->ptk, 0, sizeof(sm->ptk));
        os_memset(&sm->tptk, 0, sizeof(sm->tptk));
@@ -3189,8 +3333,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_IEEE80211R
        os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+       sm->xxkey_len = 0;
        os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+       sm->pmk_r0_len = 0;
        os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+       sm->pmk_r1_len = 0;
 #endif /* CONFIG_IEEE80211R */
 }
 
@@ -3275,27 +3422,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
 #endif /* CONFIG_WNM */
 
 
-#ifdef CONFIG_PEERKEY
-int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
-                           const u8 *buf, size_t len)
-{
-       struct wpa_peerkey *peerkey;
-
-       for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
-               if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
-                       break;
-       }
-
-       if (!peerkey)
-               return 0;
-
-       wpa_sm_rx_eapol(sm, src_addr, buf, len);
-
-       return 1;
-}
-#endif /* CONFIG_PEERKEY */
-
-
 #ifdef CONFIG_P2P
 
 int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
@@ -3340,14 +3466,28 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
 
 
 #ifdef CONFIG_TESTING_OPTIONS
+
 void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf)
 {
        wpabuf_free(sm->test_assoc_ie);
        sm->test_assoc_ie = buf;
 }
+
+
+const u8 * wpa_sm_get_anonce(struct wpa_sm *sm)
+{
+       return sm->anonce;
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
+unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm)
+{
+       return sm->key_mgmt;
+}
+
+
 #ifdef CONFIG_FILS
 
 struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md)
@@ -3573,6 +3713,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
        os_memcpy(sm->fils_anonce, elems.fils_nonce, FILS_NONCE_LEN);
        wpa_hexdump(MSG_DEBUG, "FILS: ANonce", sm->fils_anonce, FILS_NONCE_LEN);
 
+#ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->key_mgmt)) {
                struct wpa_ft_ies parse;
 
@@ -3581,7 +3722,8 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
                        goto fail;
                }
 
-               if (wpa_ft_parse_ies(pos, end - pos, &parse) < 0) {
+               if (wpa_ft_parse_ies(pos, end - pos, &parse,
+                                    wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) {
                        wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs");
                        goto fail;
                }
@@ -3620,6 +3762,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
                wpabuf_free(sm->fils_ft_ies);
                sm->fils_ft_ies = NULL;
        }
+#endif /* CONFIG_IEEE80211R */
 
        /* PMKID List */
        if (rsn.pmkid && rsn.num_pmkid > 0) {
@@ -3780,6 +3923,7 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
        struct rsn_ie_hdr *rsnie;
        u16 capab;
        u8 *pos;
+       int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
 
        /* RSNIE[PMKR0Name/PMKR1Name] */
        rsnie = wpabuf_put(buf, sizeof(*rsnie));
@@ -3831,6 +3975,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
        if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
                capab |= WPA_CAPABILITY_MFPC;
 #endif /* CONFIG_IEEE80211W */
+       if (sm->ocv)
+               capab |= WPA_CAPABILITY_OCVC;
        wpabuf_put_le16(buf, capab);
 
        /* PMKID Count */
@@ -3847,22 +3993,26 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
        if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid,
                              sm->ssid_len, sm->mobility_domain,
                              sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
-                             sm->pmk_r0, sm->pmk_r0_name) < 0) {
+                             sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) {
                wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0");
                return -1;
        }
-       wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0", sm->pmk_r0, PMK_LEN);
+       sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN;
+       wpa_hexdump_key(MSG_DEBUG, "FILS+FT: PMK-R0",
+                       sm->pmk_r0, sm->pmk_r0_len);
        wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
                    sm->pmk_r0_name, WPA_PMK_NAME_LEN);
        wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR,
                   MAC2STR(sm->r1kh_id));
        pos = wpabuf_put(buf, WPA_PMK_NAME_LEN);
        if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr,
-                                  pos) < 0) {
+                                  sm->pmk_r1_name, use_sha384) < 0) {
                wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name");
                return -1;
        }
-       wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", pos, WPA_PMK_NAME_LEN);
+       wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+                   WPA_PMK_NAME_LEN);
+       os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 
 #ifdef CONFIG_IEEE80211W
        if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
@@ -3963,6 +4113,26 @@ struct wpabuf * fils_build_assoc_req(struct wpa_sm *sm, const u8 **kek,
 
        /* TODO: FILS IP Address Assignment */
 
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+               u8 *pos;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "FILS: Failed to get channel info for OCI element");
+                       wpabuf_free(buf);
+                       return NULL;
+               }
+
+               pos = wpabuf_put(buf, OCV_OCI_EXTENDED_LEN);
+               if (ocv_insert_extended_oci(&ci, pos) < 0) {
+                       wpabuf_free(buf);
+                       return NULL;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        wpa_hexdump_buf(MSG_DEBUG, "FILS: Association Request plaintext", buf);
 
        *kek = sm->ptk.kek;
@@ -4065,6 +4235,12 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
                return -1;
        }
 
+       if (sm->fils_completed) {
+               wpa_printf(MSG_DEBUG,
+                          "FILS: Association has already been completed for this FILS authentication - ignore unexpected retransmission");
+               return -1;
+       }
+
        wpa_hexdump(MSG_DEBUG, "FILS: (Re)Association Response frame",
                    resp, len);
 
@@ -4120,6 +4296,43 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
                goto fail;
        }
 
+#ifdef CONFIG_OCV
+       if (wpa_sm_ocv_enabled(sm)) {
+               struct wpa_channel_info ci;
+
+               if (wpa_sm_channel_info(sm, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "Failed to get channel info to validate received OCI in FILS (Re)Association Response frame");
+                       goto fail;
+               }
+
+               if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+                                        channel_width_to_int(ci.chanwidth),
+                                        ci.seg1_idx) != 0) {
+                       wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr);
+                       goto fail;
+               }
+       }
+#endif /* CONFIG_OCV */
+
+#ifdef CONFIG_IEEE80211R
+       if (wpa_key_mgmt_ft(sm->key_mgmt) && sm->fils_ft_ies) {
+               struct wpa_ie_data rsn;
+
+               /* Check that PMKR1Name derived by the AP matches */
+               if (!elems.rsn_ie ||
+                   wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+                                        &rsn) < 0 ||
+                   !rsn.pmkid || rsn.num_pmkid != 1 ||
+                   os_memcmp(rsn.pmkid, sm->pmk_r1_name,
+                             WPA_PMK_NAME_LEN) != 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "FILS+FT: No RSNE[PMKR1Name] match in AssocResp");
+                       goto fail;
+               }
+       }
+#endif /* CONFIG_IEEE80211R */
+
        /* Key Delivery */
        if (!elems.key_delivery) {
                wpa_printf(MSG_DEBUG, "FILS: No Key Delivery element");
@@ -4168,6 +4381,11 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 
        alg = wpa_cipher_to_alg(sm->pairwise_cipher);
        keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+       if (keylen <= 0 || (unsigned int) keylen != sm->ptk.tk_len) {
+               wpa_printf(MSG_DEBUG, "FILS: TK length mismatch: %u != %lu",
+                          keylen, (long unsigned int) sm->ptk.tk_len);
+               goto fail;
+       }
        rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
        wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
                        sm->ptk.tk, keylen);
@@ -4184,6 +4402,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
         * takes care of association frame encryption/decryption. */
        /* TK is not needed anymore in supplicant */
        os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+       sm->ptk.tk_len = 0;
        sm->ptk.installed = 1;
 
        /* FILS HLP Container */
@@ -4408,8 +4627,10 @@ int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
                res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info,
                                      os_strlen(info), sm->pmk, hash_len);
        os_memset(prk, 0, SHA512_MAC_LEN);
-       if (res < 0)
+       if (res < 0) {
+               sm->pmk_len = 0;
                return -1;
+       }
        sm->pmk_len = hash_len;
 
        wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len);
@@ -4433,3 +4654,14 @@ void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id)
        }
 #endif /* CONFIG_FILS */
 }
+
+
+#ifdef CONFIG_DPP2
+void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
+{
+       if (sm) {
+               wpabuf_clear_free(sm->dpp_z);
+               sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+       }
+}
+#endif /* CONFIG_DPP2 */