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