[PATCH v2] wpa_supplicant: Add network option to disable PMKSA caching

Jason Huang Jason.Huang2 at infineon.com
Tue Jun 30 20:41:31 PDT 2026


From: Darren Li <Darren.Li at infineon.com>

Some certification-oriented test setups need to disable PMKSA
caching on the STA side. Using a very short dot11RSNAConfigPMKLifetime
value for this purpose lets a PMKSA entry be created and then expire,
which can trigger the standard PMKSA expiration deauthentication behavior.

Add a per-network disable_pmksa_caching parameter for wpa_supplicant so
such tests can explicitly avoid adding or selecting PMKSA cache entries.
This preserves the existing PMKSA expiration/removal deauthentication
behavior while providing a direct way to disable PMKSA caching.

The option defaults to disabled, matching existing behavior.

Signed-off-by: Darren Li <Darren.Li at infineon.com>
Signed-off-by: Jason Huang <jason.huang2 at infineon.com>
---
 src/rsn_supp/pmksa_cache.c         | 21 ++++++++++++++++++
 src/rsn_supp/wpa.c                 | 34 ++++++++++++++++++++++++++++++
 src/rsn_supp/wpa.h                 |  1 +
 src/rsn_supp/wpa_i.h               |  1 +
 wpa_supplicant/config.c            |  1 +
 wpa_supplicant/config_file.c       |  1 +
 wpa_supplicant/config_ssid.h       |  7 ++++++
 wpa_supplicant/wpa_supplicant.conf |  5 +++++
 wpa_supplicant/wpas_glue.c         |  1 +
 9 files changed, 72 insertions(+)

diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 9506dfdf1..3c4e37870 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -249,6 +249,12 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 	if (wpa_key_mgmt_suite_b(akmp) && !kck)
 		return NULL;
 
+	if (pmksa->sm && pmksa->sm->disable_pmksa_caching) {
+		wpa_printf(MSG_DEBUG,
+			   "RSN: PMKSA caching disabled - skip adding PMKSA cache entry");
+		return NULL;
+	}
+
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL)
 		return NULL;
@@ -337,6 +343,13 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
 {
 	struct rsn_pmksa_cache_entry *pos, *prev;
 
+	if (pmksa->sm && pmksa->sm->disable_pmksa_caching) {
+		wpa_printf(MSG_DEBUG,
+			   "RSN: PMKSA caching disabled - skip adding PMKSA cache entry");
+		_pmksa_cache_free_entry(entry);
+		return NULL;
+	}
+
 	/* Replace an old entry for the same Authenticator (if found) with the
 	 * new entry */
 	pos = pmksa->pmksa;
@@ -653,6 +666,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
 {
 	if (sm == NULL)
 		return NULL;
+	if (sm->disable_pmksa_caching)
+		return NULL;
 	return sm->cur_pmksa;
 }
 
@@ -693,6 +708,12 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 	wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
 		   "try_opportunistic=%d akmp=0x%x",
 		   network_ctx, try_opportunistic, akmp);
+	if (sm->disable_pmksa_caching) {
+		wpa_printf(MSG_DEBUG,
+			   "RSN: PMKSA caching disabled - skip cache search");
+		sm->cur_pmksa = NULL;
+		return -1;
+	}
 	if (pmkid)
 		wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
 			    pmkid, PMKID_LEN);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 068d653f2..15f213685 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -445,6 +445,26 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 						     fils_cache_id, auth_alg);
 			}
 			if (!sm->cur_pmksa && pmkid &&
+			    sm->disable_pmksa_caching &&
+			    sm->proto == WPA_PROTO_RSN &&
+			    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+				u8 new_pmkid[PMKID_LEN];
+
+				rsn_pmkid(sm->pmk, sm->pmk_len, src_addr,
+					  sm->own_addr, new_pmkid,
+					  sm->key_mgmt);
+				if (os_memcmp_const(pmkid, new_pmkid,
+						    PMKID_LEN) != 0) {
+					wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+						"RSN: PMKID mismatch with PMKSA caching disabled");
+					return -1;
+				}
+
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: PMKID matches fresh PMK with PMKSA caching disabled");
+				abort_cached = 0;
+			} else if (!sm->cur_pmksa && pmkid &&
 			    pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr,
 					    pmkid, NULL, 0)) {
 				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -4837,6 +4857,13 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
 		}
 #endif /* CONFIG_FILS */
 		sm->beacon_prot = config->beacon_prot;
