eap_wsc.c 13 KB

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