pmksa_cache.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. * WPA Supplicant - RSN PMKSA cache
  3. * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "wpa.h"
  17. #include "eloop.h"
  18. #include "sha1.h"
  19. #include "sha256.h"
  20. #include "wpa_i.h"
  21. #include "eapol_supp/eapol_supp_sm.h"
  22. #include "pmksa_cache.h"
  23. #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
  24. static const int pmksa_cache_max_entries = 32;
  25. struct rsn_pmksa_cache {
  26. struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
  27. int pmksa_count; /* number of entries in PMKSA cache */
  28. struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
  29. void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
  30. int replace);
  31. void *ctx;
  32. };
  33. static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
  34. static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
  35. {
  36. os_free(entry);
  37. }
  38. static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
  39. struct rsn_pmksa_cache_entry *entry,
  40. int replace)
  41. {
  42. pmksa->pmksa_count--;
  43. pmksa->free_cb(entry, pmksa->ctx, replace);
  44. _pmksa_cache_free_entry(entry);
  45. }
  46. static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
  47. {
  48. struct rsn_pmksa_cache *pmksa = eloop_ctx;
  49. struct os_time now;
  50. os_get_time(&now);
  51. while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
  52. struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
  53. pmksa->pmksa = entry->next;
  54. wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
  55. MACSTR, MAC2STR(entry->aa));
  56. pmksa_cache_free_entry(pmksa, entry, 0);
  57. }
  58. pmksa_cache_set_expiration(pmksa);
  59. }
  60. static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
  61. {
  62. struct rsn_pmksa_cache *pmksa = eloop_ctx;
  63. pmksa->sm->cur_pmksa = NULL;
  64. eapol_sm_request_reauth(pmksa->sm->eapol);
  65. }
  66. static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  67. {
  68. int sec;
  69. struct rsn_pmksa_cache_entry *entry;
  70. struct os_time now;
  71. eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
  72. eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
  73. if (pmksa->pmksa == NULL)
  74. return;
  75. os_get_time(&now);
  76. sec = pmksa->pmksa->expiration - now.sec;
  77. if (sec < 0)
  78. sec = 0;
  79. eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
  80. entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
  81. pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL);
  82. if (entry) {
  83. sec = pmksa->pmksa->reauth_time - now.sec;
  84. if (sec < 0)
  85. sec = 0;
  86. eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
  87. NULL);
  88. }
  89. }
  90. /**
  91. * pmksa_cache_add - Add a PMKSA cache entry
  92. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  93. * @pmk: The new pairwise master key
  94. * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
  95. * @aa: Authenticator address
  96. * @spa: Supplicant address
  97. * @network_ctx: Network configuration context for this PMK
  98. * @akmp: WPA_KEY_MGMT_* used in key derivation
  99. * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  100. *
  101. * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
  102. * cache. If an old entry is already in the cache for the same Authenticator,
  103. * this entry will be replaced with the new entry. PMKID will be calculated
  104. * based on the PMK and the driver interface is notified of the new PMKID.
  105. */
  106. struct rsn_pmksa_cache_entry *
  107. pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
  108. const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
  109. {
  110. struct rsn_pmksa_cache_entry *entry, *pos, *prev;
  111. struct os_time now;
  112. if (pmk_len > PMK_LEN)
  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. rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
  120. wpa_key_mgmt_sha256(akmp));
  121. os_get_time(&now);
  122. entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
  123. entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
  124. pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
  125. entry->akmp = akmp;
  126. os_memcpy(entry->aa, aa, ETH_ALEN);
  127. entry->network_ctx = network_ctx;
  128. /* Replace an old entry for the same Authenticator (if found) with the
  129. * new entry */
  130. pos = pmksa->pmksa;
  131. prev = NULL;
  132. while (pos) {
  133. if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
  134. if (pos->pmk_len == pmk_len &&
  135. os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
  136. os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
  137. 0) {
  138. wpa_printf(MSG_DEBUG, "WPA: reusing previous "
  139. "PMKSA entry");
  140. os_free(entry);
  141. return pos;
  142. }
  143. if (prev == NULL)
  144. pmksa->pmksa = pos->next;
  145. else
  146. prev->next = pos->next;
  147. if (pos == pmksa->sm->cur_pmksa) {
  148. /* We are about to replace the current PMKSA
  149. * cache entry. This happens when the PMKSA
  150. * caching attempt fails, so we don't want to
  151. * force pmksa_cache_free_entry() to disconnect
  152. * at this point. Let's just make sure the old
  153. * PMKSA cache entry will not be used in the
  154. * future.
  155. */
  156. wpa_printf(MSG_DEBUG, "RSN: replacing current "
  157. "PMKSA entry");
  158. pmksa->sm->cur_pmksa = NULL;
  159. }
  160. wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
  161. "the current AP");
  162. pmksa_cache_free_entry(pmksa, pos, 1);
  163. break;
  164. }
  165. prev = pos;
  166. pos = pos->next;
  167. }
  168. if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
  169. /* Remove the oldest entry to make room for the new entry */
  170. pos = pmksa->pmksa;
  171. pmksa->pmksa = pos->next;
  172. wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
  173. "entry (for " MACSTR ") to make room for new one",
  174. MAC2STR(pos->aa));
  175. wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
  176. pmksa_cache_free_entry(pmksa, pos, 0);
  177. }
  178. /* Add the new entry; order by expiration time */
  179. pos = pmksa->pmksa;
  180. prev = NULL;
  181. while (pos) {
  182. if (pos->expiration > entry->expiration)
  183. break;
  184. prev = pos;
  185. pos = pos->next;
  186. }
  187. if (prev == NULL) {
  188. entry->next = pmksa->pmksa;
  189. pmksa->pmksa = entry;
  190. pmksa_cache_set_expiration(pmksa);
  191. } else {
  192. entry->next = prev->next;
  193. prev->next = entry;
  194. }
  195. pmksa->pmksa_count++;
  196. wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
  197. MAC2STR(entry->aa));
  198. wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
  199. return entry;
  200. }
  201. /**
  202. * pmksa_cache_deinit - Free all entries in PMKSA cache
  203. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  204. */
  205. void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
  206. {
  207. struct rsn_pmksa_cache_entry *entry, *prev;
  208. if (pmksa == NULL)
  209. return;
  210. entry = pmksa->pmksa;
  211. pmksa->pmksa = NULL;
  212. while (entry) {
  213. prev = entry;
  214. entry = entry->next;
  215. os_free(prev);
  216. }
  217. pmksa_cache_set_expiration(pmksa);
  218. os_free(pmksa);
  219. }
  220. /**
  221. * pmksa_cache_get - Fetch a PMKSA cache entry
  222. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  223. * @aa: Authenticator address or %NULL to match any
  224. * @pmkid: PMKID or %NULL to match any
  225. * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
  226. */
  227. struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
  228. const u8 *aa, const u8 *pmkid)
  229. {
  230. struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
  231. while (entry) {
  232. if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
  233. (pmkid == NULL ||
  234. os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
  235. return entry;
  236. entry = entry->next;
  237. }
  238. return NULL;
  239. }
  240. /**
  241. * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
  242. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  243. *
  244. * Clear references to old data structures when wpa_supplicant is reconfigured.
  245. */
  246. void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
  247. {
  248. struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
  249. while (entry) {
  250. entry->network_ctx = NULL;
  251. entry = entry->next;
  252. }
  253. }
  254. static struct rsn_pmksa_cache_entry *
  255. pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
  256. const struct rsn_pmksa_cache_entry *old_entry,
  257. const u8 *aa)
  258. {
  259. struct rsn_pmksa_cache_entry *new_entry;
  260. new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
  261. aa, pmksa->sm->own_addr,
  262. old_entry->network_ctx, old_entry->akmp);
  263. if (new_entry == NULL)
  264. return NULL;
  265. /* TODO: reorder entries based on expiration time? */
  266. new_entry->expiration = old_entry->expiration;
  267. new_entry->opportunistic = 1;
  268. return new_entry;
  269. }
  270. /**
  271. * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
  272. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  273. * @network_ctx: Network configuration context
  274. * @aa: Authenticator address for the new AP
  275. * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
  276. *
  277. * Try to create a new PMKSA cache entry opportunistically by guessing that the
  278. * new AP is sharing the same PMK as another AP that has the same SSID and has
  279. * already an entry in PMKSA cache.
  280. */
  281. struct rsn_pmksa_cache_entry *
  282. pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
  283. const u8 *aa)
  284. {
  285. struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
  286. if (network_ctx == NULL)
  287. return NULL;
  288. while (entry) {
  289. if (entry->network_ctx == network_ctx) {
  290. entry = pmksa_cache_clone_entry(pmksa, entry, aa);
  291. if (entry) {
  292. wpa_printf(MSG_DEBUG, "RSN: added "
  293. "opportunistic PMKSA cache entry "
  294. "for " MACSTR, MAC2STR(aa));
  295. }
  296. return entry;
  297. }
  298. entry = entry->next;
  299. }
  300. return NULL;
  301. }
  302. /**
  303. * pmksa_cache_get_current - Get the current used PMKSA entry
  304. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  305. * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
  306. */
  307. struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
  308. {
  309. if (sm == NULL)
  310. return NULL;
  311. return sm->cur_pmksa;
  312. }
  313. /**
  314. * pmksa_cache_clear_current - Clear the current PMKSA entry selection
  315. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  316. */
  317. void pmksa_cache_clear_current(struct wpa_sm *sm)
  318. {
  319. if (sm == NULL)
  320. return;
  321. sm->cur_pmksa = NULL;
  322. }
  323. /**
  324. * pmksa_cache_set_current - Set the current PMKSA entry selection
  325. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  326. * @pmkid: PMKID for selecting PMKSA or %NULL if not used
  327. * @bssid: BSSID for PMKSA or %NULL if not used
  328. * @network_ctx: Network configuration context
  329. * @try_opportunistic: Whether to allow opportunistic PMKSA caching
  330. * Returns: 0 if PMKSA was found or -1 if no matching entry was found
  331. */
  332. int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
  333. const u8 *bssid, void *network_ctx,
  334. int try_opportunistic)
  335. {
  336. struct rsn_pmksa_cache *pmksa = sm->pmksa;
  337. sm->cur_pmksa = NULL;
  338. if (pmkid)
  339. sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid);
  340. if (sm->cur_pmksa == NULL && bssid)
  341. sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL);
  342. if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
  343. sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
  344. network_ctx,
  345. bssid);
  346. if (sm->cur_pmksa) {
  347. wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
  348. sm->cur_pmksa->pmkid, PMKID_LEN);
  349. return 0;
  350. }
  351. return -1;
  352. }
  353. /**
  354. * pmksa_cache_list - Dump text list of entries in PMKSA cache
  355. * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  356. * @buf: Buffer for the list
  357. * @len: Length of the buffer
  358. * Returns: number of bytes written to buffer
  359. *
  360. * This function is used to generate a text format representation of the
  361. * current PMKSA cache contents for the ctrl_iface PMKSA command.
  362. */
  363. int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
  364. {
  365. int i, ret;
  366. char *pos = buf;
  367. struct rsn_pmksa_cache_entry *entry;
  368. struct os_time now;
  369. os_get_time(&now);
  370. ret = os_snprintf(pos, buf + len - pos,
  371. "Index / AA / PMKID / expiration (in seconds) / "
  372. "opportunistic\n");
  373. if (ret < 0 || ret >= buf + len - pos)
  374. return pos - buf;
  375. pos += ret;
  376. i = 0;
  377. entry = pmksa->pmksa;
  378. while (entry) {
  379. i++;
  380. ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
  381. i, MAC2STR(entry->aa));
  382. if (ret < 0 || ret >= buf + len - pos)
  383. return pos - buf;
  384. pos += ret;
  385. pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
  386. PMKID_LEN);
  387. ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
  388. (int) (entry->expiration - now.sec),
  389. entry->opportunistic);
  390. if (ret < 0 || ret >= buf + len - pos)
  391. return pos - buf;
  392. pos += ret;
  393. entry = entry->next;
  394. }
  395. return pos - buf;
  396. }
  397. /**
  398. * pmksa_cache_init - Initialize PMKSA cache
  399. * @free_cb: Callback function to be called when a PMKSA cache entry is freed
  400. * @ctx: Context pointer for free_cb function
  401. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  402. * Returns: Pointer to PMKSA cache data or %NULL on failure
  403. */
  404. struct rsn_pmksa_cache *
  405. pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
  406. void *ctx, int replace),
  407. void *ctx, struct wpa_sm *sm)
  408. {
  409. struct rsn_pmksa_cache *pmksa;
  410. pmksa = os_zalloc(sizeof(*pmksa));
  411. if (pmksa) {
  412. pmksa->free_cb = free_cb;
  413. pmksa->ctx = ctx;
  414. pmksa->sm = sm;
  415. }
  416. return pmksa;
  417. }
  418. #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */