250fd0
From 4033935dd9098938838d6d7934ceb65f92a1fa3c Mon Sep 17 00:00:00 2001
250fd0
From: Jouni Malinen <jouni@qca.qualcomm.com>
250fd0
Date: Wed, 22 May 2013 13:24:30 +0300
250fd0
Subject: [PATCH] Fix OKC-based PMKSA cache entry clearing
250fd0
250fd0
Commit c3fea272747f738f5723fc577371fe03711d988f added a call to clear
250fd0
all other PMKSA cache entries for the same network if the PMKSA cache
250fd0
entry of the current AP changed. This was needed to fix OKC cases since
250fd0
the other APs would likely use the new PMK in the future. However, this
250fd0
ended up clearing entries in cases where that is not desired and this
250fd0
resulted in needing additional full EAP authentication with networks
250fd0
that did not support OKC if wpa_supplicant was configured to try to use
250fd0
it.
250fd0
250fd0
Make PMKSA cache entry flushing more limited so that the other entries
250fd0
are removed only if they used the old PMK that was replaced for the
250fd0
current AP and only if that PMK had previously been used successfully
250fd0
(i.e., opportunistic flag was already cleared back to 0 in
250fd0
wpa_supplicant_key_neg_complete()). This is still enough to fix the
250fd0
issue described in that older commit while not causing problems for
250fd0
standard PMKSA caching operations even if OKC is enabled in
250fd0
wpa_supplicant configuration.
250fd0
250fd0
Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
250fd0
---
250fd0
 src/rsn_supp/pmksa_cache.c | 27 ++++++++++++++++++++-------
250fd0
 src/rsn_supp/pmksa_cache.h |  3 ++-
250fd0
 src/rsn_supp/wpa.c         |  2 +-
250fd0
 3 files changed, 23 insertions(+), 9 deletions(-)
250fd0
250fd0
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
250fd0
index df67583..93056ea 100644
250fd0
--- a/src/rsn_supp/pmksa_cache.c
250fd0
+++ b/src/rsn_supp/pmksa_cache.c
250fd0
@@ -160,25 +160,31 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
250fd0
 				os_free(entry);
250fd0
 				return pos;
250fd0
 			}
250fd0
 			if (prev == NULL)
250fd0
 				pmksa->pmksa = pos->next;
250fd0
 			else
250fd0
 				prev->next = pos->next;
250fd0
-			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
250fd0
-				   "the current AP");
250fd0
-			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
250fd0
 
250fd0
 			/*
250fd0
 			 * If OKC is used, there may be other PMKSA cache
250fd0
 			 * entries based on the same PMK. These needs to be
250fd0
 			 * flushed so that a new entry can be created based on
250fd0
-			 * the new PMK.
250fd0
+			 * the new PMK. Only clear other entries if they have a
250fd0
+			 * matching PMK and this PMK has been used successfully
250fd0
+			 * with the current AP, i.e., if opportunistic flag has
250fd0
+			 * been cleared in wpa_supplicant_key_neg_complete().
250fd0
 			 */
250fd0
-			pmksa_cache_flush(pmksa, network_ctx);
250fd0
+			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
250fd0
+				   "the current AP and any PMKSA cache entry "
250fd0
+				   "that was based on the old PMK");
250fd0
+			if (!pos->opportunistic)
250fd0
+				pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
250fd0
+						  pos->pmk_len);
250fd0
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
250fd0
 			break;
250fd0
 		}
250fd0
 		prev = pos;
250fd0
 		pos = pos->next;
250fd0
 	}
250fd0
 
250fd0
 	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
250fd0
@@ -231,23 +237,30 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
250fd0
 }
250fd0
 
250fd0
 
250fd0
 /**
250fd0
  * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
250fd0
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
250fd0
  * @network_ctx: Network configuration context or %NULL to flush all entries
250fd0
+ * @pmk: PMK to match for or %NYLL to match all PMKs
250fd0
+ * @pmk_len: PMK length
250fd0
  */
250fd0
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
250fd0
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
250fd0
+		       const u8 *pmk, size_t pmk_len)
250fd0
 {
250fd0
 	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
250fd0
 	int removed = 0;
250fd0
 
250fd0
 	entry = pmksa->pmksa;
250fd0
 	while (entry) {
250fd0
-		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
250fd0
+		if ((entry->network_ctx == network_ctx ||
250fd0
+		     network_ctx == NULL) &&
250fd0
+		    (pmk == NULL ||
250fd0
+		     (pmk_len == entry->pmk_len &&
250fd0
+		      os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
250fd0
 			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
250fd0
 				   "for " MACSTR, MAC2STR(entry->aa));
250fd0
 			if (prev)
250fd0
 				prev->next = entry->next;
250fd0
 			else
250fd0
 				pmksa->pmksa = entry->next;
250fd0
 			tmp = entry;
250fd0
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
250fd0
index 6f3dfb3..d5aa229 100644
250fd0
--- a/src/rsn_supp/pmksa_cache.h
250fd0
+++ b/src/rsn_supp/pmksa_cache.h
250fd0
@@ -62,15 +62,16 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
250fd0
 void pmksa_cache_clear_current(struct wpa_sm *sm);
250fd0
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
250fd0
 			    const u8 *bssid, void *network_ctx,
250fd0
 			    int try_opportunistic);
250fd0
 struct rsn_pmksa_cache_entry *
250fd0
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
250fd0
 			      void *network_ctx, const u8 *aa);
250fd0
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
250fd0
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
250fd0
+		       const u8 *pmk, size_t pmk_len);
250fd0
 
250fd0
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
250fd0
 
250fd0
 static inline struct rsn_pmksa_cache *
250fd0
 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
250fd0
 				 void *ctx, int reason),
250fd0
 		 void *ctx, struct wpa_sm *sm)
250fd0
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
250fd0
index e50404c..365a710 100644
250fd0
--- a/src/rsn_supp/wpa.c
250fd0
+++ b/src/rsn_supp/wpa.c
250fd0
@@ -2618,15 +2618,15 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
250fd0
 	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
250fd0
 }
250fd0
 
250fd0
 
250fd0
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
250fd0
 {
250fd0
 #ifndef CONFIG_NO_WPA2
250fd0
-	pmksa_cache_flush(sm->pmksa, network_ctx);
250fd0
+	pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
250fd0
 #endif /* CONFIG_NO_WPA2 */
250fd0
 }
250fd0
 
250fd0
 
250fd0
 #ifdef CONFIG_WNM
250fd0
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
250fd0
 {
250fd0
-- 
250fd0
1.8.3.1
250fd0