SAE: Do not expire the current PMKSA cache entry
There is no convenient mechanism for reauthenticating and generating a new PMK during an association with SAE. As such, forced PMK update would mean having to disassociate and reauthenticate which is not really desired especially when the default PMKLifetime is only 12 hours. Postpone PMKSA cache entry expiration of the currently used entry with SAE until the association is lost. In addition, do not try to force the EAPOL state machine to perform reauthentication for SAE since that won't work. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
f332f69513
commit
b0f457b619
3 changed files with 66 additions and 7 deletions
|
@ -26,6 +26,8 @@ struct rsn_pmksa_cache {
|
|||
|
||||
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
|
||||
enum pmksa_free_reason reason);
|
||||
bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx);
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
|
@ -57,14 +59,35 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
|
|||
{
|
||||
struct rsn_pmksa_cache *pmksa = eloop_ctx;
|
||||
struct os_reltime now;
|
||||
struct rsn_pmksa_cache_entry *prev = NULL, *tmp;
|
||||
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
|
||||
|
||||
os_get_reltime(&now);
|
||||
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
|
||||
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
|
||||
pmksa->pmksa = entry->next;
|
||||
while (entry && entry->expiration <= now.sec) {
|
||||
if (wpa_key_mgmt_sae(entry->akmp) &&
|
||||
pmksa->is_current_cb(entry, pmksa->ctx)) {
|
||||
/* Do not expire the currently used PMKSA entry for SAE
|
||||
* since there is no convenient mechanism for
|
||||
* reauthenticating during an association with SAE. The
|
||||
* expired entry will be removed after this association
|
||||
* has been lost. */
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: postpone PMKSA cache entry expiration for SAE with "
|
||||
MACSTR, MAC2STR(entry->aa));
|
||||
prev = entry;
|
||||
entry = entry->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
|
||||
MACSTR, MAC2STR(entry->aa));
|
||||
pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
pmksa->pmksa = entry->next;
|
||||
tmp = entry;
|
||||
entry = entry->next;
|
||||
pmksa_cache_free_entry(pmksa, tmp, PMKSA_EXPIRE);
|
||||
}
|
||||
|
||||
pmksa_cache_set_expiration(pmksa);
|
||||
|
@ -91,13 +114,32 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
|
|||
return;
|
||||
os_get_reltime(&now);
|
||||
sec = pmksa->pmksa->expiration - now.sec;
|
||||
if (sec < 0) {
|
||||
sec = 0;
|
||||
if (wpa_key_mgmt_sae(pmksa->pmksa->akmp) &&
|
||||
pmksa->is_current_cb(pmksa->pmksa, pmksa->ctx)) {
|
||||
/* Do not continue polling for the current PMKSA entry
|
||||
* from SAE to expire every second. Use the expiration
|
||||
* time to the following entry, if any, and wait at
|
||||
* maximum 10 minutes to check again.
|
||||
*/
|
||||
entry = pmksa->pmksa->next;
|
||||
if (entry) {
|
||||
sec = entry->expiration - now.sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
else if (sec > 600)
|
||||
sec = 600;
|
||||
} else {
|
||||
sec = 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
|
||||
|
||||
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
|
||||
pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
|
||||
if (entry) {
|
||||
if (entry && !wpa_key_mgmt_sae(entry->akmp)) {
|
||||
sec = pmksa->pmksa->reauth_time - now.sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
|
@ -653,6 +695,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
|
|||
struct rsn_pmksa_cache *
|
||||
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx, enum pmksa_free_reason reason),
|
||||
bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx),
|
||||
void *ctx, struct wpa_sm *sm)
|
||||
{
|
||||
struct rsn_pmksa_cache *pmksa;
|
||||
|
@ -660,6 +704,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
|||
pmksa = os_zalloc(sizeof(*pmksa));
|
||||
if (pmksa) {
|
||||
pmksa->free_cb = free_cb;
|
||||
pmksa->is_current_cb = is_current_cb;
|
||||
pmksa->ctx = ctx;
|
||||
pmksa->sm = sm;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ enum pmksa_free_reason {
|
|||
struct rsn_pmksa_cache *
|
||||
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx, enum pmksa_free_reason reason),
|
||||
bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx),
|
||||
void *ctx, struct wpa_sm *sm);
|
||||
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
|
||||
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
|
||||
|
@ -93,6 +95,8 @@ void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa);
|
|||
static inline struct rsn_pmksa_cache *
|
||||
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx, enum pmksa_free_reason reason),
|
||||
bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx),
|
||||
void *ctx, struct wpa_sm *sm)
|
||||
{
|
||||
return (void *) -1;
|
||||
|
|
|
@ -2903,6 +2903,15 @@ static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
|
|||
}
|
||||
|
||||
|
||||
static bool wpa_sm_pmksa_is_current_cb(struct rsn_pmksa_cache_entry *entry,
|
||||
void *ctx)
|
||||
{
|
||||
struct wpa_sm *sm = ctx;
|
||||
|
||||
return sm->cur_pmksa == entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wpa_sm_init - Initialize WPA state machine
|
||||
* @ctx: Context pointer for callbacks; this needs to be an allocated buffer
|
||||
|
@ -2926,7 +2935,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
|
|||
sm->dot11RSNAConfigPMKReauthThreshold = 70;
|
||||
sm->dot11RSNAConfigSATimeout = 60;
|
||||
|
||||
sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
|
||||
sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb,
|
||||
wpa_sm_pmksa_is_current_cb, sm, sm);
|
||||
if (sm->pmksa == NULL) {
|
||||
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
|
||||
"RSN: PMKSA cache initialization failed");
|
||||
|
|
Loading…
Reference in a new issue