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.
This commit is contained in:
Jouni Malinen 2011-09-07 17:46:00 +03:00 committed by Jouni Malinen
parent f3857c2e6a
commit d8a790b922
7 changed files with 69 additions and 29 deletions

View File

@ -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,

View File

@ -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 */

View File

@ -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 */
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);