preauth.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. * RSN pre-authentication (supplicant)
  3. * Copyright (c) 2003-2010, 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 "l2_packet/l2_packet.h"
  19. #include "eapol_supp/eapol_supp_sm.h"
  20. #include "preauth.h"
  21. #include "pmksa_cache.h"
  22. #include "wpa_i.h"
  23. #include "common/ieee802_11_defs.h"
  24. #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
  25. #define PMKID_CANDIDATE_PRIO_SCAN 1000
  26. struct rsn_pmksa_candidate {
  27. struct dl_list list;
  28. u8 bssid[ETH_ALEN];
  29. int priority;
  30. };
  31. /**
  32. * pmksa_candidate_free - Free all entries in PMKSA candidate list
  33. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  34. */
  35. void pmksa_candidate_free(struct wpa_sm *sm)
  36. {
  37. struct rsn_pmksa_candidate *entry, *n;
  38. if (sm == NULL)
  39. return;
  40. dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
  41. struct rsn_pmksa_candidate, list) {
  42. dl_list_del(&entry->list);
  43. os_free(entry);
  44. }
  45. }
  46. static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
  47. const u8 *buf, size_t len)
  48. {
  49. struct wpa_sm *sm = ctx;
  50. wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
  51. wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
  52. if (sm->preauth_eapol == NULL ||
  53. is_zero_ether_addr(sm->preauth_bssid) ||
  54. os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
  55. wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
  56. "unexpected source " MACSTR " - dropped",
  57. MAC2STR(src_addr));
  58. return;
  59. }
  60. eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
  61. }
  62. static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
  63. void *ctx)
  64. {
  65. struct wpa_sm *sm = ctx;
  66. u8 pmk[PMK_LEN];
  67. if (success) {
  68. int res, pmk_len;
  69. pmk_len = PMK_LEN;
  70. res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
  71. if (res) {
  72. /*
  73. * EAP-LEAP is an exception from other EAP methods: it
  74. * uses only 16-byte PMK.
  75. */
  76. res = eapol_sm_get_key(eapol, pmk, 16);
  77. pmk_len = 16;
  78. }
  79. if (res == 0) {
  80. wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
  81. pmk, pmk_len);
  82. sm->pmk_len = pmk_len;
  83. pmksa_cache_add(sm->pmksa, pmk, pmk_len,
  84. sm->preauth_bssid, sm->own_addr,
  85. sm->network_ctx,
  86. WPA_KEY_MGMT_IEEE8021X);
  87. } else {
  88. wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
  89. "RSN: failed to get master session key from "
  90. "pre-auth EAPOL state machines");
  91. success = 0;
  92. }
  93. }
  94. wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
  95. MACSTR " %s", MAC2STR(sm->preauth_bssid),
  96. success ? "completed successfully" : "failed");
  97. rsn_preauth_deinit(sm);
  98. rsn_preauth_candidate_process(sm);
  99. }
  100. static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
  101. {
  102. struct wpa_sm *sm = eloop_ctx;
  103. wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
  104. MACSTR " timed out", MAC2STR(sm->preauth_bssid));
  105. rsn_preauth_deinit(sm);
  106. rsn_preauth_candidate_process(sm);
  107. }
  108. static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
  109. size_t len)
  110. {
  111. struct wpa_sm *sm = ctx;
  112. u8 *msg;
  113. size_t msglen;
  114. int res;
  115. /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
  116. * extra copy here */
  117. if (sm->l2_preauth == NULL)
  118. return -1;
  119. msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
  120. if (msg == NULL)
  121. return -1;
  122. wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
  123. res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
  124. ETH_P_RSN_PREAUTH, msg, msglen);
  125. os_free(msg);
  126. return res;
  127. }
  128. /**
  129. * rsn_preauth_init - Start new RSN pre-authentication
  130. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  131. * @dst: Authenticator address (BSSID) with which to preauthenticate
  132. * @eap_conf: Current EAP configuration
  133. * Returns: 0 on success, -1 on another pre-authentication is in progress,
  134. * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
  135. * initialization failure, -4 on memory allocation failure
  136. *
  137. * This function request an RSN pre-authentication with a given destination
  138. * address. This is usually called for PMKSA candidates found from scan results
  139. * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
  140. * pre-authentication.
  141. */
  142. int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
  143. struct eap_peer_config *eap_conf)
  144. {
  145. struct eapol_config eapol_conf;
  146. struct eapol_ctx *ctx;
  147. if (sm->preauth_eapol)
  148. return -1;
  149. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
  150. "RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
  151. sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
  152. ETH_P_RSN_PREAUTH,
  153. rsn_preauth_receive, sm, 0);
  154. if (sm->l2_preauth == NULL) {
  155. wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
  156. "processing for pre-authentication");
  157. return -2;
  158. }
  159. if (sm->bridge_ifname) {
  160. sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
  161. sm->own_addr,
  162. ETH_P_RSN_PREAUTH,
  163. rsn_preauth_receive, sm, 0);
  164. if (sm->l2_preauth_br == NULL) {
  165. wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
  166. "packet processing (bridge) for "
  167. "pre-authentication");
  168. return -2;
  169. }
  170. }
  171. ctx = os_zalloc(sizeof(*ctx));
  172. if (ctx == NULL) {
  173. wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
  174. return -4;
  175. }
  176. ctx->ctx = sm->ctx->ctx;
  177. ctx->msg_ctx = sm->ctx->ctx;
  178. ctx->preauth = 1;
  179. ctx->cb = rsn_preauth_eapol_cb;
  180. ctx->cb_ctx = sm;
  181. ctx->scard_ctx = sm->scard_ctx;
  182. ctx->eapol_send = rsn_preauth_eapol_send;
  183. ctx->eapol_send_ctx = sm;
  184. ctx->set_config_blob = sm->ctx->set_config_blob;
  185. ctx->get_config_blob = sm->ctx->get_config_blob;
  186. sm->preauth_eapol = eapol_sm_init(ctx);
  187. if (sm->preauth_eapol == NULL) {
  188. os_free(ctx);
  189. wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
  190. "state machines for pre-authentication");
  191. return -3;
  192. }
  193. os_memset(&eapol_conf, 0, sizeof(eapol_conf));
  194. eapol_conf.accept_802_1x_keys = 0;
  195. eapol_conf.required_keys = 0;
  196. eapol_conf.fast_reauth = sm->fast_reauth;
  197. eapol_conf.workaround = sm->eap_workaround;
  198. eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
  199. /*
  200. * Use a shorter startPeriod with preauthentication since the first
  201. * preauth EAPOL-Start frame may end up being dropped due to race
  202. * condition in the AP between the data receive and key configuration
  203. * after the 4-Way Handshake.
  204. */
  205. eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
  206. os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
  207. eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
  208. /* 802.1X::portControl = Auto */
  209. eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
  210. eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
  211. rsn_preauth_timeout, sm, NULL);
  212. return 0;
  213. }
  214. /**
  215. * rsn_preauth_deinit - Abort RSN pre-authentication
  216. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  217. *
  218. * This function aborts the current RSN pre-authentication (if one is started)
  219. * and frees resources allocated for it.
  220. */
  221. void rsn_preauth_deinit(struct wpa_sm *sm)
  222. {
  223. if (sm == NULL || !sm->preauth_eapol)
  224. return;
  225. eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
  226. eapol_sm_deinit(sm->preauth_eapol);
  227. sm->preauth_eapol = NULL;
  228. os_memset(sm->preauth_bssid, 0, ETH_ALEN);
  229. l2_packet_deinit(sm->l2_preauth);
  230. sm->l2_preauth = NULL;
  231. if (sm->l2_preauth_br) {
  232. l2_packet_deinit(sm->l2_preauth_br);
  233. sm->l2_preauth_br = NULL;
  234. }
  235. }
  236. /**
  237. * rsn_preauth_candidate_process - Process PMKSA candidates
  238. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  239. *
  240. * Go through the PMKSA candidates and start pre-authentication if a candidate
  241. * without an existing PMKSA cache entry is found. Processed candidates will be
  242. * removed from the list.
  243. */
  244. void rsn_preauth_candidate_process(struct wpa_sm *sm)
  245. {
  246. struct rsn_pmksa_candidate *candidate, *n;
  247. if (dl_list_empty(&sm->pmksa_candidates))
  248. return;
  249. /* TODO: drop priority for old candidate entries */
  250. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
  251. "list");
  252. if (sm->preauth_eapol ||
  253. sm->proto != WPA_PROTO_RSN ||
  254. wpa_sm_get_state(sm) != WPA_COMPLETED ||
  255. (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
  256. sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
  257. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
  258. "state for new pre-authentication");
  259. return; /* invalid state for new pre-auth */
  260. }
  261. dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
  262. struct rsn_pmksa_candidate, list) {
  263. struct rsn_pmksa_cache_entry *p = NULL;
  264. p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
  265. if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
  266. (p == NULL || p->opportunistic)) {
  267. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
  268. "candidate " MACSTR
  269. " selected for pre-authentication",
  270. MAC2STR(candidate->bssid));
  271. dl_list_del(&candidate->list);
  272. rsn_preauth_init(sm, candidate->bssid,
  273. sm->eap_conf_ctx);
  274. os_free(candidate);
  275. return;
  276. }
  277. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
  278. MACSTR " does not need pre-authentication anymore",
  279. MAC2STR(candidate->bssid));
  280. /* Some drivers (e.g., NDIS) expect to get notified about the
  281. * PMKIDs again, so report the existing data now. */
  282. if (p) {
  283. wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
  284. }
  285. dl_list_del(&candidate->list);
  286. os_free(candidate);
  287. }
  288. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
  289. "candidates");
  290. }
  291. /**
  292. * pmksa_candidate_add - Add a new PMKSA candidate
  293. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  294. * @bssid: BSSID (authenticator address) of the candidate
  295. * @prio: Priority (the smaller number, the higher priority)
  296. * @preauth: Whether the candidate AP advertises support for pre-authentication
  297. *
  298. * This function is used to add PMKSA candidates for RSN pre-authentication. It
  299. * is called from scan result processing and from driver events for PMKSA
  300. * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
  301. */
  302. void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
  303. int prio, int preauth)
  304. {
  305. struct rsn_pmksa_candidate *cand, *pos;
  306. if (sm->network_ctx && sm->proactive_key_caching)
  307. pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
  308. bssid);
  309. if (!preauth) {
  310. wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
  311. "preauth flag");
  312. return;
  313. }
  314. /* If BSSID already on candidate list, update the priority of the old
  315. * entry. Do not override priority based on normal scan results. */
  316. cand = NULL;
  317. dl_list_for_each(pos, &sm->pmksa_candidates,
  318. struct rsn_pmksa_candidate, list) {
  319. if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
  320. cand = pos;
  321. break;
  322. }
  323. }
  324. if (cand) {
  325. dl_list_del(&cand->list);
  326. if (prio < PMKID_CANDIDATE_PRIO_SCAN)
  327. cand->priority = prio;
  328. } else {
  329. cand = os_zalloc(sizeof(*cand));
  330. if (cand == NULL)
  331. return;
  332. os_memcpy(cand->bssid, bssid, ETH_ALEN);
  333. cand->priority = prio;
  334. }
  335. /* Add candidate to the list; order by increasing priority value. i.e.,
  336. * highest priority (smallest value) first. */
  337. dl_list_for_each(pos, &sm->pmksa_candidates,
  338. struct rsn_pmksa_candidate, list) {
  339. if (cand->priority <= pos->priority) {
  340. dl_list_add(pos->list.prev, &cand->list);
  341. cand = NULL;
  342. break;
  343. }
  344. }
  345. if (cand)
  346. dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
  347. wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
  348. "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
  349. rsn_preauth_candidate_process(sm);
  350. }
  351. /* TODO: schedule periodic scans if current AP supports preauth */
  352. /**
  353. * rsn_preauth_scan_results - Start processing scan results for canditates
  354. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  355. * Returns: 0 if ready to process results or -1 to skip processing
  356. *
  357. * This functions is used to notify RSN code about start of new scan results
  358. * processing. The actual scan results will be provided by calling
  359. * rsn_preauth_scan_result() for each BSS if this function returned 0.
  360. */
  361. int rsn_preauth_scan_results(struct wpa_sm *sm)
  362. {
  363. if (sm->ssid_len == 0)
  364. return -1;
  365. /*
  366. * TODO: is it ok to free all candidates? What about the entries
  367. * received from EVENT_PMKID_CANDIDATE?
  368. */
  369. pmksa_candidate_free(sm);
  370. return 0;
  371. }
  372. /**
  373. * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
  374. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  375. *
  376. * Add all suitable APs (Authenticators) from scan results into PMKSA
  377. * candidate list.
  378. */
  379. void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
  380. const u8 *ssid, const u8 *rsn)
  381. {
  382. struct wpa_ie_data ie;
  383. struct rsn_pmksa_cache_entry *pmksa;
  384. if (ssid[1] != sm->ssid_len ||
  385. os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
  386. return; /* Not for the current SSID */
  387. if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
  388. return; /* Ignore current AP */
  389. if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
  390. return;
  391. pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL);
  392. if (pmksa && (!pmksa->opportunistic ||
  393. !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
  394. return;
  395. /* Give less priority to candidates found from normal scan results. */
  396. pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
  397. ie.capabilities & WPA_CAPABILITY_PREAUTH);
  398. }
  399. #ifdef CONFIG_CTRL_IFACE
  400. /**
  401. * rsn_preauth_get_status - Get pre-authentication status
  402. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  403. * @buf: Buffer for status information
  404. * @buflen: Maximum buffer length
  405. * @verbose: Whether to include verbose status information
  406. * Returns: Number of bytes written to buf.
  407. *
  408. * Query WPA2 pre-authentication for status information. This function fills in
  409. * a text area with current status information. If the buffer (buf) is not
  410. * large enough, status information will be truncated to fit the buffer.
  411. */
  412. int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
  413. int verbose)
  414. {
  415. char *pos = buf, *end = buf + buflen;
  416. int res, ret;
  417. if (sm->preauth_eapol) {
  418. ret = os_snprintf(pos, end - pos, "Pre-authentication "
  419. "EAPOL state machines:\n");
  420. if (ret < 0 || ret >= end - pos)
  421. return pos - buf;
  422. pos += ret;
  423. res = eapol_sm_get_status(sm->preauth_eapol,
  424. pos, end - pos, verbose);
  425. if (res >= 0)
  426. pos += res;
  427. }
  428. return pos - buf;
  429. }
  430. #endif /* CONFIG_CTRL_IFACE */
  431. /**
  432. * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
  433. * @sm: Pointer to WPA state machine data from wpa_sm_init()
  434. */
  435. int rsn_preauth_in_progress(struct wpa_sm *sm)
  436. {
  437. return sm->preauth_eapol != NULL;
  438. }
  439. #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */