1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* 2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * WPA Supplicant - RSN PMKSA cache 3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify 6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as 7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation. 8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license. 11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details. 13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h" 16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h" 18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa.h" 19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eloop.h" 20b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha1.h" 21b349ef9e9f3f5399bf96b3c1c663cb9e547f50a1Dmitry Shmidt#include "crypto/sha256.h" 22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "wpa_i.h" 23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "eapol_supp/eapol_supp_sm.h" 24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "pmksa_cache.h" 25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) 27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic const int pmksa_cache_max_entries = 32; 29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache { 31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ 32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int pmksa_count; /* number of entries in PMKSA cache */ 33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ 34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, 36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int replace); 37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt void *ctx; 38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt}; 39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * rsn_pmkid - Calculate PMK identifier 43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk: Pairwise master key 44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk_len: Length of pmk in bytes 45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @aa: Authenticator address 46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @spa: Supplicant address 47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @use_sha256: Whether to use SHA256-based KDF 48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy 50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) 51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, 53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *spa, u8 *pmkid, int use_sha256) 54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *title = "PMK Name"; 56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *addr[3]; 57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; 58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned char hash[SHA256_MAC_LEN]; 59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[0] = (u8 *) title; 61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[1] = aa; 62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt addr[2] = spa; 63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_IEEE80211W 65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (use_sha256) 66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); 67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_IEEE80211W */ 69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); 70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(pmkid, hash, PMKID_LEN); 71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); 75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) 78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(entry); 80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, 84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry, 85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int replace) 86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa_count--; 88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->free_cb(entry, pmksa->ctx, replace); 89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt _pmksa_cache_free_entry(entry); 90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) 94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache *pmksa = eloop_ctx; 96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time now; 97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&now); 99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { 100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa = entry->next; 102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " 103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt MACSTR, MAC2STR(entry->aa)); 104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_free_entry(pmksa, entry, 0); 105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_set_expiration(pmksa); 108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) 112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache *pmksa = eloop_ctx; 114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->sm->cur_pmksa = NULL; 115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eapol_sm_request_reauth(pmksa->sm->eapol); 116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) 120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int sec; 122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry; 123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time now; 124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); 126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); 127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmksa->pmksa == NULL) 128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&now); 130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sec = pmksa->pmksa->expiration - now.sec; 131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sec < 0) 132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sec = 0; 133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); 134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : 136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL); 137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (entry) { 138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sec = pmksa->pmksa->reauth_time - now.sec; 139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sec < 0) 140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sec = 0; 141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, 142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt NULL); 143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_add - Add a PMKSA cache entry 149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk: The new pairwise master key 151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmk_len: PMK length in bytes, usually PMK_LEN (32) 152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @aa: Authenticator address 153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @spa: Supplicant address 154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @network_ctx: Network configuration context for this PMK 155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @akmp: WPA_KEY_MGMT_* used in key derivation 156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to the added PMKSA cache entry or %NULL on error 157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function create a PMKSA entry for a new PMK and adds it to the PMKSA 159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * cache. If an old entry is already in the cache for the same Authenticator, 160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * this entry will be replaced with the new entry. PMKID will be calculated 161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * based on the PMK and the driver interface is notified of the new PMKID. 162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache_entry * 164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtpmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, 165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *aa, const u8 *spa, void *network_ctx, int akmp) 166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry, *pos, *prev; 168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time now; 169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmksa->sm->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN) 171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = os_zalloc(sizeof(*entry)); 174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (entry == NULL) 175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(entry->pmk, pmk, pmk_len); 177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->pmk_len = pmk_len; 178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, 179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_key_mgmt_sha256(akmp)); 180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&now); 181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; 182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * 183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; 184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->akmp = akmp; 185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(entry->aa, aa, ETH_ALEN); 186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->network_ctx = network_ctx; 187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Replace an old entry for the same Authenticator (if found) with the 189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * new entry */ 190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = pmksa->pmksa; 191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev = NULL; 192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos) { 193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { 194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos->pmk_len == pmk_len && 195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcmp(pos->pmk, pmk, pmk_len) == 0 && 196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == 197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 0) { 198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "WPA: reusing previous " 199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "PMKSA entry"); 200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(entry); 201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos; 202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (prev == NULL) 204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa = pos->next; 205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev->next = pos->next; 207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos == pmksa->sm->cur_pmksa) { 208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* We are about to replace the current PMKSA 209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * cache entry. This happens when the PMKSA 210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * caching attempt fails, so we don't want to 211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * force pmksa_cache_free_entry() to disconnect 212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * at this point. Let's just make sure the old 213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * PMKSA cache entry will not be used in the 214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * future. 215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: replacing current " 217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "PMKSA entry"); 218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->sm->cur_pmksa = NULL; 219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " 221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "the current AP"); 222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_free_entry(pmksa, pos, 1); 223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev = pos; 226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = pos->next; 227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { 230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Remove the oldest entry to make room for the new entry */ 231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = pmksa->pmksa; 232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa = pos->next; 233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " 234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "entry (for " MACSTR ") to make room for new one", 235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt MAC2STR(pos->aa)); 236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid); 237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_free_entry(pmksa, pos, 0); 238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Add the new entry; order by expiration time */ 241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = pmksa->pmksa; 242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev = NULL; 243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos) { 244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos->expiration > entry->expiration) 245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev = pos; 247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = pos->next; 248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (prev == NULL) { 250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->next = pmksa->pmksa; 251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa = entry; 252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_set_expiration(pmksa); 253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else { 254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->next = prev->next; 255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev->next = entry; 256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa_count++; 258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, 259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt MAC2STR(entry->aa)); 260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); 261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return entry; 263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_deinit - Free all entries in PMKSA cache 268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) 271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry, *prev; 273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmksa == NULL) 275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = pmksa->pmksa; 278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->pmksa = NULL; 279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (entry) { 280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt prev = entry; 281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = entry->next; 282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(prev); 283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa_cache_set_expiration(pmksa); 285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(pmksa); 286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_get - Fetch a PMKSA cache entry 291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @aa: Authenticator address or %NULL to match any 293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmkid: PMKID or %NULL to match any 294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to PMKSA cache entry or %NULL if no match was found 295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, 297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *aa, const u8 *pmkid) 298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (entry) { 301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && 302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (pmkid == NULL || 303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) 304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return entry; 305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = entry->next; 306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache 313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Clear references to old data structures when wpa_supplicant is reconfigured. 316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) 318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (entry) { 321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->network_ctx = NULL; 322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = entry->next; 323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic struct rsn_pmksa_cache_entry * 328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtpmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, 329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const struct rsn_pmksa_cache_entry *old_entry, 330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *aa) 331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *new_entry; 333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, 335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aa, pmksa->sm->own_addr, 336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt old_entry->network_ctx, old_entry->akmp); 337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (new_entry == NULL) 338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: reorder entries based on expiration time? */ 341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt new_entry->expiration = old_entry->expiration; 342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt new_entry->opportunistic = 1; 343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return new_entry; 345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry 350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @network_ctx: Network configuration context 352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @aa: Authenticator address for the new AP 353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to a new PMKSA cache entry or %NULL if not available 354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Try to create a new PMKSA cache entry opportunistically by guessing that the 356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * new AP is sharing the same PMK as another AP that has the same SSID and has 357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * already an entry in PMKSA cache. 358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache_entry * 360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtpmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, 361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *aa) 362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (network_ctx == NULL) 366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (entry) { 368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (entry->network_ctx == network_ctx) { 369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = pmksa_cache_clone_entry(pmksa, entry, aa); 370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (entry) { 371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "RSN: added " 372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "opportunistic PMKSA cache entry " 373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "for " MACSTR, MAC2STR(aa)); 374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return entry; 376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = entry->next; 378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_get_current - Get the current used PMKSA entry 385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to the current PMKSA cache entry or %NULL if not available 387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) 389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm == NULL) 391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return sm->cur_pmksa; 393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_clear_current - Clear the current PMKSA entry selection 398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid pmksa_cache_clear_current(struct wpa_sm *sm) 401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm == NULL) 403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa = NULL; 405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_set_current - Set the current PMKSA entry selection 410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @pmkid: PMKID for selecting PMKSA or %NULL if not used 412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @bssid: BSSID for PMKSA or %NULL if not used 413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @network_ctx: Network configuration context 414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @try_opportunistic: Whether to allow opportunistic PMKSA caching 415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 if PMKSA was found or -1 if no matching entry was found 416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, 418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *bssid, void *network_ctx, 419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int try_opportunistic) 420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache *pmksa = sm->pmksa; 422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa = NULL; 423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmkid) 424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid); 425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm->cur_pmksa == NULL && bssid) 426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL); 427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm->cur_pmksa == NULL && try_opportunistic && bssid) 428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, 429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt network_ctx, 430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt bssid); 431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sm->cur_pmksa) { 432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "RSN: PMKID", 433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sm->cur_pmksa->pmkid, PMKID_LEN); 434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_list - Dump text list of entries in PMKSA cache 442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Buffer for the list 444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Length of the buffer 445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: number of bytes written to buffer 446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This function is used to generate a text format representation of the 448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * current PMKSA cache contents for the ctrl_iface PMKSA command. 449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len) 451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int i, ret; 453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *pos = buf; 454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache_entry *entry; 455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time now; 456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&now); 458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, buf + len - pos, 459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Index / AA / PMKID / expiration (in seconds) / " 460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "opportunistic\n"); 461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - buf; 463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt i = 0; 465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = sm->pmksa->pmksa; 466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (entry) { 467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt i++; 468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", 469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt i, MAC2STR(entry->aa)); 470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - buf; 472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, 474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt PMKID_LEN); 475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, buf + len - pos, " %d %d\n", 476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (int) (entry->expiration - now.sec), 477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry->opportunistic); 478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - buf; 480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt entry = entry->next; 482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pos - buf; 484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pmksa_cache_init - Initialize PMKSA cache 489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @free_cb: Callback function to be called when a PMKSA cache entry is freed 490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @ctx: Context pointer for free_cb function 491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @sm: Pointer to WPA state machine data from wpa_sm_init() 492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to PMKSA cache data or %NULL on failure 493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct rsn_pmksa_cache * 495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtpmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, 496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt void *ctx, int replace), 497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt void *ctx, struct wpa_sm *sm) 498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct rsn_pmksa_cache *pmksa; 500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa = os_zalloc(sizeof(*pmksa)); 502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pmksa) { 503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->free_cb = free_cb; 504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->ctx = ctx; 505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pmksa->sm = sm; 506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return pmksa; 509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ 512