From d8a790b9228ca91eadc8f26faf87287c330510a1 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 7 Sep 2011 17:46:00 +0300 Subject: [PATCH] Flush PMKSA cache entries and invalidate EAP state on network changes If a network configuration block is removed or modified, flush all PMKSA cache entries that were created using that network configuration. Similarly, invalidate EAP state (fast re-auth). The special case for OKC on wpa_supplicant reconfiguration (network_ctx pointer change) is now addressed as part of the PMKSA cache flushing, so it does not need a separate mechanism for clearing the network_ctx values in the PMKSA cache. --- src/rsn_supp/pmksa_cache.c | 50 ++++++++++++++++++++++----------- src/rsn_supp/pmksa_cache.h | 11 ++++---- src/rsn_supp/wpa.c | 10 +++++-- src/rsn_supp/wpa.h | 7 +++++ wpa_supplicant/ctrl_iface.c | 17 +++++++---- wpa_supplicant/notify.c | 2 ++ wpa_supplicant/wpa_supplicant.c | 1 + 7 files changed, 69 insertions(+), 29 deletions(-) diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index 12f1f1ef3..6d828a43e 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -229,6 +229,40 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, } +/** + * pmksa_cache_flush - Flush PMKSA cache entries for a specific network + * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() + * @network_ctx: Network configuration context or %NULL to flush all entries + */ +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx) +{ + struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp; + int removed = 0; + + entry = pmksa->pmksa; + while (entry) { + if (entry->network_ctx == network_ctx || network_ctx == NULL) { + wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry " + "for " MACSTR, MAC2STR(entry->aa)); + if (prev) + prev->next = entry->next; + else + pmksa->pmksa = entry->next; + tmp = entry; + entry = entry->next; + wpa_sm_remove_pmkid(pmksa->sm, tmp->aa, tmp->pmkid); + pmksa_cache_free_entry(pmksa, tmp, 0); + removed++; + } else { + prev = entry; + entry = entry->next; + } + } + if (removed) + pmksa_cache_set_expiration(pmksa); +} + + /** * pmksa_cache_deinit - Free all entries in PMKSA cache * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() @@ -274,22 +308,6 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, } -/** - * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache - * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() - * - * Clear references to old data structures when wpa_supplicant is reconfigured. - */ -void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -{ - struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; - while (entry) { - entry->network_ctx = NULL; - entry = entry->next; - } -} - - static struct rsn_pmksa_cache_entry * pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, const struct rsn_pmksa_cache_entry *old_entry, diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h index a1447e526..840827d79 100644 --- a/src/rsn_supp/pmksa_cache.h +++ b/src/rsn_supp/pmksa_cache.h @@ -57,7 +57,6 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, void *network_ctx, int akmp); -void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm); void pmksa_cache_clear_current(struct wpa_sm *sm); int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, @@ -66,6 +65,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa); +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx); #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ @@ -106,10 +106,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, return NULL; } -static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) -{ -} - static inline void pmksa_cache_clear_current(struct wpa_sm *sm) { } @@ -122,6 +118,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, return -1; } +static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, + void *network_ctx) +{ +} + #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ #endif /* PMKSA_CACHE_H */ diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 047dcc11c..4ffbac5d2 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2269,8 +2269,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->ssid_len = 0; sm->wpa_ptk_rekey = 0; } - if (config == NULL || config->network_ctx != sm->network_ctx) - pmksa_cache_notify_reconfig(sm->pmksa); } @@ -2654,3 +2652,11 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) { os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN); } + + +void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx) +{ +#ifndef CONFIG_NO_WPA2 + pmksa_cache_flush(sm->pmksa, network_ctx); +#endif /* CONFIG_NO_WPA2 */ +} diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 48090e0c8..a01baf90d 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -136,6 +136,8 @@ int wpa_sm_has_ptk(struct wpa_sm *sm); void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr); +void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); + #else /* CONFIG_NO_WPA */ static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) @@ -286,6 +288,11 @@ static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm, { } +static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, + void *network_ctx) +{ +} + #endif /* CONFIG_NO_WPA */ #ifdef CONFIG_PEERKEY diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 22c31fdff..8b3b4fdb5 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1395,8 +1395,8 @@ static int wpa_supplicant_ctrl_iface_remove_network( wpas_notify_network_removed(wpa_s, remove_ssid); wpa_config_remove_network(wpa_s->conf, id); } + eapol_sm_invalidate_cached_session(wpa_s->eapol); if (wpa_s->current_ssid) { - eapol_sm_invalidate_cached_session(wpa_s->eapol); wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_supplicant_disassociate(wpa_s, @@ -1418,12 +1418,15 @@ static int wpa_supplicant_ctrl_iface_remove_network( return -1; } - if (ssid == wpa_s->current_ssid) { + if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) { /* - * Invalidate the EAP session cache if the current network is - * removed. + * Invalidate the EAP session cache if the current or + * previously used network is removed. */ eapol_sm_invalidate_cached_session(wpa_s->eapol); + } + + if (ssid == wpa_s->current_ssid) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); @@ -1471,10 +1474,12 @@ static int wpa_supplicant_ctrl_iface_set_network( return -1; } - if (wpa_s->current_ssid == ssid) { + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); + + if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) { /* * Invalidate the EAP session cache if anything in the current - * configuration changes. + * or previously used configuration changes. */ eapol_sm_invalidate_cached_session(wpa_s->eapol); } diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c index 0d2f54253..ed466bdc4 100644 --- a/wpa_supplicant/notify.c +++ b/wpa_supplicant/notify.c @@ -22,6 +22,7 @@ #include "dbus/dbus_common.h" #include "dbus/dbus_old.h" #include "dbus/dbus_new.h" +#include "rsn_supp/wpa.h" #include "driver_i.h" #include "scan.h" #include "p2p_supplicant.h" @@ -238,6 +239,7 @@ void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s, void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); if (wpa_s->global->p2p_group_formation != wpa_s) wpas_dbus_unregister_network(wpa_s, ssid->id); } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 006cfb07a..e50c8399a 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -726,6 +726,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) } eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_sm_set_config(wpa_s->wpa, NULL); + wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth); rsn_preauth_deinit(wpa_s->wpa);