PageRenderTime 24ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/external/wpa_supplicant_6/wpa_supplicant/src/rsn_supp/preauth.c

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