wps.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. * Wi-Fi Protected Setup
  3. * Copyright (c) 2007-2009, 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 "crypto/dh_group5.h"
  17. #include "common/ieee802_11_defs.h"
  18. #include "wps_i.h"
  19. #include "wps_dev_attr.h"
  20. /**
  21. * wps_init - Initialize WPS Registration protocol data
  22. * @cfg: WPS configuration
  23. * Returns: Pointer to allocated data or %NULL on failure
  24. *
  25. * This function is used to initialize WPS data for a registration protocol
  26. * instance (i.e., each run of registration protocol as a Registrar of
  27. * Enrollee. The caller is responsible for freeing this data after the
  28. * registration run has been completed by calling wps_deinit().
  29. */
  30. struct wps_data * wps_init(const struct wps_config *cfg)
  31. {
  32. struct wps_data *data = os_zalloc(sizeof(*data));
  33. if (data == NULL)
  34. return NULL;
  35. data->wps = cfg->wps;
  36. data->registrar = cfg->registrar;
  37. if (cfg->registrar) {
  38. os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
  39. } else {
  40. os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
  41. os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
  42. }
  43. if (cfg->pin) {
  44. data->dev_pw_id = data->wps->oob_dev_pw_id == 0 ?
  45. DEV_PW_DEFAULT : data->wps->oob_dev_pw_id;
  46. data->dev_password = os_malloc(cfg->pin_len);
  47. if (data->dev_password == NULL) {
  48. os_free(data);
  49. return NULL;
  50. }
  51. os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
  52. data->dev_password_len = cfg->pin_len;
  53. }
  54. data->pbc = cfg->pbc;
  55. if (cfg->pbc) {
  56. /* Use special PIN '00000000' for PBC */
  57. data->dev_pw_id = DEV_PW_PUSHBUTTON;
  58. os_free(data->dev_password);
  59. data->dev_password = os_malloc(8);
  60. if (data->dev_password == NULL) {
  61. os_free(data);
  62. return NULL;
  63. }
  64. os_memset(data->dev_password, '0', 8);
  65. data->dev_password_len = 8;
  66. }
  67. data->state = data->registrar ? RECV_M1 : SEND_M1;
  68. if (cfg->assoc_wps_ie) {
  69. struct wps_parse_attr attr;
  70. wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
  71. cfg->assoc_wps_ie);
  72. if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
  73. wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
  74. "from (Re)AssocReq");
  75. } else if (attr.request_type == NULL) {
  76. wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
  77. "in (Re)AssocReq WPS IE");
  78. } else {
  79. wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
  80. "in (Re)AssocReq WPS IE): %d",
  81. *attr.request_type);
  82. data->request_type = *attr.request_type;
  83. }
  84. }
  85. if (cfg->new_ap_settings) {
  86. data->new_ap_settings =
  87. os_malloc(sizeof(*data->new_ap_settings));
  88. if (data->new_ap_settings == NULL) {
  89. os_free(data);
  90. return NULL;
  91. }
  92. os_memcpy(data->new_ap_settings, cfg->new_ap_settings,
  93. sizeof(*data->new_ap_settings));
  94. }
  95. if (cfg->peer_addr)
  96. os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN);
  97. return data;
  98. }
  99. /**
  100. * wps_deinit - Deinitialize WPS Registration protocol data
  101. * @data: WPS Registration protocol data from wps_init()
  102. */
  103. void wps_deinit(struct wps_data *data)
  104. {
  105. if (data->wps_pin_revealed) {
  106. wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
  107. "negotiation failed");
  108. if (data->registrar)
  109. wps_registrar_invalidate_pin(data->wps->registrar,
  110. data->uuid_e);
  111. } else if (data->registrar)
  112. wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
  113. wpabuf_free(data->dh_privkey);
  114. wpabuf_free(data->dh_pubkey_e);
  115. wpabuf_free(data->dh_pubkey_r);
  116. wpabuf_free(data->last_msg);
  117. os_free(data->dev_password);
  118. os_free(data->new_psk);
  119. wps_device_data_free(&data->peer_dev);
  120. os_free(data->new_ap_settings);
  121. dh5_free(data->dh_ctx);
  122. os_free(data);
  123. }
  124. /**
  125. * wps_process_msg - Process a WPS message
  126. * @wps: WPS Registration protocol data from wps_init()
  127. * @op_code: Message OP Code
  128. * @msg: Message data
  129. * Returns: Processing result
  130. *
  131. * This function is used to process WPS messages with OP Codes WSC_ACK,
  132. * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
  133. * responsible for reassembling the messages before calling this function.
  134. * Response to this message is built by calling wps_get_msg().
  135. */
  136. enum wps_process_res wps_process_msg(struct wps_data *wps,
  137. enum wsc_op_code op_code,
  138. const struct wpabuf *msg)
  139. {
  140. if (wps->registrar)
  141. return wps_registrar_process_msg(wps, op_code, msg);
  142. else
  143. return wps_enrollee_process_msg(wps, op_code, msg);
  144. }
  145. /**
  146. * wps_get_msg - Build a WPS message
  147. * @wps: WPS Registration protocol data from wps_init()
  148. * @op_code: Buffer for returning message OP Code
  149. * Returns: The generated WPS message or %NULL on failure
  150. *
  151. * This function is used to build a response to a message processed by calling
  152. * wps_process_msg(). The caller is responsible for freeing the buffer.
  153. */
  154. struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
  155. {
  156. if (wps->registrar)
  157. return wps_registrar_get_msg(wps, op_code);
  158. else
  159. return wps_enrollee_get_msg(wps, op_code);
  160. }
  161. /**
  162. * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
  163. * @msg: WPS IE contents from Beacon or Probe Response frame
  164. * Returns: 1 if PBC Registrar is active, 0 if not
  165. */
  166. int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
  167. {
  168. struct wps_parse_attr attr;
  169. /*
  170. * In theory, this could also verify that attr.sel_reg_config_methods
  171. * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
  172. * do not set Selected Registrar Config Methods attribute properly, so
  173. * it is safer to just use Device Password ID here.
  174. */
  175. if (wps_parse_msg(msg, &attr) < 0 ||
  176. !attr.selected_registrar || *attr.selected_registrar == 0 ||
  177. !attr.dev_password_id ||
  178. WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
  179. return 0;
  180. return 1;
  181. }
  182. /**
  183. * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
  184. * @msg: WPS IE contents from Beacon or Probe Response frame
  185. * Returns: 1 if PIN Registrar is active, 0 if not
  186. */
  187. int wps_is_selected_pin_registrar(const struct wpabuf *msg)
  188. {
  189. struct wps_parse_attr attr;
  190. /*
  191. * In theory, this could also verify that attr.sel_reg_config_methods
  192. * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
  193. * but some deployed AP implementations do not set Selected Registrar
  194. * Config Methods attribute properly, so it is safer to just use
  195. * Device Password ID here.
  196. */
  197. if (wps_parse_msg(msg, &attr) < 0)
  198. return 0;
  199. if (!attr.selected_registrar || *attr.selected_registrar == 0)
  200. return 0;
  201. if (attr.dev_password_id != NULL &&
  202. WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
  203. return 0;
  204. return 1;
  205. }
  206. /**
  207. * wps_get_uuid_e - Get UUID-E from WPS IE
  208. * @msg: WPS IE contents from Beacon or Probe Response frame
  209. * Returns: Pointer to UUID-E or %NULL if not included
  210. *
  211. * The returned pointer is to the msg contents and it remains valid only as
  212. * long as the msg buffer is valid.
  213. */
  214. const u8 * wps_get_uuid_e(const struct wpabuf *msg)
  215. {
  216. struct wps_parse_attr attr;
  217. if (wps_parse_msg(msg, &attr) < 0)
  218. return NULL;
  219. return attr.uuid_e;
  220. }
  221. /**
  222. * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
  223. * @req_type: Value for Request Type attribute
  224. * Returns: WPS IE or %NULL on failure
  225. *
  226. * The caller is responsible for freeing the buffer.
  227. */
  228. struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
  229. {
  230. struct wpabuf *ie;
  231. u8 *len;
  232. wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
  233. "Request");
  234. ie = wpabuf_alloc(100);
  235. if (ie == NULL)
  236. return NULL;
  237. wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
  238. len = wpabuf_put(ie, 1);
  239. wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
  240. if (wps_build_version(ie) ||
  241. wps_build_req_type(ie, req_type)) {
  242. wpabuf_free(ie);
  243. return NULL;
  244. }
  245. *len = wpabuf_len(ie) - 2;
  246. return ie;
  247. }
  248. /**
  249. * wps_build_probe_req_ie - Build WPS IE for Probe Request
  250. * @pbc: Whether searching for PBC mode APs
  251. * @dev: Device attributes
  252. * @uuid: Own UUID
  253. * @req_type: Value for Request Type attribute
  254. * Returns: WPS IE or %NULL on failure
  255. *
  256. * The caller is responsible for freeing the buffer.
  257. */
  258. struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
  259. const u8 *uuid,
  260. enum wps_request_type req_type)
  261. {
  262. struct wpabuf *ie;
  263. u8 *len;
  264. u16 methods;
  265. wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
  266. ie = wpabuf_alloc(200);
  267. if (ie == NULL)
  268. return NULL;
  269. wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
  270. len = wpabuf_put(ie, 1);
  271. wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
  272. if (pbc)
  273. methods = WPS_CONFIG_PUSHBUTTON;
  274. else {
  275. methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
  276. WPS_CONFIG_KEYPAD;
  277. #ifdef CONFIG_WPS_UFD
  278. methods |= WPS_CONFIG_USBA;
  279. #endif /* CONFIG_WPS_UFD */
  280. #ifdef CONFIG_WPS_NFC
  281. methods |= WPS_CONFIG_NFC_INTERFACE;
  282. #endif /* CONFIG_WPS_NFC */
  283. }
  284. if (wps_build_version(ie) ||
  285. wps_build_req_type(ie, req_type) ||
  286. wps_build_config_methods(ie, methods) ||
  287. wps_build_uuid_e(ie, uuid) ||
  288. wps_build_primary_dev_type(dev, ie) ||
  289. wps_build_rf_bands(dev, ie) ||
  290. wps_build_assoc_state(NULL, ie) ||
  291. wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
  292. wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
  293. DEV_PW_DEFAULT)) {
  294. wpabuf_free(ie);
  295. return NULL;
  296. }
  297. *len = wpabuf_len(ie) - 2;
  298. return ie;
  299. }
  300. void wps_free_pending_msgs(struct upnp_pending_message *msgs)
  301. {
  302. struct upnp_pending_message *p, *prev;
  303. p = msgs;
  304. while (p) {
  305. prev = p;
  306. p = p->next;
  307. wpabuf_free(prev->msg);
  308. os_free(prev);
  309. }
  310. }
  311. int wps_attr_text(struct wpabuf *data, char *buf, char *end)
  312. {
  313. struct wps_parse_attr attr;
  314. char *pos = buf;
  315. int ret;
  316. if (wps_parse_msg(data, &attr) < 0)
  317. return -1;
  318. if (attr.wps_state) {
  319. if (*attr.wps_state == WPS_STATE_NOT_CONFIGURED)
  320. ret = os_snprintf(pos, end - pos,
  321. "wps_state=unconfigured\n");
  322. else if (*attr.wps_state == WPS_STATE_CONFIGURED)
  323. ret = os_snprintf(pos, end - pos,
  324. "wps_state=configured\n");
  325. else
  326. ret = 0;
  327. if (ret < 0 || ret >= end - pos)
  328. return pos - buf;
  329. pos += ret;
  330. }
  331. if (attr.ap_setup_locked && *attr.ap_setup_locked) {
  332. ret = os_snprintf(pos, end - pos,
  333. "wps_ap_setup_locked=1\n");
  334. if (ret < 0 || ret >= end - pos)
  335. return pos - buf;
  336. pos += ret;
  337. }
  338. if (attr.selected_registrar && *attr.selected_registrar) {
  339. ret = os_snprintf(pos, end - pos,
  340. "wps_selected_registrar=1\n");
  341. if (ret < 0 || ret >= end - pos)
  342. return pos - buf;
  343. pos += ret;
  344. }
  345. if (attr.dev_password_id) {
  346. ret = os_snprintf(pos, end - pos,
  347. "wps_device_password_id=%u\n",
  348. WPA_GET_BE16(attr.dev_password_id));
  349. if (ret < 0 || ret >= end - pos)
  350. return pos - buf;
  351. pos += ret;
  352. }
  353. if (attr.sel_reg_config_methods) {
  354. ret = os_snprintf(pos, end - pos,
  355. "wps_selected_registrar_config_methods="
  356. "0x%04x\n",
  357. WPA_GET_BE16(attr.sel_reg_config_methods));
  358. if (ret < 0 || ret >= end - pos)
  359. return pos - buf;
  360. pos += ret;
  361. }
  362. if (attr.primary_dev_type) {
  363. char devtype[WPS_DEV_TYPE_BUFSIZE];
  364. ret = os_snprintf(pos, end - pos,
  365. "wps_primary_device_type=%s\n",
  366. wps_dev_type_bin2str(attr.primary_dev_type,
  367. devtype,
  368. sizeof(devtype)));
  369. if (ret < 0 || ret >= end - pos)
  370. return pos - buf;
  371. pos += ret;
  372. }
  373. if (attr.dev_name) {
  374. char *str = os_malloc(attr.dev_name_len + 1);
  375. size_t i;
  376. if (str == NULL)
  377. return pos - buf;
  378. for (i = 0; i < attr.dev_name_len; i++) {
  379. if (attr.dev_name[i] < 32)
  380. str[i] = '_';
  381. else
  382. str[i] = attr.dev_name[i];
  383. }
  384. str[i] = '\0';
  385. ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
  386. os_free(str);
  387. if (ret < 0 || ret >= end - pos)
  388. return pos - buf;
  389. pos += ret;
  390. }
  391. if (attr.config_methods) {
  392. ret = os_snprintf(pos, end - pos,
  393. "wps_config_methods=0x%04x\n",
  394. WPA_GET_BE16(attr.config_methods));
  395. if (ret < 0 || ret >= end - pos)
  396. return pos - buf;
  397. pos += ret;
  398. }
  399. return pos - buf;
  400. }