2 * WPA Supplicant - RSN PMKSA cache
3 * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
13 #include "eapol_supp/eapol_supp_sm.h"
16 #include "pmksa_cache.h"
18 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
20 static const int pmksa_cache_max_entries
= 32;
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(?) */
27 void (*free_cb
)(struct rsn_pmksa_cache_entry
*entry
, void *ctx
,
28 enum pmksa_free_reason reason
);
33 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache
*pmksa
);
36 static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry
*entry
)
38 bin_clear_free(entry
, sizeof(*entry
));
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
)
46 wpa_sm_remove_pmkid(pmksa
->sm
, entry
->network_ctx
, entry
->aa
,
48 entry
->fils_cache_id_set
? entry
->fils_cache_id
:
51 pmksa
->free_cb(entry
, pmksa
->ctx
, reason
);
52 _pmksa_cache_free_entry(entry
);
56 static void pmksa_cache_expire(void *eloop_ctx
, void *timeout_ctx
)
58 struct rsn_pmksa_cache
*pmksa
= eloop_ctx
;
59 struct os_reltime now
;
62 while (pmksa
->pmksa
&& pmksa
->pmksa
->expiration
<= now
.sec
) {
63 struct rsn_pmksa_cache_entry
*entry
= pmksa
->pmksa
;
64 pmksa
->pmksa
= entry
->next
;
65 wpa_printf(MSG_DEBUG
, "RSN: expired PMKSA cache entry for "
66 MACSTR
, MAC2STR(entry
->aa
));
67 pmksa_cache_free_entry(pmksa
, entry
, PMKSA_EXPIRE
);
70 pmksa_cache_set_expiration(pmksa
);
74 static void pmksa_cache_reauth(void *eloop_ctx
, void *timeout_ctx
)
76 struct rsn_pmksa_cache
*pmksa
= eloop_ctx
;
77 pmksa
->sm
->cur_pmksa
= NULL
;
78 eapol_sm_request_reauth(pmksa
->sm
->eapol
);
82 static void pmksa_cache_set_expiration(struct rsn_pmksa_cache
*pmksa
)
85 struct rsn_pmksa_cache_entry
*entry
;
86 struct os_reltime now
;
88 eloop_cancel_timeout(pmksa_cache_expire
, pmksa
, NULL
);
89 eloop_cancel_timeout(pmksa_cache_reauth
, pmksa
, NULL
);
90 if (pmksa
->pmksa
== NULL
)
93 sec
= pmksa
->pmksa
->expiration
- now
.sec
;
96 eloop_register_timeout(sec
+ 1, 0, pmksa_cache_expire
, pmksa
, NULL
);
98 entry
= pmksa
->sm
->cur_pmksa
? pmksa
->sm
->cur_pmksa
:
99 pmksa_cache_get(pmksa
, pmksa
->sm
->bssid
, NULL
, NULL
, 0);
101 sec
= pmksa
->pmksa
->reauth_time
- now
.sec
;
104 eloop_register_timeout(sec
, 0, pmksa_cache_reauth
, pmksa
,
111 * pmksa_cache_add - Add a PMKSA cache entry
112 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
113 * @pmk: The new pairwise master key
114 * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
115 * @pmkid: Calculated PMKID
116 * @kck: Key confirmation key or %NULL if not yet derived
117 * @kck_len: KCK length in bytes
118 * @aa: Authenticator address
119 * @spa: Supplicant address
120 * @network_ctx: Network configuration context for this PMK
121 * @akmp: WPA_KEY_MGMT_* used in key derivation
122 * @cache_id: Pointer to FILS Cache Identifier or %NULL if not advertised
123 * Returns: Pointer to the added PMKSA cache entry or %NULL on error
125 * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
126 * cache. If an old entry is already in the cache for the same Authenticator,
127 * this entry will be replaced with the new entry. PMKID will be calculated
128 * based on the PMK and the driver interface is notified of the new PMKID.
130 struct rsn_pmksa_cache_entry
*
131 pmksa_cache_add(struct rsn_pmksa_cache
*pmksa
, const u8
*pmk
, size_t pmk_len
,
132 const u8
*pmkid
, const u8
*kck
, size_t kck_len
,
133 const u8
*aa
, const u8
*spa
, void *network_ctx
, int akmp
,
136 struct rsn_pmksa_cache_entry
*entry
;
137 struct os_reltime now
;
139 if (pmk_len
> PMK_LEN_MAX
)
142 if (wpa_key_mgmt_suite_b(akmp
) && !kck
)
145 entry
= os_zalloc(sizeof(*entry
));
148 os_memcpy(entry
->pmk
, pmk
, pmk_len
);
149 entry
->pmk_len
= pmk_len
;
151 os_memcpy(entry
->pmkid
, pmkid
, PMKID_LEN
);
152 else if (akmp
== WPA_KEY_MGMT_IEEE8021X_SUITE_B_192
)
153 rsn_pmkid_suite_b_192(kck
, kck_len
, aa
, spa
, entry
->pmkid
);
154 else if (wpa_key_mgmt_suite_b(akmp
))
155 rsn_pmkid_suite_b(kck
, kck_len
, aa
, spa
, entry
->pmkid
);
157 rsn_pmkid(pmk
, pmk_len
, aa
, spa
, entry
->pmkid
, akmp
);
158 os_get_reltime(&now
);
159 entry
->expiration
= now
.sec
+ pmksa
->sm
->dot11RSNAConfigPMKLifetime
;
160 entry
->reauth_time
= now
.sec
+ pmksa
->sm
->dot11RSNAConfigPMKLifetime
*
161 pmksa
->sm
->dot11RSNAConfigPMKReauthThreshold
/ 100;
164 entry
->fils_cache_id_set
= 1;
165 os_memcpy(entry
->fils_cache_id
, cache_id
, FILS_CACHE_ID_LEN
);
167 os_memcpy(entry
->aa
, aa
, ETH_ALEN
);
168 entry
->network_ctx
= network_ctx
;
170 return pmksa_cache_add_entry(pmksa
, entry
);
174 struct rsn_pmksa_cache_entry
*
175 pmksa_cache_add_entry(struct rsn_pmksa_cache
*pmksa
,
176 struct rsn_pmksa_cache_entry
*entry
)
178 struct rsn_pmksa_cache_entry
*pos
, *prev
;
180 /* Replace an old entry for the same Authenticator (if found) with the
185 if (os_memcmp(entry
->aa
, pos
->aa
, ETH_ALEN
) == 0) {
186 if (pos
->pmk_len
== entry
->pmk_len
&&
187 os_memcmp_const(pos
->pmk
, entry
->pmk
,
188 entry
->pmk_len
) == 0 &&
189 os_memcmp_const(pos
->pmkid
, entry
->pmkid
,
191 wpa_printf(MSG_DEBUG
, "WPA: reusing previous "
197 pmksa
->pmksa
= pos
->next
;
199 prev
->next
= pos
->next
;
202 * If OKC is used, there may be other PMKSA cache
203 * entries based on the same PMK. These needs to be
204 * flushed so that a new entry can be created based on
205 * the new PMK. Only clear other entries if they have a
206 * matching PMK and this PMK has been used successfully
207 * with the current AP, i.e., if opportunistic flag has
208 * been cleared in wpa_supplicant_key_neg_complete().
210 wpa_printf(MSG_DEBUG
, "RSN: Replace PMKSA entry for "
211 "the current AP and any PMKSA cache entry "
212 "that was based on the old PMK");
213 if (!pos
->opportunistic
)
214 pmksa_cache_flush(pmksa
, entry
->network_ctx
,
215 pos
->pmk
, pos
->pmk_len
);
216 pmksa_cache_free_entry(pmksa
, pos
, PMKSA_REPLACE
);
223 if (pmksa
->pmksa_count
>= pmksa_cache_max_entries
&& pmksa
->pmksa
) {
224 /* Remove the oldest entry to make room for the new entry */
227 if (pos
== pmksa
->sm
->cur_pmksa
) {
229 * Never remove the current PMKSA cache entry, since
230 * it's in use, and removing it triggers a needless
234 pmksa
->pmksa
->next
= pos
? pos
->next
: NULL
;
236 pmksa
->pmksa
= pos
->next
;
239 wpa_printf(MSG_DEBUG
, "RSN: removed the oldest idle "
240 "PMKSA cache entry (for " MACSTR
") to "
241 "make room for new one",
243 pmksa_cache_free_entry(pmksa
, pos
, PMKSA_FREE
);
247 /* Add the new entry; order by expiration time */
251 if (pos
->expiration
> entry
->expiration
)
257 entry
->next
= pmksa
->pmksa
;
258 pmksa
->pmksa
= entry
;
259 pmksa_cache_set_expiration(pmksa
);
261 entry
->next
= prev
->next
;
264 pmksa
->pmksa_count
++;
265 wpa_printf(MSG_DEBUG
, "RSN: Added PMKSA cache entry for " MACSTR
266 " network_ctx=%p akmp=0x%x", MAC2STR(entry
->aa
),
267 entry
->network_ctx
, entry
->akmp
);
268 wpa_sm_add_pmkid(pmksa
->sm
, entry
->network_ctx
, entry
->aa
, entry
->pmkid
,
269 entry
->fils_cache_id_set
? entry
->fils_cache_id
: NULL
,
270 entry
->pmk
, entry
->pmk_len
,
271 pmksa
->sm
->dot11RSNAConfigPMKLifetime
,
272 pmksa
->sm
->dot11RSNAConfigPMKReauthThreshold
);
279 * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
280 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
281 * @network_ctx: Network configuration context or %NULL to flush all entries
282 * @pmk: PMK to match for or %NULL to match all PMKs
283 * @pmk_len: PMK length
285 void pmksa_cache_flush(struct rsn_pmksa_cache
*pmksa
, void *network_ctx
,
286 const u8
*pmk
, size_t pmk_len
)
288 struct rsn_pmksa_cache_entry
*entry
, *prev
= NULL
, *tmp
;
291 entry
= pmksa
->pmksa
;
293 if ((entry
->network_ctx
== network_ctx
||
294 network_ctx
== NULL
) &&
296 (pmk_len
== entry
->pmk_len
&&
297 os_memcmp(pmk
, entry
->pmk
, pmk_len
) == 0))) {
298 wpa_printf(MSG_DEBUG
, "RSN: Flush PMKSA cache entry "
299 "for " MACSTR
, MAC2STR(entry
->aa
));
301 prev
->next
= entry
->next
;
303 pmksa
->pmksa
= entry
->next
;
306 pmksa_cache_free_entry(pmksa
, tmp
, PMKSA_FREE
);
314 pmksa_cache_set_expiration(pmksa
);
319 * pmksa_cache_deinit - Free all entries in PMKSA cache
320 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
322 void pmksa_cache_deinit(struct rsn_pmksa_cache
*pmksa
)
324 struct rsn_pmksa_cache_entry
*entry
, *prev
;
329 entry
= pmksa
->pmksa
;
336 pmksa_cache_set_expiration(pmksa
);
342 * pmksa_cache_get - Fetch a PMKSA cache entry
343 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
344 * @aa: Authenticator address or %NULL to match any
345 * @pmkid: PMKID or %NULL to match any
346 * @network_ctx: Network context or %NULL to match any
347 * @akmp: Specific AKMP to search for or 0 for any
348 * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
350 struct rsn_pmksa_cache_entry
* pmksa_cache_get(struct rsn_pmksa_cache
*pmksa
,
351 const u8
*aa
, const u8
*pmkid
,
352 const void *network_ctx
,
355 struct rsn_pmksa_cache_entry
*entry
= pmksa
->pmksa
;
357 if ((aa
== NULL
|| os_memcmp(entry
->aa
, aa
, ETH_ALEN
) == 0) &&
359 os_memcmp(entry
->pmkid
, pmkid
, PMKID_LEN
) == 0) &&
360 (!akmp
|| akmp
== entry
->akmp
) &&
361 (network_ctx
== NULL
|| network_ctx
== entry
->network_ctx
))
369 static struct rsn_pmksa_cache_entry
*
370 pmksa_cache_clone_entry(struct rsn_pmksa_cache
*pmksa
,
371 const struct rsn_pmksa_cache_entry
*old_entry
,
374 struct rsn_pmksa_cache_entry
*new_entry
;
375 os_time_t old_expiration
= old_entry
->expiration
;
376 const u8
*pmkid
= NULL
;
378 if (wpa_key_mgmt_sae(old_entry
->akmp
))
379 pmkid
= old_entry
->pmkid
;
380 new_entry
= pmksa_cache_add(pmksa
, old_entry
->pmk
, old_entry
->pmk_len
,
382 aa
, pmksa
->sm
->own_addr
,
383 old_entry
->network_ctx
, old_entry
->akmp
,
384 old_entry
->fils_cache_id_set
?
385 old_entry
->fils_cache_id
: NULL
);
386 if (new_entry
== NULL
)
389 /* TODO: reorder entries based on expiration time? */
390 new_entry
->expiration
= old_expiration
;
391 new_entry
->opportunistic
= 1;
398 * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
399 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
400 * @network_ctx: Network configuration context
401 * @aa: Authenticator address for the new AP
402 * @akmp: Specific AKMP to search for or 0 for any
403 * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
405 * Try to create a new PMKSA cache entry opportunistically by guessing that the
406 * new AP is sharing the same PMK as another AP that has the same SSID and has
407 * already an entry in PMKSA cache.
409 struct rsn_pmksa_cache_entry
*
410 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache
*pmksa
, void *network_ctx
,
411 const u8
*aa
, int akmp
)
413 struct rsn_pmksa_cache_entry
*entry
= pmksa
->pmksa
;
415 wpa_printf(MSG_DEBUG
, "RSN: Consider " MACSTR
" for OKC", MAC2STR(aa
));
416 if (network_ctx
== NULL
)
419 if (entry
->network_ctx
== network_ctx
&&
420 (!akmp
|| entry
->akmp
== akmp
)) {
421 struct os_reltime now
;
423 if (wpa_key_mgmt_sae(entry
->akmp
) &&
424 os_get_reltime(&now
) == 0 &&
425 entry
->reauth_time
< now
.sec
) {
426 wpa_printf(MSG_DEBUG
,
427 "RSN: Do not clone PMKSA cache entry for "
429 " since its reauth threshold has passed",
435 entry
= pmksa_cache_clone_entry(pmksa
, entry
, aa
);
437 wpa_printf(MSG_DEBUG
, "RSN: added "
438 "opportunistic PMKSA cache entry "
439 "for " MACSTR
, MAC2STR(aa
));
449 static struct rsn_pmksa_cache_entry
*
450 pmksa_cache_get_fils_cache_id(struct rsn_pmksa_cache
*pmksa
,
451 const void *network_ctx
, const u8
*cache_id
)
453 struct rsn_pmksa_cache_entry
*entry
;
455 for (entry
= pmksa
->pmksa
; entry
; entry
= entry
->next
) {
456 if (network_ctx
== entry
->network_ctx
&&
457 entry
->fils_cache_id_set
&&
458 os_memcmp(cache_id
, entry
->fils_cache_id
,
459 FILS_CACHE_ID_LEN
) == 0)
468 * pmksa_cache_get_current - Get the current used PMKSA entry
469 * @sm: Pointer to WPA state machine data from wpa_sm_init()
470 * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
472 struct rsn_pmksa_cache_entry
* pmksa_cache_get_current(struct wpa_sm
*sm
)
476 return sm
->cur_pmksa
;
481 * pmksa_cache_clear_current - Clear the current PMKSA entry selection
482 * @sm: Pointer to WPA state machine data from wpa_sm_init()
484 void pmksa_cache_clear_current(struct wpa_sm
*sm
)
488 sm
->cur_pmksa
= NULL
;
493 * pmksa_cache_set_current - Set the current PMKSA entry selection
494 * @sm: Pointer to WPA state machine data from wpa_sm_init()
495 * @pmkid: PMKID for selecting PMKSA or %NULL if not used
496 * @bssid: BSSID for PMKSA or %NULL if not used
497 * @network_ctx: Network configuration context
498 * @try_opportunistic: Whether to allow opportunistic PMKSA caching
499 * @fils_cache_id: Pointer to FILS Cache Identifier or %NULL if not used
500 * Returns: 0 if PMKSA was found or -1 if no matching entry was found
502 int pmksa_cache_set_current(struct wpa_sm
*sm
, const u8
*pmkid
,
503 const u8
*bssid
, void *network_ctx
,
504 int try_opportunistic
, const u8
*fils_cache_id
,
507 struct rsn_pmksa_cache
*pmksa
= sm
->pmksa
;
508 wpa_printf(MSG_DEBUG
, "RSN: PMKSA cache search - network_ctx=%p "
509 "try_opportunistic=%d akmp=0x%x",
510 network_ctx
, try_opportunistic
, akmp
);
512 wpa_hexdump(MSG_DEBUG
, "RSN: Search for PMKID",
515 wpa_printf(MSG_DEBUG
, "RSN: Search for BSSID " MACSTR
,
518 wpa_printf(MSG_DEBUG
,
519 "RSN: Search for FILS Cache Identifier %02x%02x",
520 fils_cache_id
[0], fils_cache_id
[1]);
522 sm
->cur_pmksa
= NULL
;
524 sm
->cur_pmksa
= pmksa_cache_get(pmksa
, NULL
, pmkid
,
526 if (sm
->cur_pmksa
== NULL
&& bssid
)
527 sm
->cur_pmksa
= pmksa_cache_get(pmksa
, bssid
, NULL
,
529 if (sm
->cur_pmksa
== NULL
&& try_opportunistic
&& bssid
)
530 sm
->cur_pmksa
= pmksa_cache_get_opportunistic(pmksa
,
533 if (sm
->cur_pmksa
== NULL
&& fils_cache_id
)
534 sm
->cur_pmksa
= pmksa_cache_get_fils_cache_id(pmksa
,
538 struct os_reltime now
;
540 if (wpa_key_mgmt_sae(sm
->cur_pmksa
->akmp
) &&
541 os_get_reltime(&now
) == 0 &&
542 sm
->cur_pmksa
->reauth_time
< now
.sec
) {
543 wpa_printf(MSG_DEBUG
,
544 "RSN: Do not allow PMKSA cache entry for "
546 " to be used for SAE since its reauth threshold has passed",
547 MAC2STR(sm
->cur_pmksa
->aa
));
548 sm
->cur_pmksa
= NULL
;
552 wpa_hexdump(MSG_DEBUG
, "RSN: PMKSA cache entry found - PMKID",
553 sm
->cur_pmksa
->pmkid
, PMKID_LEN
);
556 wpa_printf(MSG_DEBUG
, "RSN: No PMKSA cache entry found");
562 * pmksa_cache_list - Dump text list of entries in PMKSA cache
563 * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
564 * @buf: Buffer for the list
565 * @len: Length of the buffer
566 * Returns: number of bytes written to buffer
568 * This function is used to generate a text format representation of the
569 * current PMKSA cache contents for the ctrl_iface PMKSA command.
571 int pmksa_cache_list(struct rsn_pmksa_cache
*pmksa
, char *buf
, size_t len
)
575 struct rsn_pmksa_cache_entry
*entry
;
576 struct os_reltime now
;
577 int cache_id_used
= 0;
579 for (entry
= pmksa
->pmksa
; entry
; entry
= entry
->next
) {
580 if (entry
->fils_cache_id_set
) {
586 os_get_reltime(&now
);
587 ret
= os_snprintf(pos
, buf
+ len
- pos
,
588 "Index / AA / PMKID / expiration (in seconds) / "
590 cache_id_used
? " / FILS Cache Identifier" : "");
591 if (os_snprintf_error(buf
+ len
- pos
, ret
))
595 entry
= pmksa
->pmksa
;
598 ret
= os_snprintf(pos
, buf
+ len
- pos
, "%d " MACSTR
" ",
599 i
, MAC2STR(entry
->aa
));
600 if (os_snprintf_error(buf
+ len
- pos
, ret
))
603 pos
+= wpa_snprintf_hex(pos
, buf
+ len
- pos
, entry
->pmkid
,
605 ret
= os_snprintf(pos
, buf
+ len
- pos
, " %d %d",
606 (int) (entry
->expiration
- now
.sec
),
607 entry
->opportunistic
);
608 if (os_snprintf_error(buf
+ len
- pos
, ret
))
611 if (entry
->fils_cache_id_set
) {
612 ret
= os_snprintf(pos
, buf
+ len
- pos
, " %02x%02x",
613 entry
->fils_cache_id
[0],
614 entry
->fils_cache_id
[1]);
615 if (os_snprintf_error(buf
+ len
- pos
, ret
))
619 ret
= os_snprintf(pos
, buf
+ len
- pos
, "\n");
620 if (os_snprintf_error(buf
+ len
- pos
, ret
))
629 struct rsn_pmksa_cache_entry
* pmksa_cache_head(struct rsn_pmksa_cache
*pmksa
)
636 * pmksa_cache_init - Initialize PMKSA cache
637 * @free_cb: Callback function to be called when a PMKSA cache entry is freed
638 * @ctx: Context pointer for free_cb function
639 * @sm: Pointer to WPA state machine data from wpa_sm_init()
640 * Returns: Pointer to PMKSA cache data or %NULL on failure
642 struct rsn_pmksa_cache
*
643 pmksa_cache_init(void (*free_cb
)(struct rsn_pmksa_cache_entry
*entry
,
644 void *ctx
, enum pmksa_free_reason reason
),
645 void *ctx
, struct wpa_sm
*sm
)
647 struct rsn_pmksa_cache
*pmksa
;
649 pmksa
= os_zalloc(sizeof(*pmksa
));
651 pmksa
->free_cb
= free_cb
;
659 #endif /* IEEE8021X_EAPOL */