wps_attr_build.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * Wi-Fi Protected Setup - attribute building
  3. * Copyright (c) 2008, 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 "crypto/aes_wrap.h"
  11. #include "crypto/crypto.h"
  12. #include "crypto/dh_group5.h"
  13. #include "crypto/sha256.h"
  14. #include "crypto/random.h"
  15. #include "common/ieee802_11_defs.h"
  16. #include "wps_i.h"
  17. int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
  18. {
  19. struct wpabuf *pubkey;
  20. wpa_printf(MSG_DEBUG, "WPS: * Public Key");
  21. wpabuf_free(wps->dh_privkey);
  22. wps->dh_privkey = NULL;
  23. if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey &&
  24. wps->wps->dh_ctx) {
  25. wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
  26. if (wps->wps->dh_pubkey == NULL) {
  27. wpa_printf(MSG_DEBUG,
  28. "WPS: wps->wps->dh_pubkey == NULL");
  29. return -1;
  30. }
  31. wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
  32. wps->dh_ctx = wps->wps->dh_ctx;
  33. wps->wps->dh_ctx = NULL;
  34. pubkey = wpabuf_dup(wps->wps->dh_pubkey);
  35. #ifdef CONFIG_WPS_NFC
  36. } else if ((wps->dev_pw_id >= 0x10 ||
  37. wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
  38. (wps->wps->ap ||
  39. (wps->wps->ap_nfc_dh_pubkey &&
  40. wps->wps->ap_nfc_dev_pw_id ==
  41. DEV_PW_NFC_CONNECTION_HANDOVER &&
  42. wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) &&
  43. (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
  44. wps->wps->ap_nfc_dh_pubkey)) {
  45. wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
  46. if (wps->wps->ap_nfc_dh_privkey == NULL) {
  47. wpa_printf(MSG_DEBUG,
  48. "WPS: wps->wps->ap_nfc_dh_privkey == NULL");
  49. return -1;
  50. }
  51. if (wps->wps->ap_nfc_dh_pubkey == NULL) {
  52. wpa_printf(MSG_DEBUG,
  53. "WPS: wps->wps->ap_nfc_dh_pubkey == NULL");
  54. return -1;
  55. }
  56. wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
  57. pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
  58. wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
  59. #endif /* CONFIG_WPS_NFC */
  60. } else {
  61. wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
  62. dh5_free(wps->dh_ctx);
  63. wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
  64. pubkey = wpabuf_zeropad(pubkey, 192);
  65. }
  66. if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
  67. wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
  68. "Diffie-Hellman handshake");
  69. wpabuf_free(pubkey);
  70. return -1;
  71. }
  72. wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
  73. wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
  74. wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
  75. wpabuf_put_be16(msg, wpabuf_len(pubkey));
  76. wpabuf_put_buf(msg, pubkey);
  77. if (wps->registrar) {
  78. wpabuf_free(wps->dh_pubkey_r);
  79. wps->dh_pubkey_r = pubkey;
  80. } else {
  81. wpabuf_free(wps->dh_pubkey_e);
  82. wps->dh_pubkey_e = pubkey;
  83. }
  84. return 0;
  85. }
  86. int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
  87. {
  88. wpa_printf(MSG_DEBUG, "WPS: * Request Type");
  89. wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
  90. wpabuf_put_be16(msg, 1);
  91. wpabuf_put_u8(msg, type);
  92. return 0;
  93. }
  94. int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
  95. {
  96. wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type);
  97. wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
  98. wpabuf_put_be16(msg, 1);
  99. wpabuf_put_u8(msg, type);
  100. return 0;
  101. }
  102. int wps_build_config_methods(struct wpabuf *msg, u16 methods)
  103. {
  104. wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods);
  105. wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
  106. wpabuf_put_be16(msg, 2);
  107. wpabuf_put_be16(msg, methods);
  108. return 0;
  109. }
  110. int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
  111. {
  112. if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
  113. return -1;
  114. wpa_printf(MSG_DEBUG, "WPS: * UUID-E");
  115. wpabuf_put_be16(msg, ATTR_UUID_E);
  116. wpabuf_put_be16(msg, WPS_UUID_LEN);
  117. wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
  118. return 0;
  119. }
  120. int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
  121. {
  122. wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id);
  123. wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
  124. wpabuf_put_be16(msg, 2);
  125. wpabuf_put_be16(msg, id);
  126. return 0;
  127. }
  128. int wps_build_config_error(struct wpabuf *msg, u16 err)
  129. {
  130. wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err);
  131. wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
  132. wpabuf_put_be16(msg, 2);
  133. wpabuf_put_be16(msg, err);
  134. return 0;
  135. }
  136. int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
  137. {
  138. u8 hash[SHA256_MAC_LEN];
  139. const u8 *addr[2];
  140. size_t len[2];
  141. if (wps->last_msg == NULL) {
  142. wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
  143. "building authenticator");
  144. return -1;
  145. }
  146. /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
  147. * (M_curr* is M_curr without the Authenticator attribute)
  148. */
  149. addr[0] = wpabuf_head(wps->last_msg);
  150. len[0] = wpabuf_len(wps->last_msg);
  151. addr[1] = wpabuf_head(msg);
  152. len[1] = wpabuf_len(msg);
  153. hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
  154. wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
  155. wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
  156. wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
  157. wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
  158. return 0;
  159. }
  160. int wps_build_version(struct wpabuf *msg)
  161. {
  162. /*
  163. * Note: This attribute is deprecated and set to hardcoded 0x10 for
  164. * backwards compatibility reasons. The real version negotiation is
  165. * done with Version2.
  166. */
  167. if (wpabuf_tailroom(msg) < 5)
  168. return -1;
  169. wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)");
  170. wpabuf_put_be16(msg, ATTR_VERSION);
  171. wpabuf_put_be16(msg, 1);
  172. wpabuf_put_u8(msg, 0x10);
  173. return 0;
  174. }
  175. int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
  176. const u8 *auth_macs, size_t auth_macs_count)
  177. {
  178. u8 *len;
  179. #ifdef CONFIG_WPS_TESTING
  180. if (WPS_VERSION == 0x10)
  181. return 0;
  182. #endif /* CONFIG_WPS_TESTING */
  183. if (wpabuf_tailroom(msg) <
  184. 7 + 3 + (req_to_enroll ? 3 : 0) +
  185. (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
  186. return -1;
  187. wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
  188. len = wpabuf_put(msg, 2); /* to be filled */
  189. wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
  190. wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION);
  191. wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
  192. wpabuf_put_u8(msg, 1);
  193. wpabuf_put_u8(msg, WPS_VERSION);
  194. if (req_to_enroll) {
  195. wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)");
  196. wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
  197. wpabuf_put_u8(msg, 1);
  198. wpabuf_put_u8(msg, 1);
  199. }
  200. if (auth_macs && auth_macs_count) {
  201. size_t i;
  202. wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)",
  203. (int) auth_macs_count);
  204. wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
  205. wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
  206. wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
  207. for (i = 0; i < auth_macs_count; i++)
  208. wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR,
  209. MAC2STR(&auth_macs[i * ETH_ALEN]));
  210. }
  211. WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
  212. #ifdef CONFIG_WPS_TESTING
  213. if (WPS_VERSION > 0x20) {
  214. if (wpabuf_tailroom(msg) < 5)
  215. return -1;
  216. wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra "
  217. "attribute");
  218. wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
  219. wpabuf_put_be16(msg, 1);
  220. wpabuf_put_u8(msg, 42);
  221. }
  222. #endif /* CONFIG_WPS_TESTING */
  223. return 0;
  224. }
  225. int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
  226. {
  227. wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type);
  228. wpabuf_put_be16(msg, ATTR_MSG_TYPE);
  229. wpabuf_put_be16(msg, 1);
  230. wpabuf_put_u8(msg, msg_type);
  231. return 0;
  232. }
  233. int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
  234. {
  235. wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce");
  236. wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
  237. wpabuf_put_be16(msg, WPS_NONCE_LEN);
  238. wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
  239. return 0;
  240. }
  241. int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
  242. {
  243. wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce");
  244. wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
  245. wpabuf_put_be16(msg, WPS_NONCE_LEN);
  246. wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
  247. return 0;
  248. }
  249. int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
  250. {
  251. u16 auth_types = WPS_AUTH_TYPES;
  252. /* WPA/WPA2-Enterprise enrollment not supported through WPS */
  253. auth_types &= ~WPS_AUTH_WPA;
  254. auth_types &= ~WPS_AUTH_WPA2;
  255. auth_types &= ~WPS_AUTH_SHARED;
  256. wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags");
  257. wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
  258. wpabuf_put_be16(msg, 2);
  259. wpabuf_put_be16(msg, auth_types);
  260. return 0;
  261. }
  262. int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
  263. {
  264. u16 encr_types = WPS_ENCR_TYPES;
  265. encr_types &= ~WPS_ENCR_WEP;
  266. wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags");
  267. wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
  268. wpabuf_put_be16(msg, 2);
  269. wpabuf_put_be16(msg, encr_types);
  270. return 0;
  271. }
  272. int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
  273. {
  274. wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags");
  275. wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
  276. wpabuf_put_be16(msg, 1);
  277. wpabuf_put_u8(msg, WPS_CONN_ESS);
  278. return 0;
  279. }
  280. int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
  281. {
  282. wpa_printf(MSG_DEBUG, "WPS: * Association State");
  283. wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
  284. wpabuf_put_be16(msg, 2);
  285. wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
  286. return 0;
  287. }
  288. int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
  289. {
  290. u8 hash[SHA256_MAC_LEN];
  291. wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
  292. hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
  293. wpabuf_len(msg), hash);
  294. wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
  295. wpabuf_put_be16(msg, WPS_KWA_LEN);
  296. wpabuf_put_data(msg, hash, WPS_KWA_LEN);
  297. return 0;
  298. }
  299. int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
  300. struct wpabuf *plain)
  301. {
  302. size_t pad_len;
  303. const size_t block_size = 16;
  304. u8 *iv, *data;
  305. wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings");
  306. /* PKCS#5 v2.0 pad */
  307. pad_len = block_size - wpabuf_len(plain) % block_size;
  308. os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
  309. wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
  310. wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
  311. iv = wpabuf_put(msg, block_size);
  312. if (random_get_bytes(iv, block_size) < 0)
  313. return -1;
  314. data = wpabuf_put(msg, 0);
  315. wpabuf_put_buf(msg, plain);
  316. if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
  317. return -1;
  318. return 0;
  319. }
  320. #ifdef CONFIG_WPS_OOB
  321. int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
  322. const struct wpabuf *pubkey, const u8 *dev_pw,
  323. size_t dev_pw_len)
  324. {
  325. size_t hash_len;
  326. const u8 *addr[1];
  327. u8 pubkey_hash[WPS_HASH_LEN];
  328. wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password (dev_pw_id=%u)",
  329. dev_pw_id);
  330. addr[0] = wpabuf_head(pubkey);
  331. hash_len = wpabuf_len(pubkey);
  332. sha256_vector(1, addr, &hash_len, pubkey_hash);
  333. #ifdef CONFIG_WPS_TESTING
  334. if (wps_corrupt_pkhash) {
  335. wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash",
  336. pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
  337. wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash");
  338. pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++;
  339. }
  340. #endif /* CONFIG_WPS_TESTING */
  341. wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
  342. wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
  343. wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
  344. pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
  345. wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
  346. wpabuf_put_be16(msg, dev_pw_id);
  347. if (dev_pw) {
  348. wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
  349. dev_pw, dev_pw_len);
  350. wpabuf_put_data(msg, dev_pw, dev_pw_len);
  351. }
  352. return 0;
  353. }
  354. #endif /* CONFIG_WPS_OOB */
  355. /* Encapsulate WPS IE data with one (or more, if needed) IE headers */
  356. struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
  357. {
  358. struct wpabuf *ie;
  359. const u8 *pos, *end;
  360. ie = wpabuf_alloc(wpabuf_len(data) + 100);
  361. if (ie == NULL) {
  362. wpabuf_free(data);
  363. return NULL;
  364. }
  365. pos = wpabuf_head(data);
  366. end = pos + wpabuf_len(data);
  367. while (end > pos) {
  368. size_t frag_len = end - pos;
  369. if (frag_len > 251)
  370. frag_len = 251;
  371. wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
  372. wpabuf_put_u8(ie, 4 + frag_len);
  373. wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
  374. wpabuf_put_data(ie, pos, frag_len);
  375. pos += frag_len;
  376. }
  377. wpabuf_free(data);
  378. return ie;
  379. }
  380. int wps_build_mac_addr(struct wpabuf *msg, const u8 *addr)
  381. {
  382. wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")",
  383. MAC2STR(addr));
  384. wpabuf_put_be16(msg, ATTR_MAC_ADDR);
  385. wpabuf_put_be16(msg, ETH_ALEN);
  386. wpabuf_put_data(msg, addr, ETH_ALEN);
  387. return 0;
  388. }
  389. int wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands)
  390. {
  391. wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", rf_bands);
  392. wpabuf_put_be16(msg, ATTR_RF_BANDS);
  393. wpabuf_put_be16(msg, 1);
  394. wpabuf_put_u8(msg, rf_bands);
  395. return 0;
  396. }
  397. int wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel)
  398. {
  399. wpa_printf(MSG_DEBUG, "WPS: * AP Channel (%u)", ap_channel);
  400. wpabuf_put_be16(msg, ATTR_AP_CHANNEL);
  401. wpabuf_put_be16(msg, 2);
  402. wpabuf_put_be16(msg, ap_channel);
  403. return 0;
  404. }