1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Protected Setup - common functionality 3e5b75505Sopenharmony_ci * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "common/defs.h" 13e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h" 14e5b75505Sopenharmony_ci#include "crypto/aes_wrap.h" 15e5b75505Sopenharmony_ci#include "crypto/crypto.h" 16e5b75505Sopenharmony_ci#include "crypto/dh_group5.h" 17e5b75505Sopenharmony_ci#include "crypto/sha1.h" 18e5b75505Sopenharmony_ci#include "crypto/sha256.h" 19e5b75505Sopenharmony_ci#include "crypto/random.h" 20e5b75505Sopenharmony_ci#include "wps_i.h" 21e5b75505Sopenharmony_ci#include "wps_dev_attr.h" 22e5b75505Sopenharmony_ci 23e5b75505Sopenharmony_ci 24e5b75505Sopenharmony_civoid wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, 25e5b75505Sopenharmony_ci const char *label, u8 *res, size_t res_len) 26e5b75505Sopenharmony_ci{ 27e5b75505Sopenharmony_ci u8 i_buf[4], key_bits[4]; 28e5b75505Sopenharmony_ci const u8 *addr[4]; 29e5b75505Sopenharmony_ci size_t len[4]; 30e5b75505Sopenharmony_ci int i, iter; 31e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN], *opos; 32e5b75505Sopenharmony_ci size_t left; 33e5b75505Sopenharmony_ci 34e5b75505Sopenharmony_ci WPA_PUT_BE32(key_bits, res_len * 8); 35e5b75505Sopenharmony_ci 36e5b75505Sopenharmony_ci addr[0] = i_buf; 37e5b75505Sopenharmony_ci len[0] = sizeof(i_buf); 38e5b75505Sopenharmony_ci addr[1] = label_prefix; 39e5b75505Sopenharmony_ci len[1] = label_prefix_len; 40e5b75505Sopenharmony_ci addr[2] = (const u8 *) label; 41e5b75505Sopenharmony_ci len[2] = os_strlen(label); 42e5b75505Sopenharmony_ci addr[3] = key_bits; 43e5b75505Sopenharmony_ci len[3] = sizeof(key_bits); 44e5b75505Sopenharmony_ci 45e5b75505Sopenharmony_ci iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; 46e5b75505Sopenharmony_ci opos = res; 47e5b75505Sopenharmony_ci left = res_len; 48e5b75505Sopenharmony_ci 49e5b75505Sopenharmony_ci for (i = 1; i <= iter; i++) { 50e5b75505Sopenharmony_ci WPA_PUT_BE32(i_buf, i); 51e5b75505Sopenharmony_ci hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); 52e5b75505Sopenharmony_ci if (i < iter) { 53e5b75505Sopenharmony_ci os_memcpy(opos, hash, SHA256_MAC_LEN); 54e5b75505Sopenharmony_ci opos += SHA256_MAC_LEN; 55e5b75505Sopenharmony_ci left -= SHA256_MAC_LEN; 56e5b75505Sopenharmony_ci } else 57e5b75505Sopenharmony_ci os_memcpy(opos, hash, left); 58e5b75505Sopenharmony_ci } 59e5b75505Sopenharmony_ci} 60e5b75505Sopenharmony_ci 61e5b75505Sopenharmony_ci 62e5b75505Sopenharmony_ciint wps_derive_keys(struct wps_data *wps) 63e5b75505Sopenharmony_ci{ 64e5b75505Sopenharmony_ci struct wpabuf *pubkey, *dh_shared; 65e5b75505Sopenharmony_ci u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; 66e5b75505Sopenharmony_ci const u8 *addr[3]; 67e5b75505Sopenharmony_ci size_t len[3]; 68e5b75505Sopenharmony_ci u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; 69e5b75505Sopenharmony_ci 70e5b75505Sopenharmony_ci if (wps->dh_privkey == NULL) { 71e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); 72e5b75505Sopenharmony_ci return -1; 73e5b75505Sopenharmony_ci } 74e5b75505Sopenharmony_ci 75e5b75505Sopenharmony_ci pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; 76e5b75505Sopenharmony_ci if (pubkey == NULL) { 77e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); 78e5b75505Sopenharmony_ci return -1; 79e5b75505Sopenharmony_ci } 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); 82e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey); 83e5b75505Sopenharmony_ci dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); 84e5b75505Sopenharmony_ci dh5_free(wps->dh_ctx); 85e5b75505Sopenharmony_ci wps->dh_ctx = NULL; 86e5b75505Sopenharmony_ci dh_shared = wpabuf_zeropad(dh_shared, 192); 87e5b75505Sopenharmony_ci if (dh_shared == NULL) { 88e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); 89e5b75505Sopenharmony_ci return -1; 90e5b75505Sopenharmony_ci } 91e5b75505Sopenharmony_ci 92e5b75505Sopenharmony_ci /* Own DH private key is not needed anymore */ 93e5b75505Sopenharmony_ci wpabuf_clear_free(wps->dh_privkey); 94e5b75505Sopenharmony_ci wps->dh_privkey = NULL; 95e5b75505Sopenharmony_ci 96e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); 97e5b75505Sopenharmony_ci 98e5b75505Sopenharmony_ci /* DHKey = SHA-256(g^AB mod p) */ 99e5b75505Sopenharmony_ci addr[0] = wpabuf_head(dh_shared); 100e5b75505Sopenharmony_ci len[0] = wpabuf_len(dh_shared); 101e5b75505Sopenharmony_ci sha256_vector(1, addr, len, dhkey); 102e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); 103e5b75505Sopenharmony_ci wpabuf_clear_free(dh_shared); 104e5b75505Sopenharmony_ci 105e5b75505Sopenharmony_ci /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ 106e5b75505Sopenharmony_ci addr[0] = wps->nonce_e; 107e5b75505Sopenharmony_ci len[0] = WPS_NONCE_LEN; 108e5b75505Sopenharmony_ci addr[1] = wps->mac_addr_e; 109e5b75505Sopenharmony_ci len[1] = ETH_ALEN; 110e5b75505Sopenharmony_ci addr[2] = wps->nonce_r; 111e5b75505Sopenharmony_ci len[2] = WPS_NONCE_LEN; 112e5b75505Sopenharmony_ci hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); 113e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); 114e5b75505Sopenharmony_ci 115e5b75505Sopenharmony_ci wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", 116e5b75505Sopenharmony_ci keys, sizeof(keys)); 117e5b75505Sopenharmony_ci os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); 118e5b75505Sopenharmony_ci os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); 119e5b75505Sopenharmony_ci os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, 120e5b75505Sopenharmony_ci WPS_EMSK_LEN); 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", 123e5b75505Sopenharmony_ci wps->authkey, WPS_AUTHKEY_LEN); 124e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", 125e5b75505Sopenharmony_ci wps->keywrapkey, WPS_KEYWRAPKEY_LEN); 126e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); 127e5b75505Sopenharmony_ci 128e5b75505Sopenharmony_ci return 0; 129e5b75505Sopenharmony_ci} 130e5b75505Sopenharmony_ci 131e5b75505Sopenharmony_ci 132e5b75505Sopenharmony_ciint wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd, 133e5b75505Sopenharmony_ci size_t dev_passwd_len) 134e5b75505Sopenharmony_ci{ 135e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 136e5b75505Sopenharmony_ci 137e5b75505Sopenharmony_ci if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd, 138e5b75505Sopenharmony_ci (dev_passwd_len + 1) / 2, hash) < 0) 139e5b75505Sopenharmony_ci return -1; 140e5b75505Sopenharmony_ci os_memcpy(wps->psk1, hash, WPS_PSK_LEN); 141e5b75505Sopenharmony_ci if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, 142e5b75505Sopenharmony_ci dev_passwd + (dev_passwd_len + 1) / 2, 143e5b75505Sopenharmony_ci dev_passwd_len / 2, hash) < 0) 144e5b75505Sopenharmony_ci return -1; 145e5b75505Sopenharmony_ci os_memcpy(wps->psk2, hash, WPS_PSK_LEN); 146e5b75505Sopenharmony_ci 147e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password", 148e5b75505Sopenharmony_ci dev_passwd, dev_passwd_len); 149e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN); 150e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN); 151e5b75505Sopenharmony_ci return 0; 152e5b75505Sopenharmony_ci} 153e5b75505Sopenharmony_ci 154e5b75505Sopenharmony_ci 155e5b75505Sopenharmony_cistruct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr, 156e5b75505Sopenharmony_ci size_t encr_len) 157e5b75505Sopenharmony_ci{ 158e5b75505Sopenharmony_ci struct wpabuf *decrypted; 159e5b75505Sopenharmony_ci const size_t block_size = 16; 160e5b75505Sopenharmony_ci size_t i; 161e5b75505Sopenharmony_ci u8 pad; 162e5b75505Sopenharmony_ci const u8 *pos; 163e5b75505Sopenharmony_ci 164e5b75505Sopenharmony_ci /* AES-128-CBC */ 165e5b75505Sopenharmony_ci if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size) 166e5b75505Sopenharmony_ci { 167e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received"); 168e5b75505Sopenharmony_ci return NULL; 169e5b75505Sopenharmony_ci } 170e5b75505Sopenharmony_ci 171e5b75505Sopenharmony_ci decrypted = wpabuf_alloc(encr_len - block_size); 172e5b75505Sopenharmony_ci if (decrypted == NULL) 173e5b75505Sopenharmony_ci return NULL; 174e5b75505Sopenharmony_ci 175e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len); 176e5b75505Sopenharmony_ci wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size); 177e5b75505Sopenharmony_ci if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted), 178e5b75505Sopenharmony_ci wpabuf_len(decrypted))) { 179e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 180e5b75505Sopenharmony_ci return NULL; 181e5b75505Sopenharmony_ci } 182e5b75505Sopenharmony_ci 183e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings", 184e5b75505Sopenharmony_ci decrypted); 185e5b75505Sopenharmony_ci 186e5b75505Sopenharmony_ci pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1; 187e5b75505Sopenharmony_ci pad = *pos; 188e5b75505Sopenharmony_ci if (pad > wpabuf_len(decrypted)) { 189e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value"); 190e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 191e5b75505Sopenharmony_ci return NULL; 192e5b75505Sopenharmony_ci } 193e5b75505Sopenharmony_ci for (i = 0; i < pad; i++) { 194e5b75505Sopenharmony_ci if (*pos-- != pad) { 195e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad " 196e5b75505Sopenharmony_ci "string"); 197e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 198e5b75505Sopenharmony_ci return NULL; 199e5b75505Sopenharmony_ci } 200e5b75505Sopenharmony_ci } 201e5b75505Sopenharmony_ci decrypted->used -= pad; 202e5b75505Sopenharmony_ci 203e5b75505Sopenharmony_ci return decrypted; 204e5b75505Sopenharmony_ci} 205e5b75505Sopenharmony_ci 206e5b75505Sopenharmony_ci 207e5b75505Sopenharmony_ci/** 208e5b75505Sopenharmony_ci * wps_pin_checksum - Compute PIN checksum 209e5b75505Sopenharmony_ci * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit) 210e5b75505Sopenharmony_ci * Returns: Checksum digit 211e5b75505Sopenharmony_ci */ 212e5b75505Sopenharmony_ciunsigned int wps_pin_checksum(unsigned int pin) 213e5b75505Sopenharmony_ci{ 214e5b75505Sopenharmony_ci unsigned int accum = 0; 215e5b75505Sopenharmony_ci while (pin) { 216e5b75505Sopenharmony_ci accum += 3 * (pin % 10); 217e5b75505Sopenharmony_ci pin /= 10; 218e5b75505Sopenharmony_ci accum += pin % 10; 219e5b75505Sopenharmony_ci pin /= 10; 220e5b75505Sopenharmony_ci } 221e5b75505Sopenharmony_ci 222e5b75505Sopenharmony_ci return (10 - accum % 10) % 10; 223e5b75505Sopenharmony_ci} 224e5b75505Sopenharmony_ci 225e5b75505Sopenharmony_ci 226e5b75505Sopenharmony_ci/** 227e5b75505Sopenharmony_ci * wps_pin_valid - Check whether a PIN has a valid checksum 228e5b75505Sopenharmony_ci * @pin: Eight digit PIN (i.e., including the checksum digit) 229e5b75505Sopenharmony_ci * Returns: 1 if checksum digit is valid, or 0 if not 230e5b75505Sopenharmony_ci */ 231e5b75505Sopenharmony_ciunsigned int wps_pin_valid(unsigned int pin) 232e5b75505Sopenharmony_ci{ 233e5b75505Sopenharmony_ci return wps_pin_checksum(pin / 10) == (pin % 10); 234e5b75505Sopenharmony_ci} 235e5b75505Sopenharmony_ci 236e5b75505Sopenharmony_ci 237e5b75505Sopenharmony_ci/** 238e5b75505Sopenharmony_ci * wps_generate_pin - Generate a random PIN 239e5b75505Sopenharmony_ci * Returns: Eight digit PIN (i.e., including the checksum digit) 240e5b75505Sopenharmony_ci */ 241e5b75505Sopenharmony_ciint wps_generate_pin(unsigned int *pin) 242e5b75505Sopenharmony_ci{ 243e5b75505Sopenharmony_ci unsigned int val; 244e5b75505Sopenharmony_ci 245e5b75505Sopenharmony_ci /* Generate seven random digits for the PIN */ 246e5b75505Sopenharmony_ci if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) 247e5b75505Sopenharmony_ci return -1; 248e5b75505Sopenharmony_ci val %= 10000000; 249e5b75505Sopenharmony_ci 250e5b75505Sopenharmony_ci /* Append checksum digit */ 251e5b75505Sopenharmony_ci *pin = val * 10 + wps_pin_checksum(val); 252e5b75505Sopenharmony_ci return 0; 253e5b75505Sopenharmony_ci} 254e5b75505Sopenharmony_ci 255e5b75505Sopenharmony_ci 256e5b75505Sopenharmony_ciint wps_pin_str_valid(const char *pin) 257e5b75505Sopenharmony_ci{ 258e5b75505Sopenharmony_ci const char *p; 259e5b75505Sopenharmony_ci size_t len; 260e5b75505Sopenharmony_ci 261e5b75505Sopenharmony_ci p = pin; 262e5b75505Sopenharmony_ci while (*p >= '0' && *p <= '9') 263e5b75505Sopenharmony_ci p++; 264e5b75505Sopenharmony_ci if (*p != '\0') 265e5b75505Sopenharmony_ci return 0; 266e5b75505Sopenharmony_ci 267e5b75505Sopenharmony_ci len = p - pin; 268e5b75505Sopenharmony_ci return len == 4 || len == 8; 269e5b75505Sopenharmony_ci} 270e5b75505Sopenharmony_ci 271e5b75505Sopenharmony_ci 272e5b75505Sopenharmony_civoid wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, 273e5b75505Sopenharmony_ci u16 config_error, u16 error_indication, const u8 *mac_addr) 274e5b75505Sopenharmony_ci{ 275e5b75505Sopenharmony_ci union wps_event_data data; 276e5b75505Sopenharmony_ci 277e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 278e5b75505Sopenharmony_ci return; 279e5b75505Sopenharmony_ci 280e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 281e5b75505Sopenharmony_ci data.fail.msg = msg; 282e5b75505Sopenharmony_ci data.fail.config_error = config_error; 283e5b75505Sopenharmony_ci data.fail.error_indication = error_indication; 284e5b75505Sopenharmony_ci os_memcpy(data.fail.peer_macaddr, mac_addr, ETH_ALEN); 285e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data); 286e5b75505Sopenharmony_ci} 287e5b75505Sopenharmony_ci 288e5b75505Sopenharmony_ci 289e5b75505Sopenharmony_civoid wps_success_event(struct wps_context *wps, const u8 *mac_addr) 290e5b75505Sopenharmony_ci{ 291e5b75505Sopenharmony_ci union wps_event_data data; 292e5b75505Sopenharmony_ci 293e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 294e5b75505Sopenharmony_ci return; 295e5b75505Sopenharmony_ci 296e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 297e5b75505Sopenharmony_ci os_memcpy(data.success.peer_macaddr, mac_addr, ETH_ALEN); 298e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, &data); 299e5b75505Sopenharmony_ci} 300e5b75505Sopenharmony_ci 301e5b75505Sopenharmony_ci 302e5b75505Sopenharmony_civoid wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part, 303e5b75505Sopenharmony_ci const u8 *mac_addr) 304e5b75505Sopenharmony_ci{ 305e5b75505Sopenharmony_ci union wps_event_data data; 306e5b75505Sopenharmony_ci 307e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 308e5b75505Sopenharmony_ci return; 309e5b75505Sopenharmony_ci 310e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 311e5b75505Sopenharmony_ci data.pwd_auth_fail.enrollee = enrollee; 312e5b75505Sopenharmony_ci data.pwd_auth_fail.part = part; 313e5b75505Sopenharmony_ci os_memcpy(data.pwd_auth_fail.peer_macaddr, mac_addr, ETH_ALEN); 314e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data); 315e5b75505Sopenharmony_ci} 316e5b75505Sopenharmony_ci 317e5b75505Sopenharmony_ci 318e5b75505Sopenharmony_civoid wps_pbc_overlap_event(struct wps_context *wps) 319e5b75505Sopenharmony_ci{ 320e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 321e5b75505Sopenharmony_ci return; 322e5b75505Sopenharmony_ci 323e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL); 324e5b75505Sopenharmony_ci} 325e5b75505Sopenharmony_ci 326e5b75505Sopenharmony_ci 327e5b75505Sopenharmony_civoid wps_pbc_timeout_event(struct wps_context *wps) 328e5b75505Sopenharmony_ci{ 329e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 330e5b75505Sopenharmony_ci return; 331e5b75505Sopenharmony_ci 332e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL); 333e5b75505Sopenharmony_ci} 334e5b75505Sopenharmony_ci 335e5b75505Sopenharmony_ci 336e5b75505Sopenharmony_civoid wps_pbc_active_event(struct wps_context *wps) 337e5b75505Sopenharmony_ci{ 338e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 339e5b75505Sopenharmony_ci return; 340e5b75505Sopenharmony_ci 341e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_PBC_ACTIVE, NULL); 342e5b75505Sopenharmony_ci} 343e5b75505Sopenharmony_ci 344e5b75505Sopenharmony_ci 345e5b75505Sopenharmony_civoid wps_pbc_disable_event(struct wps_context *wps) 346e5b75505Sopenharmony_ci{ 347e5b75505Sopenharmony_ci if (wps->event_cb == NULL) 348e5b75505Sopenharmony_ci return; 349e5b75505Sopenharmony_ci 350e5b75505Sopenharmony_ci wps->event_cb(wps->cb_ctx, WPS_EV_PBC_DISABLE, NULL); 351e5b75505Sopenharmony_ci} 352e5b75505Sopenharmony_ci 353e5b75505Sopenharmony_ci 354e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_OOB 355e5b75505Sopenharmony_ci 356e5b75505Sopenharmony_cistruct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band, 357e5b75505Sopenharmony_ci int channel) 358e5b75505Sopenharmony_ci{ 359e5b75505Sopenharmony_ci struct wps_data data; 360e5b75505Sopenharmony_ci struct wpabuf *plain; 361e5b75505Sopenharmony_ci 362e5b75505Sopenharmony_ci plain = wpabuf_alloc(500); 363e5b75505Sopenharmony_ci if (plain == NULL) { 364e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " 365e5b75505Sopenharmony_ci "credential"); 366e5b75505Sopenharmony_ci return NULL; 367e5b75505Sopenharmony_ci } 368e5b75505Sopenharmony_ci 369e5b75505Sopenharmony_ci os_memset(&data, 0, sizeof(data)); 370e5b75505Sopenharmony_ci data.wps = wps; 371e5b75505Sopenharmony_ci data.auth_type = wps->auth_types; 372e5b75505Sopenharmony_ci data.encr_type = wps->encr_types; 373e5b75505Sopenharmony_ci if (wps_build_cred(&data, plain) || 374e5b75505Sopenharmony_ci (rf_band && wps_build_rf_bands_attr(plain, rf_band)) || 375e5b75505Sopenharmony_ci (channel && wps_build_ap_channel(plain, channel)) || 376e5b75505Sopenharmony_ci wps_build_mac_addr(plain, wps->dev.mac_addr) || 377e5b75505Sopenharmony_ci wps_build_wfa_ext(plain, 0, NULL, 0, 0)) { 378e5b75505Sopenharmony_ci os_free(data.new_psk); 379e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 380e5b75505Sopenharmony_ci return NULL; 381e5b75505Sopenharmony_ci } 382e5b75505Sopenharmony_ci 383e5b75505Sopenharmony_ci if (wps->wps_state == WPS_STATE_NOT_CONFIGURED && data.new_psk && 384e5b75505Sopenharmony_ci wps->ap) { 385e5b75505Sopenharmony_ci struct wps_credential cred; 386e5b75505Sopenharmony_ci 387e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based " 388e5b75505Sopenharmony_ci "on credential token generation"); 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_ci os_memset(&cred, 0, sizeof(cred)); 391e5b75505Sopenharmony_ci os_memcpy(cred.ssid, wps->ssid, wps->ssid_len); 392e5b75505Sopenharmony_ci cred.ssid_len = wps->ssid_len; 393e5b75505Sopenharmony_ci cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK; 394e5b75505Sopenharmony_ci cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES; 395e5b75505Sopenharmony_ci os_memcpy(cred.key, data.new_psk, data.new_psk_len); 396e5b75505Sopenharmony_ci cred.key_len = data.new_psk_len; 397e5b75505Sopenharmony_ci 398e5b75505Sopenharmony_ci wps->wps_state = WPS_STATE_CONFIGURED; 399e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, 400e5b75505Sopenharmony_ci "WPS: Generated random passphrase", 401e5b75505Sopenharmony_ci data.new_psk, data.new_psk_len); 402e5b75505Sopenharmony_ci if (wps->cred_cb) 403e5b75505Sopenharmony_ci wps->cred_cb(wps->cb_ctx, &cred); 404e5b75505Sopenharmony_ci } 405e5b75505Sopenharmony_ci 406e5b75505Sopenharmony_ci os_free(data.new_psk); 407e5b75505Sopenharmony_ci 408e5b75505Sopenharmony_ci return plain; 409e5b75505Sopenharmony_ci} 410e5b75505Sopenharmony_ci 411e5b75505Sopenharmony_ci 412e5b75505Sopenharmony_cistruct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, 413e5b75505Sopenharmony_ci const struct wpabuf *pubkey, 414e5b75505Sopenharmony_ci const struct wpabuf *dev_pw) 415e5b75505Sopenharmony_ci{ 416e5b75505Sopenharmony_ci struct wpabuf *data; 417e5b75505Sopenharmony_ci 418e5b75505Sopenharmony_ci data = wpabuf_alloc(200); 419e5b75505Sopenharmony_ci if (data == NULL) 420e5b75505Sopenharmony_ci return NULL; 421e5b75505Sopenharmony_ci 422e5b75505Sopenharmony_ci if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey, 423e5b75505Sopenharmony_ci wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || 424e5b75505Sopenharmony_ci wps_build_wfa_ext(data, 0, NULL, 0, 0)) { 425e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " 426e5b75505Sopenharmony_ci "token"); 427e5b75505Sopenharmony_ci wpabuf_clear_free(data); 428e5b75505Sopenharmony_ci return NULL; 429e5b75505Sopenharmony_ci } 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_ci return data; 432e5b75505Sopenharmony_ci} 433e5b75505Sopenharmony_ci 434e5b75505Sopenharmony_ci 435e5b75505Sopenharmony_ciint wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr) 436e5b75505Sopenharmony_ci{ 437e5b75505Sopenharmony_ci struct wpabuf msg; 438e5b75505Sopenharmony_ci size_t i; 439e5b75505Sopenharmony_ci 440e5b75505Sopenharmony_ci for (i = 0; i < attr->num_cred; i++) { 441e5b75505Sopenharmony_ci struct wps_credential local_cred; 442e5b75505Sopenharmony_ci struct wps_parse_attr cattr; 443e5b75505Sopenharmony_ci 444e5b75505Sopenharmony_ci os_memset(&local_cred, 0, sizeof(local_cred)); 445e5b75505Sopenharmony_ci wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]); 446e5b75505Sopenharmony_ci if (wps_parse_msg(&msg, &cattr) < 0 || 447e5b75505Sopenharmony_ci wps_process_cred(&cattr, &local_cred)) { 448e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " 449e5b75505Sopenharmony_ci "credential"); 450e5b75505Sopenharmony_ci return -1; 451e5b75505Sopenharmony_ci } 452e5b75505Sopenharmony_ci wps->cred_cb(wps->cb_ctx, &local_cred); 453e5b75505Sopenharmony_ci } 454e5b75505Sopenharmony_ci 455e5b75505Sopenharmony_ci return 0; 456e5b75505Sopenharmony_ci} 457e5b75505Sopenharmony_ci 458e5b75505Sopenharmony_ci 459e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_OOB */ 460e5b75505Sopenharmony_ci 461e5b75505Sopenharmony_ci 462e5b75505Sopenharmony_ciint wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]) 463e5b75505Sopenharmony_ci{ 464e5b75505Sopenharmony_ci const char *pos; 465e5b75505Sopenharmony_ci 466e5b75505Sopenharmony_ci /* <categ>-<OUI>-<subcateg> */ 467e5b75505Sopenharmony_ci WPA_PUT_BE16(dev_type, atoi(str)); 468e5b75505Sopenharmony_ci pos = os_strchr(str, '-'); 469e5b75505Sopenharmony_ci if (pos == NULL) 470e5b75505Sopenharmony_ci return -1; 471e5b75505Sopenharmony_ci pos++; 472e5b75505Sopenharmony_ci if (hexstr2bin(pos, &dev_type[2], 4)) 473e5b75505Sopenharmony_ci return -1; 474e5b75505Sopenharmony_ci pos = os_strchr(pos, '-'); 475e5b75505Sopenharmony_ci if (pos == NULL) 476e5b75505Sopenharmony_ci return -1; 477e5b75505Sopenharmony_ci pos++; 478e5b75505Sopenharmony_ci WPA_PUT_BE16(&dev_type[6], atoi(pos)); 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ci 481e5b75505Sopenharmony_ci return 0; 482e5b75505Sopenharmony_ci} 483e5b75505Sopenharmony_ci 484e5b75505Sopenharmony_ci 485e5b75505Sopenharmony_cichar * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, 486e5b75505Sopenharmony_ci size_t buf_len) 487e5b75505Sopenharmony_ci{ 488e5b75505Sopenharmony_ci int ret; 489e5b75505Sopenharmony_ci 490e5b75505Sopenharmony_ci ret = os_snprintf(buf, buf_len, "%u-%08X-%u", 491e5b75505Sopenharmony_ci WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]), 492e5b75505Sopenharmony_ci WPA_GET_BE16(&dev_type[6])); 493e5b75505Sopenharmony_ci if (os_snprintf_error(buf_len, ret)) 494e5b75505Sopenharmony_ci return NULL; 495e5b75505Sopenharmony_ci 496e5b75505Sopenharmony_ci return buf; 497e5b75505Sopenharmony_ci} 498e5b75505Sopenharmony_ci 499e5b75505Sopenharmony_ci 500e5b75505Sopenharmony_civoid uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid) 501e5b75505Sopenharmony_ci{ 502e5b75505Sopenharmony_ci const u8 *addr[2]; 503e5b75505Sopenharmony_ci size_t len[2]; 504e5b75505Sopenharmony_ci u8 hash[SHA1_MAC_LEN]; 505e5b75505Sopenharmony_ci u8 nsid[16] = { 506e5b75505Sopenharmony_ci 0x52, 0x64, 0x80, 0xf8, 507e5b75505Sopenharmony_ci 0xc9, 0x9b, 508e5b75505Sopenharmony_ci 0x4b, 0xe5, 509e5b75505Sopenharmony_ci 0xa6, 0x55, 510e5b75505Sopenharmony_ci 0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84 511e5b75505Sopenharmony_ci }; 512e5b75505Sopenharmony_ci 513e5b75505Sopenharmony_ci addr[0] = nsid; 514e5b75505Sopenharmony_ci len[0] = sizeof(nsid); 515e5b75505Sopenharmony_ci addr[1] = mac_addr; 516e5b75505Sopenharmony_ci len[1] = 6; 517e5b75505Sopenharmony_ci sha1_vector(2, addr, len, hash); 518e5b75505Sopenharmony_ci os_memcpy(uuid, hash, 16); 519e5b75505Sopenharmony_ci 520e5b75505Sopenharmony_ci /* Version: 5 = named-based version using SHA-1 */ 521e5b75505Sopenharmony_ci uuid[6] = (5 << 4) | (uuid[6] & 0x0f); 522e5b75505Sopenharmony_ci 523e5b75505Sopenharmony_ci /* Variant specified in RFC 4122 */ 524e5b75505Sopenharmony_ci uuid[8] = 0x80 | (uuid[8] & 0x3f); 525e5b75505Sopenharmony_ci} 526e5b75505Sopenharmony_ci 527e5b75505Sopenharmony_ci 528e5b75505Sopenharmony_ciu16 wps_config_methods_str2bin(const char *str) 529e5b75505Sopenharmony_ci{ 530e5b75505Sopenharmony_ci u16 methods = 0; 531e5b75505Sopenharmony_ci 532e5b75505Sopenharmony_ci if (str == NULL || str[0] == '\0') { 533e5b75505Sopenharmony_ci /* Default to enabling methods based on build configuration */ 534e5b75505Sopenharmony_ci methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 535e5b75505Sopenharmony_ci methods |= WPS_CONFIG_VIRT_DISPLAY; 536e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 537e5b75505Sopenharmony_ci methods |= WPS_CONFIG_NFC_INTERFACE; 538e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 539e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 540e5b75505Sopenharmony_ci methods |= WPS_CONFIG_P2PS; 541e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 542e5b75505Sopenharmony_ci } else { 543e5b75505Sopenharmony_ci if (os_strstr(str, "ethernet")) 544e5b75505Sopenharmony_ci methods |= WPS_CONFIG_ETHERNET; 545e5b75505Sopenharmony_ci if (os_strstr(str, "label")) 546e5b75505Sopenharmony_ci methods |= WPS_CONFIG_LABEL; 547e5b75505Sopenharmony_ci if (os_strstr(str, "display")) 548e5b75505Sopenharmony_ci methods |= WPS_CONFIG_DISPLAY; 549e5b75505Sopenharmony_ci if (os_strstr(str, "ext_nfc_token")) 550e5b75505Sopenharmony_ci methods |= WPS_CONFIG_EXT_NFC_TOKEN; 551e5b75505Sopenharmony_ci if (os_strstr(str, "int_nfc_token")) 552e5b75505Sopenharmony_ci methods |= WPS_CONFIG_INT_NFC_TOKEN; 553e5b75505Sopenharmony_ci if (os_strstr(str, "nfc_interface")) 554e5b75505Sopenharmony_ci methods |= WPS_CONFIG_NFC_INTERFACE; 555e5b75505Sopenharmony_ci if (os_strstr(str, "push_button")) 556e5b75505Sopenharmony_ci methods |= WPS_CONFIG_PUSHBUTTON; 557e5b75505Sopenharmony_ci if (os_strstr(str, "keypad")) 558e5b75505Sopenharmony_ci methods |= WPS_CONFIG_KEYPAD; 559e5b75505Sopenharmony_ci if (os_strstr(str, "virtual_display")) 560e5b75505Sopenharmony_ci methods |= WPS_CONFIG_VIRT_DISPLAY; 561e5b75505Sopenharmony_ci if (os_strstr(str, "physical_display")) 562e5b75505Sopenharmony_ci methods |= WPS_CONFIG_PHY_DISPLAY; 563e5b75505Sopenharmony_ci if (os_strstr(str, "virtual_push_button")) 564e5b75505Sopenharmony_ci methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 565e5b75505Sopenharmony_ci if (os_strstr(str, "physical_push_button")) 566e5b75505Sopenharmony_ci methods |= WPS_CONFIG_PHY_PUSHBUTTON; 567e5b75505Sopenharmony_ci if (os_strstr(str, "p2ps")) 568e5b75505Sopenharmony_ci methods |= WPS_CONFIG_P2PS; 569e5b75505Sopenharmony_ci } 570e5b75505Sopenharmony_ci 571e5b75505Sopenharmony_ci return methods; 572e5b75505Sopenharmony_ci} 573e5b75505Sopenharmony_ci 574e5b75505Sopenharmony_ci 575e5b75505Sopenharmony_cistruct wpabuf * wps_build_wsc_ack(struct wps_data *wps) 576e5b75505Sopenharmony_ci{ 577e5b75505Sopenharmony_ci struct wpabuf *msg; 578e5b75505Sopenharmony_ci 579e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK"); 580e5b75505Sopenharmony_ci 581e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 582e5b75505Sopenharmony_ci if (msg == NULL) 583e5b75505Sopenharmony_ci return NULL; 584e5b75505Sopenharmony_ci 585e5b75505Sopenharmony_ci if (wps_build_version(msg) || 586e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_WSC_ACK) || 587e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 588e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 589e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 590e5b75505Sopenharmony_ci wpabuf_free(msg); 591e5b75505Sopenharmony_ci return NULL; 592e5b75505Sopenharmony_ci } 593e5b75505Sopenharmony_ci 594e5b75505Sopenharmony_ci return msg; 595e5b75505Sopenharmony_ci} 596e5b75505Sopenharmony_ci 597e5b75505Sopenharmony_ci 598e5b75505Sopenharmony_cistruct wpabuf * wps_build_wsc_nack(struct wps_data *wps) 599e5b75505Sopenharmony_ci{ 600e5b75505Sopenharmony_ci struct wpabuf *msg; 601e5b75505Sopenharmony_ci 602e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK"); 603e5b75505Sopenharmony_ci 604e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 605e5b75505Sopenharmony_ci if (msg == NULL) 606e5b75505Sopenharmony_ci return NULL; 607e5b75505Sopenharmony_ci 608e5b75505Sopenharmony_ci if (wps_build_version(msg) || 609e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_WSC_NACK) || 610e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 611e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 612e5b75505Sopenharmony_ci wps_build_config_error(msg, wps->config_error) || 613e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 614e5b75505Sopenharmony_ci wpabuf_free(msg); 615e5b75505Sopenharmony_ci return NULL; 616e5b75505Sopenharmony_ci } 617e5b75505Sopenharmony_ci 618e5b75505Sopenharmony_ci return msg; 619e5b75505Sopenharmony_ci} 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_ci 622e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 623e5b75505Sopenharmony_ci 624e5b75505Sopenharmony_cistruct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey, 625e5b75505Sopenharmony_ci struct wpabuf *dev_pw) 626e5b75505Sopenharmony_ci{ 627e5b75505Sopenharmony_ci struct wpabuf *ret; 628e5b75505Sopenharmony_ci 629e5b75505Sopenharmony_ci if (pubkey == NULL || dev_pw == NULL) 630e5b75505Sopenharmony_ci return NULL; 631e5b75505Sopenharmony_ci 632e5b75505Sopenharmony_ci ret = wps_build_nfc_pw_token(id, pubkey, dev_pw); 633e5b75505Sopenharmony_ci if (ndef && ret) { 634e5b75505Sopenharmony_ci struct wpabuf *tmp; 635e5b75505Sopenharmony_ci tmp = ndef_build_wifi(ret); 636e5b75505Sopenharmony_ci wpabuf_free(ret); 637e5b75505Sopenharmony_ci if (tmp == NULL) 638e5b75505Sopenharmony_ci return NULL; 639e5b75505Sopenharmony_ci ret = tmp; 640e5b75505Sopenharmony_ci } 641e5b75505Sopenharmony_ci 642e5b75505Sopenharmony_ci return ret; 643e5b75505Sopenharmony_ci} 644e5b75505Sopenharmony_ci 645e5b75505Sopenharmony_ci 646e5b75505Sopenharmony_ciint wps_nfc_gen_dh(struct wpabuf **pubkey, struct wpabuf **privkey) 647e5b75505Sopenharmony_ci{ 648e5b75505Sopenharmony_ci struct wpabuf *priv = NULL, *pub = NULL; 649e5b75505Sopenharmony_ci void *dh_ctx; 650e5b75505Sopenharmony_ci 651e5b75505Sopenharmony_ci dh_ctx = dh5_init(&priv, &pub); 652e5b75505Sopenharmony_ci if (dh_ctx == NULL) 653e5b75505Sopenharmony_ci return -1; 654e5b75505Sopenharmony_ci pub = wpabuf_zeropad(pub, 192); 655e5b75505Sopenharmony_ci if (pub == NULL) { 656e5b75505Sopenharmony_ci wpabuf_free(priv); 657e5b75505Sopenharmony_ci dh5_free(dh_ctx); 658e5b75505Sopenharmony_ci return -1; 659e5b75505Sopenharmony_ci } 660e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "WPS: Generated new DH pubkey", pub); 661e5b75505Sopenharmony_ci dh5_free(dh_ctx); 662e5b75505Sopenharmony_ci 663e5b75505Sopenharmony_ci wpabuf_free(*pubkey); 664e5b75505Sopenharmony_ci *pubkey = pub; 665e5b75505Sopenharmony_ci wpabuf_clear_free(*privkey); 666e5b75505Sopenharmony_ci *privkey = priv; 667e5b75505Sopenharmony_ci 668e5b75505Sopenharmony_ci return 0; 669e5b75505Sopenharmony_ci} 670e5b75505Sopenharmony_ci 671e5b75505Sopenharmony_ci 672e5b75505Sopenharmony_cistruct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, 673e5b75505Sopenharmony_ci struct wpabuf **privkey, 674e5b75505Sopenharmony_ci struct wpabuf **dev_pw) 675e5b75505Sopenharmony_ci{ 676e5b75505Sopenharmony_ci struct wpabuf *pw; 677e5b75505Sopenharmony_ci u16 val; 678e5b75505Sopenharmony_ci 679e5b75505Sopenharmony_ci pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN); 680e5b75505Sopenharmony_ci if (pw == NULL) 681e5b75505Sopenharmony_ci return NULL; 682e5b75505Sopenharmony_ci 683e5b75505Sopenharmony_ci if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN), 684e5b75505Sopenharmony_ci WPS_OOB_DEVICE_PASSWORD_LEN) || 685e5b75505Sopenharmony_ci random_get_bytes((u8 *) &val, sizeof(val))) { 686e5b75505Sopenharmony_ci wpabuf_free(pw); 687e5b75505Sopenharmony_ci return NULL; 688e5b75505Sopenharmony_ci } 689e5b75505Sopenharmony_ci 690e5b75505Sopenharmony_ci if (wps_nfc_gen_dh(pubkey, privkey) < 0) { 691e5b75505Sopenharmony_ci wpabuf_free(pw); 692e5b75505Sopenharmony_ci return NULL; 693e5b75505Sopenharmony_ci } 694e5b75505Sopenharmony_ci 695e5b75505Sopenharmony_ci *id = 0x10 + val % 0xfff0; 696e5b75505Sopenharmony_ci wpabuf_clear_free(*dev_pw); 697e5b75505Sopenharmony_ci *dev_pw = pw; 698e5b75505Sopenharmony_ci 699e5b75505Sopenharmony_ci return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw); 700e5b75505Sopenharmony_ci} 701e5b75505Sopenharmony_ci 702e5b75505Sopenharmony_ci 703e5b75505Sopenharmony_cistruct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx, 704e5b75505Sopenharmony_ci struct wpabuf *nfc_dh_pubkey) 705e5b75505Sopenharmony_ci{ 706e5b75505Sopenharmony_ci struct wpabuf *msg; 707e5b75505Sopenharmony_ci void *len; 708e5b75505Sopenharmony_ci 709e5b75505Sopenharmony_ci if (ctx == NULL) 710e5b75505Sopenharmony_ci return NULL; 711e5b75505Sopenharmony_ci 712e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 713e5b75505Sopenharmony_ci "handover request"); 714e5b75505Sopenharmony_ci 715e5b75505Sopenharmony_ci if (nfc_dh_pubkey == NULL) { 716e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 717e5b75505Sopenharmony_ci "configured"); 718e5b75505Sopenharmony_ci return NULL; 719e5b75505Sopenharmony_ci } 720e5b75505Sopenharmony_ci 721e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 722e5b75505Sopenharmony_ci if (msg == NULL) 723e5b75505Sopenharmony_ci return msg; 724e5b75505Sopenharmony_ci len = wpabuf_put(msg, 2); 725e5b75505Sopenharmony_ci 726e5b75505Sopenharmony_ci if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 727e5b75505Sopenharmony_ci nfc_dh_pubkey, NULL, 0) || 728e5b75505Sopenharmony_ci wps_build_uuid_e(msg, ctx->uuid) || 729e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 730e5b75505Sopenharmony_ci wpabuf_free(msg); 731e5b75505Sopenharmony_ci return NULL; 732e5b75505Sopenharmony_ci } 733e5b75505Sopenharmony_ci 734e5b75505Sopenharmony_ci WPA_PUT_BE16(len, wpabuf_len(msg) - 2); 735e5b75505Sopenharmony_ci 736e5b75505Sopenharmony_ci return msg; 737e5b75505Sopenharmony_ci} 738e5b75505Sopenharmony_ci 739e5b75505Sopenharmony_ci 740e5b75505Sopenharmony_cistatic int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps) 741e5b75505Sopenharmony_ci{ 742e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * SSID"); 743e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select", 744e5b75505Sopenharmony_ci wps->ssid, wps->ssid_len); 745e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_SSID); 746e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wps->ssid_len); 747e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->ssid, wps->ssid_len); 748e5b75505Sopenharmony_ci return 0; 749e5b75505Sopenharmony_ci} 750e5b75505Sopenharmony_ci 751e5b75505Sopenharmony_ci 752e5b75505Sopenharmony_cistatic int wps_build_ap_freq(struct wpabuf *msg, int freq) 753e5b75505Sopenharmony_ci{ 754e5b75505Sopenharmony_ci enum hostapd_hw_mode mode; 755e5b75505Sopenharmony_ci u8 channel, rf_band; 756e5b75505Sopenharmony_ci u16 ap_channel; 757e5b75505Sopenharmony_ci 758e5b75505Sopenharmony_ci if (freq <= 0) 759e5b75505Sopenharmony_ci return 0; 760e5b75505Sopenharmony_ci 761e5b75505Sopenharmony_ci mode = ieee80211_freq_to_chan(freq, &channel); 762e5b75505Sopenharmony_ci if (mode == NUM_HOSTAPD_MODES) 763e5b75505Sopenharmony_ci return 0; /* Unknown channel */ 764e5b75505Sopenharmony_ci 765e5b75505Sopenharmony_ci if (mode == HOSTAPD_MODE_IEEE80211G || mode == HOSTAPD_MODE_IEEE80211B) 766e5b75505Sopenharmony_ci rf_band = WPS_RF_24GHZ; 767e5b75505Sopenharmony_ci else if (mode == HOSTAPD_MODE_IEEE80211A) 768e5b75505Sopenharmony_ci rf_band = WPS_RF_50GHZ; 769e5b75505Sopenharmony_ci else if (mode == HOSTAPD_MODE_IEEE80211AD) 770e5b75505Sopenharmony_ci rf_band = WPS_RF_60GHZ; 771e5b75505Sopenharmony_ci else 772e5b75505Sopenharmony_ci return 0; /* Unknown band */ 773e5b75505Sopenharmony_ci ap_channel = channel; 774e5b75505Sopenharmony_ci 775e5b75505Sopenharmony_ci if (wps_build_rf_bands_attr(msg, rf_band) || 776e5b75505Sopenharmony_ci wps_build_ap_channel(msg, ap_channel)) 777e5b75505Sopenharmony_ci return -1; 778e5b75505Sopenharmony_ci 779e5b75505Sopenharmony_ci return 0; 780e5b75505Sopenharmony_ci} 781e5b75505Sopenharmony_ci 782e5b75505Sopenharmony_ci 783e5b75505Sopenharmony_cistruct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx, 784e5b75505Sopenharmony_ci struct wpabuf *nfc_dh_pubkey, 785e5b75505Sopenharmony_ci const u8 *bssid, int freq) 786e5b75505Sopenharmony_ci{ 787e5b75505Sopenharmony_ci struct wpabuf *msg; 788e5b75505Sopenharmony_ci void *len; 789e5b75505Sopenharmony_ci 790e5b75505Sopenharmony_ci if (ctx == NULL) 791e5b75505Sopenharmony_ci return NULL; 792e5b75505Sopenharmony_ci 793e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 794e5b75505Sopenharmony_ci "handover select"); 795e5b75505Sopenharmony_ci 796e5b75505Sopenharmony_ci if (nfc_dh_pubkey == NULL) { 797e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 798e5b75505Sopenharmony_ci "configured"); 799e5b75505Sopenharmony_ci return NULL; 800e5b75505Sopenharmony_ci } 801e5b75505Sopenharmony_ci 802e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 803e5b75505Sopenharmony_ci if (msg == NULL) 804e5b75505Sopenharmony_ci return msg; 805e5b75505Sopenharmony_ci len = wpabuf_put(msg, 2); 806e5b75505Sopenharmony_ci 807e5b75505Sopenharmony_ci if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 808e5b75505Sopenharmony_ci nfc_dh_pubkey, NULL, 0) || 809e5b75505Sopenharmony_ci wps_build_ssid(msg, ctx) || 810e5b75505Sopenharmony_ci wps_build_ap_freq(msg, freq) || 811e5b75505Sopenharmony_ci (bssid && wps_build_mac_addr(msg, bssid)) || 812e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 813e5b75505Sopenharmony_ci wpabuf_free(msg); 814e5b75505Sopenharmony_ci return NULL; 815e5b75505Sopenharmony_ci } 816e5b75505Sopenharmony_ci 817e5b75505Sopenharmony_ci WPA_PUT_BE16(len, wpabuf_len(msg) - 2); 818e5b75505Sopenharmony_ci 819e5b75505Sopenharmony_ci return msg; 820e5b75505Sopenharmony_ci} 821e5b75505Sopenharmony_ci 822e5b75505Sopenharmony_ci 823e5b75505Sopenharmony_cistruct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx, 824e5b75505Sopenharmony_ci struct wpabuf *nfc_dh_pubkey) 825e5b75505Sopenharmony_ci{ 826e5b75505Sopenharmony_ci struct wpabuf *msg; 827e5b75505Sopenharmony_ci 828e5b75505Sopenharmony_ci if (ctx == NULL) 829e5b75505Sopenharmony_ci return NULL; 830e5b75505Sopenharmony_ci 831e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 832e5b75505Sopenharmony_ci "handover request (P2P)"); 833e5b75505Sopenharmony_ci 834e5b75505Sopenharmony_ci if (nfc_dh_pubkey == NULL) { 835e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No NFC DH Public Key configured"); 836e5b75505Sopenharmony_ci return NULL; 837e5b75505Sopenharmony_ci } 838e5b75505Sopenharmony_ci 839e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 840e5b75505Sopenharmony_ci if (msg == NULL) 841e5b75505Sopenharmony_ci return msg; 842e5b75505Sopenharmony_ci 843e5b75505Sopenharmony_ci if (wps_build_manufacturer(&ctx->dev, msg) || 844e5b75505Sopenharmony_ci wps_build_model_name(&ctx->dev, msg) || 845e5b75505Sopenharmony_ci wps_build_model_number(&ctx->dev, msg) || 846e5b75505Sopenharmony_ci wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, 847e5b75505Sopenharmony_ci nfc_dh_pubkey, NULL, 0) || 848e5b75505Sopenharmony_ci wps_build_rf_bands(&ctx->dev, msg, 0) || 849e5b75505Sopenharmony_ci wps_build_serial_number(&ctx->dev, msg) || 850e5b75505Sopenharmony_ci wps_build_uuid_e(msg, ctx->uuid) || 851e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 852e5b75505Sopenharmony_ci wpabuf_free(msg); 853e5b75505Sopenharmony_ci return NULL; 854e5b75505Sopenharmony_ci } 855e5b75505Sopenharmony_ci 856e5b75505Sopenharmony_ci return msg; 857e5b75505Sopenharmony_ci} 858e5b75505Sopenharmony_ci 859e5b75505Sopenharmony_ci 860e5b75505Sopenharmony_cistruct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx, 861e5b75505Sopenharmony_ci int nfc_dev_pw_id, 862e5b75505Sopenharmony_ci struct wpabuf *nfc_dh_pubkey, 863e5b75505Sopenharmony_ci struct wpabuf *nfc_dev_pw) 864e5b75505Sopenharmony_ci{ 865e5b75505Sopenharmony_ci struct wpabuf *msg; 866e5b75505Sopenharmony_ci const u8 *dev_pw; 867e5b75505Sopenharmony_ci size_t dev_pw_len; 868e5b75505Sopenharmony_ci 869e5b75505Sopenharmony_ci if (ctx == NULL) 870e5b75505Sopenharmony_ci return NULL; 871e5b75505Sopenharmony_ci 872e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection " 873e5b75505Sopenharmony_ci "handover select (P2P)"); 874e5b75505Sopenharmony_ci 875e5b75505Sopenharmony_ci if (nfc_dh_pubkey == NULL || 876e5b75505Sopenharmony_ci (nfc_dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && 877e5b75505Sopenharmony_ci nfc_dev_pw == NULL)) { 878e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password " 879e5b75505Sopenharmony_ci "configured"); 880e5b75505Sopenharmony_ci return NULL; 881e5b75505Sopenharmony_ci } 882e5b75505Sopenharmony_ci 883e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 884e5b75505Sopenharmony_ci if (msg == NULL) 885e5b75505Sopenharmony_ci return msg; 886e5b75505Sopenharmony_ci 887e5b75505Sopenharmony_ci if (nfc_dev_pw) { 888e5b75505Sopenharmony_ci dev_pw = wpabuf_head(nfc_dev_pw); 889e5b75505Sopenharmony_ci dev_pw_len = wpabuf_len(nfc_dev_pw); 890e5b75505Sopenharmony_ci } else { 891e5b75505Sopenharmony_ci dev_pw = NULL; 892e5b75505Sopenharmony_ci dev_pw_len = 0; 893e5b75505Sopenharmony_ci } 894e5b75505Sopenharmony_ci 895e5b75505Sopenharmony_ci if (wps_build_manufacturer(&ctx->dev, msg) || 896e5b75505Sopenharmony_ci wps_build_model_name(&ctx->dev, msg) || 897e5b75505Sopenharmony_ci wps_build_model_number(&ctx->dev, msg) || 898e5b75505Sopenharmony_ci wps_build_oob_dev_pw(msg, nfc_dev_pw_id, nfc_dh_pubkey, 899e5b75505Sopenharmony_ci dev_pw, dev_pw_len) || 900e5b75505Sopenharmony_ci wps_build_rf_bands(&ctx->dev, msg, 0) || 901e5b75505Sopenharmony_ci wps_build_serial_number(&ctx->dev, msg) || 902e5b75505Sopenharmony_ci wps_build_uuid_e(msg, ctx->uuid) || 903e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 904e5b75505Sopenharmony_ci wpabuf_free(msg); 905e5b75505Sopenharmony_ci return NULL; 906e5b75505Sopenharmony_ci } 907e5b75505Sopenharmony_ci 908e5b75505Sopenharmony_ci return msg; 909e5b75505Sopenharmony_ci} 910e5b75505Sopenharmony_ci 911e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 912