pmksa_cache.c 15 KB

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