pmksa_cache.c 15 KB

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