+		sm->disable_pmksa_caching = config->disable_pmksa_caching;
+		if (sm->disable_pmksa_caching) {
+			pmksa_cache_clear_current(sm);
+			if (wpa_sm_get_state(sm) != WPA_COMPLETED)
+				pmksa_cache_flush(sm->pmksa, sm->network_ctx,
+						  NULL, 0, false, NULL);
+		}
 	} else {
 		sm->network_ctx = NULL;
 		sm->allowed_pairwise_cipher = 0;
@@ -4850,6 +4877,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
 		sm->owe_ptk_workaround = 0;
 		sm->beacon_prot = 0;
 		sm->force_kdk_derivation = false;
+		sm->disable_pmksa_caching = 0;
 	}
 }
 
@@ -5862,6 +5890,9 @@ 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 u8 *own_addr,
 			const void *network_ctx)
 {
+	if (sm->disable_pmksa_caching)
+		return 0;
+
 	return pmksa_cache_get(sm->pmksa, bssid, own_addr, NULL, network_ctx,
 			       0) != NULL;
 }
@@ -5873,6 +5904,9 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
 						      const void *network_ctx,
 						      int akmp)
 {
+	if (sm->disable_pmksa_caching)
+		return NULL;
+
 	return pmksa_cache_get(sm->pmksa, aa, sm->own_addr, pmkid, network_ctx,
 			       akmp);
 }
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index d42a7c102..af6f48af6 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -172,6 +172,7 @@ struct rsn_supp_config {
 	const u8 *fils_cache_id;
 	int beacon_prot;
 	bool force_kdk_derivation;
+	int disable_pmksa_caching;
 };
 
 struct wpa_sm_link {
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index fc99d2041..d8c594c7e 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -257,6 +257,7 @@ struct wpa_sm {
 	int last_kck_eapol_key_ver;
 	u8 last_kck_aa[ETH_ALEN];
 	int last_eapol_key_ver;
+	int disable_pmksa_caching;
 };
 
 
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b05a4d985..d58b603fa 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2960,6 +2960,7 @@ static const struct parse_data ssid_fields[] = {
 #ifdef CONFIG_PASN
 	{ FUNC(pasn_groups) },
 #endif /* CONFIG_PASN */
+	{ INT_RANGE(disable_pmksa_caching, 0, 1) },
 };
 
 #undef OFFSET
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 7360f7012..41c4fe06b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -981,6 +981,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid,
 	INT(beacon_prot);
 	INT(transition_disable);
 	INT(sae_pk);
+	INT(disable_pmksa_caching);
 #ifdef CONFIG_HT_OVERRIDES
 	INT_DEF(disable_ht, DEFAULT_DISABLE_HT);
 	INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 369b867b8..e41f72c93 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -1406,6 +1406,13 @@ struct wpa_ssid {
 	 */
 	int *pasn_groups;
 #endif /* CONFIG_PASN */
+
+	/**
+	 * disable_pmksa_caching - Disable PMKSA caching
+	 * 0 = PMKSA caching enabled (default)
+	 * 1 = PMKSA caching disabled
+	 */
+	int disable_pmksa_caching;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 56533cb17..62d534e37 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1260,6 +1260,11 @@ fast_reauth=1
 # 0 = disabled (default unless changed with the global okc parameter)
 # 1 = enabled
 #
+# disable_pmksa_caching:
+# Disable PMKSA caching for this network.
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#
 # ft_eap_pmksa_caching:
 # Whether FT-EAP PMKSA caching is allowed
 # 0 = do not try to use PMKSA caching with FT-EAP (default)
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index e57114503..f19052cdc 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1611,6 +1611,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
 		conf.force_kdk_derivation = wpa_s->conf->force_kdk_derivation;
 #endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_PASN */
+		conf.disable_pmksa_caching = ssid->disable_pmksa_caching;
 	}
 	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
 }
-- 
2.25.1




More information about the Hostap mailing list