1189251Ssam/* 2189251Ssam * Wi-Fi Protected Setup - attribute building 3337817Scy * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/aes_wrap.h" 13214734Srpaulo#include "crypto/crypto.h" 14214734Srpaulo#include "crypto/dh_group5.h" 15214734Srpaulo#include "crypto/sha256.h" 16252726Srpaulo#include "crypto/random.h" 17252726Srpaulo#include "common/ieee802_11_defs.h" 18189251Ssam#include "wps_i.h" 19189251Ssam 20189251Ssam 21189251Ssamint wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) 22189251Ssam{ 23337817Scy struct wpabuf *pubkey = NULL; 24189251Ssam 25189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Public Key"); 26337817Scy wpabuf_clear_free(wps->dh_privkey); 27281806Srpaulo wps->dh_privkey = NULL; 28281806Srpaulo if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey && 29281806Srpaulo wps->wps->dh_ctx) { 30214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys"); 31281806Srpaulo if (wps->wps->dh_pubkey == NULL) { 32281806Srpaulo wpa_printf(MSG_DEBUG, 33281806Srpaulo "WPS: wps->wps->dh_pubkey == NULL"); 34281806Srpaulo return -1; 35281806Srpaulo } 36214734Srpaulo wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey); 37214734Srpaulo wps->dh_ctx = wps->wps->dh_ctx; 38214734Srpaulo wps->wps->dh_ctx = NULL; 39214734Srpaulo pubkey = wpabuf_dup(wps->wps->dh_pubkey); 40252726Srpaulo#ifdef CONFIG_WPS_NFC 41281806Srpaulo } else if ((wps->dev_pw_id >= 0x10 || 42281806Srpaulo wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) && 43281806Srpaulo (wps->wps->ap || 44281806Srpaulo (wps->wps->ap_nfc_dh_pubkey && 45281806Srpaulo wps->wps->ap_nfc_dev_pw_id == 46281806Srpaulo DEV_PW_NFC_CONNECTION_HANDOVER && 47281806Srpaulo wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)) && 48281806Srpaulo (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id || 49281806Srpaulo wps->wps->ap_nfc_dh_pubkey)) { 50252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys"); 51281806Srpaulo if (wps->wps->ap_nfc_dh_privkey == NULL) { 52281806Srpaulo wpa_printf(MSG_DEBUG, 53281806Srpaulo "WPS: wps->wps->ap_nfc_dh_privkey == NULL"); 54281806Srpaulo return -1; 55281806Srpaulo } 56281806Srpaulo if (wps->wps->ap_nfc_dh_pubkey == NULL) { 57281806Srpaulo wpa_printf(MSG_DEBUG, 58281806Srpaulo "WPS: wps->wps->ap_nfc_dh_pubkey == NULL"); 59281806Srpaulo return -1; 60281806Srpaulo } 61252726Srpaulo wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey); 62252726Srpaulo pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey); 63346981Scy if (wps->dh_privkey && pubkey) 64346981Scy wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey); 65252726Srpaulo#endif /* CONFIG_WPS_NFC */ 66214734Srpaulo } else { 67214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); 68214734Srpaulo dh5_free(wps->dh_ctx); 69214734Srpaulo wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey); 70214734Srpaulo pubkey = wpabuf_zeropad(pubkey, 192); 71214734Srpaulo } 72214734Srpaulo if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) { 73189251Ssam wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " 74189251Ssam "Diffie-Hellman handshake"); 75214734Srpaulo wpabuf_free(pubkey); 76189251Ssam return -1; 77189251Ssam } 78252726Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); 79252726Srpaulo wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey); 80189251Ssam 81189251Ssam wpabuf_put_be16(msg, ATTR_PUBLIC_KEY); 82189251Ssam wpabuf_put_be16(msg, wpabuf_len(pubkey)); 83189251Ssam wpabuf_put_buf(msg, pubkey); 84189251Ssam 85189251Ssam if (wps->registrar) { 86189251Ssam wpabuf_free(wps->dh_pubkey_r); 87189251Ssam wps->dh_pubkey_r = pubkey; 88189251Ssam } else { 89189251Ssam wpabuf_free(wps->dh_pubkey_e); 90189251Ssam wps->dh_pubkey_e = pubkey; 91189251Ssam } 92189251Ssam 93189251Ssam return 0; 94189251Ssam} 95189251Ssam 96189251Ssam 97189251Ssamint wps_build_req_type(struct wpabuf *msg, enum wps_request_type type) 98189251Ssam{ 99189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Request Type"); 100189251Ssam wpabuf_put_be16(msg, ATTR_REQUEST_TYPE); 101189251Ssam wpabuf_put_be16(msg, 1); 102189251Ssam wpabuf_put_u8(msg, type); 103189251Ssam return 0; 104189251Ssam} 105189251Ssam 106189251Ssam 107214734Srpauloint wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type) 108214734Srpaulo{ 109214734Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type); 110214734Srpaulo wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE); 111214734Srpaulo wpabuf_put_be16(msg, 1); 112214734Srpaulo wpabuf_put_u8(msg, type); 113214734Srpaulo return 0; 114214734Srpaulo} 115214734Srpaulo 116214734Srpaulo 117189251Ssamint wps_build_config_methods(struct wpabuf *msg, u16 methods) 118189251Ssam{ 119189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); 120189251Ssam wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); 121189251Ssam wpabuf_put_be16(msg, 2); 122189251Ssam wpabuf_put_be16(msg, methods); 123189251Ssam return 0; 124189251Ssam} 125189251Ssam 126189251Ssam 127189251Ssamint wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid) 128189251Ssam{ 129281806Srpaulo if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN) 130281806Srpaulo return -1; 131189251Ssam wpa_printf(MSG_DEBUG, "WPS: * UUID-E"); 132189251Ssam wpabuf_put_be16(msg, ATTR_UUID_E); 133189251Ssam wpabuf_put_be16(msg, WPS_UUID_LEN); 134189251Ssam wpabuf_put_data(msg, uuid, WPS_UUID_LEN); 135189251Ssam return 0; 136189251Ssam} 137189251Ssam 138189251Ssam 139189251Ssamint wps_build_dev_password_id(struct wpabuf *msg, u16 id) 140189251Ssam{ 141189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); 142189251Ssam wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 143189251Ssam wpabuf_put_be16(msg, 2); 144189251Ssam wpabuf_put_be16(msg, id); 145189251Ssam return 0; 146189251Ssam} 147189251Ssam 148189251Ssam 149189251Ssamint wps_build_config_error(struct wpabuf *msg, u16 err) 150189251Ssam{ 151189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err); 152189251Ssam wpabuf_put_be16(msg, ATTR_CONFIG_ERROR); 153189251Ssam wpabuf_put_be16(msg, 2); 154189251Ssam wpabuf_put_be16(msg, err); 155189251Ssam return 0; 156189251Ssam} 157189251Ssam 158189251Ssam 159189251Ssamint wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) 160189251Ssam{ 161189251Ssam u8 hash[SHA256_MAC_LEN]; 162189251Ssam const u8 *addr[2]; 163189251Ssam size_t len[2]; 164189251Ssam 165189251Ssam if (wps->last_msg == NULL) { 166189251Ssam wpa_printf(MSG_DEBUG, "WPS: Last message not available for " 167189251Ssam "building authenticator"); 168189251Ssam return -1; 169189251Ssam } 170189251Ssam 171189251Ssam /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) 172189251Ssam * (M_curr* is M_curr without the Authenticator attribute) 173189251Ssam */ 174189251Ssam addr[0] = wpabuf_head(wps->last_msg); 175189251Ssam len[0] = wpabuf_len(wps->last_msg); 176189251Ssam addr[1] = wpabuf_head(msg); 177189251Ssam len[1] = wpabuf_len(msg); 178189251Ssam hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); 179189251Ssam 180189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); 181189251Ssam wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); 182189251Ssam wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); 183189251Ssam wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); 184189251Ssam 185189251Ssam return 0; 186189251Ssam} 187189251Ssam 188189251Ssam 189189251Ssamint wps_build_version(struct wpabuf *msg) 190189251Ssam{ 191252726Srpaulo /* 192252726Srpaulo * Note: This attribute is deprecated and set to hardcoded 0x10 for 193252726Srpaulo * backwards compatibility reasons. The real version negotiation is 194252726Srpaulo * done with Version2. 195252726Srpaulo */ 196281806Srpaulo if (wpabuf_tailroom(msg) < 5) 197281806Srpaulo return -1; 198252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)"); 199189251Ssam wpabuf_put_be16(msg, ATTR_VERSION); 200189251Ssam wpabuf_put_be16(msg, 1); 201252726Srpaulo wpabuf_put_u8(msg, 0x10); 202252726Srpaulo return 0; 203252726Srpaulo} 204252726Srpaulo 205252726Srpaulo 206252726Srpauloint wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, 207346981Scy const u8 *auth_macs, size_t auth_macs_count, 208346981Scy u8 multi_ap_subelem) 209252726Srpaulo{ 210252726Srpaulo u8 *len; 211252726Srpaulo 212281806Srpaulo#ifdef CONFIG_WPS_TESTING 213281806Srpaulo if (WPS_VERSION == 0x10) 214281806Srpaulo return 0; 215281806Srpaulo#endif /* CONFIG_WPS_TESTING */ 216281806Srpaulo 217281806Srpaulo if (wpabuf_tailroom(msg) < 218281806Srpaulo 7 + 3 + (req_to_enroll ? 3 : 0) + 219281806Srpaulo (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0)) 220281806Srpaulo return -1; 221252726Srpaulo wpabuf_put_be16(msg, ATTR_VENDOR_EXT); 222252726Srpaulo len = wpabuf_put(msg, 2); /* to be filled */ 223252726Srpaulo wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA); 224252726Srpaulo 225252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION); 226252726Srpaulo wpabuf_put_u8(msg, WFA_ELEM_VERSION2); 227252726Srpaulo wpabuf_put_u8(msg, 1); 228189251Ssam wpabuf_put_u8(msg, WPS_VERSION); 229252726Srpaulo 230252726Srpaulo if (req_to_enroll) { 231252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)"); 232252726Srpaulo wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL); 233252726Srpaulo wpabuf_put_u8(msg, 1); 234252726Srpaulo wpabuf_put_u8(msg, 1); 235252726Srpaulo } 236252726Srpaulo 237252726Srpaulo if (auth_macs && auth_macs_count) { 238252726Srpaulo size_t i; 239252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", 240252726Srpaulo (int) auth_macs_count); 241252726Srpaulo wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS); 242252726Srpaulo wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN); 243252726Srpaulo wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN); 244252726Srpaulo for (i = 0; i < auth_macs_count; i++) 245252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR, 246252726Srpaulo MAC2STR(&auth_macs[i * ETH_ALEN])); 247252726Srpaulo } 248252726Srpaulo 249346981Scy if (multi_ap_subelem) { 250346981Scy wpa_printf(MSG_DEBUG, "WPS: * Multi-AP (0x%x)", 251346981Scy multi_ap_subelem); 252346981Scy wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP); 253346981Scy wpabuf_put_u8(msg, 1); /* length */ 254346981Scy wpabuf_put_u8(msg, multi_ap_subelem); 255346981Scy } 256346981Scy 257252726Srpaulo WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2); 258252726Srpaulo 259252726Srpaulo#ifdef CONFIG_WPS_TESTING 260252726Srpaulo if (WPS_VERSION > 0x20) { 261281806Srpaulo if (wpabuf_tailroom(msg) < 5) 262281806Srpaulo return -1; 263252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra " 264252726Srpaulo "attribute"); 265252726Srpaulo wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST); 266252726Srpaulo wpabuf_put_be16(msg, 1); 267252726Srpaulo wpabuf_put_u8(msg, 42); 268252726Srpaulo } 269252726Srpaulo#endif /* CONFIG_WPS_TESTING */ 270189251Ssam return 0; 271189251Ssam} 272189251Ssam 273189251Ssam 274189251Ssamint wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type) 275189251Ssam{ 276189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type); 277189251Ssam wpabuf_put_be16(msg, ATTR_MSG_TYPE); 278189251Ssam wpabuf_put_be16(msg, 1); 279189251Ssam wpabuf_put_u8(msg, msg_type); 280189251Ssam return 0; 281189251Ssam} 282189251Ssam 283189251Ssam 284189251Ssamint wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg) 285189251Ssam{ 286189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce"); 287189251Ssam wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); 288189251Ssam wpabuf_put_be16(msg, WPS_NONCE_LEN); 289189251Ssam wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN); 290189251Ssam return 0; 291189251Ssam} 292189251Ssam 293189251Ssam 294189251Ssamint wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg) 295189251Ssam{ 296189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce"); 297189251Ssam wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); 298189251Ssam wpabuf_put_be16(msg, WPS_NONCE_LEN); 299189251Ssam wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN); 300189251Ssam return 0; 301189251Ssam} 302189251Ssam 303189251Ssam 304189251Ssamint wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg) 305189251Ssam{ 306252726Srpaulo u16 auth_types = WPS_AUTH_TYPES; 307281806Srpaulo /* WPA/WPA2-Enterprise enrollment not supported through WPS */ 308281806Srpaulo auth_types &= ~WPS_AUTH_WPA; 309281806Srpaulo auth_types &= ~WPS_AUTH_WPA2; 310252726Srpaulo auth_types &= ~WPS_AUTH_SHARED; 311337817Scy#ifdef CONFIG_WPS_TESTING 312337817Scy if (wps_force_auth_types_in_use) { 313337817Scy wpa_printf(MSG_DEBUG, 314337817Scy "WPS: Testing - replace auth type 0x%x with 0x%x", 315337817Scy auth_types, wps_force_auth_types); 316337817Scy auth_types = wps_force_auth_types; 317337817Scy } 318337817Scy#endif /* CONFIG_WPS_TESTING */ 319337817Scy wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags (0x%x)", 320337817Scy auth_types); 321189251Ssam wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS); 322189251Ssam wpabuf_put_be16(msg, 2); 323252726Srpaulo wpabuf_put_be16(msg, auth_types); 324189251Ssam return 0; 325189251Ssam} 326189251Ssam 327189251Ssam 328189251Ssamint wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg) 329189251Ssam{ 330252726Srpaulo u16 encr_types = WPS_ENCR_TYPES; 331252726Srpaulo encr_types &= ~WPS_ENCR_WEP; 332337817Scy#ifdef CONFIG_WPS_TESTING 333337817Scy if (wps_force_encr_types_in_use) { 334337817Scy wpa_printf(MSG_DEBUG, 335337817Scy "WPS: Testing - replace encr type 0x%x with 0x%x", 336337817Scy encr_types, wps_force_encr_types); 337337817Scy encr_types = wps_force_encr_types; 338337817Scy } 339337817Scy#endif /* CONFIG_WPS_TESTING */ 340337817Scy wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags (0x%x)", 341337817Scy encr_types); 342189251Ssam wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS); 343189251Ssam wpabuf_put_be16(msg, 2); 344252726Srpaulo wpabuf_put_be16(msg, encr_types); 345189251Ssam return 0; 346189251Ssam} 347189251Ssam 348189251Ssam 349189251Ssamint wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg) 350189251Ssam{ 351189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags"); 352189251Ssam wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS); 353189251Ssam wpabuf_put_be16(msg, 1); 354189251Ssam wpabuf_put_u8(msg, WPS_CONN_ESS); 355189251Ssam return 0; 356189251Ssam} 357189251Ssam 358189251Ssam 359189251Ssamint wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg) 360189251Ssam{ 361189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Association State"); 362189251Ssam wpabuf_put_be16(msg, ATTR_ASSOC_STATE); 363189251Ssam wpabuf_put_be16(msg, 2); 364189251Ssam wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC); 365189251Ssam return 0; 366189251Ssam} 367189251Ssam 368189251Ssam 369189251Ssamint wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg) 370189251Ssam{ 371189251Ssam u8 hash[SHA256_MAC_LEN]; 372189251Ssam 373189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator"); 374189251Ssam hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg), 375189251Ssam wpabuf_len(msg), hash); 376189251Ssam 377189251Ssam wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH); 378189251Ssam wpabuf_put_be16(msg, WPS_KWA_LEN); 379189251Ssam wpabuf_put_data(msg, hash, WPS_KWA_LEN); 380189251Ssam return 0; 381189251Ssam} 382189251Ssam 383189251Ssam 384189251Ssamint wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, 385189251Ssam struct wpabuf *plain) 386189251Ssam{ 387189251Ssam size_t pad_len; 388189251Ssam const size_t block_size = 16; 389189251Ssam u8 *iv, *data; 390189251Ssam 391189251Ssam wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings"); 392189251Ssam 393189251Ssam /* PKCS#5 v2.0 pad */ 394189251Ssam pad_len = block_size - wpabuf_len(plain) % block_size; 395189251Ssam os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len); 396189251Ssam 397189251Ssam wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS); 398189251Ssam wpabuf_put_be16(msg, block_size + wpabuf_len(plain)); 399189251Ssam 400189251Ssam iv = wpabuf_put(msg, block_size); 401252726Srpaulo if (random_get_bytes(iv, block_size) < 0) 402189251Ssam return -1; 403189251Ssam 404189251Ssam data = wpabuf_put(msg, 0); 405189251Ssam wpabuf_put_buf(msg, plain); 406189251Ssam if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain))) 407189251Ssam return -1; 408189251Ssam 409189251Ssam return 0; 410189251Ssam} 411214734Srpaulo 412214734Srpaulo 413214734Srpaulo#ifdef CONFIG_WPS_OOB 414252726Srpauloint wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, 415252726Srpaulo const struct wpabuf *pubkey, const u8 *dev_pw, 416252726Srpaulo size_t dev_pw_len) 417214734Srpaulo{ 418214734Srpaulo size_t hash_len; 419214734Srpaulo const u8 *addr[1]; 420214734Srpaulo u8 pubkey_hash[WPS_HASH_LEN]; 421214734Srpaulo 422281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password (dev_pw_id=%u)", 423281806Srpaulo dev_pw_id); 424252726Srpaulo addr[0] = wpabuf_head(pubkey); 425252726Srpaulo hash_len = wpabuf_len(pubkey); 426337817Scy if (sha256_vector(1, addr, &hash_len, pubkey_hash) < 0) 427337817Scy return -1; 428281806Srpaulo#ifdef CONFIG_WPS_TESTING 429281806Srpaulo if (wps_corrupt_pkhash) { 430281806Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Real Public Key Hash", 431281806Srpaulo pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); 432281806Srpaulo wpa_printf(MSG_INFO, "WPS: Testing - corrupt public key hash"); 433281806Srpaulo pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN - 2]++; 434281806Srpaulo } 435281806Srpaulo#endif /* CONFIG_WPS_TESTING */ 436214734Srpaulo 437252726Srpaulo wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); 438252726Srpaulo wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); 439281806Srpaulo wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash", 440281806Srpaulo pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); 441252726Srpaulo wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); 442252726Srpaulo wpabuf_put_be16(msg, dev_pw_id); 443281806Srpaulo if (dev_pw) { 444281806Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password", 445281806Srpaulo dev_pw, dev_pw_len); 446281806Srpaulo wpabuf_put_data(msg, dev_pw, dev_pw_len); 447281806Srpaulo } 448252726Srpaulo 449252726Srpaulo return 0; 450252726Srpaulo} 451252726Srpaulo#endif /* CONFIG_WPS_OOB */ 452252726Srpaulo 453252726Srpaulo 454252726Srpaulo/* Encapsulate WPS IE data with one (or more, if needed) IE headers */ 455252726Srpaulostruct wpabuf * wps_ie_encapsulate(struct wpabuf *data) 456252726Srpaulo{ 457252726Srpaulo struct wpabuf *ie; 458252726Srpaulo const u8 *pos, *end; 459252726Srpaulo 460252726Srpaulo ie = wpabuf_alloc(wpabuf_len(data) + 100); 461252726Srpaulo if (ie == NULL) { 462252726Srpaulo wpabuf_free(data); 463252726Srpaulo return NULL; 464214734Srpaulo } 465214734Srpaulo 466252726Srpaulo pos = wpabuf_head(data); 467252726Srpaulo end = pos + wpabuf_len(data); 468252726Srpaulo 469252726Srpaulo while (end > pos) { 470252726Srpaulo size_t frag_len = end - pos; 471252726Srpaulo if (frag_len > 251) 472252726Srpaulo frag_len = 251; 473252726Srpaulo wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC); 474252726Srpaulo wpabuf_put_u8(ie, 4 + frag_len); 475252726Srpaulo wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); 476252726Srpaulo wpabuf_put_data(ie, pos, frag_len); 477252726Srpaulo pos += frag_len; 478214734Srpaulo } 479214734Srpaulo 480252726Srpaulo wpabuf_free(data); 481214734Srpaulo 482252726Srpaulo return ie; 483214734Srpaulo} 484281806Srpaulo 485281806Srpaulo 486281806Srpauloint wps_build_mac_addr(struct wpabuf *msg, const u8 *addr) 487281806Srpaulo{ 488281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: * MAC Address (" MACSTR ")", 489281806Srpaulo MAC2STR(addr)); 490281806Srpaulo wpabuf_put_be16(msg, ATTR_MAC_ADDR); 491281806Srpaulo wpabuf_put_be16(msg, ETH_ALEN); 492281806Srpaulo wpabuf_put_data(msg, addr, ETH_ALEN); 493281806Srpaulo return 0; 494281806Srpaulo} 495281806Srpaulo 496281806Srpaulo 497281806Srpauloint wps_build_rf_bands_attr(struct wpabuf *msg, u8 rf_bands) 498281806Srpaulo{ 499281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", rf_bands); 500281806Srpaulo wpabuf_put_be16(msg, ATTR_RF_BANDS); 501281806Srpaulo wpabuf_put_be16(msg, 1); 502281806Srpaulo wpabuf_put_u8(msg, rf_bands); 503281806Srpaulo return 0; 504281806Srpaulo} 505281806Srpaulo 506281806Srpaulo 507281806Srpauloint wps_build_ap_channel(struct wpabuf *msg, u16 ap_channel) 508281806Srpaulo{ 509281806Srpaulo wpa_printf(MSG_DEBUG, "WPS: * AP Channel (%u)", ap_channel); 510281806Srpaulo wpabuf_put_be16(msg, ATTR_AP_CHANNEL); 511281806Srpaulo wpabuf_put_be16(msg, 2); 512281806Srpaulo wpabuf_put_be16(msg, ap_channel); 513281806Srpaulo return 0; 514281806Srpaulo} 515