139beb93cSSam Leffler /* 239beb93cSSam Leffler * Wi-Fi Protected Setup - common functionality 3f05cddf9SRui Paulo * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 125b9c547cSRui Paulo #include "common/defs.h" 135b9c547cSRui Paulo #include "common/ieee802_11_common.h" 14e28a4053SRui Paulo #include "crypto/aes_wrap.h" 15e28a4053SRui Paulo #include "crypto/crypto.h" 16e28a4053SRui Paulo #include "crypto/dh_group5.h" 17e28a4053SRui Paulo #include "crypto/sha1.h" 18e28a4053SRui Paulo #include "crypto/sha256.h" 19f05cddf9SRui Paulo #include "crypto/random.h" 2039beb93cSSam Leffler #include "wps_i.h" 215b9c547cSRui Paulo #include "wps_dev_attr.h" 2239beb93cSSam Leffler 2339beb93cSSam Leffler 2439beb93cSSam Leffler void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, 2539beb93cSSam Leffler const char *label, u8 *res, size_t res_len) 2639beb93cSSam Leffler { 2739beb93cSSam Leffler u8 i_buf[4], key_bits[4]; 2839beb93cSSam Leffler const u8 *addr[4]; 2939beb93cSSam Leffler size_t len[4]; 3039beb93cSSam Leffler int i, iter; 3139beb93cSSam Leffler u8 hash[SHA256_MAC_LEN], *opos; 3239beb93cSSam Leffler size_t left; 3339beb93cSSam Leffler 3439beb93cSSam Leffler WPA_PUT_BE32(key_bits, res_len * 8); 3539beb93cSSam Leffler 3639beb93cSSam Leffler addr[0] = i_buf; 3739beb93cSSam Leffler len[0] = sizeof(i_buf); 3839beb93cSSam Leffler addr[1] = label_prefix; 3939beb93cSSam Leffler len[1] = label_prefix_len; 4039beb93cSSam Leffler addr[2] = (const u8 *) label; 4139beb93cSSam Leffler len[2] = os_strlen(label); 4239beb93cSSam Leffler addr[3] = key_bits; 4339beb93cSSam Leffler len[3] = sizeof(key_bits); 4439beb93cSSam Leffler 4539beb93cSSam Leffler iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; 4639beb93cSSam Leffler opos = res; 4739beb93cSSam Leffler left = res_len; 4839beb93cSSam Leffler 4939beb93cSSam Leffler for (i = 1; i <= iter; i++) { 5039beb93cSSam Leffler WPA_PUT_BE32(i_buf, i); 5139beb93cSSam Leffler hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); 5239beb93cSSam Leffler if (i < iter) { 5339beb93cSSam Leffler os_memcpy(opos, hash, SHA256_MAC_LEN); 5439beb93cSSam Leffler opos += SHA256_MAC_LEN; 5539beb93cSSam Leffler left -= SHA256_MAC_LEN; 5639beb93cSSam Leffler } else 5739beb93cSSam Leffler os_memcpy(opos, hash, left); 5839beb93cSSam Leffler } 5939beb93cSSam Leffler } 6039beb93cSSam Leffler 6139beb93cSSam Leffler 6239beb93cSSam Leffler int wps_derive_keys(struct wps_data *wps) 6339beb93cSSam Leffler { 6439beb93cSSam Leffler struct wpabuf *pubkey, *dh_shared; 6539beb93cSSam Leffler u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; 6639beb93cSSam Leffler const u8 *addr[3]; 6739beb93cSSam Leffler size_t len[3]; 6839beb93cSSam Leffler u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; 6939beb93cSSam Leffler 7039beb93cSSam Leffler if (wps->dh_privkey == NULL) { 7139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); 7239beb93cSSam Leffler return -1; 7339beb93cSSam Leffler } 7439beb93cSSam Leffler 7539beb93cSSam Leffler pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; 7639beb93cSSam Leffler if (pubkey == NULL) { 7739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); 7839beb93cSSam Leffler return -1; 7939beb93cSSam Leffler } 8039beb93cSSam Leffler 81f05cddf9SRui Paulo wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); 82f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey); 83e28a4053SRui Paulo dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); 84e28a4053SRui Paulo dh5_free(wps->dh_ctx); 85e28a4053SRui Paulo wps->dh_ctx = NULL; 8639beb93cSSam Leffler dh_shared = wpabuf_zeropad(dh_shared, 192); 8739beb93cSSam Leffler if (dh_shared == NULL) { 8839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); 8939beb93cSSam Leffler return -1; 9039beb93cSSam Leffler } 9139beb93cSSam Leffler 9239beb93cSSam Leffler /* Own DH private key is not needed anymore */ 93*780fb4a2SCy Schubert wpabuf_clear_free(wps->dh_privkey); 9439beb93cSSam Leffler wps->dh_privkey = NULL; 9539beb93cSSam Leffler 9639beb93cSSam Leffler wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); 9739beb93cSSam Leffler 9839beb93cSSam Leffler /* DHKey = SHA-256(g^AB mod p) */ 9939beb93cSSam Leffler addr[0] = wpabuf_head(dh_shared); 10039beb93cSSam Leffler len[0] = wpabuf_len(dh_shared); 10139beb93cSSam Leffler sha256_vector(1, addr, len, dhkey); 10239beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); 103*780fb4a2SCy Schubert wpabuf_clear_free(dh_shared); 10439beb93cSSam Leffler 10539beb93cSSam Leffler /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ 10639beb93cSSam Leffler addr[0] = wps->nonce_e; 10739beb93cSSam Leffler len[0] = WPS_NONCE_LEN; 10839beb93cSSam Leffler addr[1] = wps->mac_addr_e; 10939beb93cSSam Leffler len[1] = ETH_ALEN; 11039beb93cSSam Leffler addr[2] = wps->nonce_r; 11139beb93cSSam Leffler len[2] = WPS_NONCE_LEN; 11239beb93cSSam Leffler hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); 11339beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); 11439beb93cSSam Leffler 11539beb93cSSam Leffler wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", 11639beb93cSSam Leffler keys, sizeof(keys)); 11739beb93cSSam Leffler os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); 11839beb93cSSam Leffler os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); 11939beb93cSSam Leffler os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, 12039beb93cSSam Leffler WPS_EMSK_LEN); 12139beb93cSSam Leffler 12239beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", 12339beb93cSSam Leffler wps->authkey, WPS_AUTHKEY_LEN); 12439beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", 12539beb93cSSam Leffler wps->keywrapkey, WPS_KEYWRAPKEY_LEN); 12639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); 12739beb93cSSam Leffler 12839beb93cSSam Leffler return 0; 12939beb93cSSam Leffler } 13039beb93cSSam Leffler 13139beb93cSSam Leffler 132*780fb4a2SCy Schubert int wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, 13339beb93cSSam Leffler size_t dev_passwd_len) 13439beb93cSSam Leffler { 13539beb93cSSam Leffler u8 hash[SHA256_MAC_LEN]; 13639beb93cSSam Leffler 137*780fb4a2SCy Schubert if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, 138*780fb4a2SCy Schubert (dev_passwd_len + 1) / 2, hash) < 0) 139*780fb4a2SCy Schubert return -1; 14039beb93cSSam Leffler os_memcpy(wps->psk1, hash, WPS_PSK_LEN); 141*780fb4a2SCy Schubert if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, 14239beb93cSSam Leffler dev_passwd + (dev_passwd_len + 1) / 2, 143*780fb4a2SCy Schubert dev_passwd_len / 2, hash) < 0) 144*780fb4a2SCy Schubert return -1; 14539beb93cSSam Leffler os_memcpy(wps->psk2, hash, WPS_PSK_LEN); 14639beb93cSSam Leffler 14739beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", 14839beb93cSSam Leffler dev_passwd, dev_passwd_len); 14939beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); 15039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); 151*780fb4a2SCy Schubert return 0; 15239beb93cSSam Leffler } 15339beb93cSSam Leffler 15439beb93cSSam Leffler 15539beb93cSSam Leffler struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 15639beb93cSSam Leffler size_t encr_len) 15739beb93cSSam Leffler { 15839beb93cSSam Leffler struct wpabuf *decrypted; 15939beb93cSSam Leffler const size_t block_size = 16; 16039beb93cSSam Leffler size_t i; 16139beb93cSSam Leffler u8 pad; 16239beb93cSSam Leffler const u8 *pos; 16339beb93cSSam Leffler 16439beb93cSSam Leffler /* AES-128-CBC */ 16539beb93cSSam Leffler if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) 16639beb93cSSam Leffler { 16739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); 16839beb93cSSam Leffler return NULL; 16939beb93cSSam Leffler } 17039beb93cSSam Leffler 17139beb93cSSam Leffler decrypted = wpabuf_alloc(encr_len - block_size); 17239beb93cSSam Leffler if (decrypted == NULL) 17339beb93cSSam Leffler return NULL; 17439beb93cSSam Leffler 17539beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); 17639beb93cSSam Leffler wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); 17739beb93cSSam Leffler if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), 17839beb93cSSam Leffler wpabuf_len(decrypted))) { 179*780fb4a2SCy Schubert wpabuf_clear_free(decrypted); 18039beb93cSSam Leffler return NULL; 18139beb93cSSam Leffler } 18239beb93cSSam Leffler 18339beb93cSSam Leffler wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", 18439beb93cSSam Leffler decrypted); 18539beb93cSSam Leffler 18639beb93cSSam Leffler pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; 18739beb93cSSam Leffler pad = *pos; 18839beb93cSSam Leffler if (pad > wpabuf_len(decrypted)) { 18939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); 190*780fb4a2SCy Schubert wpabuf_clear_free(decrypted); 19139beb93cSSam Leffler return NULL; 19239beb93cSSam Leffler } 19339beb93cSSam Leffler for (i = 0; i < pad; i++) { 19439beb93cSSam Leffler if (*pos-- != pad) { 19539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " 19639beb93cSSam Leffler "string"); 197*780fb4a2SCy Schubert wpabuf_clear_free(decrypted); 19839beb93cSSam Leffler return NULL; 19939beb93cSSam Leffler } 20039beb93cSSam Leffler } 20139beb93cSSam Leffler decrypted->used -= pad; 20239beb93cSSam Leffler 20339beb93cSSam Leffler return decrypted; 20439beb93cSSam Leffler } 20539beb93cSSam Leffler 20639beb93cSSam Leffler 20739beb93cSSam Leffler /** 20839beb93cSSam Leffler * wps_pin_checksum - Compute PIN checksum 20939beb93cSSam Leffler * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) 21039beb93cSSam Leffler * Returns: Checksum digit 21139beb93cSSam Leffler */ 21239beb93cSSam Leffler unsigned int wps_pin_checksum(unsigned int pin) 21339beb93cSSam Leffler { 21439beb93cSSam Leffler unsigned int accum = 0; 21539beb93cSSam Leffler while (pin) { 21639beb93cSSam Leffler accum += 3 * (pin % 10); 21739beb93cSSam Leffler pin /= 10; 21839beb93cSSam Leffler accum += pin % 10; 21939beb93cSSam Leffler pin /= 10; 22039beb93cSSam Leffler } 22139beb93cSSam Leffler 22239beb93cSSam Leffler return (10 - accum % 10) % 10; 22339beb93cSSam Leffler } 22439beb93cSSam Leffler 22539beb93cSSam Leffler 22639beb93cSSam Leffler /** 22739beb93cSSam Leffler * wps_pin_valid - Check whether a PIN has a valid checksum 22839beb93cSSam Leffler * @pin: Eight digit PIN (i.e., including the checksum digit) 22939beb93cSSam Leffler * Returns: 1 if checksum digit is valid, or 0 if not 23039beb93cSSam Leffler */ 23139beb93cSSam Leffler unsigned int wps_pin_valid(unsigned int pin) 23239beb93cSSam Leffler { 23339beb93cSSam Leffler return wps_pin_checksum(pin / 10) == (pin % 10); 23439beb93cSSam Leffler } 23539beb93cSSam Leffler 23639beb93cSSam Leffler 23739beb93cSSam Leffler /** 23839beb93cSSam Leffler * wps_generate_pin - Generate a random PIN 23939beb93cSSam Leffler * Returns: Eight digit PIN (i.e., including the checksum digit) 24039beb93cSSam Leffler */ 241*780fb4a2SCy Schubert int wps_generate_pin(unsigned int *pin) 24239beb93cSSam Leffler { 24339beb93cSSam Leffler unsigned int val; 24439beb93cSSam Leffler 24539beb93cSSam Leffler /* Generate seven random digits for the PIN */ 246*780fb4a2SCy Schubert if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) 247*780fb4a2SCy Schubert return -1; 24839beb93cSSam Leffler val %= 10000000; 24939beb93cSSam Leffler 25039beb93cSSam Leffler /* Append checksum digit */ 251*780fb4a2SCy Schubert *pin = val * 10 + wps_pin_checksum(val); 252*780fb4a2SCy Schubert return 0; 25339beb93cSSam Leffler } 25439beb93cSSam Leffler 25539beb93cSSam Leffler 256f05cddf9SRui Paulo int wps_pin_str_valid(const char *pin) 257f05cddf9SRui Paulo { 258f05cddf9SRui Paulo const char *p; 259f05cddf9SRui Paulo size_t len; 260f05cddf9SRui Paulo 261f05cddf9SRui Paulo p = pin; 262f05cddf9SRui Paulo while (*p >= '0' && *p <= '9') 263f05cddf9SRui Paulo p++; 264f05cddf9SRui Paulo if (*p != '\0') 265f05cddf9SRui Paulo return 0; 266f05cddf9SRui Paulo 267f05cddf9SRui Paulo len = p - pin; 268f05cddf9SRui Paulo return len == 4 || len == 8; 269f05cddf9SRui Paulo } 270f05cddf9SRui Paulo 271f05cddf9SRui Paulo 272f05cddf9SRui Paulo void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, 2735b9c547cSRui Paulo u16 config_error, u16 error_indication, const u8 *mac_addr) 27439beb93cSSam Leffler { 27539beb93cSSam Leffler union wps_event_data data; 27639beb93cSSam Leffler 27739beb93cSSam Leffler if (wps->event_cb == NULL) 27839beb93cSSam Leffler return; 27939beb93cSSam Leffler 28039beb93cSSam Leffler os_memset(&data, 0, sizeof(data)); 28139beb93cSSam Leffler data.fail.msg = msg; 282f05cddf9SRui Paulo data.fail.config_error = config_error; 283f05cddf9SRui Paulo data.fail.error_indication = error_indication; 2845b9c547cSRui Paulo os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN); 28539beb93cSSam Leffler wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); 28639beb93cSSam Leffler } 28739beb93cSSam Leffler 28839beb93cSSam Leffler 2895b9c547cSRui Paulo void wps_success_event(struct wps_context *wps, const u8 *mac_addr) 29039beb93cSSam Leffler { 2915b9c547cSRui Paulo union wps_event_data data; 2925b9c547cSRui Paulo 29339beb93cSSam Leffler if (wps->event_cb == NULL) 29439beb93cSSam Leffler return; 29539beb93cSSam Leffler 2965b9c547cSRui Paulo os_memset(&data, 0, sizeof(data)); 2975b9c547cSRui Paulo os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN); 2985b9c547cSRui Paulo wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data); 29939beb93cSSam Leffler } 30039beb93cSSam Leffler 30139beb93cSSam Leffler 3025b9c547cSRui Paulo void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part, 3035b9c547cSRui Paulo const u8 *mac_addr) 30439beb93cSSam Leffler { 30539beb93cSSam Leffler union wps_event_data data; 30639beb93cSSam Leffler 30739beb93cSSam Leffler if (wps->event_cb == NULL) 30839beb93cSSam Leffler return; 30939beb93cSSam Leffler 31039beb93cSSam Leffler os_memset(&data, 0, sizeof(data)); 31139beb93cSSam Leffler data.pwd_auth_fail.enrollee = enrollee; 31239beb93cSSam Leffler data.pwd_auth_fail.part = part; 3135b9c547cSRui Paulo os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN); 31439beb93cSSam Leffler wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); 31539beb93cSSam Leffler } 3163157ba21SRui Paulo 3173157ba21SRui Paulo 3183157ba21SRui Paulo void wps_pbc_overlap_event(struct wps_context *wps) 3193157ba21SRui Paulo { 3203157ba21SRui Paulo if (wps->event_cb == NULL) 3213157ba21SRui Paulo return; 3223157ba21SRui Paulo 3233157ba21SRui Paulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); 3243157ba21SRui Paulo } 3253157ba21SRui Paulo 3263157ba21SRui Paulo 3273157ba21SRui Paulo void wps_pbc_timeout_event(struct wps_context *wps) 3283157ba21SRui Paulo { 3293157ba21SRui Paulo if (wps->event_cb == NULL) 3303157ba21SRui Paulo return; 3313157ba21SRui Paulo 3323157ba21SRui Paulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); 3333157ba21SRui Paulo } 334e28a4053SRui Paulo 335e28a4053SRui Paulo 3365b9c547cSRui Paulo void wps_pbc_active_event(struct wps_context *wps) 3375b9c547cSRui Paulo { 3385b9c547cSRui Paulo if (wps->event_cb == NULL) 3395b9c547cSRui Paulo return; 3405b9c547cSRui Paulo 3415b9c547cSRui Paulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL); 3425b9c547cSRui Paulo } 3435b9c547cSRui Paulo 3445b9c547cSRui Paulo 3455b9c547cSRui Paulo void wps_pbc_disable_event(struct wps_context *wps) 3465b9c547cSRui Paulo { 3475b9c547cSRui Paulo if (wps->event_cb == NULL) 3485b9c547cSRui Paulo return; 3495b9c547cSRui Paulo 3505b9c547cSRui Paulo wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL); 3515b9c547cSRui Paulo } 3525b9c547cSRui Paulo 3535b9c547cSRui Paulo 354e28a4053SRui Paulo #ifdef CONFIG_WPS_OOB 355e28a4053SRui Paulo 3565b9c547cSRui Paulo struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band, 3575b9c547cSRui Paulo int channel) 358e28a4053SRui Paulo { 359e28a4053SRui Paulo struct wps_data data; 360e28a4053SRui Paulo struct wpabuf *plain; 361e28a4053SRui Paulo 362e28a4053SRui Paulo plain = wpabuf_alloc(500); 363e28a4053SRui Paulo if (plain == NULL) { 364e28a4053SRui Paulo wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 365e28a4053SRui Paulo "credential"); 366e28a4053SRui Paulo return NULL; 367e28a4053SRui Paulo } 368e28a4053SRui Paulo 369e28a4053SRui Paulo os_memset(&data, 0, sizeof(data)); 370e28a4053SRui Paulo data.wps = wps; 371e28a4053SRui Paulo data.auth_type = wps->auth_types; 372e28a4053SRui Paulo data.encr_type = wps->encr_types; 3735b9c547cSRui Paulo if (wps_build_cred(&data, plain) || 3745b9c547cSRui Paulo (rf_band && wps_build_rf_bands_attr(plain, rf_band)) || 3755b9c547cSRui Paulo (channel && wps_build_ap_channel(plain, channel)) || 3765b9c547cSRui Paulo wps_build_mac_addr(plain, wps->dev.mac_addr) || 377f05cddf9SRui Paulo wps_build_wfa_ext(plain, 0, NULL, 0)) { 3785b9c547cSRui Paulo os_free(data.new_psk); 379*780fb4a2SCy Schubert wpabuf_clear_free(plain); 380e28a4053SRui Paulo return NULL; 381e28a4053SRui Paulo } 382e28a4053SRui Paulo 3835b9c547cSRui Paulo if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk && 3845b9c547cSRui Paulo wps->ap) { 3855b9c547cSRui Paulo struct wps_credential cred; 3865b9c547cSRui Paulo 3875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based " 3885b9c547cSRui Paulo "on credential token generation"); 3895b9c547cSRui Paulo 3905b9c547cSRui Paulo os_memset(&cred, 0, sizeof(cred)); 3915b9c547cSRui Paulo os_memcpy(cred.ssid, wps->ssid, wps->ssid_len); 3925b9c547cSRui Paulo cred.ssid_len = wps->ssid_len; 3935b9c547cSRui Paulo cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK; 3945b9c547cSRui Paulo cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES; 3955b9c547cSRui Paulo os_memcpy(cred.key, data.new_psk, data.new_psk_len); 3965b9c547cSRui Paulo cred.key_len = data.new_psk_len; 3975b9c547cSRui Paulo 3985b9c547cSRui Paulo wps->wps_state = WPS_STATE_CONFIGURED; 3995b9c547cSRui Paulo wpa_hexdump_ascii_key(MSG_DEBUG, 4005b9c547cSRui Paulo "WPS: Generated random passphrase", 4015b9c547cSRui Paulo data.new_psk, data.new_psk_len); 4025b9c547cSRui Paulo if (wps->cred_cb) 4035b9c547cSRui Paulo wps->cred_cb(wps->cb_ctx, &cred); 4045b9c547cSRui Paulo } 4055b9c547cSRui Paulo 4065b9c547cSRui Paulo os_free(data.new_psk); 4075b9c547cSRui Paulo 408e28a4053SRui Paulo return plain; 409e28a4053SRui Paulo } 410e28a4053SRui Paulo 411e28a4053SRui Paulo 412f05cddf9SRui Paulo struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, 413f05cddf9SRui Paulo const struct wpabuf *pubkey, 414f05cddf9SRui Paulo const struct wpabuf *dev_pw) 415e28a4053SRui Paulo { 416e28a4053SRui Paulo struct wpabuf *data; 417e28a4053SRui Paulo 418f05cddf9SRui Paulo data = wpabuf_alloc(200); 419f05cddf9SRui Paulo if (data == NULL) 420e28a4053SRui Paulo return NULL; 421e28a4053SRui Paulo 4225b9c547cSRui Paulo if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey, 423f05cddf9SRui Paulo wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || 424f05cddf9SRui Paulo wps_build_wfa_ext(data, 0, NULL, 0)) { 425f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " 426f05cddf9SRui Paulo "token"); 427*780fb4a2SCy Schubert wpabuf_clear_free(data); 428e28a4053SRui Paulo return NULL; 429e28a4053SRui Paulo } 430e28a4053SRui Paulo 431e28a4053SRui Paulo return data; 432e28a4053SRui Paulo } 433e28a4053SRui Paulo 434e28a4053SRui Paulo 435f05cddf9SRui Paulo int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr) 436e28a4053SRui Paulo { 437e28a4053SRui Paulo struct wpabuf msg; 438e28a4053SRui Paulo size_t i; 439e28a4053SRui Paulo 440f05cddf9SRui Paulo for (i = 0; i < attr->num_cred; i++) { 441e28a4053SRui Paulo struct wps_credential local_cred; 442e28a4053SRui Paulo struct wps_parse_attr cattr; 443e28a4053SRui Paulo 444e28a4053SRui Paulo os_memset(&local_cred, 0, sizeof(local_cred)); 445f05cddf9SRui Paulo wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]); 446e28a4053SRui Paulo if (wps_parse_msg(&msg, &cattr) < 0 || 447e28a4053SRui Paulo wps_process_cred(&cattr, &local_cred)) { 448e28a4053SRui Paulo wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " 449e28a4053SRui Paulo "credential"); 450e28a4053SRui Paulo return -1; 451e28a4053SRui Paulo } 452e28a4053SRui Paulo wps->cred_cb(wps->cb_ctx, &local_cred); 453e28a4053SRui Paulo } 454e28a4053SRui Paulo 455e28a4053SRui Paulo return 0; 456e28a4053SRui Paulo } 457e28a4053SRui Paulo 458e28a4053SRui Paulo 459e28a4053SRui Paulo #endif /* CONFIG_WPS_OOB */ 460e28a4053SRui Paulo 461e28a4053SRui Paulo 462e28a4053SRui Paulo int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]) 463e28a4053SRui Paulo { 464e28a4053SRui Paulo const char *pos; 465e28a4053SRui Paulo 466e28a4053SRui Paulo /* <categ>-<OUI>-<subcateg> */ 467e28a4053SRui Paulo WPA_PUT_BE16(dev_type, atoi(str)); 468e28a4053SRui Paulo pos = os_strchr(str, '-'); 469e28a4053SRui Paulo if (pos == NULL) 470e28a4053SRui Paulo return -1; 471e28a4053SRui Paulo pos++; 472e28a4053SRui Paulo if (hexstr2bin(pos, &dev_type[2], 4)) 473e28a4053SRui Paulo return -1; 474e28a4053SRui Paulo pos = os_strchr(pos, '-'); 475e28a4053SRui Paulo if (pos == NULL) 476e28a4053SRui Paulo return -1; 477e28a4053SRui Paulo pos++; 478e28a4053SRui Paulo WPA_PUT_BE16(&dev_type[6], atoi(pos)); 479e28a4053SRui Paulo 480e28a4053SRui Paulo 481e28a4053SRui Paulo return 0; 482e28a4053SRui Paulo } 483e28a4053SRui Paulo 484e28a4053SRui Paulo 485e28a4053SRui Paulo char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, 486e28a4053SRui Paulo size_t buf_len) 487e28a4053SRui Paulo { 488e28a4053SRui Paulo int ret; 489e28a4053SRui Paulo 490e28a4053SRui Paulo ret = os_snprintf(buf, buf_len, "%u-%08X-%u", 491e28a4053SRui Paulo WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), 492e28a4053SRui Paulo WPA_GET_BE16(&dev_type[6])); 4935b9c547cSRui Paulo if (os_snprintf_error(buf_len, ret)) 494e28a4053SRui Paulo return NULL; 495e28a4053SRui Paulo 496e28a4053SRui Paulo return buf; 497e28a4053SRui Paulo } 498e28a4053SRui Paulo 499e28a4053SRui Paulo 500e28a4053SRui Paulo void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) 501e28a4053SRui Paulo { 502e28a4053SRui Paulo const u8 *addr[2]; 503e28a4053SRui Paulo size_t len[2]; 504e28a4053SRui Paulo u8 hash[SHA1_MAC_LEN]; 505e28a4053SRui Paulo u8 nsid[16] = { 506e28a4053SRui Paulo 0x52, 0x64, 0x80, 0xf8, 507e28a4053SRui Paulo 0xc9, 0x9b, 508e28a4053SRui Paulo 0x4b, 0xe5, 509e28a4053SRui Paulo 0xa6, 0x55, 510e28a4053SRui Paulo 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 511e28a4053SRui Paulo }; 512e28a4053SRui Paulo 513e28a4053SRui Paulo addr[0] = nsid; 514e28a4053SRui Paulo len[0] = sizeof(nsid); 515e28a4053SRui Paulo addr[1] = mac_addr; 516e28a4053SRui Paulo len[1] = 6; 517e28a4053SRui Paulo sha1_vector(2, addr, len, hash); 518e28a4053SRui Paulo os_memcpy(uuid, hash, 16); 519e28a4053SRui Paulo 520e28a4053SRui Paulo /* Version: 5 = named-based version using SHA-1 */ 521e28a4053SRui Paulo uuid[6] = (5 << 4) | (uuid[6] & 0x0f); 522e28a4053SRui Paulo 523e28a4053SRui Paulo /* Variant specified in RFC 4122 */ 524e28a4053SRui Paulo uuid[8] = 0x80 | (uuid[8] & 0x3f); 525e28a4053SRui Paulo } 526e28a4053SRui Paulo 527e28a4053SRui Paulo 528e28a4053SRui Paulo u16 wps_config_methods_str2bin(const char *str) 529e28a4053SRui Paulo { 530e28a4053SRui Paulo u16 methods = 0; 531e28a4053SRui Paulo 532325151a3SRui Paulo if (str == NULL || str[0] == '\0') { 533e28a4053SRui Paulo /* Default to enabling methods based on build configuration */ 534e28a4053SRui Paulo methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 535f05cddf9SRui Paulo methods |= WPS_CONFIG_VIRT_DISPLAY; 536e28a4053SRui Paulo #ifdef CONFIG_WPS_NFC 537e28a4053SRui Paulo methods |= WPS_CONFIG_NFC_INTERFACE; 538e28a4053SRui Paulo #endif /* CONFIG_WPS_NFC */ 5395b9c547cSRui Paulo #ifdef CONFIG_P2P 5405b9c547cSRui Paulo methods |= WPS_CONFIG_P2PS; 5415b9c547cSRui Paulo #endif /* CONFIG_P2P */ 542e28a4053SRui Paulo } else { 543e28a4053SRui Paulo if (os_strstr(str, "ethernet")) 544e28a4053SRui Paulo methods |= WPS_CONFIG_ETHERNET; 545e28a4053SRui Paulo if (os_strstr(str, "label")) 546e28a4053SRui Paulo methods |= WPS_CONFIG_LABEL; 547e28a4053SRui Paulo if (os_strstr(str, "display")) 548e28a4053SRui Paulo methods |= WPS_CONFIG_DISPLAY; 549e28a4053SRui Paulo if (os_strstr(str, "ext_nfc_token")) 550e28a4053SRui Paulo methods |= WPS_CONFIG_EXT_NFC_TOKEN; 551e28a4053SRui Paulo if (os_strstr(str, "int_nfc_token")) 552e28a4053SRui Paulo methods |= WPS_CONFIG_INT_NFC_TOKEN; 553e28a4053SRui Paulo if (os_strstr(str, "nfc_interface")) 554e28a4053SRui Paulo methods |= WPS_CONFIG_NFC_INTERFACE; 555e28a4053SRui Paulo if (os_strstr(str, "push_button")) 556e28a4053SRui Paulo methods |= WPS_CONFIG_PUSHBUTTON; 557e28a4053SRui Paulo if (os_strstr(str, "keypad")) 558e28a4053SRui Paulo methods |= WPS_CONFIG_KEYPAD; 559f05cddf9SRui Paulo if (os_strstr(str, "virtual_display")) 560f05cddf9SRui Paulo methods |= WPS_CONFIG_VIRT_DISPLAY; 561f05cddf9SRui Paulo if (os_strstr(str, "physical_display")) 562f05cddf9SRui Paulo methods |= WPS_CONFIG_PHY_DISPLAY; 563f05cddf9SRui Paulo if (os_strstr(str, "virtual_push_button")) 564f05cddf9SRui Paulo methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 565f05cddf9SRui Paulo if (os_strstr(str, "physical_push_button")) 566f05cddf9SRui Paulo methods |= WPS_CONFIG_PHY_PUSHBUTTON; 5675b9c547cSRui Paulo if (os_strstr(str, "p2ps")) 5685b9c547cSRui Paulo methods |= WPS_CONFIG_P2PS; 569e28a4053SRui Paulo } 570e28a4053SRui Paulo 571e28a4053SRui Paulo return methods; 572e28a4053SRui Paulo } 573f05cddf9SRui Paulo 574f05cddf9SRui Paulo 575f05cddf9SRui Paulo struct wpabuf * wps_build_wsc_ack(struct wps_data *wps) 576f05cddf9SRui Paulo { 577f05cddf9SRui Paulo struct wpabuf *msg; 578f05cddf9SRui Paulo 579f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK"); 580f05cddf9SRui Paulo 581f05cddf9SRui Paulo msg = wpabuf_alloc(1000); 582f05cddf9SRui Paulo if (msg == NULL) 583f05cddf9SRui Paulo return NULL; 584f05cddf9SRui Paulo 585f05cddf9SRui Paulo if (wps_build_version(msg) || 586f05cddf9SRui Paulo wps_build_msg_type(msg, WPS_WSC_ACK) || 587f05cddf9SRui Paulo wps_build_enrollee_nonce(wps, msg) || 588f05cddf9SRui Paulo wps_build_registrar_nonce(wps, msg) || 589f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 590f05cddf9SRui Paulo wpabuf_free(msg); 591f05cddf9SRui Paulo return NULL; 592f05cddf9SRui Paulo } 593f05cddf9SRui Paulo 594f05cddf9SRui Paulo return msg; 595f05cddf9SRui Paulo } 596f05cddf9SRui Paulo 597f05cddf9SRui Paulo 598f05cddf9SRui Paulo struct wpabuf * wps_build_wsc_nack(struct wps_data *wps) 599f05cddf9SRui Paulo { 600f05cddf9SRui Paulo struct wpabuf *msg; 601f05cddf9SRui Paulo 602f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK"); 603f05cddf9SRui Paulo 604f05cddf9SRui Paulo msg = wpabuf_alloc(1000); 605f05cddf9SRui Paulo if (msg == NULL) 606f05cddf9SRui Paulo return NULL; 607f05cddf9SRui Paulo 608f05cddf9SRui Paulo if (wps_build_version(msg) || 609f05cddf9SRui Paulo wps_build_msg_type(msg, WPS_WSC_NACK) || 610f05cddf9SRui Paulo wps_build_enrollee_nonce(wps, msg) || 611f05cddf9SRui Paulo wps_build_registrar_nonce(wps, msg) || 612f05cddf9SRui Paulo wps_build_config_error(msg, wps->config_error) || 613f05cddf9SRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 614f05cddf9SRui Paulo wpabuf_free(msg); 615f05cddf9SRui Paulo return NULL; 616f05cddf9SRui Paulo } 617f05cddf9SRui Paulo 618f05cddf9SRui Paulo return msg; 619f05cddf9SRui Paulo } 620f05cddf9SRui Paulo 621f05cddf9SRui Paulo 622f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC 6235b9c547cSRui Paulo 6245b9c547cSRui Paulo struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey, 6255b9c547cSRui Paulo struct wpabuf *dev_pw) 6265b9c547cSRui Paulo { 6275b9c547cSRui Paulo struct wpabuf *ret; 6285b9c547cSRui Paulo 6295b9c547cSRui Paulo if (pubkey == NULL || dev_pw == NULL) 6305b9c547cSRui Paulo return NULL; 6315b9c547cSRui Paulo 6325b9c547cSRui Paulo ret = wps_build_nfc_pw_token(id, pubkey, dev_pw); 6335b9c547cSRui Paulo if (ndef && ret) { 6345b9c547cSRui Paulo struct wpabuf *tmp; 6355b9c547cSRui Paulo tmp = ndef_build_wifi(ret); 6365b9c547cSRui Paulo wpabuf_free(ret); 6375b9c547cSRui Paulo if (tmp == NULL) 6385b9c547cSRui Paulo return NULL; 6395b9c547cSRui Paulo ret = tmp; 6405b9c547cSRui Paulo } 6415b9c547cSRui Paulo 6425b9c547cSRui Paulo return ret; 6435b9c547cSRui Paulo } 6445b9c547cSRui Paulo 6455b9c547cSRui Paulo 6465b9c547cSRui Paulo int wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey) 6475b9c547cSRui Paulo { 6485b9c547cSRui Paulo struct wpabuf *priv = NULL, *pub = NULL; 6495b9c547cSRui Paulo void *dh_ctx; 6505b9c547cSRui Paulo 6515b9c547cSRui Paulo dh_ctx = dh5_init(&priv, &pub); 6525b9c547cSRui Paulo if (dh_ctx == NULL) 6535b9c547cSRui Paulo return -1; 6545b9c547cSRui Paulo pub = wpabuf_zeropad(pub, 192); 6555b9c547cSRui Paulo if (pub == NULL) { 6565b9c547cSRui Paulo wpabuf_free(priv); 6575b9c547cSRui Paulo return -1; 6585b9c547cSRui Paulo } 6595b9c547cSRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub); 6605b9c547cSRui Paulo dh5_free(dh_ctx); 6615b9c547cSRui Paulo 6625b9c547cSRui Paulo wpabuf_free(*pubkey); 6635b9c547cSRui Paulo *pubkey = pub; 664*780fb4a2SCy Schubert wpabuf_clear_free(*privkey); 6655b9c547cSRui Paulo *privkey = priv; 6665b9c547cSRui Paulo 6675b9c547cSRui Paulo return 0; 6685b9c547cSRui Paulo } 6695b9c547cSRui Paulo 6705b9c547cSRui Paulo 671f05cddf9SRui Paulo struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, 672f05cddf9SRui Paulo struct wpabuf **privkey, 673f05cddf9SRui Paulo struct wpabuf **dev_pw) 674f05cddf9SRui Paulo { 6755b9c547cSRui Paulo struct wpabuf *pw; 676f05cddf9SRui Paulo u16 val; 677f05cddf9SRui Paulo 678f05cddf9SRui Paulo pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN); 679f05cddf9SRui Paulo if (pw == NULL) 680f05cddf9SRui Paulo return NULL; 681f05cddf9SRui Paulo 682f05cddf9SRui Paulo if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN), 683f05cddf9SRui Paulo WPS_OOB_DEVICE_PASSWORD_LEN) || 684f05cddf9SRui Paulo random_get_bytes((u8 *) &val, sizeof(val))) { 685f05cddf9SRui Paulo wpabuf_free(pw); 686f05cddf9SRui Paulo return NULL; 687f05cddf9SRui Paulo } 688f05cddf9SRui Paulo 6895b9c547cSRui Paulo if (wps_nfc_gen_dh(pubkey, privkey) < 0) { 690f05cddf9SRui Paulo wpabuf_free(pw); 691f05cddf9SRui Paulo return NULL; 692f05cddf9SRui Paulo } 693f05cddf9SRui Paulo 694f05cddf9SRui Paulo *id = 0x10 + val % 0xfff0; 695*780fb4a2SCy Schubert wpabuf_clear_free(*dev_pw); 696f05cddf9SRui Paulo *dev_pw = pw; 697f05cddf9SRui Paulo 6985b9c547cSRui Paulo return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw); 699f05cddf9SRui Paulo } 700f05cddf9SRui Paulo 7015b9c547cSRui Paulo 7025b9c547cSRui Paulo struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx, 7035b9c547cSRui Paulo struct wpabuf *nfc_dh_pubkey) 7045b9c547cSRui Paulo { 7055b9c547cSRui Paulo struct wpabuf *msg; 7065b9c547cSRui Paulo void *len; 7075b9c547cSRui Paulo 7085b9c547cSRui Paulo if (ctx == NULL) 7095b9c547cSRui Paulo return NULL; 7105b9c547cSRui Paulo 7115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 7125b9c547cSRui Paulo "handover request"); 7135b9c547cSRui Paulo 7145b9c547cSRui Paulo if (nfc_dh_pubkey == NULL) { 7155b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 7165b9c547cSRui Paulo "configured"); 7175b9c547cSRui Paulo return NULL; 718f05cddf9SRui Paulo } 7195b9c547cSRui Paulo 7205b9c547cSRui Paulo msg = wpabuf_alloc(1000); 7215b9c547cSRui Paulo if (msg == NULL) 7225b9c547cSRui Paulo return msg; 7235b9c547cSRui Paulo len = wpabuf_put(msg, 2); 7245b9c547cSRui Paulo 7255b9c547cSRui Paulo if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 7265b9c547cSRui Paulo nfc_dh_pubkey, NULL, 0) || 7275b9c547cSRui Paulo wps_build_uuid_e(msg, ctx->uuid) || 7285b9c547cSRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 7295b9c547cSRui Paulo wpabuf_free(msg); 7305b9c547cSRui Paulo return NULL; 7315b9c547cSRui Paulo } 7325b9c547cSRui Paulo 7335b9c547cSRui Paulo WPA_PUT_BE16(len, wpabuf_len(msg) - 2); 7345b9c547cSRui Paulo 7355b9c547cSRui Paulo return msg; 7365b9c547cSRui Paulo } 7375b9c547cSRui Paulo 7385b9c547cSRui Paulo 7395b9c547cSRui Paulo static int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps) 7405b9c547cSRui Paulo { 7415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: * SSID"); 7425b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select", 7435b9c547cSRui Paulo wps->ssid, wps->ssid_len); 7445b9c547cSRui Paulo wpabuf_put_be16(msg, ATTR_SSID); 7455b9c547cSRui Paulo wpabuf_put_be16(msg, wps->ssid_len); 7465b9c547cSRui Paulo wpabuf_put_data(msg, wps->ssid, wps->ssid_len); 7475b9c547cSRui Paulo return 0; 7485b9c547cSRui Paulo } 7495b9c547cSRui Paulo 7505b9c547cSRui Paulo 7515b9c547cSRui Paulo static int wps_build_ap_freq(struct wpabuf *msg, int freq) 7525b9c547cSRui Paulo { 7535b9c547cSRui Paulo enum hostapd_hw_mode mode; 7545b9c547cSRui Paulo u8 channel, rf_band; 7555b9c547cSRui Paulo u16 ap_channel; 7565b9c547cSRui Paulo 7575b9c547cSRui Paulo if (freq <= 0) 7585b9c547cSRui Paulo return 0; 7595b9c547cSRui Paulo 7605b9c547cSRui Paulo mode = ieee80211_freq_to_chan(freq, &channel); 7615b9c547cSRui Paulo if (mode == NUM_HOSTAPD_MODES) 7625b9c547cSRui Paulo return 0; /* Unknown channel */ 7635b9c547cSRui Paulo 7645b9c547cSRui Paulo if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B) 7655b9c547cSRui Paulo rf_band = WPS_RF_24GHZ; 7665b9c547cSRui Paulo else if (mode == HOSTAPD_MODE_IEEE80211A) 7675b9c547cSRui Paulo rf_band = WPS_RF_50GHZ; 768325151a3SRui Paulo else if (mode == HOSTAPD_MODE_IEEE80211AD) 769325151a3SRui Paulo rf_band = WPS_RF_60GHZ; 7705b9c547cSRui Paulo else 7715b9c547cSRui Paulo return 0; /* Unknown band */ 7725b9c547cSRui Paulo ap_channel = channel; 7735b9c547cSRui Paulo 7745b9c547cSRui Paulo if (wps_build_rf_bands_attr(msg, rf_band) || 7755b9c547cSRui Paulo wps_build_ap_channel(msg, ap_channel)) 7765b9c547cSRui Paulo return -1; 7775b9c547cSRui Paulo 7785b9c547cSRui Paulo return 0; 7795b9c547cSRui Paulo } 7805b9c547cSRui Paulo 7815b9c547cSRui Paulo 7825b9c547cSRui Paulo struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx, 7835b9c547cSRui Paulo struct wpabuf *nfc_dh_pubkey, 7845b9c547cSRui Paulo const u8 *bssid, int freq) 7855b9c547cSRui Paulo { 7865b9c547cSRui Paulo struct wpabuf *msg; 7875b9c547cSRui Paulo void *len; 7885b9c547cSRui Paulo 7895b9c547cSRui Paulo if (ctx == NULL) 7905b9c547cSRui Paulo return NULL; 7915b9c547cSRui Paulo 7925b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 7935b9c547cSRui Paulo "handover select"); 7945b9c547cSRui Paulo 7955b9c547cSRui Paulo if (nfc_dh_pubkey == NULL) { 7965b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 7975b9c547cSRui Paulo "configured"); 7985b9c547cSRui Paulo return NULL; 7995b9c547cSRui Paulo } 8005b9c547cSRui Paulo 8015b9c547cSRui Paulo msg = wpabuf_alloc(1000); 8025b9c547cSRui Paulo if (msg == NULL) 8035b9c547cSRui Paulo return msg; 8045b9c547cSRui Paulo len = wpabuf_put(msg, 2); 8055b9c547cSRui Paulo 8065b9c547cSRui Paulo if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 8075b9c547cSRui Paulo nfc_dh_pubkey, NULL, 0) || 8085b9c547cSRui Paulo wps_build_ssid(msg, ctx) || 8095b9c547cSRui Paulo wps_build_ap_freq(msg, freq) || 8105b9c547cSRui Paulo (bssid && wps_build_mac_addr(msg, bssid)) || 8115b9c547cSRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 8125b9c547cSRui Paulo wpabuf_free(msg); 8135b9c547cSRui Paulo return NULL; 8145b9c547cSRui Paulo } 8155b9c547cSRui Paulo 8165b9c547cSRui Paulo WPA_PUT_BE16(len, wpabuf_len(msg) - 2); 8175b9c547cSRui Paulo 8185b9c547cSRui Paulo return msg; 8195b9c547cSRui Paulo } 8205b9c547cSRui Paulo 8215b9c547cSRui Paulo 8225b9c547cSRui Paulo struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx, 8235b9c547cSRui Paulo struct wpabuf *nfc_dh_pubkey) 8245b9c547cSRui Paulo { 8255b9c547cSRui Paulo struct wpabuf *msg; 8265b9c547cSRui Paulo 8275b9c547cSRui Paulo if (ctx == NULL) 8285b9c547cSRui Paulo return NULL; 8295b9c547cSRui Paulo 8305b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 8315b9c547cSRui Paulo "handover request (P2P)"); 8325b9c547cSRui Paulo 8335b9c547cSRui Paulo if (nfc_dh_pubkey == NULL) { 8345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured"); 8355b9c547cSRui Paulo return NULL; 8365b9c547cSRui Paulo } 8375b9c547cSRui Paulo 8385b9c547cSRui Paulo msg = wpabuf_alloc(1000); 8395b9c547cSRui Paulo if (msg == NULL) 8405b9c547cSRui Paulo return msg; 8415b9c547cSRui Paulo 8425b9c547cSRui Paulo if (wps_build_manufacturer(&ctx->dev, msg) || 8435b9c547cSRui Paulo wps_build_model_name(&ctx->dev, msg) || 8445b9c547cSRui Paulo wps_build_model_number(&ctx->dev, msg) || 8455b9c547cSRui Paulo wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 8465b9c547cSRui Paulo nfc_dh_pubkey, NULL, 0) || 8475b9c547cSRui Paulo wps_build_rf_bands(&ctx->dev, msg, 0) || 8485b9c547cSRui Paulo wps_build_serial_number(&ctx->dev, msg) || 8495b9c547cSRui Paulo wps_build_uuid_e(msg, ctx->uuid) || 8505b9c547cSRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 8515b9c547cSRui Paulo wpabuf_free(msg); 8525b9c547cSRui Paulo return NULL; 8535b9c547cSRui Paulo } 8545b9c547cSRui Paulo 8555b9c547cSRui Paulo return msg; 8565b9c547cSRui Paulo } 8575b9c547cSRui Paulo 8585b9c547cSRui Paulo 8595b9c547cSRui Paulo struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx, 8605b9c547cSRui Paulo int nfc_dev_pw_id, 8615b9c547cSRui Paulo struct wpabuf *nfc_dh_pubkey, 8625b9c547cSRui Paulo struct wpabuf *nfc_dev_pw) 8635b9c547cSRui Paulo { 8645b9c547cSRui Paulo struct wpabuf *msg; 8655b9c547cSRui Paulo const u8 *dev_pw; 8665b9c547cSRui Paulo size_t dev_pw_len; 8675b9c547cSRui Paulo 8685b9c547cSRui Paulo if (ctx == NULL) 8695b9c547cSRui Paulo return NULL; 8705b9c547cSRui Paulo 8715b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 8725b9c547cSRui Paulo "handover select (P2P)"); 8735b9c547cSRui Paulo 8745b9c547cSRui Paulo if (nfc_dh_pubkey == NULL || 8755b9c547cSRui Paulo (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && 8765b9c547cSRui Paulo nfc_dev_pw == NULL)) { 8775b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 8785b9c547cSRui Paulo "configured"); 8795b9c547cSRui Paulo return NULL; 8805b9c547cSRui Paulo } 8815b9c547cSRui Paulo 8825b9c547cSRui Paulo msg = wpabuf_alloc(1000); 8835b9c547cSRui Paulo if (msg == NULL) 8845b9c547cSRui Paulo return msg; 8855b9c547cSRui Paulo 8865b9c547cSRui Paulo if (nfc_dev_pw) { 8875b9c547cSRui Paulo dev_pw = wpabuf_head(nfc_dev_pw); 8885b9c547cSRui Paulo dev_pw_len = wpabuf_len(nfc_dev_pw); 8895b9c547cSRui Paulo } else { 8905b9c547cSRui Paulo dev_pw = NULL; 8915b9c547cSRui Paulo dev_pw_len = 0; 8925b9c547cSRui Paulo } 8935b9c547cSRui Paulo 8945b9c547cSRui Paulo if (wps_build_manufacturer(&ctx->dev, msg) || 8955b9c547cSRui Paulo wps_build_model_name(&ctx->dev, msg) || 8965b9c547cSRui Paulo wps_build_model_number(&ctx->dev, msg) || 8975b9c547cSRui Paulo wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey, 8985b9c547cSRui Paulo dev_pw, dev_pw_len) || 8995b9c547cSRui Paulo wps_build_rf_bands(&ctx->dev, msg, 0) || 9005b9c547cSRui Paulo wps_build_serial_number(&ctx->dev, msg) || 9015b9c547cSRui Paulo wps_build_uuid_e(msg, ctx->uuid) || 9025b9c547cSRui Paulo wps_build_wfa_ext(msg, 0, NULL, 0)) { 9035b9c547cSRui Paulo wpabuf_free(msg); 9045b9c547cSRui Paulo return NULL; 9055b9c547cSRui Paulo } 9065b9c547cSRui Paulo 9075b9c547cSRui Paulo return msg; 9085b9c547cSRui Paulo } 9095b9c547cSRui Paulo 910f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */ 911