1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd - PMKSA cache for IEEE 802.11i RSN 3*f05cddf9SRui Paulo * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "utils/common.h" 12e28a4053SRui Paulo #include "utils/eloop.h" 13e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h" 14e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h" 15e28a4053SRui Paulo #include "sta_info.h" 16e28a4053SRui Paulo #include "ap_config.h" 17e28a4053SRui Paulo #include "pmksa_cache_auth.h" 18e28a4053SRui Paulo 19e28a4053SRui Paulo 20e28a4053SRui Paulo static const int pmksa_cache_max_entries = 1024; 21e28a4053SRui Paulo static const int dot11RSNAConfigPMKLifetime = 43200; 22e28a4053SRui Paulo 23e28a4053SRui Paulo struct rsn_pmksa_cache { 24e28a4053SRui Paulo #define PMKID_HASH_SIZE 128 25e28a4053SRui Paulo #define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f) 26e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE]; 27e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 28e28a4053SRui Paulo int pmksa_count; 29e28a4053SRui Paulo 30e28a4053SRui Paulo void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx); 31e28a4053SRui Paulo void *ctx; 32e28a4053SRui Paulo }; 33e28a4053SRui Paulo 34e28a4053SRui Paulo 35e28a4053SRui Paulo static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); 36e28a4053SRui Paulo 37e28a4053SRui Paulo 38e28a4053SRui Paulo static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) 39e28a4053SRui Paulo { 40e28a4053SRui Paulo if (entry == NULL) 41e28a4053SRui Paulo return; 42e28a4053SRui Paulo os_free(entry->identity); 43*f05cddf9SRui Paulo wpabuf_free(entry->cui); 44e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 45e28a4053SRui Paulo radius_free_class(&entry->radius_class); 46e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 47e28a4053SRui Paulo os_free(entry); 48e28a4053SRui Paulo } 49e28a4053SRui Paulo 50e28a4053SRui Paulo 51e28a4053SRui Paulo static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, 52e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry) 53e28a4053SRui Paulo { 54e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pos, *prev; 55e28a4053SRui Paulo 56e28a4053SRui Paulo pmksa->pmksa_count--; 57e28a4053SRui Paulo pmksa->free_cb(entry, pmksa->ctx); 58e28a4053SRui Paulo pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; 59e28a4053SRui Paulo prev = NULL; 60e28a4053SRui Paulo while (pos) { 61e28a4053SRui Paulo if (pos == entry) { 62e28a4053SRui Paulo if (prev != NULL) { 63e28a4053SRui Paulo prev->hnext = pos->hnext; 64e28a4053SRui Paulo } else { 65e28a4053SRui Paulo pmksa->pmkid[PMKID_HASH(entry->pmkid)] = 66e28a4053SRui Paulo pos->hnext; 67e28a4053SRui Paulo } 68e28a4053SRui Paulo break; 69e28a4053SRui Paulo } 70e28a4053SRui Paulo prev = pos; 71e28a4053SRui Paulo pos = pos->hnext; 72e28a4053SRui Paulo } 73e28a4053SRui Paulo 74e28a4053SRui Paulo pos = pmksa->pmksa; 75e28a4053SRui Paulo prev = NULL; 76e28a4053SRui Paulo while (pos) { 77e28a4053SRui Paulo if (pos == entry) { 78e28a4053SRui Paulo if (prev != NULL) 79e28a4053SRui Paulo prev->next = pos->next; 80e28a4053SRui Paulo else 81e28a4053SRui Paulo pmksa->pmksa = pos->next; 82e28a4053SRui Paulo break; 83e28a4053SRui Paulo } 84e28a4053SRui Paulo prev = pos; 85e28a4053SRui Paulo pos = pos->next; 86e28a4053SRui Paulo } 87e28a4053SRui Paulo _pmksa_cache_free_entry(entry); 88e28a4053SRui Paulo } 89e28a4053SRui Paulo 90e28a4053SRui Paulo 91e28a4053SRui Paulo static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) 92e28a4053SRui Paulo { 93e28a4053SRui Paulo struct rsn_pmksa_cache *pmksa = eloop_ctx; 94e28a4053SRui Paulo struct os_time now; 95e28a4053SRui Paulo 96e28a4053SRui Paulo os_get_time(&now); 97e28a4053SRui Paulo while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { 98e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " 99*f05cddf9SRui Paulo MACSTR, MAC2STR(pmksa->pmksa->spa)); 100*f05cddf9SRui Paulo pmksa_cache_free_entry(pmksa, pmksa->pmksa); 101e28a4053SRui Paulo } 102e28a4053SRui Paulo 103e28a4053SRui Paulo pmksa_cache_set_expiration(pmksa); 104e28a4053SRui Paulo } 105e28a4053SRui Paulo 106e28a4053SRui Paulo 107e28a4053SRui Paulo static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) 108e28a4053SRui Paulo { 109e28a4053SRui Paulo int sec; 110e28a4053SRui Paulo struct os_time now; 111e28a4053SRui Paulo 112e28a4053SRui Paulo eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); 113e28a4053SRui Paulo if (pmksa->pmksa == NULL) 114e28a4053SRui Paulo return; 115e28a4053SRui Paulo os_get_time(&now); 116e28a4053SRui Paulo sec = pmksa->pmksa->expiration - now.sec; 117e28a4053SRui Paulo if (sec < 0) 118e28a4053SRui Paulo sec = 0; 119e28a4053SRui Paulo eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); 120e28a4053SRui Paulo } 121e28a4053SRui Paulo 122e28a4053SRui Paulo 123e28a4053SRui Paulo static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry, 124e28a4053SRui Paulo struct eapol_state_machine *eapol) 125e28a4053SRui Paulo { 126e28a4053SRui Paulo if (eapol == NULL) 127e28a4053SRui Paulo return; 128e28a4053SRui Paulo 129e28a4053SRui Paulo if (eapol->identity) { 130e28a4053SRui Paulo entry->identity = os_malloc(eapol->identity_len); 131e28a4053SRui Paulo if (entry->identity) { 132e28a4053SRui Paulo entry->identity_len = eapol->identity_len; 133e28a4053SRui Paulo os_memcpy(entry->identity, eapol->identity, 134e28a4053SRui Paulo eapol->identity_len); 135e28a4053SRui Paulo } 136e28a4053SRui Paulo } 137e28a4053SRui Paulo 138*f05cddf9SRui Paulo if (eapol->radius_cui) 139*f05cddf9SRui Paulo entry->cui = wpabuf_dup(eapol->radius_cui); 140*f05cddf9SRui Paulo 141e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 142e28a4053SRui Paulo radius_copy_class(&entry->radius_class, &eapol->radius_class); 143e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 144e28a4053SRui Paulo 145e28a4053SRui Paulo entry->eap_type_authsrv = eapol->eap_type_authsrv; 146e28a4053SRui Paulo entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id; 147e28a4053SRui Paulo } 148e28a4053SRui Paulo 149e28a4053SRui Paulo 150e28a4053SRui Paulo void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, 151e28a4053SRui Paulo struct eapol_state_machine *eapol) 152e28a4053SRui Paulo { 153e28a4053SRui Paulo if (entry == NULL || eapol == NULL) 154e28a4053SRui Paulo return; 155e28a4053SRui Paulo 156e28a4053SRui Paulo if (entry->identity) { 157e28a4053SRui Paulo os_free(eapol->identity); 158e28a4053SRui Paulo eapol->identity = os_malloc(entry->identity_len); 159e28a4053SRui Paulo if (eapol->identity) { 160e28a4053SRui Paulo eapol->identity_len = entry->identity_len; 161e28a4053SRui Paulo os_memcpy(eapol->identity, entry->identity, 162e28a4053SRui Paulo entry->identity_len); 163e28a4053SRui Paulo } 164e28a4053SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA", 165e28a4053SRui Paulo eapol->identity, eapol->identity_len); 166e28a4053SRui Paulo } 167e28a4053SRui Paulo 168*f05cddf9SRui Paulo if (entry->cui) { 169*f05cddf9SRui Paulo wpabuf_free(eapol->radius_cui); 170*f05cddf9SRui Paulo eapol->radius_cui = wpabuf_dup(entry->cui); 171*f05cddf9SRui Paulo } 172*f05cddf9SRui Paulo 173e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 174e28a4053SRui Paulo radius_free_class(&eapol->radius_class); 175e28a4053SRui Paulo radius_copy_class(&eapol->radius_class, &entry->radius_class); 176e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 177e28a4053SRui Paulo if (eapol->radius_class.attr) { 178e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from " 179e28a4053SRui Paulo "PMKSA", (unsigned long) eapol->radius_class.count); 180e28a4053SRui Paulo } 181e28a4053SRui Paulo 182e28a4053SRui Paulo eapol->eap_type_authsrv = entry->eap_type_authsrv; 183e28a4053SRui Paulo ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id; 184e28a4053SRui Paulo } 185e28a4053SRui Paulo 186e28a4053SRui Paulo 187e28a4053SRui Paulo static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, 188e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry) 189e28a4053SRui Paulo { 190e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pos, *prev; 191e28a4053SRui Paulo 192e28a4053SRui Paulo /* Add the new entry; order by expiration time */ 193e28a4053SRui Paulo pos = pmksa->pmksa; 194e28a4053SRui Paulo prev = NULL; 195e28a4053SRui Paulo while (pos) { 196e28a4053SRui Paulo if (pos->expiration > entry->expiration) 197e28a4053SRui Paulo break; 198e28a4053SRui Paulo prev = pos; 199e28a4053SRui Paulo pos = pos->next; 200e28a4053SRui Paulo } 201e28a4053SRui Paulo if (prev == NULL) { 202e28a4053SRui Paulo entry->next = pmksa->pmksa; 203e28a4053SRui Paulo pmksa->pmksa = entry; 204e28a4053SRui Paulo } else { 205e28a4053SRui Paulo entry->next = prev->next; 206e28a4053SRui Paulo prev->next = entry; 207e28a4053SRui Paulo } 208e28a4053SRui Paulo entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; 209e28a4053SRui Paulo pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry; 210e28a4053SRui Paulo 211e28a4053SRui Paulo pmksa->pmksa_count++; 212*f05cddf9SRui Paulo if (prev == NULL) 213*f05cddf9SRui Paulo pmksa_cache_set_expiration(pmksa); 214e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, 215e28a4053SRui Paulo MAC2STR(entry->spa)); 216e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN); 217e28a4053SRui Paulo } 218e28a4053SRui Paulo 219e28a4053SRui Paulo 220e28a4053SRui Paulo /** 221e28a4053SRui Paulo * pmksa_cache_auth_add - Add a PMKSA cache entry 222e28a4053SRui Paulo * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() 223e28a4053SRui Paulo * @pmk: The new pairwise master key 224e28a4053SRui Paulo * @pmk_len: PMK length in bytes, usually PMK_LEN (32) 225e28a4053SRui Paulo * @aa: Authenticator address 226e28a4053SRui Paulo * @spa: Supplicant address 227e28a4053SRui Paulo * @session_timeout: Session timeout 228e28a4053SRui Paulo * @eapol: Pointer to EAPOL state machine data 229e28a4053SRui Paulo * @akmp: WPA_KEY_MGMT_* used in key derivation 230e28a4053SRui Paulo * Returns: Pointer to the added PMKSA cache entry or %NULL on error 231e28a4053SRui Paulo * 232e28a4053SRui Paulo * This function create a PMKSA entry for a new PMK and adds it to the PMKSA 233e28a4053SRui Paulo * cache. If an old entry is already in the cache for the same Supplicant, 234e28a4053SRui Paulo * this entry will be replaced with the new entry. PMKID will be calculated 235e28a4053SRui Paulo * based on the PMK. 236e28a4053SRui Paulo */ 237e28a4053SRui Paulo struct rsn_pmksa_cache_entry * 238e28a4053SRui Paulo pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, 239e28a4053SRui Paulo const u8 *pmk, size_t pmk_len, 240e28a4053SRui Paulo const u8 *aa, const u8 *spa, int session_timeout, 241e28a4053SRui Paulo struct eapol_state_machine *eapol, int akmp) 242e28a4053SRui Paulo { 243e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry, *pos; 244e28a4053SRui Paulo struct os_time now; 245e28a4053SRui Paulo 246e28a4053SRui Paulo if (pmk_len > PMK_LEN) 247e28a4053SRui Paulo return NULL; 248e28a4053SRui Paulo 249e28a4053SRui Paulo entry = os_zalloc(sizeof(*entry)); 250e28a4053SRui Paulo if (entry == NULL) 251e28a4053SRui Paulo return NULL; 252e28a4053SRui Paulo os_memcpy(entry->pmk, pmk, pmk_len); 253e28a4053SRui Paulo entry->pmk_len = pmk_len; 254e28a4053SRui Paulo rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, 255e28a4053SRui Paulo wpa_key_mgmt_sha256(akmp)); 256e28a4053SRui Paulo os_get_time(&now); 257e28a4053SRui Paulo entry->expiration = now.sec; 258e28a4053SRui Paulo if (session_timeout > 0) 259e28a4053SRui Paulo entry->expiration += session_timeout; 260e28a4053SRui Paulo else 261e28a4053SRui Paulo entry->expiration += dot11RSNAConfigPMKLifetime; 262e28a4053SRui Paulo entry->akmp = akmp; 263e28a4053SRui Paulo os_memcpy(entry->spa, spa, ETH_ALEN); 264e28a4053SRui Paulo pmksa_cache_from_eapol_data(entry, eapol); 265e28a4053SRui Paulo 266e28a4053SRui Paulo /* Replace an old entry for the same STA (if found) with the new entry 267e28a4053SRui Paulo */ 268e28a4053SRui Paulo pos = pmksa_cache_auth_get(pmksa, spa, NULL); 269e28a4053SRui Paulo if (pos) 270e28a4053SRui Paulo pmksa_cache_free_entry(pmksa, pos); 271e28a4053SRui Paulo 272e28a4053SRui Paulo if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { 273e28a4053SRui Paulo /* Remove the oldest entry to make room for the new entry */ 274e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " 275e28a4053SRui Paulo "entry (for " MACSTR ") to make room for new one", 276e28a4053SRui Paulo MAC2STR(pmksa->pmksa->spa)); 277e28a4053SRui Paulo pmksa_cache_free_entry(pmksa, pmksa->pmksa); 278e28a4053SRui Paulo } 279e28a4053SRui Paulo 280e28a4053SRui Paulo pmksa_cache_link_entry(pmksa, entry); 281e28a4053SRui Paulo 282e28a4053SRui Paulo return entry; 283e28a4053SRui Paulo } 284e28a4053SRui Paulo 285e28a4053SRui Paulo 286e28a4053SRui Paulo struct rsn_pmksa_cache_entry * 287e28a4053SRui Paulo pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa, 288e28a4053SRui Paulo const struct rsn_pmksa_cache_entry *old_entry, 289e28a4053SRui Paulo const u8 *aa, const u8 *pmkid) 290e28a4053SRui Paulo { 291e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry; 292e28a4053SRui Paulo 293e28a4053SRui Paulo entry = os_zalloc(sizeof(*entry)); 294e28a4053SRui Paulo if (entry == NULL) 295e28a4053SRui Paulo return NULL; 296e28a4053SRui Paulo os_memcpy(entry->pmkid, pmkid, PMKID_LEN); 297e28a4053SRui Paulo os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len); 298e28a4053SRui Paulo entry->pmk_len = old_entry->pmk_len; 299e28a4053SRui Paulo entry->expiration = old_entry->expiration; 300e28a4053SRui Paulo entry->akmp = old_entry->akmp; 301e28a4053SRui Paulo os_memcpy(entry->spa, old_entry->spa, ETH_ALEN); 302e28a4053SRui Paulo entry->opportunistic = 1; 303e28a4053SRui Paulo if (old_entry->identity) { 304e28a4053SRui Paulo entry->identity = os_malloc(old_entry->identity_len); 305e28a4053SRui Paulo if (entry->identity) { 306e28a4053SRui Paulo entry->identity_len = old_entry->identity_len; 307e28a4053SRui Paulo os_memcpy(entry->identity, old_entry->identity, 308e28a4053SRui Paulo old_entry->identity_len); 309e28a4053SRui Paulo } 310e28a4053SRui Paulo } 311*f05cddf9SRui Paulo if (old_entry->cui) 312*f05cddf9SRui Paulo entry->cui = wpabuf_dup(old_entry->cui); 313e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 314e28a4053SRui Paulo radius_copy_class(&entry->radius_class, &old_entry->radius_class); 315e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 316e28a4053SRui Paulo entry->eap_type_authsrv = old_entry->eap_type_authsrv; 317e28a4053SRui Paulo entry->vlan_id = old_entry->vlan_id; 318e28a4053SRui Paulo entry->opportunistic = 1; 319e28a4053SRui Paulo 320e28a4053SRui Paulo pmksa_cache_link_entry(pmksa, entry); 321e28a4053SRui Paulo 322e28a4053SRui Paulo return entry; 323e28a4053SRui Paulo } 324e28a4053SRui Paulo 325e28a4053SRui Paulo 326e28a4053SRui Paulo /** 327e28a4053SRui Paulo * pmksa_cache_auth_deinit - Free all entries in PMKSA cache 328e28a4053SRui Paulo * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() 329e28a4053SRui Paulo */ 330e28a4053SRui Paulo void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa) 331e28a4053SRui Paulo { 332e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry, *prev; 333e28a4053SRui Paulo int i; 334e28a4053SRui Paulo 335e28a4053SRui Paulo if (pmksa == NULL) 336e28a4053SRui Paulo return; 337e28a4053SRui Paulo 338e28a4053SRui Paulo entry = pmksa->pmksa; 339e28a4053SRui Paulo while (entry) { 340e28a4053SRui Paulo prev = entry; 341e28a4053SRui Paulo entry = entry->next; 342e28a4053SRui Paulo _pmksa_cache_free_entry(prev); 343e28a4053SRui Paulo } 344e28a4053SRui Paulo eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); 345e28a4053SRui Paulo for (i = 0; i < PMKID_HASH_SIZE; i++) 346e28a4053SRui Paulo pmksa->pmkid[i] = NULL; 347e28a4053SRui Paulo os_free(pmksa); 348e28a4053SRui Paulo } 349e28a4053SRui Paulo 350e28a4053SRui Paulo 351e28a4053SRui Paulo /** 352e28a4053SRui Paulo * pmksa_cache_auth_get - Fetch a PMKSA cache entry 353e28a4053SRui Paulo * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() 354e28a4053SRui Paulo * @spa: Supplicant address or %NULL to match any 355e28a4053SRui Paulo * @pmkid: PMKID or %NULL to match any 356e28a4053SRui Paulo * Returns: Pointer to PMKSA cache entry or %NULL if no match was found 357e28a4053SRui Paulo */ 358e28a4053SRui Paulo struct rsn_pmksa_cache_entry * 359e28a4053SRui Paulo pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, 360e28a4053SRui Paulo const u8 *spa, const u8 *pmkid) 361e28a4053SRui Paulo { 362e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry; 363e28a4053SRui Paulo 364e28a4053SRui Paulo if (pmkid) 365e28a4053SRui Paulo entry = pmksa->pmkid[PMKID_HASH(pmkid)]; 366e28a4053SRui Paulo else 367e28a4053SRui Paulo entry = pmksa->pmksa; 368e28a4053SRui Paulo while (entry) { 369e28a4053SRui Paulo if ((spa == NULL || 370e28a4053SRui Paulo os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && 371e28a4053SRui Paulo (pmkid == NULL || 372e28a4053SRui Paulo os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) 373e28a4053SRui Paulo return entry; 374e28a4053SRui Paulo entry = pmkid ? entry->hnext : entry->next; 375e28a4053SRui Paulo } 376e28a4053SRui Paulo return NULL; 377e28a4053SRui Paulo } 378e28a4053SRui Paulo 379e28a4053SRui Paulo 380e28a4053SRui Paulo /** 381e28a4053SRui Paulo * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC 382e28a4053SRui Paulo * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init() 383e28a4053SRui Paulo * @aa: Authenticator address 384e28a4053SRui Paulo * @spa: Supplicant address 385e28a4053SRui Paulo * @pmkid: PMKID 386e28a4053SRui Paulo * Returns: Pointer to PMKSA cache entry or %NULL if no match was found 387e28a4053SRui Paulo * 388e28a4053SRui Paulo * Use opportunistic key caching (OKC) to find a PMK for a supplicant. 389e28a4053SRui Paulo */ 390e28a4053SRui Paulo struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( 391e28a4053SRui Paulo struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, 392e28a4053SRui Paulo const u8 *pmkid) 393e28a4053SRui Paulo { 394e28a4053SRui Paulo struct rsn_pmksa_cache_entry *entry; 395e28a4053SRui Paulo u8 new_pmkid[PMKID_LEN]; 396e28a4053SRui Paulo 397e28a4053SRui Paulo entry = pmksa->pmksa; 398e28a4053SRui Paulo while (entry) { 399e28a4053SRui Paulo if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) 400e28a4053SRui Paulo continue; 401e28a4053SRui Paulo rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, 402e28a4053SRui Paulo wpa_key_mgmt_sha256(entry->akmp)); 403e28a4053SRui Paulo if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) 404e28a4053SRui Paulo return entry; 405e28a4053SRui Paulo entry = entry->next; 406e28a4053SRui Paulo } 407e28a4053SRui Paulo return NULL; 408e28a4053SRui Paulo } 409e28a4053SRui Paulo 410e28a4053SRui Paulo 411e28a4053SRui Paulo /** 412e28a4053SRui Paulo * pmksa_cache_auth_init - Initialize PMKSA cache 413e28a4053SRui Paulo * @free_cb: Callback function to be called when a PMKSA cache entry is freed 414e28a4053SRui Paulo * @ctx: Context pointer for free_cb function 415e28a4053SRui Paulo * Returns: Pointer to PMKSA cache data or %NULL on failure 416e28a4053SRui Paulo */ 417e28a4053SRui Paulo struct rsn_pmksa_cache * 418e28a4053SRui Paulo pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, 419e28a4053SRui Paulo void *ctx), void *ctx) 420e28a4053SRui Paulo { 421e28a4053SRui Paulo struct rsn_pmksa_cache *pmksa; 422e28a4053SRui Paulo 423e28a4053SRui Paulo pmksa = os_zalloc(sizeof(*pmksa)); 424e28a4053SRui Paulo if (pmksa) { 425e28a4053SRui Paulo pmksa->free_cb = free_cb; 426e28a4053SRui Paulo pmksa->ctx = ctx; 427e28a4053SRui Paulo } 428e28a4053SRui Paulo 429e28a4053SRui Paulo return pmksa; 430e28a4053SRui Paulo } 431