eap_wsc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. * EAP-WSC peer for Wi-Fi Protected Setup
  3. * Copyright (c) 2007-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 "uuid.h"
  17. #include "eap_i.h"
  18. #include "eap_common/eap_wsc_common.h"
  19. #include "wps/wps.h"
  20. #include "wps/wps_defs.h"
  21. struct eap_wsc_data {
  22. enum { WAIT_START, MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
  23. int registrar;
  24. struct wpabuf *in_buf;
  25. struct wpabuf *out_buf;
  26. u8 in_op_code, out_op_code;
  27. size_t out_used;
  28. size_t fragment_size;
  29. struct wps_data *wps;
  30. struct wps_context *wps_ctx;
  31. };
  32. static const char * eap_wsc_state_txt(int state)
  33. {
  34. switch (state) {
  35. case WAIT_START:
  36. return "WAIT_START";
  37. case MSG:
  38. return "MSG";
  39. case FRAG_ACK:
  40. return "FRAG_ACK";
  41. case WAIT_FRAG_ACK:
  42. return "WAIT_FRAG_ACK";
  43. case DONE:
  44. return "DONE";
  45. case FAIL:
  46. return "FAIL";
  47. default:
  48. return "?";
  49. }
  50. }
  51. static void eap_wsc_state(struct eap_wsc_data *data, int state)
  52. {
  53. wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
  54. eap_wsc_state_txt(data->state),
  55. eap_wsc_state_txt(state));
  56. data->state = state;
  57. }
  58. static int eap_wsc_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
  59. size_t psk_len)
  60. {
  61. /* struct eap_wsc_data *data = ctx; */
  62. wpa_printf(MSG_DEBUG, "EAP-SC: Received new WPA/WPA2-PSK from WPS for "
  63. "STA " MACSTR, MAC2STR(mac_addr));
  64. wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
  65. /* TODO */
  66. return 0;
  67. }
  68. static void eap_wsc_pin_needed_cb(void *ctx, const u8 *uuid_e,
  69. const struct wps_device_data *dev)
  70. {
  71. /* struct eap_wsc_data *data = ctx; */
  72. char uuid[40], txt[400];
  73. int len;
  74. if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
  75. return;
  76. wpa_printf(MSG_DEBUG, "EAP-WSC: PIN needed for E-UUID %s", uuid);
  77. len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED "
  78. "%s " MACSTR " [%s|%s|%s|%s|%s|%d-%08X-%d]",
  79. uuid, MAC2STR(dev->mac_addr), dev->device_name,
  80. dev->manufacturer, dev->model_name,
  81. dev->model_number, dev->serial_number,
  82. dev->categ, dev->oui, dev->sub_categ);
  83. if (len > 0 && len < (int) sizeof(txt))
  84. wpa_printf(MSG_INFO, "%s", txt);
  85. }
  86. static void * eap_wsc_init(struct eap_sm *sm)
  87. {
  88. struct eap_wsc_data *data;
  89. const u8 *identity;
  90. size_t identity_len;
  91. int registrar;
  92. struct wps_config cfg;
  93. const char *pos;
  94. const char *phase1;
  95. struct wps_context *wps = NULL;
  96. identity = eap_get_config_identity(sm, &identity_len);
  97. if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
  98. os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
  99. registrar = 1; /* Supplicant is Registrar */
  100. else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
  101. os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
  102. registrar = 0; /* Supplicant is Enrollee */
  103. else {
  104. wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
  105. identity, identity_len);
  106. return NULL;
  107. }
  108. data = os_zalloc(sizeof(*data));
  109. if (data == NULL)
  110. return NULL;
  111. data->state = registrar ? MSG : WAIT_START;
  112. data->registrar = registrar;
  113. if (registrar) {
  114. struct wps_registrar_config rcfg;
  115. wps = os_zalloc(sizeof(*wps));
  116. if (wps == NULL) {
  117. os_free(data);
  118. return NULL;
  119. }
  120. wps->cb_ctx = data;
  121. /* TODO: configure.. */
  122. wps->auth_types = WPS_AUTH_WPA2PSK;
  123. wps->encr_types = WPS_ENCR_AES;
  124. os_memcpy(wps->ssid, "test", 4);
  125. wps->ssid_len = 4;
  126. os_memset(&rcfg, 0, sizeof(rcfg));
  127. rcfg.new_psk_cb = eap_wsc_new_psk_cb;
  128. rcfg.pin_needed_cb = eap_wsc_pin_needed_cb;
  129. rcfg.cb_ctx = data;
  130. wps->registrar = wps_registrar_init(wps, &rcfg);
  131. if (wps->registrar == NULL) {
  132. wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to initialize "
  133. "WPS Registrar");
  134. os_free(wps->network_key);
  135. os_free(wps);
  136. os_free(data);
  137. return NULL;
  138. }
  139. data->wps_ctx = wps;
  140. }
  141. os_memset(&cfg, 0, sizeof(cfg));
  142. cfg.authenticator = 0;
  143. cfg.wps = wps;
  144. cfg.registrar = data->wps_ctx ? data->wps_ctx->registrar : NULL;
  145. cfg.enrollee_mac_addr = sm->mac_addr;
  146. phase1 = eap_get_config_phase1(sm);
  147. if (phase1 == NULL) {
  148. wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
  149. "set");
  150. os_free(data);
  151. return NULL;
  152. }
  153. pos = os_strstr(phase1, "pin=");
  154. if (pos) {
  155. pos += 4;
  156. cfg.pin = (const u8 *) pos;
  157. while (*pos != '\0' && *pos != ' ')
  158. pos++;
  159. cfg.pin_len = pos - (const char *) cfg.pin;
  160. } else {
  161. pos = os_strstr(phase1, "pbc=1");
  162. if (pos)
  163. cfg.pbc = 1;
  164. }
  165. if (cfg.pin == NULL && !cfg.pbc) {
  166. wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
  167. "configuration data");
  168. os_free(data);
  169. return NULL;
  170. }
  171. if (registrar && wps)
  172. os_memcpy(wps->uuid, sm->uuid, UUID_LEN);
  173. else
  174. cfg.uuid = sm->uuid;
  175. cfg.wps_cred_cb = sm->eapol_cb->wps_cred;
  176. cfg.cb_ctx = sm->eapol_ctx;
  177. data->wps = wps_init(&cfg);
  178. if (data->wps == NULL) {
  179. os_free(data);
  180. return NULL;
  181. }
  182. data->fragment_size = WSC_FRAGMENT_SIZE;
  183. if (registrar) {
  184. /* Testing */
  185. wpa_printf(MSG_INFO, "EAP-WSC: Registrar functionality not "
  186. "yet fully supported - using test values");
  187. u8 uuid_e[UUID_LEN];
  188. os_memset(uuid_e, 0, UUID_LEN);
  189. wps_registrar_add_pin(data->wps_ctx->registrar, uuid_e,
  190. (const u8 *) "12345670", 8);
  191. }
  192. return data;
  193. }
  194. static void eap_wsc_deinit(struct eap_sm *sm, void *priv)
  195. {
  196. struct eap_wsc_data *data = priv;
  197. wpabuf_free(data->in_buf);
  198. wpabuf_free(data->out_buf);
  199. wps_deinit(data->wps);
  200. if (data->wps_ctx) {
  201. wps_registrar_deinit(data->wps_ctx->registrar);
  202. os_free(data->wps_ctx->network_key);
  203. os_free(data->wps_ctx);
  204. }
  205. os_free(data);
  206. }
  207. static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,
  208. struct eap_method_ret *ret, u8 id)
  209. {
  210. struct wpabuf *resp;
  211. u8 flags;
  212. size_t send_len, plen;
  213. ret->ignore = FALSE;
  214. wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
  215. ret->allowNotifications = TRUE;
  216. flags = 0;
  217. send_len = wpabuf_len(data->out_buf) - data->out_used;
  218. if (2 + send_len > data->fragment_size) {
  219. send_len = data->fragment_size - 2;
  220. flags |= WSC_FLAGS_MF;
  221. if (data->out_used == 0) {
  222. flags |= WSC_FLAGS_LF;
  223. send_len -= 2;
  224. }
  225. }
  226. plen = 2 + send_len;
  227. if (flags & WSC_FLAGS_LF)
  228. plen += 2;
  229. resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
  230. EAP_CODE_RESPONSE, id);
  231. if (resp == NULL)
  232. return NULL;
  233. wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
  234. wpabuf_put_u8(resp, flags); /* Flags */
  235. if (flags & WSC_FLAGS_LF)
  236. wpabuf_put_be16(resp, wpabuf_len(data->out_buf));
  237. wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
  238. send_len);
  239. data->out_used += send_len;
  240. ret->methodState = METHOD_MAY_CONT;
  241. ret->decision = DECISION_FAIL;
  242. if (data->out_used == wpabuf_len(data->out_buf)) {
  243. wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
  244. "(message sent completely)",
  245. (unsigned long) send_len);
  246. wpabuf_free(data->out_buf);
  247. data->out_buf = NULL;
  248. data->out_used = 0;
  249. if ((data->state == FAIL && data->out_op_code == WSC_ACK) ||
  250. data->out_op_code == WSC_NACK ||
  251. data->out_op_code == WSC_Done) {
  252. eap_wsc_state(data, FAIL);
  253. ret->methodState = METHOD_DONE;
  254. } else
  255. eap_wsc_state(data, MSG);
  256. } else {
  257. wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
  258. "(%lu more to send)", (unsigned long) send_len,
  259. (unsigned long) wpabuf_len(data->out_buf) -
  260. data->out_used);
  261. eap_wsc_state(data, WAIT_FRAG_ACK);
  262. }
  263. return resp;
  264. }
  265. static int eap_wsc_process_cont(struct eap_wsc_data *data,
  266. const u8 *buf, size_t len, u8 op_code)
  267. {
  268. /* Process continuation of a pending message */
  269. if (op_code != data->in_op_code) {
  270. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
  271. "fragment (expected %d)",
  272. op_code, data->in_op_code);
  273. return -1;
  274. }
  275. if (len > wpabuf_tailroom(data->in_buf)) {
  276. wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
  277. eap_wsc_state(data, FAIL);
  278. return -1;
  279. }
  280. wpabuf_put_data(data->in_buf, buf, len);
  281. wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
  282. "for %lu bytes more", (unsigned long) len,
  283. (unsigned long) wpabuf_tailroom(data->in_buf));
  284. return 0;
  285. }
  286. static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
  287. struct eap_method_ret *ret,
  288. u8 id, u8 flags, u8 op_code,
  289. u16 message_length,
  290. const u8 *buf, size_t len)
  291. {
  292. /* Process a fragment that is not the last one of the message */
  293. if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
  294. wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
  295. "fragmented packet");
  296. ret->ignore = TRUE;
  297. return NULL;
  298. }
  299. if (data->in_buf == NULL) {
  300. /* First fragment of the message */
  301. data->in_buf = wpabuf_alloc(message_length);
  302. if (data->in_buf == NULL) {
  303. wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
  304. "message");
  305. ret->ignore = TRUE;
  306. return NULL;
  307. }
  308. data->in_op_code = op_code;
  309. wpabuf_put_data(data->in_buf, buf, len);
  310. wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first "
  311. "fragment, waiting for %lu bytes more",
  312. (unsigned long) len,
  313. (unsigned long) wpabuf_tailroom(data->in_buf));
  314. }
  315. return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
  316. }
  317. static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
  318. struct eap_method_ret *ret,
  319. const struct wpabuf *reqData)
  320. {
  321. struct eap_wsc_data *data = priv;
  322. const u8 *start, *pos, *end;
  323. size_t len;
  324. u8 op_code, flags, id;
  325. u16 message_length = 0;
  326. enum wps_process_res res;
  327. struct wpabuf tmpbuf;
  328. pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
  329. &len);
  330. if (pos == NULL || len < 2) {
  331. ret->ignore = TRUE;
  332. return NULL;
  333. }
  334. id = eap_get_id(reqData);
  335. start = pos;
  336. end = start + len;
  337. op_code = *pos++;
  338. flags = *pos++;
  339. if (flags & WSC_FLAGS_LF) {
  340. if (end - pos < 2) {
  341. wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
  342. ret->ignore = TRUE;
  343. return NULL;
  344. }
  345. message_length = WPA_GET_BE16(pos);
  346. pos += 2;
  347. if (message_length < end - pos) {
  348. wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
  349. "Length");
  350. ret->ignore = TRUE;
  351. return NULL;
  352. }
  353. }
  354. wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
  355. "Flags 0x%x Message Length %d",
  356. op_code, flags, message_length);
  357. if (data->state == WAIT_FRAG_ACK) {
  358. if (op_code != WSC_FRAG_ACK) {
  359. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
  360. "in WAIT_FRAG_ACK state", op_code);
  361. ret->ignore = TRUE;
  362. return NULL;
  363. }
  364. wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
  365. eap_wsc_state(data, MSG);
  366. return eap_wsc_build_msg(data, ret, id);
  367. }
  368. if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
  369. op_code != WSC_Done && op_code != WSC_Start) {
  370. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
  371. op_code);
  372. ret->ignore = TRUE;
  373. return NULL;
  374. }
  375. if (data->state == WAIT_START) {
  376. if (op_code != WSC_Start) {
  377. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
  378. "in WAIT_START state", op_code);
  379. ret->ignore = TRUE;
  380. return NULL;
  381. }
  382. wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
  383. eap_wsc_state(data, MSG);
  384. /* Start message has empty payload, skip processing */
  385. goto send_msg;
  386. } else if (op_code == WSC_Start) {
  387. wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
  388. op_code);
  389. ret->ignore = TRUE;
  390. return NULL;
  391. }
  392. if (data->in_buf &&
  393. eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
  394. ret->ignore = TRUE;
  395. return NULL;
  396. }
  397. if (flags & WSC_FLAGS_MF) {
  398. return eap_wsc_process_fragment(data, ret, id, flags, op_code,
  399. message_length, pos,
  400. end - pos);
  401. }
  402. if (data->in_buf == NULL) {
  403. /* Wrap unfragmented messages as wpabuf without extra copy */
  404. wpabuf_set(&tmpbuf, pos, end - pos);
  405. data->in_buf = &tmpbuf;
  406. }
  407. res = wps_process_msg(data->wps, op_code, data->in_buf);
  408. switch (res) {
  409. case WPS_DONE:
  410. wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
  411. "successfully - wait for EAP failure");
  412. eap_wsc_state(data, FAIL);
  413. break;
  414. case WPS_CONTINUE:
  415. eap_wsc_state(data, MSG);
  416. break;
  417. case WPS_FAILURE:
  418. wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
  419. eap_wsc_state(data, FAIL);
  420. break;
  421. case WPS_PENDING:
  422. wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing pending");
  423. ret->ignore = TRUE;
  424. if (data->in_buf == &tmpbuf)
  425. data->in_buf = NULL;
  426. return NULL;
  427. }
  428. if (data->in_buf != &tmpbuf)
  429. wpabuf_free(data->in_buf);
  430. data->in_buf = NULL;
  431. send_msg:
  432. if (data->out_buf == NULL) {
  433. data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
  434. if (data->out_buf == NULL) {
  435. wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
  436. "message from WPS");
  437. return NULL;
  438. }
  439. data->out_used = 0;
  440. }
  441. eap_wsc_state(data, MSG);
  442. return eap_wsc_build_msg(data, ret, id);
  443. }
  444. int eap_peer_wsc_register(void)
  445. {
  446. struct eap_method *eap;
  447. int ret;
  448. eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
  449. EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
  450. "WSC");
  451. if (eap == NULL)
  452. return -1;
  453. eap->init = eap_wsc_init;
  454. eap->deinit = eap_wsc_deinit;
  455. eap->process = eap_wsc_process;
  456. ret = eap_peer_method_register(eap);
  457. if (ret)
  458. eap_peer_method_free(eap);
  459. return ret;
  460. }