pmksa_cache.c 16 KB

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