1 /* 2 * WPA Supplicant - RSN PMKSA cache 3 * Copyright (c) 2004-2008, Jouni Malinen <j (at) w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "eloop.h" 19 #include "eapol_supp/eapol_supp_sm.h" 20 #include "wpa.h" 21 #include "wpa_i.h" 22 #include "pmksa_cache.h" 23 24 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2) 25 26 static const int pmksa_cache_max_entries = 32; 27 28 struct rsn_pmksa_cache { 29 struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */ 30 int pmksa_count; /* number of entries in PMKSA cache */ 31 struct wpa_sm *sm; /* TODO: get rid of this reference(?) */ 32 33 void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, 34 int replace); 35 void *ctx; 36 }; 37 38 39 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); 40 41 42 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) 43 { 44 os_free(entry); 45 } 46 47 48 static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, 49 struct rsn_pmksa_cache_entry *entry, 50 int replace) 51 { 52 pmksa->pmksa_count--; 53 pmksa->free_cb(entry, pmksa->ctx, replace); 54 _pmksa_cache_free_entry(entry); 55 } 56 57 58 static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) 59 { 60 struct rsn_pmksa_cache *pmksa = eloop_ctx; 61 struct os_time now; 62 63 os_get_time(&now); 64 while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) { 65 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 66 pmksa->pmksa = entry->next; 67 wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for " 68 MACSTR, MAC2STR(entry->aa)); 69 pmksa_cache_free_entry(pmksa, entry, 0); 70 } 71 72 pmksa_cache_set_expiration(pmksa); 73 } 74 75 76 static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) 77 { 78 struct rsn_pmksa_cache *pmksa = eloop_ctx; 79 pmksa->sm->cur_pmksa = NULL; 80 eapol_sm_request_reauth(pmksa->sm->eapol); 81 } 82 83 84 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) 85 { 86 int sec; 87 struct rsn_pmksa_cache_entry *entry; 88 struct os_time now; 89 90 eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); 91 eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL); 92 if (pmksa->pmksa == NULL) 93 return; 94 os_get_time(&now); 95 sec = pmksa->pmksa->expiration - now.sec; 96 if (sec < 0) 97 sec = 0; 98 eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); 99 100 entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : 101 pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL); 102 if (entry) { 103 sec = pmksa->pmksa->reauth_time - now.sec; 104 if (sec < 0) 105 sec = 0; 106 eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa, 107 NULL); 108 } 109 } 110 111 112 /** 113 * pmksa_cache_add - Add a PMKSA cache entry 114 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 115 * @pmk: The new pairwise master key 116 * @pmk_len: PMK length in bytes, usually PMK_LEN (32) 117 * @aa: Authenticator address 118 * @spa: Supplicant address 119 * @network_ctx: Network configuration context for this PMK 120 * @akmp: WPA_KEY_MGMT_* used in key derivation 121 * Returns: Pointer to the added PMKSA cache entry or %NULL on error 122 * 123 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA 124 * cache. If an old entry is already in the cache for the same Authenticator, 125 * this entry will be replaced with the new entry. PMKID will be calculated 126 * based on the PMK and the driver interface is notified of the new PMKID. 127 */ 128 struct rsn_pmksa_cache_entry * 129 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, 130 const u8 *aa, const u8 *spa, void *network_ctx, int akmp) 131 { 132 struct rsn_pmksa_cache_entry *entry, *pos, *prev; 133 struct os_time now; 134 135 if (pmk_len > PMK_LEN) 136 return NULL; 137 138 entry = os_zalloc(sizeof(*entry)); 139 if (entry == NULL) 140 return NULL; 141 os_memcpy(entry->pmk, pmk, pmk_len); 142 entry->pmk_len = pmk_len; 143 rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, 144 wpa_key_mgmt_sha256(akmp)); 145 os_get_time(&now); 146 entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; 147 entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * 148 pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; 149 entry->akmp = akmp; 150 os_memcpy(entry->aa, aa, ETH_ALEN); 151 entry->network_ctx = network_ctx; 152 153 /* Replace an old entry for the same Authenticator (if found) with the 154 * new entry */ 155 pos = pmksa->pmksa; 156 prev = NULL; 157 while (pos) { 158 if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { 159 if (pos->pmk_len == pmk_len && 160 os_memcmp(pos->pmk, pmk, pmk_len) == 0 && 161 os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == 162 0) { 163 wpa_printf(MSG_DEBUG, "WPA: reusing previous " 164 "PMKSA entry"); 165 os_free(entry); 166 return pos; 167 } 168 if (prev == NULL) 169 pmksa->pmksa = pos->next; 170 else 171 prev->next = pos->next; 172 if (pos == pmksa->sm->cur_pmksa) { 173 /* We are about to replace the current PMKSA 174 * cache entry. This happens when the PMKSA 175 * caching attempt fails, so we don't want to 176 * force pmksa_cache_free_entry() to disconnect 177 * at this point. Let's just make sure the old 178 * PMKSA cache entry will not be used in the 179 * future. 180 */ 181 wpa_printf(MSG_DEBUG, "RSN: replacing current " 182 "PMKSA entry"); 183 pmksa->sm->cur_pmksa = NULL; 184 } 185 wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for " 186 "the current AP"); 187 pmksa_cache_free_entry(pmksa, pos, 1); 188 break; 189 } 190 prev = pos; 191 pos = pos->next; 192 } 193 194 if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) { 195 /* Remove the oldest entry to make room for the new entry */ 196 pos = pmksa->pmksa; 197 pmksa->pmksa = pos->next; 198 wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache " 199 "entry (for " MACSTR ") to make room for new one", 200 MAC2STR(pos->aa)); 201 wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid); 202 pmksa_cache_free_entry(pmksa, pos, 0); 203 } 204 205 /* Add the new entry; order by expiration time */ 206 pos = pmksa->pmksa; 207 prev = NULL; 208 while (pos) { 209 if (pos->expiration > entry->expiration) 210 break; 211 prev = pos; 212 pos = pos->next; 213 } 214 if (prev == NULL) { 215 entry->next = pmksa->pmksa; 216 pmksa->pmksa = entry; 217 pmksa_cache_set_expiration(pmksa); 218 } else { 219 entry->next = prev->next; 220 prev->next = entry; 221 } 222 pmksa->pmksa_count++; 223 wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR, 224 MAC2STR(entry->aa)); 225 wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid); 226 227 return entry; 228 } 229 230 231 /** 232 * pmksa_cache_deinit - Free all entries in PMKSA cache 233 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 234 */ 235 void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) 236 { 237 struct rsn_pmksa_cache_entry *entry, *prev; 238 239 if (pmksa == NULL) 240 return; 241 242 entry = pmksa->pmksa; 243 pmksa->pmksa = NULL; 244 while (entry) { 245 prev = entry; 246 entry = entry->next; 247 os_free(prev); 248 } 249 pmksa_cache_set_expiration(pmksa); 250 os_free(pmksa); 251 } 252 253 254 /** 255 * pmksa_cache_get - Fetch a PMKSA cache entry 256 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 257 * @aa: Authenticator address or %NULL to match any 258 * @pmkid: PMKID or %NULL to match any 259 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found 260 */ 261 struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, 262 const u8 *aa, const u8 *pmkid) 263 { 264 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 265 while (entry) { 266 if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && 267 (pmkid == NULL || 268 os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) 269 return entry; 270 entry = entry->next; 271 } 272 return NULL; 273 } 274 275 276 /** 277 * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache 278 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 279 * 280 * Clear references to old data structures when wpa_supplicant is reconfigured. 281 */ 282 void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa) 283 { 284 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 285 while (entry) { 286 entry->network_ctx = NULL; 287 entry = entry->next; 288 } 289 } 290 291 292 static struct rsn_pmksa_cache_entry * 293 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, 294 const struct rsn_pmksa_cache_entry *old_entry, 295 const u8 *aa) 296 { 297 struct rsn_pmksa_cache_entry *new_entry; 298 299 new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, 300 aa, pmksa->sm->own_addr, 301 old_entry->network_ctx, old_entry->akmp); 302 if (new_entry == NULL) 303 return NULL; 304 305 /* TODO: reorder entries based on expiration time? */ 306 new_entry->expiration = old_entry->expiration; 307 new_entry->opportunistic = 1; 308 309 return new_entry; 310 } 311 312 313 /** 314 * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry 315 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 316 * @network_ctx: Network configuration context 317 * @aa: Authenticator address for the new AP 318 * Returns: Pointer to a new PMKSA cache entry or %NULL if not available 319 * 320 * Try to create a new PMKSA cache entry opportunistically by guessing that the 321 * new AP is sharing the same PMK as another AP that has the same SSID and has 322 * already an entry in PMKSA cache. 323 */ 324 struct rsn_pmksa_cache_entry * 325 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, 326 const u8 *aa) 327 { 328 struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; 329 330 if (network_ctx == NULL) 331 return NULL; 332 while (entry) { 333 if (entry->network_ctx == network_ctx) { 334 entry = pmksa_cache_clone_entry(pmksa, entry, aa); 335 if (entry) { 336 wpa_printf(MSG_DEBUG, "RSN: added " 337 "opportunistic PMKSA cache entry " 338 "for " MACSTR, MAC2STR(aa)); 339 } 340 return entry; 341 } 342 entry = entry->next; 343 } 344 return NULL; 345 } 346 347 348 /** 349 * pmksa_cache_get_current - Get the current used PMKSA entry 350 * @sm: Pointer to WPA state machine data from wpa_sm_init() 351 * Returns: Pointer to the current PMKSA cache entry or %NULL if not available 352 */ 353 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm) 354 { 355 if (sm == NULL) 356 return NULL; 357 return sm->cur_pmksa; 358 } 359 360 361 /** 362 * pmksa_cache_clear_current - Clear the current PMKSA entry selection 363 * @sm: Pointer to WPA state machine data from wpa_sm_init() 364 */ 365 void pmksa_cache_clear_current(struct wpa_sm *sm) 366 { 367 if (sm == NULL) 368 return; 369 sm->cur_pmksa = NULL; 370 } 371 372 373 /** 374 * pmksa_cache_set_current - Set the current PMKSA entry selection 375 * @sm: Pointer to WPA state machine data from wpa_sm_init() 376 * @pmkid: PMKID for selecting PMKSA or %NULL if not used 377 * @bssid: BSSID for PMKSA or %NULL if not used 378 * @network_ctx: Network configuration context 379 * @try_opportunistic: Whether to allow opportunistic PMKSA caching 380 * Returns: 0 if PMKSA was found or -1 if no matching entry was found 381 */ 382 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, 383 const u8 *bssid, void *network_ctx, 384 int try_opportunistic) 385 { 386 struct rsn_pmksa_cache *pmksa = sm->pmksa; 387 sm->cur_pmksa = NULL; 388 if (pmkid) 389 sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid); 390 if (sm->cur_pmksa == NULL && bssid) 391 sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL); 392 if (sm->cur_pmksa == NULL && try_opportunistic && bssid) 393 sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, 394 network_ctx, 395 bssid); 396 if (sm->cur_pmksa) { 397 wpa_hexdump(MSG_DEBUG, "RSN: PMKID", 398 sm->cur_pmksa->pmkid, PMKID_LEN); 399 return 0; 400 } 401 return -1; 402 } 403 404 405 /** 406 * pmksa_cache_list - Dump text list of entries in PMKSA cache 407 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() 408 * @buf: Buffer for the list 409 * @len: Length of the buffer 410 * Returns: number of bytes written to buffer 411 * 412 * This function is used to generate a text format representation of the 413 * current PMKSA cache contents for the ctrl_iface PMKSA command. 414 */ 415 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) 416 { 417 int i, ret; 418 char *pos = buf; 419 struct rsn_pmksa_cache_entry *entry; 420 struct os_time now; 421 422 os_get_time(&now); 423 ret = os_snprintf(pos, buf + len - pos, 424 "Index / AA / PMKID / expiration (in seconds) / " 425 "opportunistic\n"); 426 if (ret < 0 || ret >= buf + len - pos) 427 return pos - buf; 428 pos += ret; 429 i = 0; 430 entry = pmksa->pmksa; 431 while (entry) { 432 i++; 433 ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", 434 i, MAC2STR(entry->aa)); 435 if (ret < 0 || ret >= buf + len - pos) 436 return pos - buf; 437 pos += ret; 438 pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid, 439 PMKID_LEN); 440 ret = os_snprintf(pos, buf + len - pos, " %d %d\n", 441 (int) (entry->expiration - now.sec), 442 entry->opportunistic); 443 if (ret < 0 || ret >= buf + len - pos) 444 return pos - buf; 445 pos += ret; 446 entry = entry->next; 447 } 448 return pos - buf; 449 } 450 451 452 /** 453 * pmksa_cache_init - Initialize PMKSA cache 454 * @free_cb: Callback function to be called when a PMKSA cache entry is freed 455 * @ctx: Context pointer for free_cb function 456 * @sm: Pointer to WPA state machine data from wpa_sm_init() 457 * Returns: Pointer to PMKSA cache data or %NULL on failure 458 */ 459 struct rsn_pmksa_cache * 460 pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, 461 void *ctx, int replace), 462 void *ctx, struct wpa_sm *sm) 463 { 464 struct rsn_pmksa_cache *pmksa; 465 466 pmksa = os_zalloc(sizeof(*pmksa)); 467 if (pmksa) { 468 pmksa->free_cb = free_cb; 469 pmksa->ctx = ctx; 470 pmksa->sm = sm; 471 } 472 473 return pmksa; 474 } 475 476 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */ 477