1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Protected Setup - Registrar 3e5b75505Sopenharmony_ci * Copyright (c) 2008-2016, 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 "utils/includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "utils/common.h" 12e5b75505Sopenharmony_ci#include "utils/base64.h" 13e5b75505Sopenharmony_ci#include "utils/eloop.h" 14e5b75505Sopenharmony_ci#include "utils/uuid.h" 15e5b75505Sopenharmony_ci#include "utils/list.h" 16e5b75505Sopenharmony_ci#include "crypto/crypto.h" 17e5b75505Sopenharmony_ci#include "crypto/sha256.h" 18e5b75505Sopenharmony_ci#include "crypto/random.h" 19e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 20e5b75505Sopenharmony_ci#include "wps_i.h" 21e5b75505Sopenharmony_ci#include "wps_dev_attr.h" 22e5b75505Sopenharmony_ci#include "wps_upnp.h" 23e5b75505Sopenharmony_ci#include "wps_upnp_i.h" 24e5b75505Sopenharmony_ci 25e5b75505Sopenharmony_ci#ifndef CONFIG_WPS_STRICT 26e5b75505Sopenharmony_ci#define WPS_WORKAROUNDS 27e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */ 28e5b75505Sopenharmony_ci 29e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 30e5b75505Sopenharmony_ci 31e5b75505Sopenharmony_cistruct wps_nfc_pw_token { 32e5b75505Sopenharmony_ci struct dl_list list; 33e5b75505Sopenharmony_ci u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN]; 34e5b75505Sopenharmony_ci unsigned int peer_pk_hash_known:1; 35e5b75505Sopenharmony_ci u16 pw_id; 36e5b75505Sopenharmony_ci u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1]; 37e5b75505Sopenharmony_ci size_t dev_pw_len; 38e5b75505Sopenharmony_ci int pk_hash_provided_oob; /* whether own PK hash was provided OOB */ 39e5b75505Sopenharmony_ci}; 40e5b75505Sopenharmony_ci 41e5b75505Sopenharmony_ci 42e5b75505Sopenharmony_cistatic void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token) 43e5b75505Sopenharmony_ci{ 44e5b75505Sopenharmony_ci dl_list_del(&token->list); 45e5b75505Sopenharmony_ci bin_clear_free(token, sizeof(*token)); 46e5b75505Sopenharmony_ci} 47e5b75505Sopenharmony_ci 48e5b75505Sopenharmony_ci 49e5b75505Sopenharmony_cistatic void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id) 50e5b75505Sopenharmony_ci{ 51e5b75505Sopenharmony_ci struct wps_nfc_pw_token *token, *prev; 52e5b75505Sopenharmony_ci dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token, 53e5b75505Sopenharmony_ci list) { 54e5b75505Sopenharmony_ci if (pw_id == 0 || pw_id == token->pw_id) 55e5b75505Sopenharmony_ci wps_remove_nfc_pw_token(token); 56e5b75505Sopenharmony_ci } 57e5b75505Sopenharmony_ci} 58e5b75505Sopenharmony_ci 59e5b75505Sopenharmony_ci 60e5b75505Sopenharmony_cistatic struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens, 61e5b75505Sopenharmony_ci u16 pw_id) 62e5b75505Sopenharmony_ci{ 63e5b75505Sopenharmony_ci struct wps_nfc_pw_token *token; 64e5b75505Sopenharmony_ci dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) { 65e5b75505Sopenharmony_ci if (pw_id == token->pw_id) 66e5b75505Sopenharmony_ci return token; 67e5b75505Sopenharmony_ci } 68e5b75505Sopenharmony_ci return NULL; 69e5b75505Sopenharmony_ci} 70e5b75505Sopenharmony_ci 71e5b75505Sopenharmony_ci#else /* CONFIG_WPS_NFC */ 72e5b75505Sopenharmony_ci 73e5b75505Sopenharmony_ci#define wps_free_nfc_pw_tokens(t, p) do { } while (0) 74e5b75505Sopenharmony_ci 75e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 76e5b75505Sopenharmony_ci 77e5b75505Sopenharmony_ci 78e5b75505Sopenharmony_cistruct wps_uuid_pin { 79e5b75505Sopenharmony_ci struct dl_list list; 80e5b75505Sopenharmony_ci u8 uuid[WPS_UUID_LEN]; 81e5b75505Sopenharmony_ci int wildcard_uuid; 82e5b75505Sopenharmony_ci u8 *pin; 83e5b75505Sopenharmony_ci size_t pin_len; 84e5b75505Sopenharmony_ci#define PIN_LOCKED BIT(0) 85e5b75505Sopenharmony_ci#define PIN_EXPIRES BIT(1) 86e5b75505Sopenharmony_ci int flags; 87e5b75505Sopenharmony_ci struct os_reltime expiration; 88e5b75505Sopenharmony_ci u8 enrollee_addr[ETH_ALEN]; 89e5b75505Sopenharmony_ci}; 90e5b75505Sopenharmony_ci 91e5b75505Sopenharmony_ci 92e5b75505Sopenharmony_cistatic void wps_free_pin(struct wps_uuid_pin *pin) 93e5b75505Sopenharmony_ci{ 94e5b75505Sopenharmony_ci bin_clear_free(pin->pin, pin->pin_len); 95e5b75505Sopenharmony_ci os_free(pin); 96e5b75505Sopenharmony_ci} 97e5b75505Sopenharmony_ci 98e5b75505Sopenharmony_ci 99e5b75505Sopenharmony_cistatic void wps_remove_pin(struct wps_uuid_pin *pin) 100e5b75505Sopenharmony_ci{ 101e5b75505Sopenharmony_ci dl_list_del(&pin->list); 102e5b75505Sopenharmony_ci wps_free_pin(pin); 103e5b75505Sopenharmony_ci} 104e5b75505Sopenharmony_ci 105e5b75505Sopenharmony_ci 106e5b75505Sopenharmony_cistatic void wps_free_pins(struct dl_list *pins) 107e5b75505Sopenharmony_ci{ 108e5b75505Sopenharmony_ci struct wps_uuid_pin *pin, *prev; 109e5b75505Sopenharmony_ci dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list) 110e5b75505Sopenharmony_ci wps_remove_pin(pin); 111e5b75505Sopenharmony_ci} 112e5b75505Sopenharmony_ci 113e5b75505Sopenharmony_ci 114e5b75505Sopenharmony_cistruct wps_pbc_session { 115e5b75505Sopenharmony_ci struct wps_pbc_session *next; 116e5b75505Sopenharmony_ci u8 addr[ETH_ALEN]; 117e5b75505Sopenharmony_ci u8 uuid_e[WPS_UUID_LEN]; 118e5b75505Sopenharmony_ci struct os_reltime timestamp; 119e5b75505Sopenharmony_ci}; 120e5b75505Sopenharmony_ci 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_cistatic void wps_free_pbc_sessions(struct wps_pbc_session *pbc) 123e5b75505Sopenharmony_ci{ 124e5b75505Sopenharmony_ci struct wps_pbc_session *prev; 125e5b75505Sopenharmony_ci 126e5b75505Sopenharmony_ci while (pbc) { 127e5b75505Sopenharmony_ci prev = pbc; 128e5b75505Sopenharmony_ci pbc = pbc->next; 129e5b75505Sopenharmony_ci os_free(prev); 130e5b75505Sopenharmony_ci } 131e5b75505Sopenharmony_ci} 132e5b75505Sopenharmony_ci 133e5b75505Sopenharmony_ci 134e5b75505Sopenharmony_cistruct wps_registrar_device { 135e5b75505Sopenharmony_ci struct wps_registrar_device *next; 136e5b75505Sopenharmony_ci struct wps_device_data dev; 137e5b75505Sopenharmony_ci u8 uuid[WPS_UUID_LEN]; 138e5b75505Sopenharmony_ci}; 139e5b75505Sopenharmony_ci 140e5b75505Sopenharmony_ci 141e5b75505Sopenharmony_cistruct wps_registrar { 142e5b75505Sopenharmony_ci struct wps_context *wps; 143e5b75505Sopenharmony_ci 144e5b75505Sopenharmony_ci int pbc; 145e5b75505Sopenharmony_ci int selected_registrar; 146e5b75505Sopenharmony_ci 147e5b75505Sopenharmony_ci int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr, 148e5b75505Sopenharmony_ci const u8 *psk, size_t psk_len); 149e5b75505Sopenharmony_ci int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie, 150e5b75505Sopenharmony_ci struct wpabuf *probe_resp_ie); 151e5b75505Sopenharmony_ci void (*pin_needed_cb)(void *ctx, const u8 *uuid_e, 152e5b75505Sopenharmony_ci const struct wps_device_data *dev); 153e5b75505Sopenharmony_ci void (*reg_success_cb)(void *ctx, const u8 *mac_addr, 154e5b75505Sopenharmony_ci const u8 *uuid_e, const u8 *dev_pw, 155e5b75505Sopenharmony_ci size_t dev_pw_len); 156e5b75505Sopenharmony_ci void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id, 157e5b75505Sopenharmony_ci u16 sel_reg_config_methods); 158e5b75505Sopenharmony_ci void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e, 159e5b75505Sopenharmony_ci const u8 *pri_dev_type, u16 config_methods, 160e5b75505Sopenharmony_ci u16 dev_password_id, u8 request_type, 161e5b75505Sopenharmony_ci const char *dev_name); 162e5b75505Sopenharmony_ci void *cb_ctx; 163e5b75505Sopenharmony_ci 164e5b75505Sopenharmony_ci struct dl_list pins; 165e5b75505Sopenharmony_ci struct dl_list nfc_pw_tokens; 166e5b75505Sopenharmony_ci struct wps_pbc_session *pbc_sessions; 167e5b75505Sopenharmony_ci 168e5b75505Sopenharmony_ci int skip_cred_build; 169e5b75505Sopenharmony_ci struct wpabuf *extra_cred; 170e5b75505Sopenharmony_ci int disable_auto_conf; 171e5b75505Sopenharmony_ci int sel_reg_union; 172e5b75505Sopenharmony_ci int sel_reg_dev_password_id_override; 173e5b75505Sopenharmony_ci int sel_reg_config_methods_override; 174e5b75505Sopenharmony_ci int static_wep_only; 175e5b75505Sopenharmony_ci int dualband; 176e5b75505Sopenharmony_ci int force_per_enrollee_psk; 177e5b75505Sopenharmony_ci 178e5b75505Sopenharmony_ci struct wps_registrar_device *devices; 179e5b75505Sopenharmony_ci 180e5b75505Sopenharmony_ci int force_pbc_overlap; 181e5b75505Sopenharmony_ci 182e5b75505Sopenharmony_ci u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; 183e5b75505Sopenharmony_ci u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; 184e5b75505Sopenharmony_ci 185e5b75505Sopenharmony_ci u8 p2p_dev_addr[ETH_ALEN]; 186e5b75505Sopenharmony_ci 187e5b75505Sopenharmony_ci u8 pbc_ignore_uuid[WPS_UUID_LEN]; 188e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 189e5b75505Sopenharmony_ci struct os_reltime pbc_ignore_start; 190e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 191e5b75505Sopenharmony_ci 192e5b75505Sopenharmony_ci /** 193e5b75505Sopenharmony_ci * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul 194e5b75505Sopenharmony_ci * enrollee 195e5b75505Sopenharmony_ci * 196e5b75505Sopenharmony_ci * This SSID is used by the Registrar to fill in information for 197e5b75505Sopenharmony_ci * Credentials when the enrollee advertises it is a Multi-AP backhaul 198e5b75505Sopenharmony_ci * STA. 199e5b75505Sopenharmony_ci */ 200e5b75505Sopenharmony_ci u8 multi_ap_backhaul_ssid[SSID_MAX_LEN]; 201e5b75505Sopenharmony_ci 202e5b75505Sopenharmony_ci /** 203e5b75505Sopenharmony_ci * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in 204e5b75505Sopenharmony_ci * octets 205e5b75505Sopenharmony_ci */ 206e5b75505Sopenharmony_ci size_t multi_ap_backhaul_ssid_len; 207e5b75505Sopenharmony_ci 208e5b75505Sopenharmony_ci /** 209e5b75505Sopenharmony_ci * multi_ap_backhaul_network_key - The Network Key (PSK) for the 210e5b75505Sopenharmony_ci * Multi-AP backhaul enrollee. 211e5b75505Sopenharmony_ci * 212e5b75505Sopenharmony_ci * This key can be either the ASCII passphrase (8..63 characters) or the 213e5b75505Sopenharmony_ci * 32-octet PSK (64 hex characters). 214e5b75505Sopenharmony_ci */ 215e5b75505Sopenharmony_ci u8 *multi_ap_backhaul_network_key; 216e5b75505Sopenharmony_ci 217e5b75505Sopenharmony_ci /** 218e5b75505Sopenharmony_ci * multi_ap_backhaul_network_key_len - Length of 219e5b75505Sopenharmony_ci * multi_ap_backhaul_network_key in octets 220e5b75505Sopenharmony_ci */ 221e5b75505Sopenharmony_ci size_t multi_ap_backhaul_network_key_len; 222e5b75505Sopenharmony_ci}; 223e5b75505Sopenharmony_ci 224e5b75505Sopenharmony_ci 225e5b75505Sopenharmony_cistatic int wps_set_ie(struct wps_registrar *reg); 226e5b75505Sopenharmony_cistatic void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx); 227e5b75505Sopenharmony_cistatic void wps_registrar_set_selected_timeout(void *eloop_ctx, 228e5b75505Sopenharmony_ci void *timeout_ctx); 229e5b75505Sopenharmony_cistatic void wps_registrar_remove_pin(struct wps_registrar *reg, 230e5b75505Sopenharmony_ci struct wps_uuid_pin *pin); 231e5b75505Sopenharmony_ci 232e5b75505Sopenharmony_ci 233e5b75505Sopenharmony_cistatic void wps_registrar_add_authorized_mac(struct wps_registrar *reg, 234e5b75505Sopenharmony_ci const u8 *addr) 235e5b75505Sopenharmony_ci{ 236e5b75505Sopenharmony_ci int i; 237e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR, 238e5b75505Sopenharmony_ci MAC2STR(addr)); 239e5b75505Sopenharmony_ci for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) 240e5b75505Sopenharmony_ci if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) { 241e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was " 242e5b75505Sopenharmony_ci "already in the list"); 243e5b75505Sopenharmony_ci return; /* already in list */ 244e5b75505Sopenharmony_ci } 245e5b75505Sopenharmony_ci for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--) 246e5b75505Sopenharmony_ci os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1], 247e5b75505Sopenharmony_ci ETH_ALEN); 248e5b75505Sopenharmony_ci os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN); 249e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs", 250e5b75505Sopenharmony_ci (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs)); 251e5b75505Sopenharmony_ci} 252e5b75505Sopenharmony_ci 253e5b75505Sopenharmony_ci 254e5b75505Sopenharmony_cistatic void wps_registrar_remove_authorized_mac(struct wps_registrar *reg, 255e5b75505Sopenharmony_ci const u8 *addr) 256e5b75505Sopenharmony_ci{ 257e5b75505Sopenharmony_ci int i; 258e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR, 259e5b75505Sopenharmony_ci MAC2STR(addr)); 260e5b75505Sopenharmony_ci for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) { 261e5b75505Sopenharmony_ci if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0) 262e5b75505Sopenharmony_ci break; 263e5b75505Sopenharmony_ci } 264e5b75505Sopenharmony_ci if (i == WPS_MAX_AUTHORIZED_MACS) { 265e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the " 266e5b75505Sopenharmony_ci "list"); 267e5b75505Sopenharmony_ci return; /* not in the list */ 268e5b75505Sopenharmony_ci } 269e5b75505Sopenharmony_ci for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++) 270e5b75505Sopenharmony_ci os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1], 271e5b75505Sopenharmony_ci ETH_ALEN); 272e5b75505Sopenharmony_ci os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0, 273e5b75505Sopenharmony_ci ETH_ALEN); 274e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs", 275e5b75505Sopenharmony_ci (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs)); 276e5b75505Sopenharmony_ci} 277e5b75505Sopenharmony_ci 278e5b75505Sopenharmony_ci 279e5b75505Sopenharmony_cistatic void wps_free_devices(struct wps_registrar_device *dev) 280e5b75505Sopenharmony_ci{ 281e5b75505Sopenharmony_ci struct wps_registrar_device *prev; 282e5b75505Sopenharmony_ci 283e5b75505Sopenharmony_ci while (dev) { 284e5b75505Sopenharmony_ci prev = dev; 285e5b75505Sopenharmony_ci dev = dev->next; 286e5b75505Sopenharmony_ci wps_device_data_free(&prev->dev); 287e5b75505Sopenharmony_ci os_free(prev); 288e5b75505Sopenharmony_ci } 289e5b75505Sopenharmony_ci} 290e5b75505Sopenharmony_ci 291e5b75505Sopenharmony_ci 292e5b75505Sopenharmony_cistatic struct wps_registrar_device * wps_device_get(struct wps_registrar *reg, 293e5b75505Sopenharmony_ci const u8 *addr) 294e5b75505Sopenharmony_ci{ 295e5b75505Sopenharmony_ci struct wps_registrar_device *dev; 296e5b75505Sopenharmony_ci 297e5b75505Sopenharmony_ci for (dev = reg->devices; dev; dev = dev->next) { 298e5b75505Sopenharmony_ci if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0) 299e5b75505Sopenharmony_ci return dev; 300e5b75505Sopenharmony_ci } 301e5b75505Sopenharmony_ci return NULL; 302e5b75505Sopenharmony_ci} 303e5b75505Sopenharmony_ci 304e5b75505Sopenharmony_ci 305e5b75505Sopenharmony_cistatic void wps_device_clone_data(struct wps_device_data *dst, 306e5b75505Sopenharmony_ci struct wps_device_data *src) 307e5b75505Sopenharmony_ci{ 308e5b75505Sopenharmony_ci os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN); 309e5b75505Sopenharmony_ci os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN); 310e5b75505Sopenharmony_ci 311e5b75505Sopenharmony_ci#define WPS_STRDUP(n) \ 312e5b75505Sopenharmony_ci os_free(dst->n); \ 313e5b75505Sopenharmony_ci dst->n = src->n ? os_strdup(src->n) : NULL 314e5b75505Sopenharmony_ci 315e5b75505Sopenharmony_ci WPS_STRDUP(device_name); 316e5b75505Sopenharmony_ci WPS_STRDUP(manufacturer); 317e5b75505Sopenharmony_ci WPS_STRDUP(model_name); 318e5b75505Sopenharmony_ci WPS_STRDUP(model_number); 319e5b75505Sopenharmony_ci WPS_STRDUP(serial_number); 320e5b75505Sopenharmony_ci#undef WPS_STRDUP 321e5b75505Sopenharmony_ci} 322e5b75505Sopenharmony_ci 323e5b75505Sopenharmony_ci 324e5b75505Sopenharmony_ciint wps_device_store(struct wps_registrar *reg, 325e5b75505Sopenharmony_ci struct wps_device_data *dev, const u8 *uuid) 326e5b75505Sopenharmony_ci{ 327e5b75505Sopenharmony_ci struct wps_registrar_device *d; 328e5b75505Sopenharmony_ci 329e5b75505Sopenharmony_ci d = wps_device_get(reg, dev->mac_addr); 330e5b75505Sopenharmony_ci if (d == NULL) { 331e5b75505Sopenharmony_ci d = os_zalloc(sizeof(*d)); 332e5b75505Sopenharmony_ci if (d == NULL) 333e5b75505Sopenharmony_ci return -1; 334e5b75505Sopenharmony_ci d->next = reg->devices; 335e5b75505Sopenharmony_ci reg->devices = d; 336e5b75505Sopenharmony_ci } 337e5b75505Sopenharmony_ci 338e5b75505Sopenharmony_ci wps_device_clone_data(&d->dev, dev); 339e5b75505Sopenharmony_ci os_memcpy(d->uuid, uuid, WPS_UUID_LEN); 340e5b75505Sopenharmony_ci 341e5b75505Sopenharmony_ci return 0; 342e5b75505Sopenharmony_ci} 343e5b75505Sopenharmony_ci 344e5b75505Sopenharmony_ci 345e5b75505Sopenharmony_cistatic void wps_registrar_add_pbc_session(struct wps_registrar *reg, 346e5b75505Sopenharmony_ci const u8 *addr, const u8 *uuid_e) 347e5b75505Sopenharmony_ci{ 348e5b75505Sopenharmony_ci struct wps_pbc_session *pbc, *prev = NULL; 349e5b75505Sopenharmony_ci struct os_reltime now; 350e5b75505Sopenharmony_ci 351e5b75505Sopenharmony_ci os_get_reltime(&now); 352e5b75505Sopenharmony_ci 353e5b75505Sopenharmony_ci pbc = reg->pbc_sessions; 354e5b75505Sopenharmony_ci while (pbc) { 355e5b75505Sopenharmony_ci if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 && 356e5b75505Sopenharmony_ci os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { 357e5b75505Sopenharmony_ci if (prev) 358e5b75505Sopenharmony_ci prev->next = pbc->next; 359e5b75505Sopenharmony_ci else 360e5b75505Sopenharmony_ci reg->pbc_sessions = pbc->next; 361e5b75505Sopenharmony_ci break; 362e5b75505Sopenharmony_ci } 363e5b75505Sopenharmony_ci prev = pbc; 364e5b75505Sopenharmony_ci pbc = pbc->next; 365e5b75505Sopenharmony_ci } 366e5b75505Sopenharmony_ci 367e5b75505Sopenharmony_ci if (!pbc) { 368e5b75505Sopenharmony_ci pbc = os_zalloc(sizeof(*pbc)); 369e5b75505Sopenharmony_ci if (pbc == NULL) 370e5b75505Sopenharmony_ci return; 371e5b75505Sopenharmony_ci os_memcpy(pbc->addr, addr, ETH_ALEN); 372e5b75505Sopenharmony_ci if (uuid_e) 373e5b75505Sopenharmony_ci os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN); 374e5b75505Sopenharmony_ci } 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci pbc->next = reg->pbc_sessions; 377e5b75505Sopenharmony_ci reg->pbc_sessions = pbc; 378e5b75505Sopenharmony_ci pbc->timestamp = now; 379e5b75505Sopenharmony_ci 380e5b75505Sopenharmony_ci /* remove entries that have timed out */ 381e5b75505Sopenharmony_ci prev = pbc; 382e5b75505Sopenharmony_ci pbc = pbc->next; 383e5b75505Sopenharmony_ci 384e5b75505Sopenharmony_ci while (pbc) { 385e5b75505Sopenharmony_ci if (os_reltime_expired(&now, &pbc->timestamp, 386e5b75505Sopenharmony_ci WPS_PBC_WALK_TIME)) { 387e5b75505Sopenharmony_ci prev->next = NULL; 388e5b75505Sopenharmony_ci wps_free_pbc_sessions(pbc); 389e5b75505Sopenharmony_ci break; 390e5b75505Sopenharmony_ci } 391e5b75505Sopenharmony_ci prev = pbc; 392e5b75505Sopenharmony_ci pbc = pbc->next; 393e5b75505Sopenharmony_ci } 394e5b75505Sopenharmony_ci} 395e5b75505Sopenharmony_ci 396e5b75505Sopenharmony_ci 397e5b75505Sopenharmony_cistatic void wps_registrar_remove_pbc_session(struct wps_registrar *reg, 398e5b75505Sopenharmony_ci const u8 *uuid_e, 399e5b75505Sopenharmony_ci const u8 *p2p_dev_addr) 400e5b75505Sopenharmony_ci{ 401e5b75505Sopenharmony_ci struct wps_pbc_session *pbc, *prev = NULL, *tmp; 402e5b75505Sopenharmony_ci 403e5b75505Sopenharmony_ci pbc = reg->pbc_sessions; 404e5b75505Sopenharmony_ci while (pbc) { 405e5b75505Sopenharmony_ci if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 || 406e5b75505Sopenharmony_ci (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) && 407e5b75505Sopenharmony_ci os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == 408e5b75505Sopenharmony_ci 0)) { 409e5b75505Sopenharmony_ci if (prev) 410e5b75505Sopenharmony_ci prev->next = pbc->next; 411e5b75505Sopenharmony_ci else 412e5b75505Sopenharmony_ci reg->pbc_sessions = pbc->next; 413e5b75505Sopenharmony_ci tmp = pbc; 414e5b75505Sopenharmony_ci pbc = pbc->next; 415e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for " 416e5b75505Sopenharmony_ci "addr=" MACSTR, MAC2STR(tmp->addr)); 417e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E", 418e5b75505Sopenharmony_ci tmp->uuid_e, WPS_UUID_LEN); 419e5b75505Sopenharmony_ci os_free(tmp); 420e5b75505Sopenharmony_ci continue; 421e5b75505Sopenharmony_ci } 422e5b75505Sopenharmony_ci prev = pbc; 423e5b75505Sopenharmony_ci pbc = pbc->next; 424e5b75505Sopenharmony_ci } 425e5b75505Sopenharmony_ci} 426e5b75505Sopenharmony_ci 427e5b75505Sopenharmony_ci 428e5b75505Sopenharmony_ciint wps_registrar_pbc_overlap(struct wps_registrar *reg, 429e5b75505Sopenharmony_ci const u8 *addr, const u8 *uuid_e) 430e5b75505Sopenharmony_ci{ 431e5b75505Sopenharmony_ci int count = 0; 432e5b75505Sopenharmony_ci struct wps_pbc_session *pbc; 433e5b75505Sopenharmony_ci struct wps_pbc_session *first = NULL; 434e5b75505Sopenharmony_ci struct os_reltime now; 435e5b75505Sopenharmony_ci 436e5b75505Sopenharmony_ci os_get_reltime(&now); 437e5b75505Sopenharmony_ci 438e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap"); 439e5b75505Sopenharmony_ci 440e5b75505Sopenharmony_ci if (uuid_e) { 441e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID"); 442e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID", 443e5b75505Sopenharmony_ci uuid_e, WPS_UUID_LEN); 444e5b75505Sopenharmony_ci count++; 445e5b75505Sopenharmony_ci } 446e5b75505Sopenharmony_ci 447e5b75505Sopenharmony_ci for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) { 448e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR, 449e5b75505Sopenharmony_ci MAC2STR(pbc->addr)); 450e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", 451e5b75505Sopenharmony_ci pbc->uuid_e, WPS_UUID_LEN); 452e5b75505Sopenharmony_ci if (os_reltime_expired(&now, &pbc->timestamp, 453e5b75505Sopenharmony_ci WPS_PBC_WALK_TIME)) { 454e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired"); 455e5b75505Sopenharmony_ci break; 456e5b75505Sopenharmony_ci } 457e5b75505Sopenharmony_ci if (first && 458e5b75505Sopenharmony_ci os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) { 459e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Same Enrollee"); 460e5b75505Sopenharmony_ci continue; /* same Enrollee */ 461e5b75505Sopenharmony_ci } 462e5b75505Sopenharmony_ci if (uuid_e == NULL || 463e5b75505Sopenharmony_ci os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) { 464e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: New Enrollee"); 465e5b75505Sopenharmony_ci count++; 466e5b75505Sopenharmony_ci } 467e5b75505Sopenharmony_ci if (first == NULL) 468e5b75505Sopenharmony_ci first = pbc; 469e5b75505Sopenharmony_ci } 470e5b75505Sopenharmony_ci 471e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count); 472e5b75505Sopenharmony_ci 473e5b75505Sopenharmony_ci return count > 1 ? 1 : 0; 474e5b75505Sopenharmony_ci} 475e5b75505Sopenharmony_ci 476e5b75505Sopenharmony_ci 477e5b75505Sopenharmony_cistatic int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg) 478e5b75505Sopenharmony_ci{ 479e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)", 480e5b75505Sopenharmony_ci wps->wps_state); 481e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_WPS_STATE); 482e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 1); 483e5b75505Sopenharmony_ci wpabuf_put_u8(msg, wps->wps_state); 484e5b75505Sopenharmony_ci return 0; 485e5b75505Sopenharmony_ci} 486e5b75505Sopenharmony_ci 487e5b75505Sopenharmony_ci 488e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 489e5b75505Sopenharmony_cistatic void wps_registrar_free_pending_m2(struct wps_context *wps) 490e5b75505Sopenharmony_ci{ 491e5b75505Sopenharmony_ci struct upnp_pending_message *p, *p2, *prev = NULL; 492e5b75505Sopenharmony_ci p = wps->upnp_msgs; 493e5b75505Sopenharmony_ci while (p) { 494e5b75505Sopenharmony_ci if (p->type == WPS_M2 || p->type == WPS_M2D) { 495e5b75505Sopenharmony_ci if (prev == NULL) 496e5b75505Sopenharmony_ci wps->upnp_msgs = p->next; 497e5b75505Sopenharmony_ci else 498e5b75505Sopenharmony_ci prev->next = p->next; 499e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D"); 500e5b75505Sopenharmony_ci p2 = p; 501e5b75505Sopenharmony_ci p = p->next; 502e5b75505Sopenharmony_ci wpabuf_free(p2->msg); 503e5b75505Sopenharmony_ci os_free(p2); 504e5b75505Sopenharmony_ci continue; 505e5b75505Sopenharmony_ci } 506e5b75505Sopenharmony_ci prev = p; 507e5b75505Sopenharmony_ci p = p->next; 508e5b75505Sopenharmony_ci } 509e5b75505Sopenharmony_ci} 510e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 511e5b75505Sopenharmony_ci 512e5b75505Sopenharmony_ci 513e5b75505Sopenharmony_cistatic int wps_build_ap_setup_locked(struct wps_context *wps, 514e5b75505Sopenharmony_ci struct wpabuf *msg) 515e5b75505Sopenharmony_ci{ 516e5b75505Sopenharmony_ci if (wps->ap_setup_locked && wps->ap_setup_locked != 2) { 517e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * AP Setup Locked"); 518e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED); 519e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 1); 520e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 1); 521e5b75505Sopenharmony_ci } 522e5b75505Sopenharmony_ci return 0; 523e5b75505Sopenharmony_ci} 524e5b75505Sopenharmony_ci 525e5b75505Sopenharmony_ci 526e5b75505Sopenharmony_cistatic int wps_build_selected_registrar(struct wps_registrar *reg, 527e5b75505Sopenharmony_ci struct wpabuf *msg) 528e5b75505Sopenharmony_ci{ 529e5b75505Sopenharmony_ci if (!reg->sel_reg_union) 530e5b75505Sopenharmony_ci return 0; 531e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar"); 532e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR); 533e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 1); 534e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 1); 535e5b75505Sopenharmony_ci return 0; 536e5b75505Sopenharmony_ci} 537e5b75505Sopenharmony_ci 538e5b75505Sopenharmony_ci 539e5b75505Sopenharmony_cistatic int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg, 540e5b75505Sopenharmony_ci struct wpabuf *msg) 541e5b75505Sopenharmony_ci{ 542e5b75505Sopenharmony_ci u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT; 543e5b75505Sopenharmony_ci if (!reg->sel_reg_union) 544e5b75505Sopenharmony_ci return 0; 545e5b75505Sopenharmony_ci if (reg->sel_reg_dev_password_id_override >= 0) 546e5b75505Sopenharmony_ci id = reg->sel_reg_dev_password_id_override; 547e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id); 548e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 549e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 550e5b75505Sopenharmony_ci wpabuf_put_be16(msg, id); 551e5b75505Sopenharmony_ci return 0; 552e5b75505Sopenharmony_ci} 553e5b75505Sopenharmony_ci 554e5b75505Sopenharmony_ci 555e5b75505Sopenharmony_cistatic int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg, 556e5b75505Sopenharmony_ci struct wpabuf *msg) 557e5b75505Sopenharmony_ci{ 558e5b75505Sopenharmony_ci u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT; 559e5b75505Sopenharmony_ci if (!reg->sel_reg_union) 560e5b75505Sopenharmony_ci return 0; 561e5b75505Sopenharmony_ci if (reg->sel_reg_dev_password_id_override >= 0) 562e5b75505Sopenharmony_ci id = reg->sel_reg_dev_password_id_override; 563e5b75505Sopenharmony_ci if (id != DEV_PW_PUSHBUTTON || !reg->dualband) 564e5b75505Sopenharmony_ci return 0; 565e5b75505Sopenharmony_ci return wps_build_uuid_e(msg, reg->wps->uuid); 566e5b75505Sopenharmony_ci} 567e5b75505Sopenharmony_ci 568e5b75505Sopenharmony_ci 569e5b75505Sopenharmony_cistatic void wps_set_pushbutton(u16 *methods, u16 conf_methods) 570e5b75505Sopenharmony_ci{ 571e5b75505Sopenharmony_ci *methods |= WPS_CONFIG_PUSHBUTTON; 572e5b75505Sopenharmony_ci if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) == 573e5b75505Sopenharmony_ci WPS_CONFIG_VIRT_PUSHBUTTON) 574e5b75505Sopenharmony_ci *methods |= WPS_CONFIG_VIRT_PUSHBUTTON; 575e5b75505Sopenharmony_ci if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) == 576e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON) 577e5b75505Sopenharmony_ci *methods |= WPS_CONFIG_PHY_PUSHBUTTON; 578e5b75505Sopenharmony_ci if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) != 579e5b75505Sopenharmony_ci WPS_CONFIG_VIRT_PUSHBUTTON && 580e5b75505Sopenharmony_ci (*methods & WPS_CONFIG_PHY_PUSHBUTTON) != 581e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON) { 582e5b75505Sopenharmony_ci /* 583e5b75505Sopenharmony_ci * Required to include virtual/physical flag, but we were not 584e5b75505Sopenharmony_ci * configured with push button type, so have to default to one 585e5b75505Sopenharmony_ci * of them. 586e5b75505Sopenharmony_ci */ 587e5b75505Sopenharmony_ci *methods |= WPS_CONFIG_PHY_PUSHBUTTON; 588e5b75505Sopenharmony_ci } 589e5b75505Sopenharmony_ci} 590e5b75505Sopenharmony_ci 591e5b75505Sopenharmony_ci 592e5b75505Sopenharmony_cistatic int wps_build_sel_reg_config_methods(struct wps_registrar *reg, 593e5b75505Sopenharmony_ci struct wpabuf *msg) 594e5b75505Sopenharmony_ci{ 595e5b75505Sopenharmony_ci u16 methods; 596e5b75505Sopenharmony_ci if (!reg->sel_reg_union) 597e5b75505Sopenharmony_ci return 0; 598e5b75505Sopenharmony_ci methods = reg->wps->config_methods; 599e5b75505Sopenharmony_ci methods &= ~WPS_CONFIG_PUSHBUTTON; 600e5b75505Sopenharmony_ci methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 601e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON); 602e5b75505Sopenharmony_ci if (reg->pbc) 603e5b75505Sopenharmony_ci wps_set_pushbutton(&methods, reg->wps->config_methods); 604e5b75505Sopenharmony_ci if (reg->sel_reg_config_methods_override >= 0) 605e5b75505Sopenharmony_ci methods = reg->sel_reg_config_methods_override; 606e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar Config Methods (%x)", 607e5b75505Sopenharmony_ci methods); 608e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS); 609e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 610e5b75505Sopenharmony_ci wpabuf_put_be16(msg, methods); 611e5b75505Sopenharmony_ci return 0; 612e5b75505Sopenharmony_ci} 613e5b75505Sopenharmony_ci 614e5b75505Sopenharmony_ci 615e5b75505Sopenharmony_cistatic int wps_build_probe_config_methods(struct wps_registrar *reg, 616e5b75505Sopenharmony_ci struct wpabuf *msg) 617e5b75505Sopenharmony_ci{ 618e5b75505Sopenharmony_ci u16 methods; 619e5b75505Sopenharmony_ci /* 620e5b75505Sopenharmony_ci * These are the methods that the AP supports as an Enrollee for adding 621e5b75505Sopenharmony_ci * external Registrars. 622e5b75505Sopenharmony_ci */ 623e5b75505Sopenharmony_ci methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; 624e5b75505Sopenharmony_ci methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 625e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON); 626e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods); 627e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_CONFIG_METHODS); 628e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 629e5b75505Sopenharmony_ci wpabuf_put_be16(msg, methods); 630e5b75505Sopenharmony_ci return 0; 631e5b75505Sopenharmony_ci} 632e5b75505Sopenharmony_ci 633e5b75505Sopenharmony_ci 634e5b75505Sopenharmony_cistatic int wps_build_config_methods_r(struct wps_registrar *reg, 635e5b75505Sopenharmony_ci struct wpabuf *msg) 636e5b75505Sopenharmony_ci{ 637e5b75505Sopenharmony_ci return wps_build_config_methods(msg, reg->wps->config_methods); 638e5b75505Sopenharmony_ci} 639e5b75505Sopenharmony_ci 640e5b75505Sopenharmony_ci 641e5b75505Sopenharmony_ciconst u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count) 642e5b75505Sopenharmony_ci{ 643e5b75505Sopenharmony_ci *count = 0; 644e5b75505Sopenharmony_ci 645e5b75505Sopenharmony_ci while (*count < WPS_MAX_AUTHORIZED_MACS) { 646e5b75505Sopenharmony_ci if (is_zero_ether_addr(reg->authorized_macs_union[*count])) 647e5b75505Sopenharmony_ci break; 648e5b75505Sopenharmony_ci (*count)++; 649e5b75505Sopenharmony_ci } 650e5b75505Sopenharmony_ci 651e5b75505Sopenharmony_ci return (const u8 *) reg->authorized_macs_union; 652e5b75505Sopenharmony_ci} 653e5b75505Sopenharmony_ci 654e5b75505Sopenharmony_ci 655e5b75505Sopenharmony_ci/** 656e5b75505Sopenharmony_ci * wps_registrar_init - Initialize WPS Registrar data 657e5b75505Sopenharmony_ci * @wps: Pointer to longterm WPS context 658e5b75505Sopenharmony_ci * @cfg: Registrar configuration 659e5b75505Sopenharmony_ci * Returns: Pointer to allocated Registrar data or %NULL on failure 660e5b75505Sopenharmony_ci * 661e5b75505Sopenharmony_ci * This function is used to initialize WPS Registrar functionality. It can be 662e5b75505Sopenharmony_ci * used for a single Registrar run (e.g., when run in a supplicant) or multiple 663e5b75505Sopenharmony_ci * runs (e.g., when run as an internal Registrar in an AP). Caller is 664e5b75505Sopenharmony_ci * responsible for freeing the returned data with wps_registrar_deinit() when 665e5b75505Sopenharmony_ci * Registrar functionality is not needed anymore. 666e5b75505Sopenharmony_ci */ 667e5b75505Sopenharmony_cistruct wps_registrar * 668e5b75505Sopenharmony_ciwps_registrar_init(struct wps_context *wps, 669e5b75505Sopenharmony_ci const struct wps_registrar_config *cfg) 670e5b75505Sopenharmony_ci{ 671e5b75505Sopenharmony_ci struct wps_registrar *reg = os_zalloc(sizeof(*reg)); 672e5b75505Sopenharmony_ci if (reg == NULL) 673e5b75505Sopenharmony_ci return NULL; 674e5b75505Sopenharmony_ci 675e5b75505Sopenharmony_ci dl_list_init(®->pins); 676e5b75505Sopenharmony_ci dl_list_init(®->nfc_pw_tokens); 677e5b75505Sopenharmony_ci reg->wps = wps; 678e5b75505Sopenharmony_ci reg->new_psk_cb = cfg->new_psk_cb; 679e5b75505Sopenharmony_ci reg->set_ie_cb = cfg->set_ie_cb; 680e5b75505Sopenharmony_ci reg->pin_needed_cb = cfg->pin_needed_cb; 681e5b75505Sopenharmony_ci reg->reg_success_cb = cfg->reg_success_cb; 682e5b75505Sopenharmony_ci reg->set_sel_reg_cb = cfg->set_sel_reg_cb; 683e5b75505Sopenharmony_ci reg->enrollee_seen_cb = cfg->enrollee_seen_cb; 684e5b75505Sopenharmony_ci reg->cb_ctx = cfg->cb_ctx; 685e5b75505Sopenharmony_ci reg->skip_cred_build = cfg->skip_cred_build; 686e5b75505Sopenharmony_ci if (cfg->extra_cred) { 687e5b75505Sopenharmony_ci reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred, 688e5b75505Sopenharmony_ci cfg->extra_cred_len); 689e5b75505Sopenharmony_ci if (reg->extra_cred == NULL) { 690e5b75505Sopenharmony_ci os_free(reg); 691e5b75505Sopenharmony_ci return NULL; 692e5b75505Sopenharmony_ci } 693e5b75505Sopenharmony_ci } 694e5b75505Sopenharmony_ci reg->disable_auto_conf = cfg->disable_auto_conf; 695e5b75505Sopenharmony_ci reg->sel_reg_dev_password_id_override = -1; 696e5b75505Sopenharmony_ci reg->sel_reg_config_methods_override = -1; 697e5b75505Sopenharmony_ci reg->static_wep_only = cfg->static_wep_only; 698e5b75505Sopenharmony_ci reg->dualband = cfg->dualband; 699e5b75505Sopenharmony_ci reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk; 700e5b75505Sopenharmony_ci 701e5b75505Sopenharmony_ci if (cfg->multi_ap_backhaul_ssid) { 702e5b75505Sopenharmony_ci os_memcpy(reg->multi_ap_backhaul_ssid, 703e5b75505Sopenharmony_ci cfg->multi_ap_backhaul_ssid, 704e5b75505Sopenharmony_ci cfg->multi_ap_backhaul_ssid_len); 705e5b75505Sopenharmony_ci reg->multi_ap_backhaul_ssid_len = 706e5b75505Sopenharmony_ci cfg->multi_ap_backhaul_ssid_len; 707e5b75505Sopenharmony_ci } 708e5b75505Sopenharmony_ci if (cfg->multi_ap_backhaul_network_key) { 709e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key = 710e5b75505Sopenharmony_ci os_memdup(cfg->multi_ap_backhaul_network_key, 711e5b75505Sopenharmony_ci cfg->multi_ap_backhaul_network_key_len); 712e5b75505Sopenharmony_ci if (reg->multi_ap_backhaul_network_key) 713e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key_len = 714e5b75505Sopenharmony_ci cfg->multi_ap_backhaul_network_key_len; 715e5b75505Sopenharmony_ci } 716e5b75505Sopenharmony_ci 717e5b75505Sopenharmony_ci if (wps_set_ie(reg)) { 718e5b75505Sopenharmony_ci wps_registrar_deinit(reg); 719e5b75505Sopenharmony_ci return NULL; 720e5b75505Sopenharmony_ci } 721e5b75505Sopenharmony_ci 722e5b75505Sopenharmony_ci return reg; 723e5b75505Sopenharmony_ci} 724e5b75505Sopenharmony_ci 725e5b75505Sopenharmony_ci 726e5b75505Sopenharmony_civoid wps_registrar_flush(struct wps_registrar *reg) 727e5b75505Sopenharmony_ci{ 728e5b75505Sopenharmony_ci if (reg == NULL) 729e5b75505Sopenharmony_ci return; 730e5b75505Sopenharmony_ci wps_free_pins(®->pins); 731e5b75505Sopenharmony_ci wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0); 732e5b75505Sopenharmony_ci wps_free_pbc_sessions(reg->pbc_sessions); 733e5b75505Sopenharmony_ci reg->pbc_sessions = NULL; 734e5b75505Sopenharmony_ci wps_free_devices(reg->devices); 735e5b75505Sopenharmony_ci reg->devices = NULL; 736e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 737e5b75505Sopenharmony_ci reg->pbc_ignore_start.sec = 0; 738e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 739e5b75505Sopenharmony_ci} 740e5b75505Sopenharmony_ci 741e5b75505Sopenharmony_ci 742e5b75505Sopenharmony_ci/** 743e5b75505Sopenharmony_ci * wps_registrar_deinit - Deinitialize WPS Registrar data 744e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 745e5b75505Sopenharmony_ci */ 746e5b75505Sopenharmony_civoid wps_registrar_deinit(struct wps_registrar *reg) 747e5b75505Sopenharmony_ci{ 748e5b75505Sopenharmony_ci if (reg == NULL) 749e5b75505Sopenharmony_ci return; 750e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); 751e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); 752e5b75505Sopenharmony_ci wps_registrar_flush(reg); 753e5b75505Sopenharmony_ci wpabuf_clear_free(reg->extra_cred); 754e5b75505Sopenharmony_ci bin_clear_free(reg->multi_ap_backhaul_network_key, 755e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key_len); 756e5b75505Sopenharmony_ci os_free(reg); 757e5b75505Sopenharmony_ci} 758e5b75505Sopenharmony_ci 759e5b75505Sopenharmony_ci 760e5b75505Sopenharmony_cistatic void wps_registrar_invalidate_unused(struct wps_registrar *reg) 761e5b75505Sopenharmony_ci{ 762e5b75505Sopenharmony_ci struct wps_uuid_pin *pin; 763e5b75505Sopenharmony_ci 764e5b75505Sopenharmony_ci dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { 765e5b75505Sopenharmony_ci if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) { 766e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalidate previously " 767e5b75505Sopenharmony_ci "configured wildcard PIN"); 768e5b75505Sopenharmony_ci wps_registrar_remove_pin(reg, pin); 769e5b75505Sopenharmony_ci break; 770e5b75505Sopenharmony_ci } 771e5b75505Sopenharmony_ci } 772e5b75505Sopenharmony_ci} 773e5b75505Sopenharmony_ci 774e5b75505Sopenharmony_ci 775e5b75505Sopenharmony_ci/** 776e5b75505Sopenharmony_ci * wps_registrar_add_pin - Configure a new PIN for Registrar 777e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 778e5b75505Sopenharmony_ci * @addr: Enrollee MAC address or %NULL if not known 779e5b75505Sopenharmony_ci * @uuid: UUID-E or %NULL for wildcard (any UUID) 780e5b75505Sopenharmony_ci * @pin: PIN (Device Password) 781e5b75505Sopenharmony_ci * @pin_len: Length of pin in octets 782e5b75505Sopenharmony_ci * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout 783e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 784e5b75505Sopenharmony_ci */ 785e5b75505Sopenharmony_ciint wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, 786e5b75505Sopenharmony_ci const u8 *uuid, const u8 *pin, size_t pin_len, 787e5b75505Sopenharmony_ci int timeout) 788e5b75505Sopenharmony_ci{ 789e5b75505Sopenharmony_ci struct wps_uuid_pin *p; 790e5b75505Sopenharmony_ci 791e5b75505Sopenharmony_ci p = os_zalloc(sizeof(*p)); 792e5b75505Sopenharmony_ci if (p == NULL) 793e5b75505Sopenharmony_ci return -1; 794e5b75505Sopenharmony_ci if (addr) 795e5b75505Sopenharmony_ci os_memcpy(p->enrollee_addr, addr, ETH_ALEN); 796e5b75505Sopenharmony_ci if (uuid == NULL) 797e5b75505Sopenharmony_ci p->wildcard_uuid = 1; 798e5b75505Sopenharmony_ci else 799e5b75505Sopenharmony_ci os_memcpy(p->uuid, uuid, WPS_UUID_LEN); 800e5b75505Sopenharmony_ci p->pin = os_memdup(pin, pin_len); 801e5b75505Sopenharmony_ci if (p->pin == NULL) { 802e5b75505Sopenharmony_ci os_free(p); 803e5b75505Sopenharmony_ci return -1; 804e5b75505Sopenharmony_ci } 805e5b75505Sopenharmony_ci p->pin_len = pin_len; 806e5b75505Sopenharmony_ci 807e5b75505Sopenharmony_ci if (timeout) { 808e5b75505Sopenharmony_ci p->flags |= PIN_EXPIRES; 809e5b75505Sopenharmony_ci os_get_reltime(&p->expiration); 810e5b75505Sopenharmony_ci p->expiration.sec += timeout; 811e5b75505Sopenharmony_ci } 812e5b75505Sopenharmony_ci 813e5b75505Sopenharmony_ci if (p->wildcard_uuid) 814e5b75505Sopenharmony_ci wps_registrar_invalidate_unused(reg); 815e5b75505Sopenharmony_ci 816e5b75505Sopenharmony_ci dl_list_add(®->pins, &p->list); 817e5b75505Sopenharmony_ci 818e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)", 819e5b75505Sopenharmony_ci timeout); 820e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN); 821e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len); 822e5b75505Sopenharmony_ci reg->selected_registrar = 1; 823e5b75505Sopenharmony_ci reg->pbc = 0; 824e5b75505Sopenharmony_ci if (addr) 825e5b75505Sopenharmony_ci wps_registrar_add_authorized_mac(reg, addr); 826e5b75505Sopenharmony_ci else 827e5b75505Sopenharmony_ci wps_registrar_add_authorized_mac( 828e5b75505Sopenharmony_ci reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); 829e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 830e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); 831e5b75505Sopenharmony_ci eloop_register_timeout(WPS_PBC_WALK_TIME, 0, 832e5b75505Sopenharmony_ci wps_registrar_set_selected_timeout, 833e5b75505Sopenharmony_ci reg, NULL); 834e5b75505Sopenharmony_ci 835e5b75505Sopenharmony_ci return 0; 836e5b75505Sopenharmony_ci} 837e5b75505Sopenharmony_ci 838e5b75505Sopenharmony_ci 839e5b75505Sopenharmony_cistatic void wps_registrar_remove_pin(struct wps_registrar *reg, 840e5b75505Sopenharmony_ci struct wps_uuid_pin *pin) 841e5b75505Sopenharmony_ci{ 842e5b75505Sopenharmony_ci u8 *addr; 843e5b75505Sopenharmony_ci u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 844e5b75505Sopenharmony_ci 845e5b75505Sopenharmony_ci if (is_zero_ether_addr(pin->enrollee_addr)) 846e5b75505Sopenharmony_ci addr = bcast; 847e5b75505Sopenharmony_ci else 848e5b75505Sopenharmony_ci addr = pin->enrollee_addr; 849e5b75505Sopenharmony_ci wps_registrar_remove_authorized_mac(reg, addr); 850e5b75505Sopenharmony_ci wps_remove_pin(pin); 851e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 852e5b75505Sopenharmony_ci} 853e5b75505Sopenharmony_ci 854e5b75505Sopenharmony_ci 855e5b75505Sopenharmony_cistatic void wps_registrar_expire_pins(struct wps_registrar *reg) 856e5b75505Sopenharmony_ci{ 857e5b75505Sopenharmony_ci struct wps_uuid_pin *pin, *prev; 858e5b75505Sopenharmony_ci struct os_reltime now; 859e5b75505Sopenharmony_ci 860e5b75505Sopenharmony_ci os_get_reltime(&now); 861e5b75505Sopenharmony_ci dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) 862e5b75505Sopenharmony_ci { 863e5b75505Sopenharmony_ci if ((pin->flags & PIN_EXPIRES) && 864e5b75505Sopenharmony_ci os_reltime_before(&pin->expiration, &now)) { 865e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID", 866e5b75505Sopenharmony_ci pin->uuid, WPS_UUID_LEN); 867e5b75505Sopenharmony_ci wps_registrar_remove_pin(reg, pin); 868e5b75505Sopenharmony_ci } 869e5b75505Sopenharmony_ci } 870e5b75505Sopenharmony_ci} 871e5b75505Sopenharmony_ci 872e5b75505Sopenharmony_ci 873e5b75505Sopenharmony_ci/** 874e5b75505Sopenharmony_ci * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN 875e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 876e5b75505Sopenharmony_ci * @dev_pw: PIN to search for or %NULL to match any 877e5b75505Sopenharmony_ci * @dev_pw_len: Length of dev_pw in octets 878e5b75505Sopenharmony_ci * Returns: 0 on success, -1 if not wildcard PIN is enabled 879e5b75505Sopenharmony_ci */ 880e5b75505Sopenharmony_cistatic int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg, 881e5b75505Sopenharmony_ci const u8 *dev_pw, 882e5b75505Sopenharmony_ci size_t dev_pw_len) 883e5b75505Sopenharmony_ci{ 884e5b75505Sopenharmony_ci struct wps_uuid_pin *pin, *prev; 885e5b75505Sopenharmony_ci 886e5b75505Sopenharmony_ci dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) 887e5b75505Sopenharmony_ci { 888e5b75505Sopenharmony_ci if (dev_pw && pin->pin && 889e5b75505Sopenharmony_ci (dev_pw_len != pin->pin_len || 890e5b75505Sopenharmony_ci os_memcmp_const(dev_pw, pin->pin, dev_pw_len) != 0)) 891e5b75505Sopenharmony_ci continue; /* different PIN */ 892e5b75505Sopenharmony_ci if (pin->wildcard_uuid) { 893e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", 894e5b75505Sopenharmony_ci pin->uuid, WPS_UUID_LEN); 895e5b75505Sopenharmony_ci wps_registrar_remove_pin(reg, pin); 896e5b75505Sopenharmony_ci return 0; 897e5b75505Sopenharmony_ci } 898e5b75505Sopenharmony_ci } 899e5b75505Sopenharmony_ci 900e5b75505Sopenharmony_ci return -1; 901e5b75505Sopenharmony_ci} 902e5b75505Sopenharmony_ci 903e5b75505Sopenharmony_ci 904e5b75505Sopenharmony_ci/** 905e5b75505Sopenharmony_ci * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E 906e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 907e5b75505Sopenharmony_ci * @uuid: UUID-E 908e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure (e.g., PIN not found) 909e5b75505Sopenharmony_ci */ 910e5b75505Sopenharmony_ciint wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid) 911e5b75505Sopenharmony_ci{ 912e5b75505Sopenharmony_ci struct wps_uuid_pin *pin, *prev; 913e5b75505Sopenharmony_ci 914e5b75505Sopenharmony_ci dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) 915e5b75505Sopenharmony_ci { 916e5b75505Sopenharmony_ci if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { 917e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", 918e5b75505Sopenharmony_ci pin->uuid, WPS_UUID_LEN); 919e5b75505Sopenharmony_ci wps_registrar_remove_pin(reg, pin); 920e5b75505Sopenharmony_ci return 0; 921e5b75505Sopenharmony_ci } 922e5b75505Sopenharmony_ci } 923e5b75505Sopenharmony_ci 924e5b75505Sopenharmony_ci return -1; 925e5b75505Sopenharmony_ci} 926e5b75505Sopenharmony_ci 927e5b75505Sopenharmony_ci 928e5b75505Sopenharmony_cistatic const u8 * wps_registrar_get_pin(struct wps_registrar *reg, 929e5b75505Sopenharmony_ci const u8 *uuid, size_t *pin_len) 930e5b75505Sopenharmony_ci{ 931e5b75505Sopenharmony_ci struct wps_uuid_pin *pin, *found = NULL; 932e5b75505Sopenharmony_ci int wildcard = 0; 933e5b75505Sopenharmony_ci 934e5b75505Sopenharmony_ci wps_registrar_expire_pins(reg); 935e5b75505Sopenharmony_ci 936e5b75505Sopenharmony_ci dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { 937e5b75505Sopenharmony_ci if (!pin->wildcard_uuid && 938e5b75505Sopenharmony_ci os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { 939e5b75505Sopenharmony_ci found = pin; 940e5b75505Sopenharmony_ci break; 941e5b75505Sopenharmony_ci } 942e5b75505Sopenharmony_ci } 943e5b75505Sopenharmony_ci 944e5b75505Sopenharmony_ci if (!found) { 945e5b75505Sopenharmony_ci /* Check for wildcard UUIDs since none of the UUID-specific 946e5b75505Sopenharmony_ci * PINs matched */ 947e5b75505Sopenharmony_ci dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { 948e5b75505Sopenharmony_ci if (pin->wildcard_uuid == 1 || 949e5b75505Sopenharmony_ci pin->wildcard_uuid == 2) { 950e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Found a wildcard " 951e5b75505Sopenharmony_ci "PIN. Assigned it for this UUID-E"); 952e5b75505Sopenharmony_ci wildcard = 1; 953e5b75505Sopenharmony_ci os_memcpy(pin->uuid, uuid, WPS_UUID_LEN); 954e5b75505Sopenharmony_ci found = pin; 955e5b75505Sopenharmony_ci break; 956e5b75505Sopenharmony_ci } 957e5b75505Sopenharmony_ci } 958e5b75505Sopenharmony_ci } 959e5b75505Sopenharmony_ci 960e5b75505Sopenharmony_ci if (!found) 961e5b75505Sopenharmony_ci return NULL; 962e5b75505Sopenharmony_ci 963e5b75505Sopenharmony_ci /* 964e5b75505Sopenharmony_ci * Lock the PIN to avoid attacks based on concurrent re-use of the PIN 965e5b75505Sopenharmony_ci * that could otherwise avoid PIN invalidations. 966e5b75505Sopenharmony_ci */ 967e5b75505Sopenharmony_ci if (found->flags & PIN_LOCKED) { 968e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not " 969e5b75505Sopenharmony_ci "allow concurrent re-use"); 970e5b75505Sopenharmony_ci return NULL; 971e5b75505Sopenharmony_ci } 972e5b75505Sopenharmony_ci *pin_len = found->pin_len; 973e5b75505Sopenharmony_ci found->flags |= PIN_LOCKED; 974e5b75505Sopenharmony_ci if (wildcard) 975e5b75505Sopenharmony_ci found->wildcard_uuid++; 976e5b75505Sopenharmony_ci return found->pin; 977e5b75505Sopenharmony_ci} 978e5b75505Sopenharmony_ci 979e5b75505Sopenharmony_ci 980e5b75505Sopenharmony_ci/** 981e5b75505Sopenharmony_ci * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E 982e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 983e5b75505Sopenharmony_ci * @uuid: UUID-E 984e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure 985e5b75505Sopenharmony_ci * 986e5b75505Sopenharmony_ci * PINs are locked to enforce only one concurrent use. This function unlocks a 987e5b75505Sopenharmony_ci * PIN to allow it to be used again. If the specified PIN was configured using 988e5b75505Sopenharmony_ci * a wildcard UUID, it will be removed instead of allowing multiple uses. 989e5b75505Sopenharmony_ci */ 990e5b75505Sopenharmony_ciint wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid) 991e5b75505Sopenharmony_ci{ 992e5b75505Sopenharmony_ci struct wps_uuid_pin *pin; 993e5b75505Sopenharmony_ci 994e5b75505Sopenharmony_ci dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) { 995e5b75505Sopenharmony_ci if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) { 996e5b75505Sopenharmony_ci if (pin->wildcard_uuid == 3) { 997e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalidating used " 998e5b75505Sopenharmony_ci "wildcard PIN"); 999e5b75505Sopenharmony_ci return wps_registrar_invalidate_pin(reg, uuid); 1000e5b75505Sopenharmony_ci } 1001e5b75505Sopenharmony_ci pin->flags &= ~PIN_LOCKED; 1002e5b75505Sopenharmony_ci return 0; 1003e5b75505Sopenharmony_ci } 1004e5b75505Sopenharmony_ci } 1005e5b75505Sopenharmony_ci 1006e5b75505Sopenharmony_ci return -1; 1007e5b75505Sopenharmony_ci} 1008e5b75505Sopenharmony_ci 1009e5b75505Sopenharmony_ci 1010e5b75505Sopenharmony_cistatic void wps_registrar_stop_pbc(struct wps_registrar *reg) 1011e5b75505Sopenharmony_ci{ 1012e5b75505Sopenharmony_ci reg->selected_registrar = 0; 1013e5b75505Sopenharmony_ci reg->pbc = 0; 1014e5b75505Sopenharmony_ci os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); 1015e5b75505Sopenharmony_ci wps_registrar_remove_authorized_mac(reg, 1016e5b75505Sopenharmony_ci (u8 *) "\xff\xff\xff\xff\xff\xff"); 1017e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 1018e5b75505Sopenharmony_ci} 1019e5b75505Sopenharmony_ci 1020e5b75505Sopenharmony_ci 1021e5b75505Sopenharmony_cistatic void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx) 1022e5b75505Sopenharmony_ci{ 1023e5b75505Sopenharmony_ci struct wps_registrar *reg = eloop_ctx; 1024e5b75505Sopenharmony_ci 1025e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode"); 1026e5b75505Sopenharmony_ci wps_pbc_timeout_event(reg->wps); 1027e5b75505Sopenharmony_ci wps_registrar_stop_pbc(reg); 1028e5b75505Sopenharmony_ci} 1029e5b75505Sopenharmony_ci 1030e5b75505Sopenharmony_ci 1031e5b75505Sopenharmony_ci/** 1032e5b75505Sopenharmony_ci * wps_registrar_button_pushed - Notify Registrar that AP button was pushed 1033e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 1034e5b75505Sopenharmony_ci * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL 1035e5b75505Sopenharmony_ci * indicates no such filtering 1036e5b75505Sopenharmony_ci * Returns: 0 on success, -1 on failure, -2 on session overlap 1037e5b75505Sopenharmony_ci * 1038e5b75505Sopenharmony_ci * This function is called on an AP when a push button is pushed to activate 1039e5b75505Sopenharmony_ci * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout 1040e5b75505Sopenharmony_ci * or when a PBC registration is completed. If more than one Enrollee in active 1041e5b75505Sopenharmony_ci * PBC mode has been detected during the monitor time (previous 2 minutes), the 1042e5b75505Sopenharmony_ci * PBC mode is not activated and -2 is returned to indicate session overlap. 1043e5b75505Sopenharmony_ci * This is skipped if a specific Enrollee is selected. 1044e5b75505Sopenharmony_ci */ 1045e5b75505Sopenharmony_ciint wps_registrar_button_pushed(struct wps_registrar *reg, 1046e5b75505Sopenharmony_ci const u8 *p2p_dev_addr) 1047e5b75505Sopenharmony_ci{ 1048e5b75505Sopenharmony_ci if (p2p_dev_addr == NULL && 1049e5b75505Sopenharmony_ci wps_registrar_pbc_overlap(reg, NULL, NULL)) { 1050e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC " 1051e5b75505Sopenharmony_ci "mode"); 1052e5b75505Sopenharmony_ci wps_pbc_overlap_event(reg->wps); 1053e5b75505Sopenharmony_ci return -2; 1054e5b75505Sopenharmony_ci } 1055e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started"); 1056e5b75505Sopenharmony_ci reg->force_pbc_overlap = 0; 1057e5b75505Sopenharmony_ci reg->selected_registrar = 1; 1058e5b75505Sopenharmony_ci reg->pbc = 1; 1059e5b75505Sopenharmony_ci if (p2p_dev_addr) 1060e5b75505Sopenharmony_ci os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); 1061e5b75505Sopenharmony_ci else 1062e5b75505Sopenharmony_ci os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); 1063e5b75505Sopenharmony_ci wps_registrar_add_authorized_mac(reg, 1064e5b75505Sopenharmony_ci (u8 *) "\xff\xff\xff\xff\xff\xff"); 1065e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 1066e5b75505Sopenharmony_ci 1067e5b75505Sopenharmony_ci wps_pbc_active_event(reg->wps); 1068e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); 1069e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); 1070e5b75505Sopenharmony_ci eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout, 1071e5b75505Sopenharmony_ci reg, NULL); 1072e5b75505Sopenharmony_ci return 0; 1073e5b75505Sopenharmony_ci} 1074e5b75505Sopenharmony_ci 1075e5b75505Sopenharmony_ci 1076e5b75505Sopenharmony_cistatic void wps_registrar_pbc_completed(struct wps_registrar *reg) 1077e5b75505Sopenharmony_ci{ 1078e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode"); 1079e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); 1080e5b75505Sopenharmony_ci wps_registrar_stop_pbc(reg); 1081e5b75505Sopenharmony_ci wps_pbc_disable_event(reg->wps); 1082e5b75505Sopenharmony_ci} 1083e5b75505Sopenharmony_ci 1084e5b75505Sopenharmony_ci 1085e5b75505Sopenharmony_cistatic void wps_registrar_pin_completed(struct wps_registrar *reg) 1086e5b75505Sopenharmony_ci{ 1087e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar"); 1088e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); 1089e5b75505Sopenharmony_ci reg->selected_registrar = 0; 1090e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 1091e5b75505Sopenharmony_ci} 1092e5b75505Sopenharmony_ci 1093e5b75505Sopenharmony_ci 1094e5b75505Sopenharmony_civoid wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, 1095e5b75505Sopenharmony_ci const u8 *dev_pw, size_t dev_pw_len) 1096e5b75505Sopenharmony_ci{ 1097e5b75505Sopenharmony_ci if (registrar->pbc) { 1098e5b75505Sopenharmony_ci wps_registrar_remove_pbc_session(registrar, 1099e5b75505Sopenharmony_ci uuid_e, NULL); 1100e5b75505Sopenharmony_ci wps_registrar_pbc_completed(registrar); 1101e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 1102e5b75505Sopenharmony_ci os_get_reltime(®istrar->pbc_ignore_start); 1103e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 1104e5b75505Sopenharmony_ci os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN); 1105e5b75505Sopenharmony_ci } else { 1106e5b75505Sopenharmony_ci wps_registrar_pin_completed(registrar); 1107e5b75505Sopenharmony_ci } 1108e5b75505Sopenharmony_ci 1109e5b75505Sopenharmony_ci if (dev_pw && 1110e5b75505Sopenharmony_ci wps_registrar_invalidate_wildcard_pin(registrar, dev_pw, 1111e5b75505Sopenharmony_ci dev_pw_len) == 0) { 1112e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN", 1113e5b75505Sopenharmony_ci dev_pw, dev_pw_len); 1114e5b75505Sopenharmony_ci } 1115e5b75505Sopenharmony_ci} 1116e5b75505Sopenharmony_ci 1117e5b75505Sopenharmony_ci 1118e5b75505Sopenharmony_ciint wps_registrar_wps_cancel(struct wps_registrar *reg) 1119e5b75505Sopenharmony_ci{ 1120e5b75505Sopenharmony_ci if (reg->pbc) { 1121e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it"); 1122e5b75505Sopenharmony_ci wps_registrar_pbc_timeout(reg, NULL); 1123e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); 1124e5b75505Sopenharmony_ci return 1; 1125e5b75505Sopenharmony_ci } else if (reg->selected_registrar) { 1126e5b75505Sopenharmony_ci /* PIN Method */ 1127e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it"); 1128e5b75505Sopenharmony_ci wps_registrar_pin_completed(reg); 1129e5b75505Sopenharmony_ci wps_registrar_invalidate_wildcard_pin(reg, NULL, 0); 1130e5b75505Sopenharmony_ci return 1; 1131e5b75505Sopenharmony_ci } 1132e5b75505Sopenharmony_ci return 0; 1133e5b75505Sopenharmony_ci} 1134e5b75505Sopenharmony_ci 1135e5b75505Sopenharmony_ci 1136e5b75505Sopenharmony_ci/** 1137e5b75505Sopenharmony_ci * wps_registrar_probe_req_rx - Notify Registrar of Probe Request 1138e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 1139e5b75505Sopenharmony_ci * @addr: MAC address of the Probe Request sender 1140e5b75505Sopenharmony_ci * @wps_data: WPS IE contents 1141e5b75505Sopenharmony_ci * 1142e5b75505Sopenharmony_ci * This function is called on an AP when a Probe Request with WPS IE is 1143e5b75505Sopenharmony_ci * received. This is used to track PBC mode use and to detect possible overlap 1144e5b75505Sopenharmony_ci * situation with other WPS APs. 1145e5b75505Sopenharmony_ci */ 1146e5b75505Sopenharmony_civoid wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, 1147e5b75505Sopenharmony_ci const struct wpabuf *wps_data, 1148e5b75505Sopenharmony_ci int p2p_wildcard) 1149e5b75505Sopenharmony_ci{ 1150e5b75505Sopenharmony_ci struct wps_parse_attr attr; 1151e5b75505Sopenharmony_ci int skip_add = 0; 1152e5b75505Sopenharmony_ci 1153e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, 1154e5b75505Sopenharmony_ci "WPS: Probe Request with WPS data received", 1155e5b75505Sopenharmony_ci wps_data); 1156e5b75505Sopenharmony_ci 1157e5b75505Sopenharmony_ci if (wps_parse_msg(wps_data, &attr) < 0) 1158e5b75505Sopenharmony_ci return; 1159e5b75505Sopenharmony_ci 1160e5b75505Sopenharmony_ci if (attr.config_methods == NULL) { 1161e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in " 1162e5b75505Sopenharmony_ci "Probe Request"); 1163e5b75505Sopenharmony_ci return; 1164e5b75505Sopenharmony_ci } 1165e5b75505Sopenharmony_ci 1166e5b75505Sopenharmony_ci if (attr.dev_password_id == NULL) { 1167e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute " 1168e5b75505Sopenharmony_ci "in Probe Request"); 1169e5b75505Sopenharmony_ci return; 1170e5b75505Sopenharmony_ci } 1171e5b75505Sopenharmony_ci 1172e5b75505Sopenharmony_ci if (reg->enrollee_seen_cb && attr.uuid_e && 1173e5b75505Sopenharmony_ci attr.primary_dev_type && attr.request_type && !p2p_wildcard) { 1174e5b75505Sopenharmony_ci char *dev_name = NULL; 1175e5b75505Sopenharmony_ci if (attr.dev_name) { 1176e5b75505Sopenharmony_ci dev_name = os_zalloc(attr.dev_name_len + 1); 1177e5b75505Sopenharmony_ci if (dev_name) { 1178e5b75505Sopenharmony_ci os_memcpy(dev_name, attr.dev_name, 1179e5b75505Sopenharmony_ci attr.dev_name_len); 1180e5b75505Sopenharmony_ci } 1181e5b75505Sopenharmony_ci } 1182e5b75505Sopenharmony_ci reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e, 1183e5b75505Sopenharmony_ci attr.primary_dev_type, 1184e5b75505Sopenharmony_ci WPA_GET_BE16(attr.config_methods), 1185e5b75505Sopenharmony_ci WPA_GET_BE16(attr.dev_password_id), 1186e5b75505Sopenharmony_ci *attr.request_type, dev_name); 1187e5b75505Sopenharmony_ci os_free(dev_name); 1188e5b75505Sopenharmony_ci } 1189e5b75505Sopenharmony_ci 1190e5b75505Sopenharmony_ci if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON) 1191e5b75505Sopenharmony_ci return; /* Not PBC */ 1192e5b75505Sopenharmony_ci 1193e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from " 1194e5b75505Sopenharmony_ci MACSTR, MAC2STR(addr)); 1195e5b75505Sopenharmony_ci if (attr.uuid_e == NULL) { 1196e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No " 1197e5b75505Sopenharmony_ci "UUID-E included"); 1198e5b75505Sopenharmony_ci return; 1199e5b75505Sopenharmony_ci } 1200e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e, 1201e5b75505Sopenharmony_ci WPS_UUID_LEN); 1202e5b75505Sopenharmony_ci 1203e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 1204e5b75505Sopenharmony_ci if (reg->pbc_ignore_start.sec && 1205e5b75505Sopenharmony_ci os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) { 1206e5b75505Sopenharmony_ci struct os_reltime now, dur; 1207e5b75505Sopenharmony_ci os_get_reltime(&now); 1208e5b75505Sopenharmony_ci os_reltime_sub(&now, ®->pbc_ignore_start, &dur); 1209e5b75505Sopenharmony_ci if (dur.sec >= 0 && dur.sec < 5) { 1210e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation " 1211e5b75505Sopenharmony_ci "based on Probe Request from the Enrollee " 1212e5b75505Sopenharmony_ci "that just completed PBC provisioning"); 1213e5b75505Sopenharmony_ci skip_add = 1; 1214e5b75505Sopenharmony_ci } else 1215e5b75505Sopenharmony_ci reg->pbc_ignore_start.sec = 0; 1216e5b75505Sopenharmony_ci } 1217e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 1218e5b75505Sopenharmony_ci 1219e5b75505Sopenharmony_ci if (!skip_add) 1220e5b75505Sopenharmony_ci wps_registrar_add_pbc_session(reg, addr, attr.uuid_e); 1221e5b75505Sopenharmony_ci if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) { 1222e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected"); 1223e5b75505Sopenharmony_ci reg->force_pbc_overlap = 1; 1224e5b75505Sopenharmony_ci wps_pbc_overlap_event(reg->wps); 1225e5b75505Sopenharmony_ci } 1226e5b75505Sopenharmony_ci} 1227e5b75505Sopenharmony_ci 1228e5b75505Sopenharmony_ci 1229e5b75505Sopenharmony_ciint wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr, 1230e5b75505Sopenharmony_ci const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) 1231e5b75505Sopenharmony_ci{ 1232e5b75505Sopenharmony_ci if (reg->new_psk_cb == NULL) 1233e5b75505Sopenharmony_ci return 0; 1234e5b75505Sopenharmony_ci 1235e5b75505Sopenharmony_ci return reg->new_psk_cb(reg->cb_ctx, mac_addr, p2p_dev_addr, psk, 1236e5b75505Sopenharmony_ci psk_len); 1237e5b75505Sopenharmony_ci} 1238e5b75505Sopenharmony_ci 1239e5b75505Sopenharmony_ci 1240e5b75505Sopenharmony_cistatic void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e, 1241e5b75505Sopenharmony_ci const struct wps_device_data *dev) 1242e5b75505Sopenharmony_ci{ 1243e5b75505Sopenharmony_ci if (reg->pin_needed_cb == NULL) 1244e5b75505Sopenharmony_ci return; 1245e5b75505Sopenharmony_ci 1246e5b75505Sopenharmony_ci reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev); 1247e5b75505Sopenharmony_ci} 1248e5b75505Sopenharmony_ci 1249e5b75505Sopenharmony_ci 1250e5b75505Sopenharmony_cistatic void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr, 1251e5b75505Sopenharmony_ci const u8 *uuid_e, const u8 *dev_pw, 1252e5b75505Sopenharmony_ci size_t dev_pw_len) 1253e5b75505Sopenharmony_ci{ 1254e5b75505Sopenharmony_ci if (reg->reg_success_cb == NULL) 1255e5b75505Sopenharmony_ci return; 1256e5b75505Sopenharmony_ci 1257e5b75505Sopenharmony_ci reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len); 1258e5b75505Sopenharmony_ci} 1259e5b75505Sopenharmony_ci 1260e5b75505Sopenharmony_ci 1261e5b75505Sopenharmony_cistatic int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie, 1262e5b75505Sopenharmony_ci struct wpabuf *probe_resp_ie) 1263e5b75505Sopenharmony_ci{ 1264e5b75505Sopenharmony_ci return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie); 1265e5b75505Sopenharmony_ci} 1266e5b75505Sopenharmony_ci 1267e5b75505Sopenharmony_ci 1268e5b75505Sopenharmony_cistatic void wps_cb_set_sel_reg(struct wps_registrar *reg) 1269e5b75505Sopenharmony_ci{ 1270e5b75505Sopenharmony_ci u16 methods = 0; 1271e5b75505Sopenharmony_ci if (reg->set_sel_reg_cb == NULL) 1272e5b75505Sopenharmony_ci return; 1273e5b75505Sopenharmony_ci 1274e5b75505Sopenharmony_ci if (reg->selected_registrar) { 1275e5b75505Sopenharmony_ci methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; 1276e5b75505Sopenharmony_ci methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 1277e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON); 1278e5b75505Sopenharmony_ci if (reg->pbc) 1279e5b75505Sopenharmony_ci wps_set_pushbutton(&methods, reg->wps->config_methods); 1280e5b75505Sopenharmony_ci } 1281e5b75505Sopenharmony_ci 1282e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d " 1283e5b75505Sopenharmony_ci "config_methods=0x%x pbc=%d methods=0x%x", 1284e5b75505Sopenharmony_ci reg->selected_registrar, reg->wps->config_methods, 1285e5b75505Sopenharmony_ci reg->pbc, methods); 1286e5b75505Sopenharmony_ci 1287e5b75505Sopenharmony_ci reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar, 1288e5b75505Sopenharmony_ci reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT, 1289e5b75505Sopenharmony_ci methods); 1290e5b75505Sopenharmony_ci} 1291e5b75505Sopenharmony_ci 1292e5b75505Sopenharmony_ci 1293e5b75505Sopenharmony_cistatic int wps_set_ie(struct wps_registrar *reg) 1294e5b75505Sopenharmony_ci{ 1295e5b75505Sopenharmony_ci struct wpabuf *beacon; 1296e5b75505Sopenharmony_ci struct wpabuf *probe; 1297e5b75505Sopenharmony_ci const u8 *auth_macs; 1298e5b75505Sopenharmony_ci size_t count; 1299e5b75505Sopenharmony_ci size_t vendor_len = 0; 1300e5b75505Sopenharmony_ci int i; 1301e5b75505Sopenharmony_ci 1302e5b75505Sopenharmony_ci if (reg->set_ie_cb == NULL) 1303e5b75505Sopenharmony_ci return 0; 1304e5b75505Sopenharmony_ci 1305e5b75505Sopenharmony_ci for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { 1306e5b75505Sopenharmony_ci if (reg->wps->dev.vendor_ext[i]) { 1307e5b75505Sopenharmony_ci vendor_len += 2 + 2; 1308e5b75505Sopenharmony_ci vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]); 1309e5b75505Sopenharmony_ci } 1310e5b75505Sopenharmony_ci } 1311e5b75505Sopenharmony_ci 1312e5b75505Sopenharmony_ci beacon = wpabuf_alloc(400 + vendor_len); 1313e5b75505Sopenharmony_ci if (beacon == NULL) 1314e5b75505Sopenharmony_ci return -1; 1315e5b75505Sopenharmony_ci probe = wpabuf_alloc(500 + vendor_len); 1316e5b75505Sopenharmony_ci if (probe == NULL) { 1317e5b75505Sopenharmony_ci wpabuf_free(beacon); 1318e5b75505Sopenharmony_ci return -1; 1319e5b75505Sopenharmony_ci } 1320e5b75505Sopenharmony_ci 1321e5b75505Sopenharmony_ci auth_macs = wps_authorized_macs(reg, &count); 1322e5b75505Sopenharmony_ci 1323e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs"); 1324e5b75505Sopenharmony_ci 1325e5b75505Sopenharmony_ci if (wps_build_version(beacon) || 1326e5b75505Sopenharmony_ci wps_build_wps_state(reg->wps, beacon) || 1327e5b75505Sopenharmony_ci wps_build_ap_setup_locked(reg->wps, beacon) || 1328e5b75505Sopenharmony_ci wps_build_selected_registrar(reg, beacon) || 1329e5b75505Sopenharmony_ci wps_build_sel_reg_dev_password_id(reg, beacon) || 1330e5b75505Sopenharmony_ci wps_build_sel_reg_config_methods(reg, beacon) || 1331e5b75505Sopenharmony_ci wps_build_sel_pbc_reg_uuid_e(reg, beacon) || 1332e5b75505Sopenharmony_ci (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || 1333e5b75505Sopenharmony_ci wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) || 1334e5b75505Sopenharmony_ci wps_build_vendor_ext(®->wps->dev, beacon)) { 1335e5b75505Sopenharmony_ci wpabuf_free(beacon); 1336e5b75505Sopenharmony_ci wpabuf_free(probe); 1337e5b75505Sopenharmony_ci return -1; 1338e5b75505Sopenharmony_ci } 1339e5b75505Sopenharmony_ci 1340e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 1341e5b75505Sopenharmony_ci if (wps_build_dev_name(®->wps->dev, beacon) || 1342e5b75505Sopenharmony_ci wps_build_primary_dev_type(®->wps->dev, beacon)) { 1343e5b75505Sopenharmony_ci wpabuf_free(beacon); 1344e5b75505Sopenharmony_ci wpabuf_free(probe); 1345e5b75505Sopenharmony_ci return -1; 1346e5b75505Sopenharmony_ci } 1347e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 1348e5b75505Sopenharmony_ci 1349e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs"); 1350e5b75505Sopenharmony_ci 1351e5b75505Sopenharmony_ci if (wps_build_version(probe) || 1352e5b75505Sopenharmony_ci wps_build_wps_state(reg->wps, probe) || 1353e5b75505Sopenharmony_ci wps_build_ap_setup_locked(reg->wps, probe) || 1354e5b75505Sopenharmony_ci wps_build_selected_registrar(reg, probe) || 1355e5b75505Sopenharmony_ci wps_build_sel_reg_dev_password_id(reg, probe) || 1356e5b75505Sopenharmony_ci wps_build_sel_reg_config_methods(reg, probe) || 1357e5b75505Sopenharmony_ci wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP : 1358e5b75505Sopenharmony_ci WPS_RESP_REGISTRAR) || 1359e5b75505Sopenharmony_ci wps_build_uuid_e(probe, reg->wps->uuid) || 1360e5b75505Sopenharmony_ci wps_build_device_attrs(®->wps->dev, probe) || 1361e5b75505Sopenharmony_ci wps_build_probe_config_methods(reg, probe) || 1362e5b75505Sopenharmony_ci (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || 1363e5b75505Sopenharmony_ci wps_build_wfa_ext(probe, 0, auth_macs, count, 0) || 1364e5b75505Sopenharmony_ci wps_build_vendor_ext(®->wps->dev, probe)) { 1365e5b75505Sopenharmony_ci wpabuf_free(beacon); 1366e5b75505Sopenharmony_ci wpabuf_free(probe); 1367e5b75505Sopenharmony_ci return -1; 1368e5b75505Sopenharmony_ci } 1369e5b75505Sopenharmony_ci 1370e5b75505Sopenharmony_ci beacon = wps_ie_encapsulate(beacon); 1371e5b75505Sopenharmony_ci probe = wps_ie_encapsulate(probe); 1372e5b75505Sopenharmony_ci 1373e5b75505Sopenharmony_ci if (!beacon || !probe) { 1374e5b75505Sopenharmony_ci wpabuf_free(beacon); 1375e5b75505Sopenharmony_ci wpabuf_free(probe); 1376e5b75505Sopenharmony_ci return -1; 1377e5b75505Sopenharmony_ci } 1378e5b75505Sopenharmony_ci 1379e5b75505Sopenharmony_ci if (reg->static_wep_only) { 1380e5b75505Sopenharmony_ci /* 1381e5b75505Sopenharmony_ci * Windows XP and Vista clients can get confused about 1382e5b75505Sopenharmony_ci * EAP-Identity/Request when they probe the network with 1383e5b75505Sopenharmony_ci * EAPOL-Start. In such a case, they may assume the network is 1384e5b75505Sopenharmony_ci * using IEEE 802.1X and prompt user for a certificate while 1385e5b75505Sopenharmony_ci * the correct (non-WPS) behavior would be to ask for the 1386e5b75505Sopenharmony_ci * static WEP key. As a workaround, use Microsoft Provisioning 1387e5b75505Sopenharmony_ci * IE to advertise that legacy 802.1X is not supported. 1388e5b75505Sopenharmony_ci */ 1389e5b75505Sopenharmony_ci const u8 ms_wps[7] = { 1390e5b75505Sopenharmony_ci WLAN_EID_VENDOR_SPECIFIC, 5, 1391e5b75505Sopenharmony_ci /* Microsoft Provisioning IE (00:50:f2:5) */ 1392e5b75505Sopenharmony_ci 0x00, 0x50, 0xf2, 5, 1393e5b75505Sopenharmony_ci 0x00 /* no legacy 802.1X or MS WPS */ 1394e5b75505Sopenharmony_ci }; 1395e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE " 1396e5b75505Sopenharmony_ci "into Beacon/Probe Response frames"); 1397e5b75505Sopenharmony_ci wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps)); 1398e5b75505Sopenharmony_ci wpabuf_put_data(probe, ms_wps, sizeof(ms_wps)); 1399e5b75505Sopenharmony_ci } 1400e5b75505Sopenharmony_ci 1401e5b75505Sopenharmony_ci return wps_cb_set_ie(reg, beacon, probe); 1402e5b75505Sopenharmony_ci} 1403e5b75505Sopenharmony_ci 1404e5b75505Sopenharmony_ci 1405e5b75505Sopenharmony_cistatic int wps_get_dev_password(struct wps_data *wps) 1406e5b75505Sopenharmony_ci{ 1407e5b75505Sopenharmony_ci const u8 *pin; 1408e5b75505Sopenharmony_ci size_t pin_len = 0; 1409e5b75505Sopenharmony_ci 1410e5b75505Sopenharmony_ci bin_clear_free(wps->dev_password, wps->dev_password_len); 1411e5b75505Sopenharmony_ci wps->dev_password = NULL; 1412e5b75505Sopenharmony_ci 1413e5b75505Sopenharmony_ci if (wps->pbc) { 1414e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC"); 1415e5b75505Sopenharmony_ci pin = (const u8 *) "00000000"; 1416e5b75505Sopenharmony_ci pin_len = 8; 1417e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 1418e5b75505Sopenharmony_ci } else if (wps->nfc_pw_token) { 1419e5b75505Sopenharmony_ci if (wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) 1420e5b75505Sopenharmony_ci { 1421e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Using NFC connection " 1422e5b75505Sopenharmony_ci "handover and abbreviated WPS handshake " 1423e5b75505Sopenharmony_ci "without Device Password"); 1424e5b75505Sopenharmony_ci return 0; 1425e5b75505Sopenharmony_ci } 1426e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC " 1427e5b75505Sopenharmony_ci "Password Token"); 1428e5b75505Sopenharmony_ci pin = wps->nfc_pw_token->dev_pw; 1429e5b75505Sopenharmony_ci pin_len = wps->nfc_pw_token->dev_pw_len; 1430e5b75505Sopenharmony_ci } else if (wps->dev_pw_id >= 0x10 && 1431e5b75505Sopenharmony_ci wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id && 1432e5b75505Sopenharmony_ci wps->wps->ap_nfc_dev_pw) { 1433e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from own NFC Password Token"); 1434e5b75505Sopenharmony_ci pin = wpabuf_head(wps->wps->ap_nfc_dev_pw); 1435e5b75505Sopenharmony_ci pin_len = wpabuf_len(wps->wps->ap_nfc_dev_pw); 1436e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 1437e5b75505Sopenharmony_ci } else { 1438e5b75505Sopenharmony_ci pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e, 1439e5b75505Sopenharmony_ci &pin_len); 1440e5b75505Sopenharmony_ci if (pin && wps->dev_pw_id >= 0x10) { 1441e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device " 1442e5b75505Sopenharmony_ci "Password ID, but PIN found"); 1443e5b75505Sopenharmony_ci /* 1444e5b75505Sopenharmony_ci * See whether Enrollee is willing to use PIN instead. 1445e5b75505Sopenharmony_ci */ 1446e5b75505Sopenharmony_ci wps->dev_pw_id = DEV_PW_DEFAULT; 1447e5b75505Sopenharmony_ci } 1448e5b75505Sopenharmony_ci } 1449e5b75505Sopenharmony_ci if (pin == NULL) { 1450e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Device Password available for " 1451e5b75505Sopenharmony_ci "the Enrollee (context %p registrar %p)", 1452e5b75505Sopenharmony_ci wps->wps, wps->wps->registrar); 1453e5b75505Sopenharmony_ci wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e, 1454e5b75505Sopenharmony_ci &wps->peer_dev); 1455e5b75505Sopenharmony_ci return -1; 1456e5b75505Sopenharmony_ci } 1457e5b75505Sopenharmony_ci 1458e5b75505Sopenharmony_ci wps->dev_password = os_memdup(pin, pin_len); 1459e5b75505Sopenharmony_ci if (wps->dev_password == NULL) 1460e5b75505Sopenharmony_ci return -1; 1461e5b75505Sopenharmony_ci wps->dev_password_len = pin_len; 1462e5b75505Sopenharmony_ci 1463e5b75505Sopenharmony_ci return 0; 1464e5b75505Sopenharmony_ci} 1465e5b75505Sopenharmony_ci 1466e5b75505Sopenharmony_ci 1467e5b75505Sopenharmony_cistatic int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg) 1468e5b75505Sopenharmony_ci{ 1469e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * UUID-R"); 1470e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_UUID_R); 1471e5b75505Sopenharmony_ci wpabuf_put_be16(msg, WPS_UUID_LEN); 1472e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN); 1473e5b75505Sopenharmony_ci return 0; 1474e5b75505Sopenharmony_ci} 1475e5b75505Sopenharmony_ci 1476e5b75505Sopenharmony_ci 1477e5b75505Sopenharmony_cistatic int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg) 1478e5b75505Sopenharmony_ci{ 1479e5b75505Sopenharmony_ci u8 *hash; 1480e5b75505Sopenharmony_ci const u8 *addr[4]; 1481e5b75505Sopenharmony_ci size_t len[4]; 1482e5b75505Sopenharmony_ci 1483e5b75505Sopenharmony_ci if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) 1484e5b75505Sopenharmony_ci return -1; 1485e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN); 1486e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-S2", 1487e5b75505Sopenharmony_ci wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); 1488e5b75505Sopenharmony_ci 1489e5b75505Sopenharmony_ci if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { 1490e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " 1491e5b75505Sopenharmony_ci "R-Hash derivation"); 1492e5b75505Sopenharmony_ci return -1; 1493e5b75505Sopenharmony_ci } 1494e5b75505Sopenharmony_ci 1495e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * R-Hash1"); 1496e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_R_HASH1); 1497e5b75505Sopenharmony_ci wpabuf_put_be16(msg, SHA256_MAC_LEN); 1498e5b75505Sopenharmony_ci hash = wpabuf_put(msg, SHA256_MAC_LEN); 1499e5b75505Sopenharmony_ci /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */ 1500e5b75505Sopenharmony_ci addr[0] = wps->snonce; 1501e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 1502e5b75505Sopenharmony_ci addr[1] = wps->psk1; 1503e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 1504e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 1505e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 1506e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 1507e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 1508e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 1509e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN); 1510e5b75505Sopenharmony_ci 1511e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * R-Hash2"); 1512e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_R_HASH2); 1513e5b75505Sopenharmony_ci wpabuf_put_be16(msg, SHA256_MAC_LEN); 1514e5b75505Sopenharmony_ci hash = wpabuf_put(msg, SHA256_MAC_LEN); 1515e5b75505Sopenharmony_ci /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ 1516e5b75505Sopenharmony_ci addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; 1517e5b75505Sopenharmony_ci addr[1] = wps->psk2; 1518e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 1519e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN); 1520e5b75505Sopenharmony_ci 1521e5b75505Sopenharmony_ci return 0; 1522e5b75505Sopenharmony_ci} 1523e5b75505Sopenharmony_ci 1524e5b75505Sopenharmony_ci 1525e5b75505Sopenharmony_cistatic int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg) 1526e5b75505Sopenharmony_ci{ 1527e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * R-SNonce1"); 1528e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_R_SNONCE1); 1529e5b75505Sopenharmony_ci wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 1530e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN); 1531e5b75505Sopenharmony_ci return 0; 1532e5b75505Sopenharmony_ci} 1533e5b75505Sopenharmony_ci 1534e5b75505Sopenharmony_ci 1535e5b75505Sopenharmony_cistatic int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg) 1536e5b75505Sopenharmony_ci{ 1537e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * R-SNonce2"); 1538e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_R_SNONCE2); 1539e5b75505Sopenharmony_ci wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN); 1540e5b75505Sopenharmony_ci wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN, 1541e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 1542e5b75505Sopenharmony_ci return 0; 1543e5b75505Sopenharmony_ci} 1544e5b75505Sopenharmony_ci 1545e5b75505Sopenharmony_ci 1546e5b75505Sopenharmony_cistatic int wps_build_cred_network_idx(struct wpabuf *msg, 1547e5b75505Sopenharmony_ci const struct wps_credential *cred) 1548e5b75505Sopenharmony_ci{ 1549e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Network Index (1)"); 1550e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_NETWORK_INDEX); 1551e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 1); 1552e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 1); 1553e5b75505Sopenharmony_ci return 0; 1554e5b75505Sopenharmony_ci} 1555e5b75505Sopenharmony_ci 1556e5b75505Sopenharmony_ci 1557e5b75505Sopenharmony_cistatic int wps_build_cred_ssid(struct wpabuf *msg, 1558e5b75505Sopenharmony_ci const struct wps_credential *cred) 1559e5b75505Sopenharmony_ci{ 1560e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * SSID"); 1561e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential", 1562e5b75505Sopenharmony_ci cred->ssid, cred->ssid_len); 1563e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_SSID); 1564e5b75505Sopenharmony_ci wpabuf_put_be16(msg, cred->ssid_len); 1565e5b75505Sopenharmony_ci wpabuf_put_data(msg, cred->ssid, cred->ssid_len); 1566e5b75505Sopenharmony_ci return 0; 1567e5b75505Sopenharmony_ci} 1568e5b75505Sopenharmony_ci 1569e5b75505Sopenharmony_ci 1570e5b75505Sopenharmony_cistatic int wps_build_cred_auth_type(struct wpabuf *msg, 1571e5b75505Sopenharmony_ci const struct wps_credential *cred) 1572e5b75505Sopenharmony_ci{ 1573e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)", 1574e5b75505Sopenharmony_ci cred->auth_type); 1575e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_AUTH_TYPE); 1576e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 1577e5b75505Sopenharmony_ci wpabuf_put_be16(msg, cred->auth_type); 1578e5b75505Sopenharmony_ci return 0; 1579e5b75505Sopenharmony_ci} 1580e5b75505Sopenharmony_ci 1581e5b75505Sopenharmony_ci 1582e5b75505Sopenharmony_cistatic int wps_build_cred_encr_type(struct wpabuf *msg, 1583e5b75505Sopenharmony_ci const struct wps_credential *cred) 1584e5b75505Sopenharmony_ci{ 1585e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)", 1586e5b75505Sopenharmony_ci cred->encr_type); 1587e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_ENCR_TYPE); 1588e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 2); 1589e5b75505Sopenharmony_ci wpabuf_put_be16(msg, cred->encr_type); 1590e5b75505Sopenharmony_ci return 0; 1591e5b75505Sopenharmony_ci} 1592e5b75505Sopenharmony_ci 1593e5b75505Sopenharmony_ci 1594e5b75505Sopenharmony_cistatic int wps_build_cred_network_key(struct wpabuf *msg, 1595e5b75505Sopenharmony_ci const struct wps_credential *cred) 1596e5b75505Sopenharmony_ci{ 1597e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%d)", 1598e5b75505Sopenharmony_ci (int) cred->key_len); 1599e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", 1600e5b75505Sopenharmony_ci cred->key, cred->key_len); 1601e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_NETWORK_KEY); 1602e5b75505Sopenharmony_ci wpabuf_put_be16(msg, cred->key_len); 1603e5b75505Sopenharmony_ci wpabuf_put_data(msg, cred->key, cred->key_len); 1604e5b75505Sopenharmony_ci return 0; 1605e5b75505Sopenharmony_ci} 1606e5b75505Sopenharmony_ci 1607e5b75505Sopenharmony_ci 1608e5b75505Sopenharmony_cistatic int wps_build_credential(struct wpabuf *msg, 1609e5b75505Sopenharmony_ci const struct wps_credential *cred) 1610e5b75505Sopenharmony_ci{ 1611e5b75505Sopenharmony_ci if (wps_build_cred_network_idx(msg, cred) || 1612e5b75505Sopenharmony_ci wps_build_cred_ssid(msg, cred) || 1613e5b75505Sopenharmony_ci wps_build_cred_auth_type(msg, cred) || 1614e5b75505Sopenharmony_ci wps_build_cred_encr_type(msg, cred) || 1615e5b75505Sopenharmony_ci wps_build_cred_network_key(msg, cred) || 1616e5b75505Sopenharmony_ci wps_build_mac_addr(msg, cred->mac_addr)) 1617e5b75505Sopenharmony_ci return -1; 1618e5b75505Sopenharmony_ci return 0; 1619e5b75505Sopenharmony_ci} 1620e5b75505Sopenharmony_ci 1621e5b75505Sopenharmony_ci 1622e5b75505Sopenharmony_ciint wps_build_credential_wrap(struct wpabuf *msg, 1623e5b75505Sopenharmony_ci const struct wps_credential *cred) 1624e5b75505Sopenharmony_ci{ 1625e5b75505Sopenharmony_ci struct wpabuf *wbuf; 1626e5b75505Sopenharmony_ci wbuf = wpabuf_alloc(200); 1627e5b75505Sopenharmony_ci if (wbuf == NULL) 1628e5b75505Sopenharmony_ci return -1; 1629e5b75505Sopenharmony_ci if (wps_build_credential(wbuf, cred)) { 1630e5b75505Sopenharmony_ci wpabuf_clear_free(wbuf); 1631e5b75505Sopenharmony_ci return -1; 1632e5b75505Sopenharmony_ci } 1633e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_CRED); 1634e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wpabuf_len(wbuf)); 1635e5b75505Sopenharmony_ci wpabuf_put_buf(msg, wbuf); 1636e5b75505Sopenharmony_ci wpabuf_clear_free(wbuf); 1637e5b75505Sopenharmony_ci return 0; 1638e5b75505Sopenharmony_ci} 1639e5b75505Sopenharmony_ci 1640e5b75505Sopenharmony_ci 1641e5b75505Sopenharmony_ciint wps_build_cred(struct wps_data *wps, struct wpabuf *msg) 1642e5b75505Sopenharmony_ci{ 1643e5b75505Sopenharmony_ci struct wpabuf *cred; 1644e5b75505Sopenharmony_ci struct wps_registrar *reg = wps->wps->registrar; 1645e5b75505Sopenharmony_ci 1646e5b75505Sopenharmony_ci if (wps->wps->registrar->skip_cred_build) 1647e5b75505Sopenharmony_ci goto skip_cred_build; 1648e5b75505Sopenharmony_ci 1649e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Credential"); 1650e5b75505Sopenharmony_ci if (wps->use_cred) { 1651e5b75505Sopenharmony_ci os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred)); 1652e5b75505Sopenharmony_ci goto use_provided; 1653e5b75505Sopenharmony_ci } 1654e5b75505Sopenharmony_ci os_memset(&wps->cred, 0, sizeof(wps->cred)); 1655e5b75505Sopenharmony_ci 1656e5b75505Sopenharmony_ci if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA && 1657e5b75505Sopenharmony_ci reg->multi_ap_backhaul_ssid_len) { 1658e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use backhaul STA credentials"); 1659e5b75505Sopenharmony_ci os_memcpy(wps->cred.ssid, reg->multi_ap_backhaul_ssid, 1660e5b75505Sopenharmony_ci reg->multi_ap_backhaul_ssid_len); 1661e5b75505Sopenharmony_ci wps->cred.ssid_len = reg->multi_ap_backhaul_ssid_len; 1662e5b75505Sopenharmony_ci /* Backhaul is always WPA2PSK */ 1663e5b75505Sopenharmony_ci wps->cred.auth_type = WPS_AUTH_WPA2PSK; 1664e5b75505Sopenharmony_ci wps->cred.encr_type = WPS_ENCR_AES; 1665e5b75505Sopenharmony_ci /* Set MAC address in the Credential to be the Enrollee's MAC 1666e5b75505Sopenharmony_ci * address 1667e5b75505Sopenharmony_ci */ 1668e5b75505Sopenharmony_ci os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN); 1669e5b75505Sopenharmony_ci if (reg->multi_ap_backhaul_network_key) { 1670e5b75505Sopenharmony_ci os_memcpy(wps->cred.key, 1671e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key, 1672e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key_len); 1673e5b75505Sopenharmony_ci wps->cred.key_len = 1674e5b75505Sopenharmony_ci reg->multi_ap_backhaul_network_key_len; 1675e5b75505Sopenharmony_ci } 1676e5b75505Sopenharmony_ci goto use_provided; 1677e5b75505Sopenharmony_ci } 1678e5b75505Sopenharmony_ci 1679e5b75505Sopenharmony_ci os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len); 1680e5b75505Sopenharmony_ci wps->cred.ssid_len = wps->wps->ssid_len; 1681e5b75505Sopenharmony_ci 1682e5b75505Sopenharmony_ci /* Select the best authentication and encryption type */ 1683e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1684e5b75505Sopenharmony_ci "WPS: Own auth types 0x%x - masked Enrollee auth types 0x%x", 1685e5b75505Sopenharmony_ci wps->wps->auth_types, wps->auth_type); 1686e5b75505Sopenharmony_ci if (wps->auth_type & WPS_AUTH_WPA2PSK) 1687e5b75505Sopenharmony_ci wps->auth_type = WPS_AUTH_WPA2PSK; 1688e5b75505Sopenharmony_ci else if (wps->auth_type & WPS_AUTH_WPAPSK) 1689e5b75505Sopenharmony_ci wps->auth_type = WPS_AUTH_WPAPSK; 1690e5b75505Sopenharmony_ci else if (wps->auth_type & WPS_AUTH_OPEN) 1691e5b75505Sopenharmony_ci wps->auth_type = WPS_AUTH_OPEN; 1692e5b75505Sopenharmony_ci else { 1693e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x", 1694e5b75505Sopenharmony_ci wps->auth_type); 1695e5b75505Sopenharmony_ci return -1; 1696e5b75505Sopenharmony_ci } 1697e5b75505Sopenharmony_ci wps->cred.auth_type = wps->auth_type; 1698e5b75505Sopenharmony_ci 1699e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1700e5b75505Sopenharmony_ci "WPS: Own encr types 0x%x (rsn: 0x%x, wpa: 0x%x) - masked Enrollee encr types 0x%x", 1701e5b75505Sopenharmony_ci wps->wps->encr_types, wps->wps->encr_types_rsn, 1702e5b75505Sopenharmony_ci wps->wps->encr_types_wpa, wps->encr_type); 1703e5b75505Sopenharmony_ci if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPA2PSK) 1704e5b75505Sopenharmony_ci wps->encr_type &= wps->wps->encr_types_rsn; 1705e5b75505Sopenharmony_ci else if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPAPSK) 1706e5b75505Sopenharmony_ci wps->encr_type &= wps->wps->encr_types_wpa; 1707e5b75505Sopenharmony_ci if (wps->auth_type == WPS_AUTH_WPA2PSK || 1708e5b75505Sopenharmony_ci wps->auth_type == WPS_AUTH_WPAPSK) { 1709e5b75505Sopenharmony_ci if (wps->encr_type & WPS_ENCR_AES) 1710e5b75505Sopenharmony_ci wps->encr_type = WPS_ENCR_AES; 1711e5b75505Sopenharmony_ci else if (wps->encr_type & WPS_ENCR_TKIP) 1712e5b75505Sopenharmony_ci wps->encr_type = WPS_ENCR_TKIP; 1713e5b75505Sopenharmony_ci else { 1714e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No suitable encryption " 1715e5b75505Sopenharmony_ci "type for WPA/WPA2"); 1716e5b75505Sopenharmony_ci return -1; 1717e5b75505Sopenharmony_ci } 1718e5b75505Sopenharmony_ci } else { 1719e5b75505Sopenharmony_ci if (wps->encr_type & WPS_ENCR_NONE) 1720e5b75505Sopenharmony_ci wps->encr_type = WPS_ENCR_NONE; 1721e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 1722e5b75505Sopenharmony_ci else if (wps->encr_type & WPS_ENCR_WEP) 1723e5b75505Sopenharmony_ci wps->encr_type = WPS_ENCR_WEP; 1724e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1725e5b75505Sopenharmony_ci else { 1726e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No suitable encryption " 1727e5b75505Sopenharmony_ci "type for non-WPA/WPA2 mode"); 1728e5b75505Sopenharmony_ci return -1; 1729e5b75505Sopenharmony_ci } 1730e5b75505Sopenharmony_ci } 1731e5b75505Sopenharmony_ci wps->cred.encr_type = wps->encr_type; 1732e5b75505Sopenharmony_ci /* 1733e5b75505Sopenharmony_ci * Set MAC address in the Credential to be the Enrollee's MAC address 1734e5b75505Sopenharmony_ci */ 1735e5b75505Sopenharmony_ci os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN); 1736e5b75505Sopenharmony_ci 1737e5b75505Sopenharmony_ci if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap && 1738e5b75505Sopenharmony_ci !wps->wps->registrar->disable_auto_conf) { 1739e5b75505Sopenharmony_ci u8 r[16]; 1740e5b75505Sopenharmony_ci /* Generate a random passphrase */ 1741e5b75505Sopenharmony_ci if (random_pool_ready() != 1 || 1742e5b75505Sopenharmony_ci random_get_bytes(r, sizeof(r)) < 0) { 1743e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1744e5b75505Sopenharmony_ci "WPS: Could not generate random PSK"); 1745e5b75505Sopenharmony_ci return -1; 1746e5b75505Sopenharmony_ci } 1747e5b75505Sopenharmony_ci os_free(wps->new_psk); 1748e5b75505Sopenharmony_ci wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len); 1749e5b75505Sopenharmony_ci if (wps->new_psk == NULL) 1750e5b75505Sopenharmony_ci return -1; 1751e5b75505Sopenharmony_ci wps->new_psk_len--; /* remove newline */ 1752e5b75505Sopenharmony_ci while (wps->new_psk_len && 1753e5b75505Sopenharmony_ci wps->new_psk[wps->new_psk_len - 1] == '=') 1754e5b75505Sopenharmony_ci wps->new_psk_len--; 1755e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase", 1756e5b75505Sopenharmony_ci wps->new_psk, wps->new_psk_len); 1757e5b75505Sopenharmony_ci os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len); 1758e5b75505Sopenharmony_ci wps->cred.key_len = wps->new_psk_len; 1759e5b75505Sopenharmony_ci } else if (!wps->wps->registrar->force_per_enrollee_psk && 1760e5b75505Sopenharmony_ci wps->use_psk_key && wps->wps->psk_set) { 1761e5b75505Sopenharmony_ci char hex[65]; 1762e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); 1763e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32); 1764e5b75505Sopenharmony_ci os_memcpy(wps->cred.key, hex, 32 * 2); 1765e5b75505Sopenharmony_ci wps->cred.key_len = 32 * 2; 1766e5b75505Sopenharmony_ci } else if (!wps->wps->registrar->force_per_enrollee_psk && 1767e5b75505Sopenharmony_ci wps->wps->network_key) { 1768e5b75505Sopenharmony_ci os_memcpy(wps->cred.key, wps->wps->network_key, 1769e5b75505Sopenharmony_ci wps->wps->network_key_len); 1770e5b75505Sopenharmony_ci wps->cred.key_len = wps->wps->network_key_len; 1771e5b75505Sopenharmony_ci } else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { 1772e5b75505Sopenharmony_ci char hex[65]; 1773e5b75505Sopenharmony_ci /* Generate a random per-device PSK */ 1774e5b75505Sopenharmony_ci os_free(wps->new_psk); 1775e5b75505Sopenharmony_ci wps->new_psk_len = 32; 1776e5b75505Sopenharmony_ci wps->new_psk = os_malloc(wps->new_psk_len); 1777e5b75505Sopenharmony_ci if (wps->new_psk == NULL) 1778e5b75505Sopenharmony_ci return -1; 1779e5b75505Sopenharmony_ci if (random_pool_ready() != 1 || 1780e5b75505Sopenharmony_ci random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) { 1781e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1782e5b75505Sopenharmony_ci "WPS: Could not generate random PSK"); 1783e5b75505Sopenharmony_ci os_free(wps->new_psk); 1784e5b75505Sopenharmony_ci wps->new_psk = NULL; 1785e5b75505Sopenharmony_ci return -1; 1786e5b75505Sopenharmony_ci } 1787e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", 1788e5b75505Sopenharmony_ci wps->new_psk, wps->new_psk_len); 1789e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk, 1790e5b75505Sopenharmony_ci wps->new_psk_len); 1791e5b75505Sopenharmony_ci os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2); 1792e5b75505Sopenharmony_ci wps->cred.key_len = wps->new_psk_len * 2; 1793e5b75505Sopenharmony_ci } 1794e5b75505Sopenharmony_ci 1795e5b75505Sopenharmony_ciuse_provided: 1796e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_TESTING 1797e5b75505Sopenharmony_ci if (wps_testing_dummy_cred) 1798e5b75505Sopenharmony_ci cred = wpabuf_alloc(200); 1799e5b75505Sopenharmony_ci else 1800e5b75505Sopenharmony_ci cred = NULL; 1801e5b75505Sopenharmony_ci if (cred) { 1802e5b75505Sopenharmony_ci struct wps_credential dummy; 1803e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add dummy credential"); 1804e5b75505Sopenharmony_ci os_memset(&dummy, 0, sizeof(dummy)); 1805e5b75505Sopenharmony_ci os_memcpy(dummy.ssid, "dummy", 5); 1806e5b75505Sopenharmony_ci dummy.ssid_len = 5; 1807e5b75505Sopenharmony_ci dummy.auth_type = WPS_AUTH_WPA2PSK; 1808e5b75505Sopenharmony_ci dummy.encr_type = WPS_ENCR_AES; 1809e5b75505Sopenharmony_ci os_memcpy(dummy.key, "dummy psk", 9); 1810e5b75505Sopenharmony_ci dummy.key_len = 9; 1811e5b75505Sopenharmony_ci os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN); 1812e5b75505Sopenharmony_ci wps_build_credential(cred, &dummy); 1813e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred); 1814e5b75505Sopenharmony_ci 1815e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_CRED); 1816e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wpabuf_len(cred)); 1817e5b75505Sopenharmony_ci wpabuf_put_buf(msg, cred); 1818e5b75505Sopenharmony_ci 1819e5b75505Sopenharmony_ci wpabuf_free(cred); 1820e5b75505Sopenharmony_ci } 1821e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_TESTING */ 1822e5b75505Sopenharmony_ci 1823e5b75505Sopenharmony_ci cred = wpabuf_alloc(200); 1824e5b75505Sopenharmony_ci if (cred == NULL) 1825e5b75505Sopenharmony_ci return -1; 1826e5b75505Sopenharmony_ci 1827e5b75505Sopenharmony_ci if (wps_build_credential(cred, &wps->cred)) { 1828e5b75505Sopenharmony_ci wpabuf_clear_free(cred); 1829e5b75505Sopenharmony_ci return -1; 1830e5b75505Sopenharmony_ci } 1831e5b75505Sopenharmony_ci 1832e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_CRED); 1833e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wpabuf_len(cred)); 1834e5b75505Sopenharmony_ci wpabuf_put_buf(msg, cred); 1835e5b75505Sopenharmony_ci wpabuf_clear_free(cred); 1836e5b75505Sopenharmony_ci 1837e5b75505Sopenharmony_ciskip_cred_build: 1838e5b75505Sopenharmony_ci if (wps->wps->registrar->extra_cred) { 1839e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * Credential (pre-configured)"); 1840e5b75505Sopenharmony_ci wpabuf_put_buf(msg, wps->wps->registrar->extra_cred); 1841e5b75505Sopenharmony_ci } 1842e5b75505Sopenharmony_ci 1843e5b75505Sopenharmony_ci return 0; 1844e5b75505Sopenharmony_ci} 1845e5b75505Sopenharmony_ci 1846e5b75505Sopenharmony_ci 1847e5b75505Sopenharmony_cistatic int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg) 1848e5b75505Sopenharmony_ci{ 1849e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: * AP Settings"); 1850e5b75505Sopenharmony_ci 1851e5b75505Sopenharmony_ci if (wps_build_credential(msg, &wps->cred)) 1852e5b75505Sopenharmony_ci return -1; 1853e5b75505Sopenharmony_ci 1854e5b75505Sopenharmony_ci return 0; 1855e5b75505Sopenharmony_ci} 1856e5b75505Sopenharmony_ci 1857e5b75505Sopenharmony_ci 1858e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_ap_cred(struct wps_data *wps) 1859e5b75505Sopenharmony_ci{ 1860e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 1861e5b75505Sopenharmony_ci 1862e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 1863e5b75505Sopenharmony_ci if (msg == NULL) 1864e5b75505Sopenharmony_ci return NULL; 1865e5b75505Sopenharmony_ci 1866e5b75505Sopenharmony_ci plain = wpabuf_alloc(200); 1867e5b75505Sopenharmony_ci if (plain == NULL) { 1868e5b75505Sopenharmony_ci wpabuf_free(msg); 1869e5b75505Sopenharmony_ci return NULL; 1870e5b75505Sopenharmony_ci } 1871e5b75505Sopenharmony_ci 1872e5b75505Sopenharmony_ci if (wps_build_ap_settings(wps, plain)) { 1873e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 1874e5b75505Sopenharmony_ci wpabuf_free(msg); 1875e5b75505Sopenharmony_ci return NULL; 1876e5b75505Sopenharmony_ci } 1877e5b75505Sopenharmony_ci 1878e5b75505Sopenharmony_ci wpabuf_put_be16(msg, ATTR_CRED); 1879e5b75505Sopenharmony_ci wpabuf_put_be16(msg, wpabuf_len(plain)); 1880e5b75505Sopenharmony_ci wpabuf_put_buf(msg, plain); 1881e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 1882e5b75505Sopenharmony_ci 1883e5b75505Sopenharmony_ci return msg; 1884e5b75505Sopenharmony_ci} 1885e5b75505Sopenharmony_ci 1886e5b75505Sopenharmony_ci 1887e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m2(struct wps_data *wps) 1888e5b75505Sopenharmony_ci{ 1889e5b75505Sopenharmony_ci struct wpabuf *msg; 1890e5b75505Sopenharmony_ci int config_in_m2 = 0; 1891e5b75505Sopenharmony_ci 1892e5b75505Sopenharmony_ci if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0) 1893e5b75505Sopenharmony_ci return NULL; 1894e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce", 1895e5b75505Sopenharmony_ci wps->nonce_r, WPS_NONCE_LEN); 1896e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN); 1897e5b75505Sopenharmony_ci 1898e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M2"); 1899e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 1900e5b75505Sopenharmony_ci if (msg == NULL) 1901e5b75505Sopenharmony_ci return NULL; 1902e5b75505Sopenharmony_ci 1903e5b75505Sopenharmony_ci if (wps_build_version(msg) || 1904e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M2) || 1905e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 1906e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 1907e5b75505Sopenharmony_ci wps_build_uuid_r(wps, msg) || 1908e5b75505Sopenharmony_ci wps_build_public_key(wps, msg) || 1909e5b75505Sopenharmony_ci wps_derive_keys(wps) || 1910e5b75505Sopenharmony_ci wps_build_auth_type_flags(wps, msg) || 1911e5b75505Sopenharmony_ci wps_build_encr_type_flags(wps, msg) || 1912e5b75505Sopenharmony_ci wps_build_conn_type_flags(wps, msg) || 1913e5b75505Sopenharmony_ci wps_build_config_methods_r(wps->wps->registrar, msg) || 1914e5b75505Sopenharmony_ci wps_build_device_attrs(&wps->wps->dev, msg) || 1915e5b75505Sopenharmony_ci wps_build_rf_bands(&wps->wps->dev, msg, 1916e5b75505Sopenharmony_ci wps->wps->rf_band_cb(wps->wps->cb_ctx)) || 1917e5b75505Sopenharmony_ci wps_build_assoc_state(wps, msg) || 1918e5b75505Sopenharmony_ci wps_build_config_error(msg, WPS_CFG_NO_ERROR) || 1919e5b75505Sopenharmony_ci wps_build_dev_password_id(msg, wps->dev_pw_id) || 1920e5b75505Sopenharmony_ci wps_build_os_version(&wps->wps->dev, msg) || 1921e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 1922e5b75505Sopenharmony_ci wpabuf_free(msg); 1923e5b75505Sopenharmony_ci return NULL; 1924e5b75505Sopenharmony_ci } 1925e5b75505Sopenharmony_ci 1926e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 1927e5b75505Sopenharmony_ci if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob && 1928e5b75505Sopenharmony_ci wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) { 1929e5b75505Sopenharmony_ci /* 1930e5b75505Sopenharmony_ci * Use abbreviated handshake since public key hash allowed 1931e5b75505Sopenharmony_ci * Enrollee to validate our public key similarly to how Enrollee 1932e5b75505Sopenharmony_ci * public key was validated. There is no need to validate Device 1933e5b75505Sopenharmony_ci * Password in this case. 1934e5b75505Sopenharmony_ci */ 1935e5b75505Sopenharmony_ci struct wpabuf *plain = wpabuf_alloc(500); 1936e5b75505Sopenharmony_ci if (plain == NULL || 1937e5b75505Sopenharmony_ci wps_build_cred(wps, plain) || 1938e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 1939e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain)) { 1940e5b75505Sopenharmony_ci wpabuf_free(msg); 1941e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 1942e5b75505Sopenharmony_ci return NULL; 1943e5b75505Sopenharmony_ci } 1944e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 1945e5b75505Sopenharmony_ci config_in_m2 = 1; 1946e5b75505Sopenharmony_ci } 1947e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 1948e5b75505Sopenharmony_ci 1949e5b75505Sopenharmony_ci if (wps_build_authenticator(wps, msg)) { 1950e5b75505Sopenharmony_ci wpabuf_free(msg); 1951e5b75505Sopenharmony_ci return NULL; 1952e5b75505Sopenharmony_ci } 1953e5b75505Sopenharmony_ci 1954e5b75505Sopenharmony_ci wps->int_reg = 1; 1955e5b75505Sopenharmony_ci wps->state = config_in_m2 ? RECV_DONE : RECV_M3; 1956e5b75505Sopenharmony_ci return msg; 1957e5b75505Sopenharmony_ci} 1958e5b75505Sopenharmony_ci 1959e5b75505Sopenharmony_ci 1960e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m2d(struct wps_data *wps) 1961e5b75505Sopenharmony_ci{ 1962e5b75505Sopenharmony_ci struct wpabuf *msg; 1963e5b75505Sopenharmony_ci u16 err = wps->config_error; 1964e5b75505Sopenharmony_ci 1965e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M2D"); 1966e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 1967e5b75505Sopenharmony_ci if (msg == NULL) 1968e5b75505Sopenharmony_ci return NULL; 1969e5b75505Sopenharmony_ci 1970e5b75505Sopenharmony_ci if (wps->wps->ap && wps->wps->ap_setup_locked && 1971e5b75505Sopenharmony_ci err == WPS_CFG_NO_ERROR) 1972e5b75505Sopenharmony_ci err = WPS_CFG_SETUP_LOCKED; 1973e5b75505Sopenharmony_ci 1974e5b75505Sopenharmony_ci if (wps_build_version(msg) || 1975e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M2D) || 1976e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 1977e5b75505Sopenharmony_ci wps_build_registrar_nonce(wps, msg) || 1978e5b75505Sopenharmony_ci wps_build_uuid_r(wps, msg) || 1979e5b75505Sopenharmony_ci wps_build_auth_type_flags(wps, msg) || 1980e5b75505Sopenharmony_ci wps_build_encr_type_flags(wps, msg) || 1981e5b75505Sopenharmony_ci wps_build_conn_type_flags(wps, msg) || 1982e5b75505Sopenharmony_ci wps_build_config_methods_r(wps->wps->registrar, msg) || 1983e5b75505Sopenharmony_ci wps_build_device_attrs(&wps->wps->dev, msg) || 1984e5b75505Sopenharmony_ci wps_build_rf_bands(&wps->wps->dev, msg, 1985e5b75505Sopenharmony_ci wps->wps->rf_band_cb(wps->wps->cb_ctx)) || 1986e5b75505Sopenharmony_ci wps_build_assoc_state(wps, msg) || 1987e5b75505Sopenharmony_ci wps_build_config_error(msg, err) || 1988e5b75505Sopenharmony_ci wps_build_os_version(&wps->wps->dev, msg) || 1989e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { 1990e5b75505Sopenharmony_ci wpabuf_free(msg); 1991e5b75505Sopenharmony_ci return NULL; 1992e5b75505Sopenharmony_ci } 1993e5b75505Sopenharmony_ci 1994e5b75505Sopenharmony_ci wps->state = RECV_M2D_ACK; 1995e5b75505Sopenharmony_ci return msg; 1996e5b75505Sopenharmony_ci} 1997e5b75505Sopenharmony_ci 1998e5b75505Sopenharmony_ci 1999e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m4(struct wps_data *wps) 2000e5b75505Sopenharmony_ci{ 2001e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 2002e5b75505Sopenharmony_ci 2003e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M4"); 2004e5b75505Sopenharmony_ci 2005e5b75505Sopenharmony_ci if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0) 2006e5b75505Sopenharmony_ci return NULL; 2007e5b75505Sopenharmony_ci 2008e5b75505Sopenharmony_ci plain = wpabuf_alloc(200); 2009e5b75505Sopenharmony_ci if (plain == NULL) 2010e5b75505Sopenharmony_ci return NULL; 2011e5b75505Sopenharmony_ci 2012e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 2013e5b75505Sopenharmony_ci if (msg == NULL) { 2014e5b75505Sopenharmony_ci wpabuf_free(plain); 2015e5b75505Sopenharmony_ci return NULL; 2016e5b75505Sopenharmony_ci } 2017e5b75505Sopenharmony_ci 2018e5b75505Sopenharmony_ci if (wps_build_version(msg) || 2019e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M4) || 2020e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 2021e5b75505Sopenharmony_ci wps_build_r_hash(wps, msg) || 2022e5b75505Sopenharmony_ci wps_build_r_snonce1(wps, plain) || 2023e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 2024e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain) || 2025e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 2026e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 2027e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2028e5b75505Sopenharmony_ci wpabuf_free(msg); 2029e5b75505Sopenharmony_ci return NULL; 2030e5b75505Sopenharmony_ci } 2031e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2032e5b75505Sopenharmony_ci 2033e5b75505Sopenharmony_ci wps->state = RECV_M5; 2034e5b75505Sopenharmony_ci return msg; 2035e5b75505Sopenharmony_ci} 2036e5b75505Sopenharmony_ci 2037e5b75505Sopenharmony_ci 2038e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m6(struct wps_data *wps) 2039e5b75505Sopenharmony_ci{ 2040e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 2041e5b75505Sopenharmony_ci 2042e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M6"); 2043e5b75505Sopenharmony_ci 2044e5b75505Sopenharmony_ci plain = wpabuf_alloc(200); 2045e5b75505Sopenharmony_ci if (plain == NULL) 2046e5b75505Sopenharmony_ci return NULL; 2047e5b75505Sopenharmony_ci 2048e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 2049e5b75505Sopenharmony_ci if (msg == NULL) { 2050e5b75505Sopenharmony_ci wpabuf_free(plain); 2051e5b75505Sopenharmony_ci return NULL; 2052e5b75505Sopenharmony_ci } 2053e5b75505Sopenharmony_ci 2054e5b75505Sopenharmony_ci if (wps_build_version(msg) || 2055e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M6) || 2056e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 2057e5b75505Sopenharmony_ci wps_build_r_snonce2(wps, plain) || 2058e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 2059e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain) || 2060e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 2061e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 2062e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2063e5b75505Sopenharmony_ci wpabuf_free(msg); 2064e5b75505Sopenharmony_ci return NULL; 2065e5b75505Sopenharmony_ci } 2066e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2067e5b75505Sopenharmony_ci 2068e5b75505Sopenharmony_ci wps->wps_pin_revealed = 1; 2069e5b75505Sopenharmony_ci wps->state = RECV_M7; 2070e5b75505Sopenharmony_ci return msg; 2071e5b75505Sopenharmony_ci} 2072e5b75505Sopenharmony_ci 2073e5b75505Sopenharmony_ci 2074e5b75505Sopenharmony_cistatic struct wpabuf * wps_build_m8(struct wps_data *wps) 2075e5b75505Sopenharmony_ci{ 2076e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 2077e5b75505Sopenharmony_ci 2078e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Building Message M8"); 2079e5b75505Sopenharmony_ci 2080e5b75505Sopenharmony_ci plain = wpabuf_alloc(500); 2081e5b75505Sopenharmony_ci if (plain == NULL) 2082e5b75505Sopenharmony_ci return NULL; 2083e5b75505Sopenharmony_ci 2084e5b75505Sopenharmony_ci msg = wpabuf_alloc(1000); 2085e5b75505Sopenharmony_ci if (msg == NULL) { 2086e5b75505Sopenharmony_ci wpabuf_free(plain); 2087e5b75505Sopenharmony_ci return NULL; 2088e5b75505Sopenharmony_ci } 2089e5b75505Sopenharmony_ci 2090e5b75505Sopenharmony_ci if (wps_build_version(msg) || 2091e5b75505Sopenharmony_ci wps_build_msg_type(msg, WPS_M8) || 2092e5b75505Sopenharmony_ci wps_build_enrollee_nonce(wps, msg) || 2093e5b75505Sopenharmony_ci ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) || 2094e5b75505Sopenharmony_ci (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || 2095e5b75505Sopenharmony_ci wps_build_key_wrap_auth(wps, plain) || 2096e5b75505Sopenharmony_ci wps_build_encr_settings(wps, msg, plain) || 2097e5b75505Sopenharmony_ci wps_build_wfa_ext(msg, 0, NULL, 0, 0) || 2098e5b75505Sopenharmony_ci wps_build_authenticator(wps, msg)) { 2099e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2100e5b75505Sopenharmony_ci wpabuf_clear_free(msg); 2101e5b75505Sopenharmony_ci return NULL; 2102e5b75505Sopenharmony_ci } 2103e5b75505Sopenharmony_ci wpabuf_clear_free(plain); 2104e5b75505Sopenharmony_ci 2105e5b75505Sopenharmony_ci wps->state = RECV_DONE; 2106e5b75505Sopenharmony_ci return msg; 2107e5b75505Sopenharmony_ci} 2108e5b75505Sopenharmony_ci 2109e5b75505Sopenharmony_ci 2110e5b75505Sopenharmony_cistruct wpabuf * wps_registrar_get_msg(struct wps_data *wps, 2111e5b75505Sopenharmony_ci enum wsc_op_code *op_code) 2112e5b75505Sopenharmony_ci{ 2113e5b75505Sopenharmony_ci struct wpabuf *msg; 2114e5b75505Sopenharmony_ci 2115e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 2116e5b75505Sopenharmony_ci if (!wps->int_reg && wps->wps->wps_upnp) { 2117e5b75505Sopenharmony_ci struct upnp_pending_message *p, *prev = NULL; 2118e5b75505Sopenharmony_ci if (wps->ext_reg > 1) 2119e5b75505Sopenharmony_ci wps_registrar_free_pending_m2(wps->wps); 2120e5b75505Sopenharmony_ci p = wps->wps->upnp_msgs; 2121e5b75505Sopenharmony_ci /* TODO: check pending message MAC address */ 2122e5b75505Sopenharmony_ci while (p && p->next) { 2123e5b75505Sopenharmony_ci prev = p; 2124e5b75505Sopenharmony_ci p = p->next; 2125e5b75505Sopenharmony_ci } 2126e5b75505Sopenharmony_ci if (p) { 2127e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Use pending message from " 2128e5b75505Sopenharmony_ci "UPnP"); 2129e5b75505Sopenharmony_ci if (prev) 2130e5b75505Sopenharmony_ci prev->next = NULL; 2131e5b75505Sopenharmony_ci else 2132e5b75505Sopenharmony_ci wps->wps->upnp_msgs = NULL; 2133e5b75505Sopenharmony_ci msg = p->msg; 2134e5b75505Sopenharmony_ci switch (p->type) { 2135e5b75505Sopenharmony_ci case WPS_WSC_ACK: 2136e5b75505Sopenharmony_ci *op_code = WSC_ACK; 2137e5b75505Sopenharmony_ci break; 2138e5b75505Sopenharmony_ci case WPS_WSC_NACK: 2139e5b75505Sopenharmony_ci *op_code = WSC_NACK; 2140e5b75505Sopenharmony_ci break; 2141e5b75505Sopenharmony_ci default: 2142e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2143e5b75505Sopenharmony_ci break; 2144e5b75505Sopenharmony_ci } 2145e5b75505Sopenharmony_ci os_free(p); 2146e5b75505Sopenharmony_ci if (wps->ext_reg == 0) 2147e5b75505Sopenharmony_ci wps->ext_reg = 1; 2148e5b75505Sopenharmony_ci return msg; 2149e5b75505Sopenharmony_ci } 2150e5b75505Sopenharmony_ci } 2151e5b75505Sopenharmony_ci if (wps->ext_reg) { 2152e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no " 2153e5b75505Sopenharmony_ci "pending message available"); 2154e5b75505Sopenharmony_ci return NULL; 2155e5b75505Sopenharmony_ci } 2156e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 2157e5b75505Sopenharmony_ci 2158e5b75505Sopenharmony_ci switch (wps->state) { 2159e5b75505Sopenharmony_ci case SEND_M2: 2160e5b75505Sopenharmony_ci if (wps_get_dev_password(wps) < 0) 2161e5b75505Sopenharmony_ci msg = wps_build_m2d(wps); 2162e5b75505Sopenharmony_ci else 2163e5b75505Sopenharmony_ci msg = wps_build_m2(wps); 2164e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2165e5b75505Sopenharmony_ci break; 2166e5b75505Sopenharmony_ci case SEND_M2D: 2167e5b75505Sopenharmony_ci msg = wps_build_m2d(wps); 2168e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2169e5b75505Sopenharmony_ci break; 2170e5b75505Sopenharmony_ci case SEND_M4: 2171e5b75505Sopenharmony_ci msg = wps_build_m4(wps); 2172e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2173e5b75505Sopenharmony_ci break; 2174e5b75505Sopenharmony_ci case SEND_M6: 2175e5b75505Sopenharmony_ci msg = wps_build_m6(wps); 2176e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2177e5b75505Sopenharmony_ci break; 2178e5b75505Sopenharmony_ci case SEND_M8: 2179e5b75505Sopenharmony_ci msg = wps_build_m8(wps); 2180e5b75505Sopenharmony_ci *op_code = WSC_MSG; 2181e5b75505Sopenharmony_ci break; 2182e5b75505Sopenharmony_ci case RECV_DONE: 2183e5b75505Sopenharmony_ci msg = wps_build_wsc_ack(wps); 2184e5b75505Sopenharmony_ci *op_code = WSC_ACK; 2185e5b75505Sopenharmony_ci break; 2186e5b75505Sopenharmony_ci case SEND_WSC_NACK: 2187e5b75505Sopenharmony_ci msg = wps_build_wsc_nack(wps); 2188e5b75505Sopenharmony_ci *op_code = WSC_NACK; 2189e5b75505Sopenharmony_ci break; 2190e5b75505Sopenharmony_ci default: 2191e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building " 2192e5b75505Sopenharmony_ci "a message", wps->state); 2193e5b75505Sopenharmony_ci msg = NULL; 2194e5b75505Sopenharmony_ci break; 2195e5b75505Sopenharmony_ci } 2196e5b75505Sopenharmony_ci 2197e5b75505Sopenharmony_ci if (*op_code == WSC_MSG && msg) { 2198e5b75505Sopenharmony_ci /* Save a copy of the last message for Authenticator derivation 2199e5b75505Sopenharmony_ci */ 2200e5b75505Sopenharmony_ci wpabuf_free(wps->last_msg); 2201e5b75505Sopenharmony_ci wps->last_msg = wpabuf_dup(msg); 2202e5b75505Sopenharmony_ci } 2203e5b75505Sopenharmony_ci 2204e5b75505Sopenharmony_ci return msg; 2205e5b75505Sopenharmony_ci} 2206e5b75505Sopenharmony_ci 2207e5b75505Sopenharmony_ci 2208e5b75505Sopenharmony_cistatic int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce) 2209e5b75505Sopenharmony_ci{ 2210e5b75505Sopenharmony_ci if (e_nonce == NULL) { 2211e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received"); 2212e5b75505Sopenharmony_ci return -1; 2213e5b75505Sopenharmony_ci } 2214e5b75505Sopenharmony_ci 2215e5b75505Sopenharmony_ci os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN); 2216e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", 2217e5b75505Sopenharmony_ci wps->nonce_e, WPS_NONCE_LEN); 2218e5b75505Sopenharmony_ci 2219e5b75505Sopenharmony_ci return 0; 2220e5b75505Sopenharmony_ci} 2221e5b75505Sopenharmony_ci 2222e5b75505Sopenharmony_ci 2223e5b75505Sopenharmony_cistatic int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce) 2224e5b75505Sopenharmony_ci{ 2225e5b75505Sopenharmony_ci if (r_nonce == NULL) { 2226e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received"); 2227e5b75505Sopenharmony_ci return -1; 2228e5b75505Sopenharmony_ci } 2229e5b75505Sopenharmony_ci 2230e5b75505Sopenharmony_ci if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) { 2231e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received"); 2232e5b75505Sopenharmony_ci return -1; 2233e5b75505Sopenharmony_ci } 2234e5b75505Sopenharmony_ci 2235e5b75505Sopenharmony_ci return 0; 2236e5b75505Sopenharmony_ci} 2237e5b75505Sopenharmony_ci 2238e5b75505Sopenharmony_ci 2239e5b75505Sopenharmony_cistatic int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e) 2240e5b75505Sopenharmony_ci{ 2241e5b75505Sopenharmony_ci if (uuid_e == NULL) { 2242e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No UUID-E received"); 2243e5b75505Sopenharmony_ci return -1; 2244e5b75505Sopenharmony_ci } 2245e5b75505Sopenharmony_ci 2246e5b75505Sopenharmony_ci os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN); 2247e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN); 2248e5b75505Sopenharmony_ci 2249e5b75505Sopenharmony_ci return 0; 2250e5b75505Sopenharmony_ci} 2251e5b75505Sopenharmony_ci 2252e5b75505Sopenharmony_ci 2253e5b75505Sopenharmony_cistatic int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id) 2254e5b75505Sopenharmony_ci{ 2255e5b75505Sopenharmony_ci if (pw_id == NULL) { 2256e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received"); 2257e5b75505Sopenharmony_ci return -1; 2258e5b75505Sopenharmony_ci } 2259e5b75505Sopenharmony_ci 2260e5b75505Sopenharmony_ci wps->dev_pw_id = WPA_GET_BE16(pw_id); 2261e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id); 2262e5b75505Sopenharmony_ci 2263e5b75505Sopenharmony_ci return 0; 2264e5b75505Sopenharmony_ci} 2265e5b75505Sopenharmony_ci 2266e5b75505Sopenharmony_ci 2267e5b75505Sopenharmony_cistatic int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1) 2268e5b75505Sopenharmony_ci{ 2269e5b75505Sopenharmony_ci if (e_hash1 == NULL) { 2270e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received"); 2271e5b75505Sopenharmony_ci return -1; 2272e5b75505Sopenharmony_ci } 2273e5b75505Sopenharmony_ci 2274e5b75505Sopenharmony_ci os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN); 2275e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN); 2276e5b75505Sopenharmony_ci 2277e5b75505Sopenharmony_ci return 0; 2278e5b75505Sopenharmony_ci} 2279e5b75505Sopenharmony_ci 2280e5b75505Sopenharmony_ci 2281e5b75505Sopenharmony_cistatic int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2) 2282e5b75505Sopenharmony_ci{ 2283e5b75505Sopenharmony_ci if (e_hash2 == NULL) { 2284e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received"); 2285e5b75505Sopenharmony_ci return -1; 2286e5b75505Sopenharmony_ci } 2287e5b75505Sopenharmony_ci 2288e5b75505Sopenharmony_ci os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN); 2289e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN); 2290e5b75505Sopenharmony_ci 2291e5b75505Sopenharmony_ci return 0; 2292e5b75505Sopenharmony_ci} 2293e5b75505Sopenharmony_ci 2294e5b75505Sopenharmony_ci 2295e5b75505Sopenharmony_cistatic int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1) 2296e5b75505Sopenharmony_ci{ 2297e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 2298e5b75505Sopenharmony_ci const u8 *addr[4]; 2299e5b75505Sopenharmony_ci size_t len[4]; 2300e5b75505Sopenharmony_ci 2301e5b75505Sopenharmony_ci if (e_snonce1 == NULL) { 2302e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received"); 2303e5b75505Sopenharmony_ci return -1; 2304e5b75505Sopenharmony_ci } 2305e5b75505Sopenharmony_ci 2306e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1, 2307e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 2308e5b75505Sopenharmony_ci 2309e5b75505Sopenharmony_ci /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ 2310e5b75505Sopenharmony_ci addr[0] = e_snonce1; 2311e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 2312e5b75505Sopenharmony_ci addr[1] = wps->psk1; 2313e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 2314e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 2315e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 2316e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 2317e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 2318e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 2319e5b75505Sopenharmony_ci 2320e5b75505Sopenharmony_ci if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { 2321e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does " 2322e5b75505Sopenharmony_ci "not match with the pre-committed value"); 2323e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 2324e5b75505Sopenharmony_ci wps_pwd_auth_fail_event(wps->wps, 0, 1, wps->mac_addr_e); 2325e5b75505Sopenharmony_ci return -1; 2326e5b75505Sopenharmony_ci } 2327e5b75505Sopenharmony_ci 2328e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first " 2329e5b75505Sopenharmony_ci "half of the device password"); 2330e5b75505Sopenharmony_ci 2331e5b75505Sopenharmony_ci return 0; 2332e5b75505Sopenharmony_ci} 2333e5b75505Sopenharmony_ci 2334e5b75505Sopenharmony_ci 2335e5b75505Sopenharmony_cistatic int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2) 2336e5b75505Sopenharmony_ci{ 2337e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 2338e5b75505Sopenharmony_ci const u8 *addr[4]; 2339e5b75505Sopenharmony_ci size_t len[4]; 2340e5b75505Sopenharmony_ci 2341e5b75505Sopenharmony_ci if (e_snonce2 == NULL) { 2342e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received"); 2343e5b75505Sopenharmony_ci return -1; 2344e5b75505Sopenharmony_ci } 2345e5b75505Sopenharmony_ci 2346e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2, 2347e5b75505Sopenharmony_ci WPS_SECRET_NONCE_LEN); 2348e5b75505Sopenharmony_ci 2349e5b75505Sopenharmony_ci /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ 2350e5b75505Sopenharmony_ci addr[0] = e_snonce2; 2351e5b75505Sopenharmony_ci len[0] = WPS_SECRET_NONCE_LEN; 2352e5b75505Sopenharmony_ci addr[1] = wps->psk2; 2353e5b75505Sopenharmony_ci len[1] = WPS_PSK_LEN; 2354e5b75505Sopenharmony_ci addr[2] = wpabuf_head(wps->dh_pubkey_e); 2355e5b75505Sopenharmony_ci len[2] = wpabuf_len(wps->dh_pubkey_e); 2356e5b75505Sopenharmony_ci addr[3] = wpabuf_head(wps->dh_pubkey_r); 2357e5b75505Sopenharmony_ci len[3] = wpabuf_len(wps->dh_pubkey_r); 2358e5b75505Sopenharmony_ci hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); 2359e5b75505Sopenharmony_ci 2360e5b75505Sopenharmony_ci if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { 2361e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does " 2362e5b75505Sopenharmony_ci "not match with the pre-committed value"); 2363e5b75505Sopenharmony_ci wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e); 2364e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; 2365e5b75505Sopenharmony_ci wps_pwd_auth_fail_event(wps->wps, 0, 2, wps->mac_addr_e); 2366e5b75505Sopenharmony_ci return -1; 2367e5b75505Sopenharmony_ci } 2368e5b75505Sopenharmony_ci 2369e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second " 2370e5b75505Sopenharmony_ci "half of the device password"); 2371e5b75505Sopenharmony_ci wps->wps_pin_revealed = 0; 2372e5b75505Sopenharmony_ci wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e); 2373e5b75505Sopenharmony_ci 2374e5b75505Sopenharmony_ci /* 2375e5b75505Sopenharmony_ci * In case wildcard PIN is used and WPS handshake succeeds in the first 2376e5b75505Sopenharmony_ci * attempt, wps_registrar_unlock_pin() would not free the PIN, so make 2377e5b75505Sopenharmony_ci * sure the PIN gets invalidated here. 2378e5b75505Sopenharmony_ci */ 2379e5b75505Sopenharmony_ci wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e); 2380e5b75505Sopenharmony_ci 2381e5b75505Sopenharmony_ci return 0; 2382e5b75505Sopenharmony_ci} 2383e5b75505Sopenharmony_ci 2384e5b75505Sopenharmony_ci 2385e5b75505Sopenharmony_cistatic int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr) 2386e5b75505Sopenharmony_ci{ 2387e5b75505Sopenharmony_ci if (mac_addr == NULL) { 2388e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No MAC Address received"); 2389e5b75505Sopenharmony_ci return -1; 2390e5b75505Sopenharmony_ci } 2391e5b75505Sopenharmony_ci 2392e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR, 2393e5b75505Sopenharmony_ci MAC2STR(mac_addr)); 2394e5b75505Sopenharmony_ci os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN); 2395e5b75505Sopenharmony_ci os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN); 2396e5b75505Sopenharmony_ci 2397e5b75505Sopenharmony_ci return 0; 2398e5b75505Sopenharmony_ci} 2399e5b75505Sopenharmony_ci 2400e5b75505Sopenharmony_ci 2401e5b75505Sopenharmony_cistatic int wps_process_pubkey(struct wps_data *wps, const u8 *pk, 2402e5b75505Sopenharmony_ci size_t pk_len) 2403e5b75505Sopenharmony_ci{ 2404e5b75505Sopenharmony_ci if (pk == NULL || pk_len == 0) { 2405e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Public Key received"); 2406e5b75505Sopenharmony_ci return -1; 2407e5b75505Sopenharmony_ci } 2408e5b75505Sopenharmony_ci 2409e5b75505Sopenharmony_ci wpabuf_free(wps->dh_pubkey_e); 2410e5b75505Sopenharmony_ci wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len); 2411e5b75505Sopenharmony_ci if (wps->dh_pubkey_e == NULL) 2412e5b75505Sopenharmony_ci return -1; 2413e5b75505Sopenharmony_ci 2414e5b75505Sopenharmony_ci return 0; 2415e5b75505Sopenharmony_ci} 2416e5b75505Sopenharmony_ci 2417e5b75505Sopenharmony_ci 2418e5b75505Sopenharmony_cistatic int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth) 2419e5b75505Sopenharmony_ci{ 2420e5b75505Sopenharmony_ci u16 auth_types; 2421e5b75505Sopenharmony_ci 2422e5b75505Sopenharmony_ci if (auth == NULL) { 2423e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags " 2424e5b75505Sopenharmony_ci "received"); 2425e5b75505Sopenharmony_ci return -1; 2426e5b75505Sopenharmony_ci } 2427e5b75505Sopenharmony_ci 2428e5b75505Sopenharmony_ci auth_types = WPA_GET_BE16(auth); 2429e5b75505Sopenharmony_ci 2430e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x", 2431e5b75505Sopenharmony_ci auth_types); 2432e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 2433e5b75505Sopenharmony_ci /* 2434e5b75505Sopenharmony_ci * Some deployed implementations seem to advertise incorrect information 2435e5b75505Sopenharmony_ci * in this attribute. A value of 0x1b (WPA2 + WPA + WPAPSK + OPEN, but 2436e5b75505Sopenharmony_ci * no WPA2PSK) has been reported to be used. Add WPA2PSK to the list to 2437e5b75505Sopenharmony_ci * avoid issues with building Credentials that do not use the strongest 2438e5b75505Sopenharmony_ci * actually supported authentication option (that device does support 2439e5b75505Sopenharmony_ci * WPA2PSK even when it does not claim it here). 2440e5b75505Sopenharmony_ci */ 2441e5b75505Sopenharmony_ci if ((auth_types & 2442e5b75505Sopenharmony_ci (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) == 2443e5b75505Sopenharmony_ci (WPS_AUTH_WPA2 | WPS_AUTH_WPAPSK)) { 2444e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2445e5b75505Sopenharmony_ci "WPS: Workaround - assume Enrollee supports WPA2PSK based on claimed WPA2 support"); 2446e5b75505Sopenharmony_ci auth_types |= WPS_AUTH_WPA2PSK; 2447e5b75505Sopenharmony_ci } 2448e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 2449e5b75505Sopenharmony_ci wps->auth_type = wps->wps->auth_types & auth_types; 2450e5b75505Sopenharmony_ci if (wps->auth_type == 0) { 2451e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No match in supported " 2452e5b75505Sopenharmony_ci "authentication types (own 0x%x Enrollee 0x%x)", 2453e5b75505Sopenharmony_ci wps->wps->auth_types, auth_types); 2454e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 2455e5b75505Sopenharmony_ci /* 2456e5b75505Sopenharmony_ci * Some deployed implementations seem to advertise incorrect 2457e5b75505Sopenharmony_ci * information in this attribute. For example, Linksys WRT350N 2458e5b75505Sopenharmony_ci * seems to have a byteorder bug that breaks this negotiation. 2459e5b75505Sopenharmony_ci * In order to interoperate with existing implementations, 2460e5b75505Sopenharmony_ci * assume that the Enrollee supports everything we do. 2461e5b75505Sopenharmony_ci */ 2462e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee " 2463e5b75505Sopenharmony_ci "does not advertise supported authentication types " 2464e5b75505Sopenharmony_ci "correctly"); 2465e5b75505Sopenharmony_ci wps->auth_type = wps->wps->auth_types; 2466e5b75505Sopenharmony_ci#else /* WPS_WORKAROUNDS */ 2467e5b75505Sopenharmony_ci return -1; 2468e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 2469e5b75505Sopenharmony_ci } 2470e5b75505Sopenharmony_ci 2471e5b75505Sopenharmony_ci return 0; 2472e5b75505Sopenharmony_ci} 2473e5b75505Sopenharmony_ci 2474e5b75505Sopenharmony_ci 2475e5b75505Sopenharmony_cistatic int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr) 2476e5b75505Sopenharmony_ci{ 2477e5b75505Sopenharmony_ci u16 encr_types; 2478e5b75505Sopenharmony_ci 2479e5b75505Sopenharmony_ci if (encr == NULL) { 2480e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags " 2481e5b75505Sopenharmony_ci "received"); 2482e5b75505Sopenharmony_ci return -1; 2483e5b75505Sopenharmony_ci } 2484e5b75505Sopenharmony_ci 2485e5b75505Sopenharmony_ci encr_types = WPA_GET_BE16(encr); 2486e5b75505Sopenharmony_ci 2487e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x", 2488e5b75505Sopenharmony_ci encr_types); 2489e5b75505Sopenharmony_ci wps->encr_type = wps->wps->encr_types & encr_types; 2490e5b75505Sopenharmony_ci if (wps->encr_type == 0) { 2491e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No match in supported " 2492e5b75505Sopenharmony_ci "encryption types (own 0x%x Enrollee 0x%x)", 2493e5b75505Sopenharmony_ci wps->wps->encr_types, encr_types); 2494e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 2495e5b75505Sopenharmony_ci /* 2496e5b75505Sopenharmony_ci * Some deployed implementations seem to advertise incorrect 2497e5b75505Sopenharmony_ci * information in this attribute. For example, Linksys WRT350N 2498e5b75505Sopenharmony_ci * seems to have a byteorder bug that breaks this negotiation. 2499e5b75505Sopenharmony_ci * In order to interoperate with existing implementations, 2500e5b75505Sopenharmony_ci * assume that the Enrollee supports everything we do. 2501e5b75505Sopenharmony_ci */ 2502e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee " 2503e5b75505Sopenharmony_ci "does not advertise supported encryption types " 2504e5b75505Sopenharmony_ci "correctly"); 2505e5b75505Sopenharmony_ci wps->encr_type = wps->wps->encr_types; 2506e5b75505Sopenharmony_ci#else /* WPS_WORKAROUNDS */ 2507e5b75505Sopenharmony_ci return -1; 2508e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 2509e5b75505Sopenharmony_ci } 2510e5b75505Sopenharmony_ci 2511e5b75505Sopenharmony_ci return 0; 2512e5b75505Sopenharmony_ci} 2513e5b75505Sopenharmony_ci 2514e5b75505Sopenharmony_ci 2515e5b75505Sopenharmony_cistatic int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn) 2516e5b75505Sopenharmony_ci{ 2517e5b75505Sopenharmony_ci if (conn == NULL) { 2518e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags " 2519e5b75505Sopenharmony_ci "received"); 2520e5b75505Sopenharmony_ci return -1; 2521e5b75505Sopenharmony_ci } 2522e5b75505Sopenharmony_ci 2523e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x", 2524e5b75505Sopenharmony_ci *conn); 2525e5b75505Sopenharmony_ci 2526e5b75505Sopenharmony_ci return 0; 2527e5b75505Sopenharmony_ci} 2528e5b75505Sopenharmony_ci 2529e5b75505Sopenharmony_ci 2530e5b75505Sopenharmony_cistatic int wps_process_config_methods(struct wps_data *wps, const u8 *methods) 2531e5b75505Sopenharmony_ci{ 2532e5b75505Sopenharmony_ci u16 m; 2533e5b75505Sopenharmony_ci 2534e5b75505Sopenharmony_ci if (methods == NULL) { 2535e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Config Methods received"); 2536e5b75505Sopenharmony_ci return -1; 2537e5b75505Sopenharmony_ci } 2538e5b75505Sopenharmony_ci 2539e5b75505Sopenharmony_ci m = WPA_GET_BE16(methods); 2540e5b75505Sopenharmony_ci 2541e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x" 2542e5b75505Sopenharmony_ci "%s%s%s%s%s%s%s%s%s", m, 2543e5b75505Sopenharmony_ci m & WPS_CONFIG_USBA ? " [USBA]" : "", 2544e5b75505Sopenharmony_ci m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "", 2545e5b75505Sopenharmony_ci m & WPS_CONFIG_LABEL ? " [Label]" : "", 2546e5b75505Sopenharmony_ci m & WPS_CONFIG_DISPLAY ? " [Display]" : "", 2547e5b75505Sopenharmony_ci m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "", 2548e5b75505Sopenharmony_ci m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "", 2549e5b75505Sopenharmony_ci m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "", 2550e5b75505Sopenharmony_ci m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "", 2551e5b75505Sopenharmony_ci m & WPS_CONFIG_KEYPAD ? " [Keypad]" : ""); 2552e5b75505Sopenharmony_ci 2553e5b75505Sopenharmony_ci if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) { 2554e5b75505Sopenharmony_ci /* 2555e5b75505Sopenharmony_ci * The Enrollee does not have a display so it is unlikely to be 2556e5b75505Sopenharmony_ci * able to show the passphrase to a user and as such, could 2557e5b75505Sopenharmony_ci * benefit from receiving PSK to reduce key derivation time. 2558e5b75505Sopenharmony_ci */ 2559e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to " 2560e5b75505Sopenharmony_ci "Enrollee not supporting display"); 2561e5b75505Sopenharmony_ci wps->use_psk_key = 1; 2562e5b75505Sopenharmony_ci } 2563e5b75505Sopenharmony_ci 2564e5b75505Sopenharmony_ci return 0; 2565e5b75505Sopenharmony_ci} 2566e5b75505Sopenharmony_ci 2567e5b75505Sopenharmony_ci 2568e5b75505Sopenharmony_cistatic int wps_process_wps_state(struct wps_data *wps, const u8 *state) 2569e5b75505Sopenharmony_ci{ 2570e5b75505Sopenharmony_ci if (state == NULL) { 2571e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State " 2572e5b75505Sopenharmony_ci "received"); 2573e5b75505Sopenharmony_ci return -1; 2574e5b75505Sopenharmony_ci } 2575e5b75505Sopenharmony_ci 2576e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d", 2577e5b75505Sopenharmony_ci *state); 2578e5b75505Sopenharmony_ci 2579e5b75505Sopenharmony_ci return 0; 2580e5b75505Sopenharmony_ci} 2581e5b75505Sopenharmony_ci 2582e5b75505Sopenharmony_ci 2583e5b75505Sopenharmony_cistatic int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc) 2584e5b75505Sopenharmony_ci{ 2585e5b75505Sopenharmony_ci u16 a; 2586e5b75505Sopenharmony_ci 2587e5b75505Sopenharmony_ci if (assoc == NULL) { 2588e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Association State received"); 2589e5b75505Sopenharmony_ci return -1; 2590e5b75505Sopenharmony_ci } 2591e5b75505Sopenharmony_ci 2592e5b75505Sopenharmony_ci a = WPA_GET_BE16(assoc); 2593e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a); 2594e5b75505Sopenharmony_ci 2595e5b75505Sopenharmony_ci return 0; 2596e5b75505Sopenharmony_ci} 2597e5b75505Sopenharmony_ci 2598e5b75505Sopenharmony_ci 2599e5b75505Sopenharmony_cistatic int wps_process_config_error(struct wps_data *wps, const u8 *err) 2600e5b75505Sopenharmony_ci{ 2601e5b75505Sopenharmony_ci u16 e; 2602e5b75505Sopenharmony_ci 2603e5b75505Sopenharmony_ci if (err == NULL) { 2604e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received"); 2605e5b75505Sopenharmony_ci return -1; 2606e5b75505Sopenharmony_ci } 2607e5b75505Sopenharmony_ci 2608e5b75505Sopenharmony_ci e = WPA_GET_BE16(err); 2609e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e); 2610e5b75505Sopenharmony_ci 2611e5b75505Sopenharmony_ci return 0; 2612e5b75505Sopenharmony_ci} 2613e5b75505Sopenharmony_ci 2614e5b75505Sopenharmony_ci 2615e5b75505Sopenharmony_cistatic int wps_registrar_p2p_dev_addr_match(struct wps_data *wps) 2616e5b75505Sopenharmony_ci{ 2617e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 2618e5b75505Sopenharmony_ci struct wps_registrar *reg = wps->wps->registrar; 2619e5b75505Sopenharmony_ci 2620e5b75505Sopenharmony_ci if (is_zero_ether_addr(reg->p2p_dev_addr)) 2621e5b75505Sopenharmony_ci return 1; /* no filtering in use */ 2622e5b75505Sopenharmony_ci 2623e5b75505Sopenharmony_ci if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) { 2624e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address " 2625e5b75505Sopenharmony_ci "filtering for PBC: expected " MACSTR " was " 2626e5b75505Sopenharmony_ci MACSTR " - indicate PBC session overlap", 2627e5b75505Sopenharmony_ci MAC2STR(reg->p2p_dev_addr), 2628e5b75505Sopenharmony_ci MAC2STR(wps->p2p_dev_addr)); 2629e5b75505Sopenharmony_ci return 0; 2630e5b75505Sopenharmony_ci } 2631e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 2632e5b75505Sopenharmony_ci return 1; 2633e5b75505Sopenharmony_ci} 2634e5b75505Sopenharmony_ci 2635e5b75505Sopenharmony_ci 2636e5b75505Sopenharmony_cistatic int wps_registrar_skip_overlap(struct wps_data *wps) 2637e5b75505Sopenharmony_ci{ 2638e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 2639e5b75505Sopenharmony_ci struct wps_registrar *reg = wps->wps->registrar; 2640e5b75505Sopenharmony_ci 2641e5b75505Sopenharmony_ci if (is_zero_ether_addr(reg->p2p_dev_addr)) 2642e5b75505Sopenharmony_ci return 0; /* no specific Enrollee selected */ 2643e5b75505Sopenharmony_ci 2644e5b75505Sopenharmony_ci if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) { 2645e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected " 2646e5b75505Sopenharmony_ci "Enrollee match"); 2647e5b75505Sopenharmony_ci return 1; 2648e5b75505Sopenharmony_ci } 2649e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 2650e5b75505Sopenharmony_ci return 0; 2651e5b75505Sopenharmony_ci} 2652e5b75505Sopenharmony_ci 2653e5b75505Sopenharmony_ci 2654e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m1(struct wps_data *wps, 2655e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 2656e5b75505Sopenharmony_ci{ 2657e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M1"); 2658e5b75505Sopenharmony_ci 2659e5b75505Sopenharmony_ci if (wps->state != RECV_M1) { 2660e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 2661e5b75505Sopenharmony_ci "receiving M1", wps->state); 2662e5b75505Sopenharmony_ci return WPS_FAILURE; 2663e5b75505Sopenharmony_ci } 2664e5b75505Sopenharmony_ci 2665e5b75505Sopenharmony_ci if (wps_process_uuid_e(wps, attr->uuid_e) || 2666e5b75505Sopenharmony_ci wps_process_mac_addr(wps, attr->mac_addr) || 2667e5b75505Sopenharmony_ci wps_process_enrollee_nonce(wps, attr->enrollee_nonce) || 2668e5b75505Sopenharmony_ci wps_process_pubkey(wps, attr->public_key, attr->public_key_len) || 2669e5b75505Sopenharmony_ci wps_process_auth_type_flags(wps, attr->auth_type_flags) || 2670e5b75505Sopenharmony_ci wps_process_encr_type_flags(wps, attr->encr_type_flags) || 2671e5b75505Sopenharmony_ci wps_process_conn_type_flags(wps, attr->conn_type_flags) || 2672e5b75505Sopenharmony_ci wps_process_config_methods(wps, attr->config_methods) || 2673e5b75505Sopenharmony_ci wps_process_wps_state(wps, attr->wps_state) || 2674e5b75505Sopenharmony_ci wps_process_device_attrs(&wps->peer_dev, attr) || 2675e5b75505Sopenharmony_ci wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) || 2676e5b75505Sopenharmony_ci wps_process_assoc_state(wps, attr->assoc_state) || 2677e5b75505Sopenharmony_ci wps_process_dev_password_id(wps, attr->dev_password_id) || 2678e5b75505Sopenharmony_ci wps_process_config_error(wps, attr->config_error) || 2679e5b75505Sopenharmony_ci wps_process_os_version(&wps->peer_dev, attr->os_version)) 2680e5b75505Sopenharmony_ci return WPS_FAILURE; 2681e5b75505Sopenharmony_ci 2682e5b75505Sopenharmony_ci if (wps->dev_pw_id < 0x10 && 2683e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_DEFAULT && 2684e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_P2PS_DEFAULT && 2685e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_USER_SPECIFIED && 2686e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED && 2687e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED && 2688e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 2689e5b75505Sopenharmony_ci wps->dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER && 2690e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 2691e5b75505Sopenharmony_ci (wps->dev_pw_id != DEV_PW_PUSHBUTTON || 2692e5b75505Sopenharmony_ci !wps->wps->registrar->pbc)) { 2693e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d", 2694e5b75505Sopenharmony_ci wps->dev_pw_id); 2695e5b75505Sopenharmony_ci wps->state = SEND_M2D; 2696e5b75505Sopenharmony_ci return WPS_CONTINUE; 2697e5b75505Sopenharmony_ci } 2698e5b75505Sopenharmony_ci 2699e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 2700e5b75505Sopenharmony_ci if (wps->dev_pw_id >= 0x10 || 2701e5b75505Sopenharmony_ci wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) { 2702e5b75505Sopenharmony_ci struct wps_nfc_pw_token *token; 2703e5b75505Sopenharmony_ci const u8 *addr[1]; 2704e5b75505Sopenharmony_ci u8 hash[WPS_HASH_LEN]; 2705e5b75505Sopenharmony_ci 2706e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Searching for NFC token match for id=%d (ctx %p registrar %p)", 2707e5b75505Sopenharmony_ci wps->dev_pw_id, wps->wps, wps->wps->registrar); 2708e5b75505Sopenharmony_ci token = wps_get_nfc_pw_token( 2709e5b75505Sopenharmony_ci &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id); 2710e5b75505Sopenharmony_ci if (token && token->peer_pk_hash_known) { 2711e5b75505Sopenharmony_ci size_t len; 2712e5b75505Sopenharmony_ci 2713e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Found matching NFC " 2714e5b75505Sopenharmony_ci "Password Token"); 2715e5b75505Sopenharmony_ci dl_list_del(&token->list); 2716e5b75505Sopenharmony_ci wps->nfc_pw_token = token; 2717e5b75505Sopenharmony_ci 2718e5b75505Sopenharmony_ci addr[0] = attr->public_key; 2719e5b75505Sopenharmony_ci len = attr->public_key_len; 2720e5b75505Sopenharmony_ci sha256_vector(1, addr, &len, hash); 2721e5b75505Sopenharmony_ci if (os_memcmp_const(hash, 2722e5b75505Sopenharmony_ci wps->nfc_pw_token->pubkey_hash, 2723e5b75505Sopenharmony_ci WPS_OOB_PUBKEY_HASH_LEN) != 0) { 2724e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "WPS: Public Key hash " 2725e5b75505Sopenharmony_ci "mismatch"); 2726e5b75505Sopenharmony_ci wps->state = SEND_M2D; 2727e5b75505Sopenharmony_ci wps->config_error = 2728e5b75505Sopenharmony_ci WPS_CFG_PUBLIC_KEY_HASH_MISMATCH; 2729e5b75505Sopenharmony_ci return WPS_CONTINUE; 2730e5b75505Sopenharmony_ci } 2731e5b75505Sopenharmony_ci } else if (token) { 2732e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Found matching NFC " 2733e5b75505Sopenharmony_ci "Password Token (no peer PK hash)"); 2734e5b75505Sopenharmony_ci wps->nfc_pw_token = token; 2735e5b75505Sopenharmony_ci } else if (wps->dev_pw_id >= 0x10 && 2736e5b75505Sopenharmony_ci wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id && 2737e5b75505Sopenharmony_ci wps->wps->ap_nfc_dev_pw) { 2738e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Found match with own NFC Password Token"); 2739e5b75505Sopenharmony_ci } 2740e5b75505Sopenharmony_ci } 2741e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 2742e5b75505Sopenharmony_ci 2743e5b75505Sopenharmony_ci if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) { 2744e5b75505Sopenharmony_ci if ((wps->wps->registrar->force_pbc_overlap || 2745e5b75505Sopenharmony_ci wps_registrar_pbc_overlap(wps->wps->registrar, 2746e5b75505Sopenharmony_ci wps->mac_addr_e, wps->uuid_e) || 2747e5b75505Sopenharmony_ci !wps_registrar_p2p_dev_addr_match(wps)) && 2748e5b75505Sopenharmony_ci !wps_registrar_skip_overlap(wps)) { 2749e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC " 2750e5b75505Sopenharmony_ci "negotiation"); 2751e5b75505Sopenharmony_ci wps->state = SEND_M2D; 2752e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; 2753e5b75505Sopenharmony_ci wps_pbc_overlap_event(wps->wps); 2754e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M1, 2755e5b75505Sopenharmony_ci WPS_CFG_MULTIPLE_PBC_DETECTED, 2756e5b75505Sopenharmony_ci WPS_EI_NO_ERROR, wps->mac_addr_e); 2757e5b75505Sopenharmony_ci wps->wps->registrar->force_pbc_overlap = 1; 2758e5b75505Sopenharmony_ci return WPS_CONTINUE; 2759e5b75505Sopenharmony_ci } 2760e5b75505Sopenharmony_ci wps_registrar_add_pbc_session(wps->wps->registrar, 2761e5b75505Sopenharmony_ci wps->mac_addr_e, wps->uuid_e); 2762e5b75505Sopenharmony_ci wps->pbc = 1; 2763e5b75505Sopenharmony_ci } 2764e5b75505Sopenharmony_ci 2765e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 2766e5b75505Sopenharmony_ci /* 2767e5b75505Sopenharmony_ci * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in 2768e5b75505Sopenharmony_ci * passphrase format. To avoid interop issues, force PSK format to be 2769e5b75505Sopenharmony_ci * used. 2770e5b75505Sopenharmony_ci */ 2771e5b75505Sopenharmony_ci if (!wps->use_psk_key && 2772e5b75505Sopenharmony_ci wps->peer_dev.manufacturer && 2773e5b75505Sopenharmony_ci os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 && 2774e5b75505Sopenharmony_ci wps->peer_dev.model_name && 2775e5b75505Sopenharmony_ci os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) { 2776e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in " 2777e5b75505Sopenharmony_ci "PSK format"); 2778e5b75505Sopenharmony_ci wps->use_psk_key = 1; 2779e5b75505Sopenharmony_ci } 2780e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 2781e5b75505Sopenharmony_ci wps_process_vendor_ext_m1(&wps->peer_dev, attr->multi_ap_ext); 2782e5b75505Sopenharmony_ci 2783e5b75505Sopenharmony_ci wps->state = SEND_M2; 2784e5b75505Sopenharmony_ci return WPS_CONTINUE; 2785e5b75505Sopenharmony_ci} 2786e5b75505Sopenharmony_ci 2787e5b75505Sopenharmony_ci 2788e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m3(struct wps_data *wps, 2789e5b75505Sopenharmony_ci const struct wpabuf *msg, 2790e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 2791e5b75505Sopenharmony_ci{ 2792e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M3"); 2793e5b75505Sopenharmony_ci 2794e5b75505Sopenharmony_ci if (wps->state != RECV_M3) { 2795e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 2796e5b75505Sopenharmony_ci "receiving M3", wps->state); 2797e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2798e5b75505Sopenharmony_ci return WPS_CONTINUE; 2799e5b75505Sopenharmony_ci } 2800e5b75505Sopenharmony_ci 2801e5b75505Sopenharmony_ci if (wps->pbc && wps->wps->registrar->force_pbc_overlap && 2802e5b75505Sopenharmony_ci !wps_registrar_skip_overlap(wps)) { 2803e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " 2804e5b75505Sopenharmony_ci "session overlap"); 2805e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2806e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; 2807e5b75505Sopenharmony_ci return WPS_CONTINUE; 2808e5b75505Sopenharmony_ci } 2809e5b75505Sopenharmony_ci 2810e5b75505Sopenharmony_ci if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || 2811e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg) || 2812e5b75505Sopenharmony_ci wps_process_e_hash1(wps, attr->e_hash1) || 2813e5b75505Sopenharmony_ci wps_process_e_hash2(wps, attr->e_hash2)) { 2814e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2815e5b75505Sopenharmony_ci return WPS_CONTINUE; 2816e5b75505Sopenharmony_ci } 2817e5b75505Sopenharmony_ci 2818e5b75505Sopenharmony_ci wps->state = SEND_M4; 2819e5b75505Sopenharmony_ci return WPS_CONTINUE; 2820e5b75505Sopenharmony_ci} 2821e5b75505Sopenharmony_ci 2822e5b75505Sopenharmony_ci 2823e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m5(struct wps_data *wps, 2824e5b75505Sopenharmony_ci const struct wpabuf *msg, 2825e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 2826e5b75505Sopenharmony_ci{ 2827e5b75505Sopenharmony_ci struct wpabuf *decrypted; 2828e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 2829e5b75505Sopenharmony_ci 2830e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M5"); 2831e5b75505Sopenharmony_ci 2832e5b75505Sopenharmony_ci if (wps->state != RECV_M5) { 2833e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 2834e5b75505Sopenharmony_ci "receiving M5", wps->state); 2835e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2836e5b75505Sopenharmony_ci return WPS_CONTINUE; 2837e5b75505Sopenharmony_ci } 2838e5b75505Sopenharmony_ci 2839e5b75505Sopenharmony_ci if (wps->pbc && wps->wps->registrar->force_pbc_overlap && 2840e5b75505Sopenharmony_ci !wps_registrar_skip_overlap(wps)) { 2841e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " 2842e5b75505Sopenharmony_ci "session overlap"); 2843e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2844e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; 2845e5b75505Sopenharmony_ci return WPS_CONTINUE; 2846e5b75505Sopenharmony_ci } 2847e5b75505Sopenharmony_ci 2848e5b75505Sopenharmony_ci if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || 2849e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg)) { 2850e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2851e5b75505Sopenharmony_ci return WPS_CONTINUE; 2852e5b75505Sopenharmony_ci } 2853e5b75505Sopenharmony_ci 2854e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 2855e5b75505Sopenharmony_ci attr->encr_settings_len); 2856e5b75505Sopenharmony_ci if (decrypted == NULL) { 2857e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted " 2858e5b75505Sopenharmony_ci "Settings attribute"); 2859e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2860e5b75505Sopenharmony_ci return WPS_CONTINUE; 2861e5b75505Sopenharmony_ci } 2862e5b75505Sopenharmony_ci 2863e5b75505Sopenharmony_ci if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) { 2864e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 2865e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2866e5b75505Sopenharmony_ci return WPS_CONTINUE; 2867e5b75505Sopenharmony_ci } 2868e5b75505Sopenharmony_ci 2869e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 2870e5b75505Sopenharmony_ci "attribute"); 2871e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 2872e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 2873e5b75505Sopenharmony_ci wps_process_e_snonce1(wps, eattr.e_snonce1)) { 2874e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 2875e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2876e5b75505Sopenharmony_ci return WPS_CONTINUE; 2877e5b75505Sopenharmony_ci } 2878e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 2879e5b75505Sopenharmony_ci 2880e5b75505Sopenharmony_ci wps->state = SEND_M6; 2881e5b75505Sopenharmony_ci return WPS_CONTINUE; 2882e5b75505Sopenharmony_ci} 2883e5b75505Sopenharmony_ci 2884e5b75505Sopenharmony_ci 2885e5b75505Sopenharmony_cistatic void wps_sta_cred_cb(struct wps_data *wps) 2886e5b75505Sopenharmony_ci{ 2887e5b75505Sopenharmony_ci /* 2888e5b75505Sopenharmony_ci * Update credential to only include a single authentication and 2889e5b75505Sopenharmony_ci * encryption type in case the AP configuration includes more than one 2890e5b75505Sopenharmony_ci * option. 2891e5b75505Sopenharmony_ci */ 2892e5b75505Sopenharmony_ci if (wps->cred.auth_type & WPS_AUTH_WPA2PSK) 2893e5b75505Sopenharmony_ci wps->cred.auth_type = WPS_AUTH_WPA2PSK; 2894e5b75505Sopenharmony_ci else if (wps->cred.auth_type & WPS_AUTH_WPAPSK) 2895e5b75505Sopenharmony_ci wps->cred.auth_type = WPS_AUTH_WPAPSK; 2896e5b75505Sopenharmony_ci if (wps->cred.encr_type & WPS_ENCR_AES) 2897e5b75505Sopenharmony_ci wps->cred.encr_type = WPS_ENCR_AES; 2898e5b75505Sopenharmony_ci else if (wps->cred.encr_type & WPS_ENCR_TKIP) 2899e5b75505Sopenharmony_ci wps->cred.encr_type = WPS_ENCR_TKIP; 2900e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the " 2901e5b75505Sopenharmony_ci "AP configuration"); 2902e5b75505Sopenharmony_ci if (wps->wps->cred_cb) 2903e5b75505Sopenharmony_ci wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred); 2904e5b75505Sopenharmony_ci} 2905e5b75505Sopenharmony_ci 2906e5b75505Sopenharmony_ci 2907e5b75505Sopenharmony_cistatic void wps_cred_update(struct wps_credential *dst, 2908e5b75505Sopenharmony_ci struct wps_credential *src) 2909e5b75505Sopenharmony_ci{ 2910e5b75505Sopenharmony_ci os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid)); 2911e5b75505Sopenharmony_ci dst->ssid_len = src->ssid_len; 2912e5b75505Sopenharmony_ci dst->auth_type = src->auth_type; 2913e5b75505Sopenharmony_ci dst->encr_type = src->encr_type; 2914e5b75505Sopenharmony_ci dst->key_idx = src->key_idx; 2915e5b75505Sopenharmony_ci os_memcpy(dst->key, src->key, sizeof(dst->key)); 2916e5b75505Sopenharmony_ci dst->key_len = src->key_len; 2917e5b75505Sopenharmony_ci} 2918e5b75505Sopenharmony_ci 2919e5b75505Sopenharmony_ci 2920e5b75505Sopenharmony_cistatic int wps_process_ap_settings_r(struct wps_data *wps, 2921e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 2922e5b75505Sopenharmony_ci{ 2923e5b75505Sopenharmony_ci struct wpabuf *msg; 2924e5b75505Sopenharmony_ci 2925e5b75505Sopenharmony_ci if (wps->wps->ap || wps->er) 2926e5b75505Sopenharmony_ci return 0; 2927e5b75505Sopenharmony_ci 2928e5b75505Sopenharmony_ci /* AP Settings Attributes in M7 when Enrollee is an AP */ 2929e5b75505Sopenharmony_ci if (wps_process_ap_settings(attr, &wps->cred) < 0) 2930e5b75505Sopenharmony_ci return -1; 2931e5b75505Sopenharmony_ci 2932e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP"); 2933e5b75505Sopenharmony_ci 2934e5b75505Sopenharmony_ci if (wps->new_ap_settings) { 2935e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Update AP configuration based on " 2936e5b75505Sopenharmony_ci "new settings"); 2937e5b75505Sopenharmony_ci wps_cred_update(&wps->cred, wps->new_ap_settings); 2938e5b75505Sopenharmony_ci return 0; 2939e5b75505Sopenharmony_ci } else { 2940e5b75505Sopenharmony_ci /* 2941e5b75505Sopenharmony_ci * Use the AP PIN only to receive the current AP settings, not 2942e5b75505Sopenharmony_ci * to reconfigure the AP. 2943e5b75505Sopenharmony_ci */ 2944e5b75505Sopenharmony_ci 2945e5b75505Sopenharmony_ci /* 2946e5b75505Sopenharmony_ci * Clear selected registrar here since we do not get to 2947e5b75505Sopenharmony_ci * WSC_Done in this protocol run. 2948e5b75505Sopenharmony_ci */ 2949e5b75505Sopenharmony_ci wps_registrar_pin_completed(wps->wps->registrar); 2950e5b75505Sopenharmony_ci 2951e5b75505Sopenharmony_ci msg = wps_build_ap_cred(wps); 2952e5b75505Sopenharmony_ci if (msg == NULL) 2953e5b75505Sopenharmony_ci return -1; 2954e5b75505Sopenharmony_ci wps->cred.cred_attr = wpabuf_head(msg); 2955e5b75505Sopenharmony_ci wps->cred.cred_attr_len = wpabuf_len(msg); 2956e5b75505Sopenharmony_ci 2957e5b75505Sopenharmony_ci if (wps->ap_settings_cb) { 2958e5b75505Sopenharmony_ci wps->ap_settings_cb(wps->ap_settings_cb_ctx, 2959e5b75505Sopenharmony_ci &wps->cred); 2960e5b75505Sopenharmony_ci wpabuf_free(msg); 2961e5b75505Sopenharmony_ci return 1; 2962e5b75505Sopenharmony_ci } 2963e5b75505Sopenharmony_ci wps_sta_cred_cb(wps); 2964e5b75505Sopenharmony_ci 2965e5b75505Sopenharmony_ci wps->cred.cred_attr = NULL; 2966e5b75505Sopenharmony_ci wps->cred.cred_attr_len = 0; 2967e5b75505Sopenharmony_ci wpabuf_free(msg); 2968e5b75505Sopenharmony_ci 2969e5b75505Sopenharmony_ci return 1; 2970e5b75505Sopenharmony_ci } 2971e5b75505Sopenharmony_ci} 2972e5b75505Sopenharmony_ci 2973e5b75505Sopenharmony_ci 2974e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_m7(struct wps_data *wps, 2975e5b75505Sopenharmony_ci const struct wpabuf *msg, 2976e5b75505Sopenharmony_ci struct wps_parse_attr *attr) 2977e5b75505Sopenharmony_ci{ 2978e5b75505Sopenharmony_ci struct wpabuf *decrypted; 2979e5b75505Sopenharmony_ci struct wps_parse_attr eattr; 2980e5b75505Sopenharmony_ci 2981e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received M7"); 2982e5b75505Sopenharmony_ci 2983e5b75505Sopenharmony_ci if (wps->state != RECV_M7) { 2984e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 2985e5b75505Sopenharmony_ci "receiving M7", wps->state); 2986e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2987e5b75505Sopenharmony_ci return WPS_CONTINUE; 2988e5b75505Sopenharmony_ci } 2989e5b75505Sopenharmony_ci 2990e5b75505Sopenharmony_ci if (wps->pbc && wps->wps->registrar->force_pbc_overlap && 2991e5b75505Sopenharmony_ci !wps_registrar_skip_overlap(wps)) { 2992e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC " 2993e5b75505Sopenharmony_ci "session overlap"); 2994e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 2995e5b75505Sopenharmony_ci wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; 2996e5b75505Sopenharmony_ci return WPS_CONTINUE; 2997e5b75505Sopenharmony_ci } 2998e5b75505Sopenharmony_ci 2999e5b75505Sopenharmony_ci if (wps_process_registrar_nonce(wps, attr->registrar_nonce) || 3000e5b75505Sopenharmony_ci wps_process_authenticator(wps, attr->authenticator, msg)) { 3001e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3002e5b75505Sopenharmony_ci return WPS_CONTINUE; 3003e5b75505Sopenharmony_ci } 3004e5b75505Sopenharmony_ci 3005e5b75505Sopenharmony_ci decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings, 3006e5b75505Sopenharmony_ci attr->encr_settings_len); 3007e5b75505Sopenharmony_ci if (decrypted == NULL) { 3008e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted " 3009e5b75505Sopenharmony_ci "Settings attribute"); 3010e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3011e5b75505Sopenharmony_ci return WPS_CONTINUE; 3012e5b75505Sopenharmony_ci } 3013e5b75505Sopenharmony_ci 3014e5b75505Sopenharmony_ci if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er, 3015e5b75505Sopenharmony_ci attr->version2 != NULL) < 0) { 3016e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 3017e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3018e5b75505Sopenharmony_ci return WPS_CONTINUE; 3019e5b75505Sopenharmony_ci } 3020e5b75505Sopenharmony_ci 3021e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " 3022e5b75505Sopenharmony_ci "attribute"); 3023e5b75505Sopenharmony_ci if (wps_parse_msg(decrypted, &eattr) < 0 || 3024e5b75505Sopenharmony_ci wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || 3025e5b75505Sopenharmony_ci wps_process_e_snonce2(wps, eattr.e_snonce2) || 3026e5b75505Sopenharmony_ci wps_process_ap_settings_r(wps, &eattr)) { 3027e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 3028e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3029e5b75505Sopenharmony_ci return WPS_CONTINUE; 3030e5b75505Sopenharmony_ci } 3031e5b75505Sopenharmony_ci 3032e5b75505Sopenharmony_ci wpabuf_clear_free(decrypted); 3033e5b75505Sopenharmony_ci 3034e5b75505Sopenharmony_ci wps->state = SEND_M8; 3035e5b75505Sopenharmony_ci return WPS_CONTINUE; 3036e5b75505Sopenharmony_ci} 3037e5b75505Sopenharmony_ci 3038e5b75505Sopenharmony_ci 3039e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, 3040e5b75505Sopenharmony_ci const struct wpabuf *msg) 3041e5b75505Sopenharmony_ci{ 3042e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3043e5b75505Sopenharmony_ci enum wps_process_res ret = WPS_CONTINUE; 3044e5b75505Sopenharmony_ci 3045e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG"); 3046e5b75505Sopenharmony_ci 3047e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 3048e5b75505Sopenharmony_ci return WPS_FAILURE; 3049e5b75505Sopenharmony_ci 3050e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 3051e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 3052e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3053e5b75505Sopenharmony_ci return WPS_CONTINUE; 3054e5b75505Sopenharmony_ci } 3055e5b75505Sopenharmony_ci 3056e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_M1 && 3057e5b75505Sopenharmony_ci (attr.registrar_nonce == NULL || 3058e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, 3059e5b75505Sopenharmony_ci WPS_NONCE_LEN) != 0)) { 3060e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 3061e5b75505Sopenharmony_ci return WPS_FAILURE; 3062e5b75505Sopenharmony_ci } 3063e5b75505Sopenharmony_ci 3064e5b75505Sopenharmony_ci switch (*attr.msg_type) { 3065e5b75505Sopenharmony_ci case WPS_M1: 3066e5b75505Sopenharmony_ci if (wps_validate_m1(msg) < 0) 3067e5b75505Sopenharmony_ci return WPS_FAILURE; 3068e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3069e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && attr.mac_addr) { 3070e5b75505Sopenharmony_ci /* Remove old pending messages when starting new run */ 3071e5b75505Sopenharmony_ci wps_free_pending_msgs(wps->wps->upnp_msgs); 3072e5b75505Sopenharmony_ci wps->wps->upnp_msgs = NULL; 3073e5b75505Sopenharmony_ci 3074e5b75505Sopenharmony_ci upnp_wps_device_send_wlan_event( 3075e5b75505Sopenharmony_ci wps->wps->wps_upnp, attr.mac_addr, 3076e5b75505Sopenharmony_ci UPNP_WPS_WLANEVENT_TYPE_EAP, msg); 3077e5b75505Sopenharmony_ci } 3078e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3079e5b75505Sopenharmony_ci ret = wps_process_m1(wps, &attr); 3080e5b75505Sopenharmony_ci break; 3081e5b75505Sopenharmony_ci case WPS_M3: 3082e5b75505Sopenharmony_ci if (wps_validate_m3(msg) < 0) 3083e5b75505Sopenharmony_ci return WPS_FAILURE; 3084e5b75505Sopenharmony_ci ret = wps_process_m3(wps, msg, &attr); 3085e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 3086e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M3, wps->config_error, 3087e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3088e5b75505Sopenharmony_ci break; 3089e5b75505Sopenharmony_ci case WPS_M5: 3090e5b75505Sopenharmony_ci if (wps_validate_m5(msg) < 0) 3091e5b75505Sopenharmony_ci return WPS_FAILURE; 3092e5b75505Sopenharmony_ci ret = wps_process_m5(wps, msg, &attr); 3093e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 3094e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M5, wps->config_error, 3095e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3096e5b75505Sopenharmony_ci break; 3097e5b75505Sopenharmony_ci case WPS_M7: 3098e5b75505Sopenharmony_ci if (wps_validate_m7(msg) < 0) 3099e5b75505Sopenharmony_ci return WPS_FAILURE; 3100e5b75505Sopenharmony_ci ret = wps_process_m7(wps, msg, &attr); 3101e5b75505Sopenharmony_ci if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK) 3102e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M7, wps->config_error, 3103e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3104e5b75505Sopenharmony_ci break; 3105e5b75505Sopenharmony_ci default: 3106e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d", 3107e5b75505Sopenharmony_ci *attr.msg_type); 3108e5b75505Sopenharmony_ci return WPS_FAILURE; 3109e5b75505Sopenharmony_ci } 3110e5b75505Sopenharmony_ci 3111e5b75505Sopenharmony_ci if (ret == WPS_CONTINUE) { 3112e5b75505Sopenharmony_ci /* Save a copy of the last message for Authenticator derivation 3113e5b75505Sopenharmony_ci */ 3114e5b75505Sopenharmony_ci wpabuf_free(wps->last_msg); 3115e5b75505Sopenharmony_ci wps->last_msg = wpabuf_dup(msg); 3116e5b75505Sopenharmony_ci } 3117e5b75505Sopenharmony_ci 3118e5b75505Sopenharmony_ci return ret; 3119e5b75505Sopenharmony_ci} 3120e5b75505Sopenharmony_ci 3121e5b75505Sopenharmony_ci 3122e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, 3123e5b75505Sopenharmony_ci const struct wpabuf *msg) 3124e5b75505Sopenharmony_ci{ 3125e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3126e5b75505Sopenharmony_ci 3127e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK"); 3128e5b75505Sopenharmony_ci 3129e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 3130e5b75505Sopenharmony_ci return WPS_FAILURE; 3131e5b75505Sopenharmony_ci 3132e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 3133e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 3134e5b75505Sopenharmony_ci return WPS_FAILURE; 3135e5b75505Sopenharmony_ci } 3136e5b75505Sopenharmony_ci 3137e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_WSC_ACK) { 3138e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 3139e5b75505Sopenharmony_ci *attr.msg_type); 3140e5b75505Sopenharmony_ci return WPS_FAILURE; 3141e5b75505Sopenharmony_ci } 3142e5b75505Sopenharmony_ci 3143e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3144e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK && 3145e5b75505Sopenharmony_ci upnp_wps_subscribers(wps->wps->wps_upnp)) { 3146e5b75505Sopenharmony_ci if (wps->wps->upnp_msgs) 3147e5b75505Sopenharmony_ci return WPS_CONTINUE; 3148e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Wait for response from an " 3149e5b75505Sopenharmony_ci "external Registrar"); 3150e5b75505Sopenharmony_ci return WPS_PENDING; 3151e5b75505Sopenharmony_ci } 3152e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3153e5b75505Sopenharmony_ci 3154e5b75505Sopenharmony_ci if (attr.registrar_nonce == NULL || 3155e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 3156e5b75505Sopenharmony_ci { 3157e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 3158e5b75505Sopenharmony_ci return WPS_FAILURE; 3159e5b75505Sopenharmony_ci } 3160e5b75505Sopenharmony_ci 3161e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 3162e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 3163e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 3164e5b75505Sopenharmony_ci return WPS_FAILURE; 3165e5b75505Sopenharmony_ci } 3166e5b75505Sopenharmony_ci 3167e5b75505Sopenharmony_ci if (wps->state == RECV_M2D_ACK) { 3168e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3169e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && 3170e5b75505Sopenharmony_ci upnp_wps_subscribers(wps->wps->wps_upnp)) { 3171e5b75505Sopenharmony_ci if (wps->wps->upnp_msgs) 3172e5b75505Sopenharmony_ci return WPS_CONTINUE; 3173e5b75505Sopenharmony_ci if (wps->ext_reg == 0) 3174e5b75505Sopenharmony_ci wps->ext_reg = 1; 3175e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Wait for response from an " 3176e5b75505Sopenharmony_ci "external Registrar"); 3177e5b75505Sopenharmony_ci return WPS_PENDING; 3178e5b75505Sopenharmony_ci } 3179e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3180e5b75505Sopenharmony_ci 3181e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No more registrars available - " 3182e5b75505Sopenharmony_ci "terminate negotiation"); 3183e5b75505Sopenharmony_ci } 3184e5b75505Sopenharmony_ci 3185e5b75505Sopenharmony_ci return WPS_FAILURE; 3186e5b75505Sopenharmony_ci} 3187e5b75505Sopenharmony_ci 3188e5b75505Sopenharmony_ci 3189e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, 3190e5b75505Sopenharmony_ci const struct wpabuf *msg) 3191e5b75505Sopenharmony_ci{ 3192e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3193e5b75505Sopenharmony_ci int old_state; 3194e5b75505Sopenharmony_ci u16 config_error; 3195e5b75505Sopenharmony_ci 3196e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK"); 3197e5b75505Sopenharmony_ci 3198e5b75505Sopenharmony_ci old_state = wps->state; 3199e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3200e5b75505Sopenharmony_ci 3201e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 3202e5b75505Sopenharmony_ci return WPS_FAILURE; 3203e5b75505Sopenharmony_ci 3204e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 3205e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 3206e5b75505Sopenharmony_ci return WPS_FAILURE; 3207e5b75505Sopenharmony_ci } 3208e5b75505Sopenharmony_ci 3209e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_WSC_NACK) { 3210e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 3211e5b75505Sopenharmony_ci *attr.msg_type); 3212e5b75505Sopenharmony_ci return WPS_FAILURE; 3213e5b75505Sopenharmony_ci } 3214e5b75505Sopenharmony_ci 3215e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3216e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && wps->ext_reg) { 3217e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Negotiation using external " 3218e5b75505Sopenharmony_ci "Registrar terminated by the Enrollee"); 3219e5b75505Sopenharmony_ci return WPS_FAILURE; 3220e5b75505Sopenharmony_ci } 3221e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3222e5b75505Sopenharmony_ci 3223e5b75505Sopenharmony_ci if (attr.registrar_nonce == NULL || 3224e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 3225e5b75505Sopenharmony_ci { 3226e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 3227e5b75505Sopenharmony_ci return WPS_FAILURE; 3228e5b75505Sopenharmony_ci } 3229e5b75505Sopenharmony_ci 3230e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 3231e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 3232e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 3233e5b75505Sopenharmony_ci return WPS_FAILURE; 3234e5b75505Sopenharmony_ci } 3235e5b75505Sopenharmony_ci 3236e5b75505Sopenharmony_ci if (attr.config_error == NULL) { 3237e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute " 3238e5b75505Sopenharmony_ci "in WSC_NACK"); 3239e5b75505Sopenharmony_ci return WPS_FAILURE; 3240e5b75505Sopenharmony_ci } 3241e5b75505Sopenharmony_ci 3242e5b75505Sopenharmony_ci config_error = WPA_GET_BE16(attr.config_error); 3243e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with " 3244e5b75505Sopenharmony_ci "Configuration Error %d", config_error); 3245e5b75505Sopenharmony_ci 3246e5b75505Sopenharmony_ci switch (old_state) { 3247e5b75505Sopenharmony_ci case RECV_M3: 3248e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M2, config_error, 3249e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3250e5b75505Sopenharmony_ci break; 3251e5b75505Sopenharmony_ci case RECV_M5: 3252e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M4, config_error, 3253e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3254e5b75505Sopenharmony_ci break; 3255e5b75505Sopenharmony_ci case RECV_M7: 3256e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M6, config_error, 3257e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3258e5b75505Sopenharmony_ci break; 3259e5b75505Sopenharmony_ci case RECV_DONE: 3260e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_M8, config_error, 3261e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3262e5b75505Sopenharmony_ci break; 3263e5b75505Sopenharmony_ci default: 3264e5b75505Sopenharmony_ci break; 3265e5b75505Sopenharmony_ci } 3266e5b75505Sopenharmony_ci 3267e5b75505Sopenharmony_ci return WPS_FAILURE; 3268e5b75505Sopenharmony_ci} 3269e5b75505Sopenharmony_ci 3270e5b75505Sopenharmony_ci 3271e5b75505Sopenharmony_cistatic enum wps_process_res wps_process_wsc_done(struct wps_data *wps, 3272e5b75505Sopenharmony_ci const struct wpabuf *msg) 3273e5b75505Sopenharmony_ci{ 3274e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3275e5b75505Sopenharmony_ci 3276e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done"); 3277e5b75505Sopenharmony_ci 3278e5b75505Sopenharmony_ci if (wps->state != RECV_DONE && 3279e5b75505Sopenharmony_ci (!wps->wps->wps_upnp || !wps->ext_reg)) { 3280e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " 3281e5b75505Sopenharmony_ci "receiving WSC_Done", wps->state); 3282e5b75505Sopenharmony_ci return WPS_FAILURE; 3283e5b75505Sopenharmony_ci } 3284e5b75505Sopenharmony_ci 3285e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0) 3286e5b75505Sopenharmony_ci return WPS_FAILURE; 3287e5b75505Sopenharmony_ci 3288e5b75505Sopenharmony_ci if (attr.msg_type == NULL) { 3289e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); 3290e5b75505Sopenharmony_ci return WPS_FAILURE; 3291e5b75505Sopenharmony_ci } 3292e5b75505Sopenharmony_ci 3293e5b75505Sopenharmony_ci if (*attr.msg_type != WPS_WSC_DONE) { 3294e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d", 3295e5b75505Sopenharmony_ci *attr.msg_type); 3296e5b75505Sopenharmony_ci return WPS_FAILURE; 3297e5b75505Sopenharmony_ci } 3298e5b75505Sopenharmony_ci 3299e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3300e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && wps->ext_reg) { 3301e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Negotiation using external " 3302e5b75505Sopenharmony_ci "Registrar completed successfully"); 3303e5b75505Sopenharmony_ci wps_device_store(wps->wps->registrar, &wps->peer_dev, 3304e5b75505Sopenharmony_ci wps->uuid_e); 3305e5b75505Sopenharmony_ci return WPS_DONE; 3306e5b75505Sopenharmony_ci } 3307e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3308e5b75505Sopenharmony_ci 3309e5b75505Sopenharmony_ci if (attr.registrar_nonce == NULL || 3310e5b75505Sopenharmony_ci os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0) 3311e5b75505Sopenharmony_ci { 3312e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce"); 3313e5b75505Sopenharmony_ci return WPS_FAILURE; 3314e5b75505Sopenharmony_ci } 3315e5b75505Sopenharmony_ci 3316e5b75505Sopenharmony_ci if (attr.enrollee_nonce == NULL || 3317e5b75505Sopenharmony_ci os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) { 3318e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); 3319e5b75505Sopenharmony_ci return WPS_FAILURE; 3320e5b75505Sopenharmony_ci } 3321e5b75505Sopenharmony_ci 3322e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully"); 3323e5b75505Sopenharmony_ci wps_device_store(wps->wps->registrar, &wps->peer_dev, 3324e5b75505Sopenharmony_ci wps->uuid_e); 3325e5b75505Sopenharmony_ci 3326e5b75505Sopenharmony_ci if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk && 3327e5b75505Sopenharmony_ci wps->wps->ap && !wps->wps->registrar->disable_auto_conf) { 3328e5b75505Sopenharmony_ci struct wps_credential cred; 3329e5b75505Sopenharmony_ci 3330e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based " 3331e5b75505Sopenharmony_ci "on first Enrollee connection"); 3332e5b75505Sopenharmony_ci 3333e5b75505Sopenharmony_ci os_memset(&cred, 0, sizeof(cred)); 3334e5b75505Sopenharmony_ci os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len); 3335e5b75505Sopenharmony_ci cred.ssid_len = wps->wps->ssid_len; 3336e5b75505Sopenharmony_ci if (wps->wps->rf_band_cb(wps->wps->cb_ctx) == WPS_RF_60GHZ) { 3337e5b75505Sopenharmony_ci cred.auth_type = WPS_AUTH_WPA2PSK; 3338e5b75505Sopenharmony_ci cred.encr_type = WPS_ENCR_AES; 3339e5b75505Sopenharmony_ci } else { 3340e5b75505Sopenharmony_ci cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK; 3341e5b75505Sopenharmony_ci cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES; 3342e5b75505Sopenharmony_ci } 3343e5b75505Sopenharmony_ci os_memcpy(cred.key, wps->new_psk, wps->new_psk_len); 3344e5b75505Sopenharmony_ci cred.key_len = wps->new_psk_len; 3345e5b75505Sopenharmony_ci 3346e5b75505Sopenharmony_ci wps->wps->wps_state = WPS_STATE_CONFIGURED; 3347e5b75505Sopenharmony_ci wpa_hexdump_ascii_key(MSG_DEBUG, 3348e5b75505Sopenharmony_ci "WPS: Generated random passphrase", 3349e5b75505Sopenharmony_ci wps->new_psk, wps->new_psk_len); 3350e5b75505Sopenharmony_ci if (wps->wps->cred_cb) 3351e5b75505Sopenharmony_ci wps->wps->cred_cb(wps->wps->cb_ctx, &cred); 3352e5b75505Sopenharmony_ci 3353e5b75505Sopenharmony_ci os_free(wps->new_psk); 3354e5b75505Sopenharmony_ci wps->new_psk = NULL; 3355e5b75505Sopenharmony_ci } 3356e5b75505Sopenharmony_ci 3357e5b75505Sopenharmony_ci if (!wps->wps->ap && !wps->er) 3358e5b75505Sopenharmony_ci wps_sta_cred_cb(wps); 3359e5b75505Sopenharmony_ci 3360e5b75505Sopenharmony_ci if (wps->new_psk) { 3361e5b75505Sopenharmony_ci if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e, 3362e5b75505Sopenharmony_ci wps->p2p_dev_addr, wps->new_psk, 3363e5b75505Sopenharmony_ci wps->new_psk_len)) { 3364e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Failed to configure the " 3365e5b75505Sopenharmony_ci "new PSK"); 3366e5b75505Sopenharmony_ci } 3367e5b75505Sopenharmony_ci os_free(wps->new_psk); 3368e5b75505Sopenharmony_ci wps->new_psk = NULL; 3369e5b75505Sopenharmony_ci } 3370e5b75505Sopenharmony_ci 3371e5b75505Sopenharmony_ci wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e, 3372e5b75505Sopenharmony_ci wps->dev_password, wps->dev_password_len); 3373e5b75505Sopenharmony_ci 3374e5b75505Sopenharmony_ci if (wps->pbc) { 3375e5b75505Sopenharmony_ci wps_registrar_remove_pbc_session(wps->wps->registrar, 3376e5b75505Sopenharmony_ci wps->uuid_e, 3377e5b75505Sopenharmony_ci wps->p2p_dev_addr); 3378e5b75505Sopenharmony_ci wps_registrar_pbc_completed(wps->wps->registrar); 3379e5b75505Sopenharmony_ci#ifdef WPS_WORKAROUNDS 3380e5b75505Sopenharmony_ci os_get_reltime(&wps->wps->registrar->pbc_ignore_start); 3381e5b75505Sopenharmony_ci#endif /* WPS_WORKAROUNDS */ 3382e5b75505Sopenharmony_ci os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e, 3383e5b75505Sopenharmony_ci WPS_UUID_LEN); 3384e5b75505Sopenharmony_ci } else { 3385e5b75505Sopenharmony_ci wps_registrar_pin_completed(wps->wps->registrar); 3386e5b75505Sopenharmony_ci } 3387e5b75505Sopenharmony_ci /* TODO: maintain AuthorizedMACs somewhere separately for each ER and 3388e5b75505Sopenharmony_ci * merge them into APs own list.. */ 3389e5b75505Sopenharmony_ci 3390e5b75505Sopenharmony_ci wps_success_event(wps->wps, wps->mac_addr_e); 3391e5b75505Sopenharmony_ci 3392e5b75505Sopenharmony_ci return WPS_DONE; 3393e5b75505Sopenharmony_ci} 3394e5b75505Sopenharmony_ci 3395e5b75505Sopenharmony_ci 3396e5b75505Sopenharmony_cienum wps_process_res wps_registrar_process_msg(struct wps_data *wps, 3397e5b75505Sopenharmony_ci enum wsc_op_code op_code, 3398e5b75505Sopenharmony_ci const struct wpabuf *msg) 3399e5b75505Sopenharmony_ci{ 3400e5b75505Sopenharmony_ci enum wps_process_res ret; 3401e5b75505Sopenharmony_ci 3402e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu " 3403e5b75505Sopenharmony_ci "op_code=%d)", 3404e5b75505Sopenharmony_ci (unsigned long) wpabuf_len(msg), op_code); 3405e5b75505Sopenharmony_ci 3406e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3407e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) { 3408e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3409e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type && 3410e5b75505Sopenharmony_ci *attr.msg_type == WPS_M3) 3411e5b75505Sopenharmony_ci wps->ext_reg = 2; /* past M2/M2D phase */ 3412e5b75505Sopenharmony_ci } 3413e5b75505Sopenharmony_ci if (wps->ext_reg > 1) 3414e5b75505Sopenharmony_ci wps_registrar_free_pending_m2(wps->wps); 3415e5b75505Sopenharmony_ci if (wps->wps->wps_upnp && wps->ext_reg && 3416e5b75505Sopenharmony_ci wps->wps->upnp_msgs == NULL && 3417e5b75505Sopenharmony_ci (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK)) 3418e5b75505Sopenharmony_ci { 3419e5b75505Sopenharmony_ci struct wps_parse_attr attr; 3420e5b75505Sopenharmony_ci int type; 3421e5b75505Sopenharmony_ci if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL) 3422e5b75505Sopenharmony_ci type = -1; 3423e5b75505Sopenharmony_ci else 3424e5b75505Sopenharmony_ci type = *attr.msg_type; 3425e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)" 3426e5b75505Sopenharmony_ci " to external Registrar for processing", type); 3427e5b75505Sopenharmony_ci upnp_wps_device_send_wlan_event(wps->wps->wps_upnp, 3428e5b75505Sopenharmony_ci wps->mac_addr_e, 3429e5b75505Sopenharmony_ci UPNP_WPS_WLANEVENT_TYPE_EAP, 3430e5b75505Sopenharmony_ci msg); 3431e5b75505Sopenharmony_ci if (op_code == WSC_MSG) 3432e5b75505Sopenharmony_ci return WPS_PENDING; 3433e5b75505Sopenharmony_ci } else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) { 3434e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using " 3435e5b75505Sopenharmony_ci "external Registrar"); 3436e5b75505Sopenharmony_ci return WPS_CONTINUE; 3437e5b75505Sopenharmony_ci } 3438e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3439e5b75505Sopenharmony_ci 3440e5b75505Sopenharmony_ci switch (op_code) { 3441e5b75505Sopenharmony_ci case WSC_MSG: 3442e5b75505Sopenharmony_ci return wps_process_wsc_msg(wps, msg); 3443e5b75505Sopenharmony_ci case WSC_ACK: 3444e5b75505Sopenharmony_ci if (wps_validate_wsc_ack(msg) < 0) 3445e5b75505Sopenharmony_ci return WPS_FAILURE; 3446e5b75505Sopenharmony_ci return wps_process_wsc_ack(wps, msg); 3447e5b75505Sopenharmony_ci case WSC_NACK: 3448e5b75505Sopenharmony_ci if (wps_validate_wsc_nack(msg) < 0) 3449e5b75505Sopenharmony_ci return WPS_FAILURE; 3450e5b75505Sopenharmony_ci return wps_process_wsc_nack(wps, msg); 3451e5b75505Sopenharmony_ci case WSC_Done: 3452e5b75505Sopenharmony_ci if (wps_validate_wsc_done(msg) < 0) 3453e5b75505Sopenharmony_ci return WPS_FAILURE; 3454e5b75505Sopenharmony_ci ret = wps_process_wsc_done(wps, msg); 3455e5b75505Sopenharmony_ci if (ret == WPS_FAILURE) { 3456e5b75505Sopenharmony_ci wps->state = SEND_WSC_NACK; 3457e5b75505Sopenharmony_ci wps_fail_event(wps->wps, WPS_WSC_DONE, 3458e5b75505Sopenharmony_ci wps->config_error, 3459e5b75505Sopenharmony_ci wps->error_indication, wps->mac_addr_e); 3460e5b75505Sopenharmony_ci } 3461e5b75505Sopenharmony_ci return ret; 3462e5b75505Sopenharmony_ci default: 3463e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code); 3464e5b75505Sopenharmony_ci return WPS_FAILURE; 3465e5b75505Sopenharmony_ci } 3466e5b75505Sopenharmony_ci} 3467e5b75505Sopenharmony_ci 3468e5b75505Sopenharmony_ci 3469e5b75505Sopenharmony_ciint wps_registrar_update_ie(struct wps_registrar *reg) 3470e5b75505Sopenharmony_ci{ 3471e5b75505Sopenharmony_ci return wps_set_ie(reg); 3472e5b75505Sopenharmony_ci} 3473e5b75505Sopenharmony_ci 3474e5b75505Sopenharmony_ci 3475e5b75505Sopenharmony_cistatic void wps_registrar_set_selected_timeout(void *eloop_ctx, 3476e5b75505Sopenharmony_ci void *timeout_ctx) 3477e5b75505Sopenharmony_ci{ 3478e5b75505Sopenharmony_ci struct wps_registrar *reg = eloop_ctx; 3479e5b75505Sopenharmony_ci 3480e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - " 3481e5b75505Sopenharmony_ci "unselect internal Registrar"); 3482e5b75505Sopenharmony_ci reg->selected_registrar = 0; 3483e5b75505Sopenharmony_ci reg->pbc = 0; 3484e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 3485e5b75505Sopenharmony_ci} 3486e5b75505Sopenharmony_ci 3487e5b75505Sopenharmony_ci 3488e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3489e5b75505Sopenharmony_cistatic void wps_registrar_sel_reg_add(struct wps_registrar *reg, 3490e5b75505Sopenharmony_ci struct subscription *s) 3491e5b75505Sopenharmony_ci{ 3492e5b75505Sopenharmony_ci int i, j; 3493e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d " 3494e5b75505Sopenharmony_ci "config_methods=0x%x)", 3495e5b75505Sopenharmony_ci s->dev_password_id, s->config_methods); 3496e5b75505Sopenharmony_ci reg->sel_reg_union = 1; 3497e5b75505Sopenharmony_ci if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON) 3498e5b75505Sopenharmony_ci reg->sel_reg_dev_password_id_override = s->dev_password_id; 3499e5b75505Sopenharmony_ci if (reg->sel_reg_config_methods_override == -1) 3500e5b75505Sopenharmony_ci reg->sel_reg_config_methods_override = 0; 3501e5b75505Sopenharmony_ci reg->sel_reg_config_methods_override |= s->config_methods; 3502e5b75505Sopenharmony_ci for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) 3503e5b75505Sopenharmony_ci if (is_zero_ether_addr(reg->authorized_macs_union[i])) 3504e5b75505Sopenharmony_ci break; 3505e5b75505Sopenharmony_ci for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS; 3506e5b75505Sopenharmony_ci j++) { 3507e5b75505Sopenharmony_ci if (is_zero_ether_addr(s->authorized_macs[j])) 3508e5b75505Sopenharmony_ci break; 3509e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: " 3510e5b75505Sopenharmony_ci MACSTR, MAC2STR(s->authorized_macs[j])); 3511e5b75505Sopenharmony_ci os_memcpy(reg->authorized_macs_union[i], 3512e5b75505Sopenharmony_ci s->authorized_macs[j], ETH_ALEN); 3513e5b75505Sopenharmony_ci i++; 3514e5b75505Sopenharmony_ci } 3515e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union", 3516e5b75505Sopenharmony_ci (u8 *) reg->authorized_macs_union, 3517e5b75505Sopenharmony_ci sizeof(reg->authorized_macs_union)); 3518e5b75505Sopenharmony_ci} 3519e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3520e5b75505Sopenharmony_ci 3521e5b75505Sopenharmony_ci 3522e5b75505Sopenharmony_cistatic void wps_registrar_sel_reg_union(struct wps_registrar *reg) 3523e5b75505Sopenharmony_ci{ 3524e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_UPNP 3525e5b75505Sopenharmony_ci struct subscription *s; 3526e5b75505Sopenharmony_ci 3527e5b75505Sopenharmony_ci if (reg->wps->wps_upnp == NULL) 3528e5b75505Sopenharmony_ci return; 3529e5b75505Sopenharmony_ci 3530e5b75505Sopenharmony_ci dl_list_for_each(s, ®->wps->wps_upnp->subscriptions, 3531e5b75505Sopenharmony_ci struct subscription, list) { 3532e5b75505Sopenharmony_ci struct subscr_addr *sa; 3533e5b75505Sopenharmony_ci sa = dl_list_first(&s->addr_list, struct subscr_addr, list); 3534e5b75505Sopenharmony_ci if (sa) { 3535e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d", 3536e5b75505Sopenharmony_ci inet_ntoa(sa->saddr.sin_addr), 3537e5b75505Sopenharmony_ci ntohs(sa->saddr.sin_port)); 3538e5b75505Sopenharmony_ci } 3539e5b75505Sopenharmony_ci if (s->selected_registrar) 3540e5b75505Sopenharmony_ci wps_registrar_sel_reg_add(reg, s); 3541e5b75505Sopenharmony_ci else 3542e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: External Registrar not " 3543e5b75505Sopenharmony_ci "selected"); 3544e5b75505Sopenharmony_ci } 3545e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_UPNP */ 3546e5b75505Sopenharmony_ci} 3547e5b75505Sopenharmony_ci 3548e5b75505Sopenharmony_ci 3549e5b75505Sopenharmony_ci/** 3550e5b75505Sopenharmony_ci * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change 3551e5b75505Sopenharmony_ci * @reg: Registrar data from wps_registrar_init() 3552e5b75505Sopenharmony_ci * 3553e5b75505Sopenharmony_ci * This function is called when selected registrar state changes, e.g., when an 3554e5b75505Sopenharmony_ci * AP receives a SetSelectedRegistrar UPnP message. 3555e5b75505Sopenharmony_ci */ 3556e5b75505Sopenharmony_civoid wps_registrar_selected_registrar_changed(struct wps_registrar *reg, 3557e5b75505Sopenharmony_ci u16 dev_pw_id) 3558e5b75505Sopenharmony_ci{ 3559e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed"); 3560e5b75505Sopenharmony_ci 3561e5b75505Sopenharmony_ci reg->sel_reg_union = reg->selected_registrar; 3562e5b75505Sopenharmony_ci reg->sel_reg_dev_password_id_override = -1; 3563e5b75505Sopenharmony_ci reg->sel_reg_config_methods_override = -1; 3564e5b75505Sopenharmony_ci os_memcpy(reg->authorized_macs_union, reg->authorized_macs, 3565e5b75505Sopenharmony_ci WPS_MAX_AUTHORIZED_MACS * ETH_ALEN); 3566e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)", 3567e5b75505Sopenharmony_ci (u8 *) reg->authorized_macs_union, 3568e5b75505Sopenharmony_ci sizeof(reg->authorized_macs_union)); 3569e5b75505Sopenharmony_ci if (reg->selected_registrar) { 3570e5b75505Sopenharmony_ci u16 methods; 3571e5b75505Sopenharmony_ci 3572e5b75505Sopenharmony_ci methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON; 3573e5b75505Sopenharmony_ci methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON | 3574e5b75505Sopenharmony_ci WPS_CONFIG_PHY_PUSHBUTTON); 3575e5b75505Sopenharmony_ci if (reg->pbc) { 3576e5b75505Sopenharmony_ci reg->sel_reg_dev_password_id_override = 3577e5b75505Sopenharmony_ci DEV_PW_PUSHBUTTON; 3578e5b75505Sopenharmony_ci wps_set_pushbutton(&methods, reg->wps->config_methods); 3579e5b75505Sopenharmony_ci } else if (dev_pw_id) 3580e5b75505Sopenharmony_ci reg->sel_reg_dev_password_id_override = dev_pw_id; 3581e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected " 3582e5b75505Sopenharmony_ci "(pbc=%d)", reg->pbc); 3583e5b75505Sopenharmony_ci reg->sel_reg_config_methods_override = methods; 3584e5b75505Sopenharmony_ci } else 3585e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected"); 3586e5b75505Sopenharmony_ci 3587e5b75505Sopenharmony_ci wps_registrar_sel_reg_union(reg); 3588e5b75505Sopenharmony_ci 3589e5b75505Sopenharmony_ci wps_set_ie(reg); 3590e5b75505Sopenharmony_ci wps_cb_set_sel_reg(reg); 3591e5b75505Sopenharmony_ci} 3592e5b75505Sopenharmony_ci 3593e5b75505Sopenharmony_ci 3594e5b75505Sopenharmony_ciint wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, 3595e5b75505Sopenharmony_ci char *buf, size_t buflen) 3596e5b75505Sopenharmony_ci{ 3597e5b75505Sopenharmony_ci struct wps_registrar_device *d; 3598e5b75505Sopenharmony_ci int len = 0, ret; 3599e5b75505Sopenharmony_ci char uuid[40]; 3600e5b75505Sopenharmony_ci char devtype[WPS_DEV_TYPE_BUFSIZE]; 3601e5b75505Sopenharmony_ci 3602e5b75505Sopenharmony_ci d = wps_device_get(reg, addr); 3603e5b75505Sopenharmony_ci if (d == NULL) 3604e5b75505Sopenharmony_ci return 0; 3605e5b75505Sopenharmony_ci if (uuid_bin2str(d->uuid, uuid, sizeof(uuid))) 3606e5b75505Sopenharmony_ci return 0; 3607e5b75505Sopenharmony_ci 3608e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 3609e5b75505Sopenharmony_ci "wpsUuid=%s\n" 3610e5b75505Sopenharmony_ci "wpsPrimaryDeviceType=%s\n" 3611e5b75505Sopenharmony_ci "wpsDeviceName=%s\n" 3612e5b75505Sopenharmony_ci "wpsManufacturer=%s\n" 3613e5b75505Sopenharmony_ci "wpsModelName=%s\n" 3614e5b75505Sopenharmony_ci "wpsModelNumber=%s\n" 3615e5b75505Sopenharmony_ci "wpsSerialNumber=%s\n", 3616e5b75505Sopenharmony_ci uuid, 3617e5b75505Sopenharmony_ci wps_dev_type_bin2str(d->dev.pri_dev_type, devtype, 3618e5b75505Sopenharmony_ci sizeof(devtype)), 3619e5b75505Sopenharmony_ci d->dev.device_name ? d->dev.device_name : "", 3620e5b75505Sopenharmony_ci d->dev.manufacturer ? d->dev.manufacturer : "", 3621e5b75505Sopenharmony_ci d->dev.model_name ? d->dev.model_name : "", 3622e5b75505Sopenharmony_ci d->dev.model_number ? d->dev.model_number : "", 3623e5b75505Sopenharmony_ci d->dev.serial_number ? d->dev.serial_number : ""); 3624e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 3625e5b75505Sopenharmony_ci return len; 3626e5b75505Sopenharmony_ci len += ret; 3627e5b75505Sopenharmony_ci 3628e5b75505Sopenharmony_ci return len; 3629e5b75505Sopenharmony_ci} 3630e5b75505Sopenharmony_ci 3631e5b75505Sopenharmony_ci 3632e5b75505Sopenharmony_ciint wps_registrar_config_ap(struct wps_registrar *reg, 3633e5b75505Sopenharmony_ci struct wps_credential *cred) 3634e5b75505Sopenharmony_ci{ 3635e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type); 3636e5b75505Sopenharmony_ci if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | 3637e5b75505Sopenharmony_ci WPS_ENCR_AES))) { 3638e5b75505Sopenharmony_ci if (cred->encr_type & WPS_ENCR_WEP) { 3639e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject new AP settings " 3640e5b75505Sopenharmony_ci "due to WEP configuration"); 3641e5b75505Sopenharmony_ci return -1; 3642e5b75505Sopenharmony_ci } 3643e5b75505Sopenharmony_ci 3644e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to " 3645e5b75505Sopenharmony_ci "invalid encr_type 0x%x", cred->encr_type); 3646e5b75505Sopenharmony_ci return -1; 3647e5b75505Sopenharmony_ci } 3648e5b75505Sopenharmony_ci 3649e5b75505Sopenharmony_ci if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == 3650e5b75505Sopenharmony_ci WPS_ENCR_TKIP) { 3651e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> " 3652e5b75505Sopenharmony_ci "TKIP+AES"); 3653e5b75505Sopenharmony_ci cred->encr_type |= WPS_ENCR_AES; 3654e5b75505Sopenharmony_ci } 3655e5b75505Sopenharmony_ci 3656e5b75505Sopenharmony_ci if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) == 3657e5b75505Sopenharmony_ci WPS_AUTH_WPAPSK) { 3658e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> " 3659e5b75505Sopenharmony_ci "WPAPSK+WPA2PSK"); 3660e5b75505Sopenharmony_ci cred->auth_type |= WPS_AUTH_WPA2PSK; 3661e5b75505Sopenharmony_ci } 3662e5b75505Sopenharmony_ci 3663e5b75505Sopenharmony_ci if (reg->wps->cred_cb) 3664e5b75505Sopenharmony_ci return reg->wps->cred_cb(reg->wps->cb_ctx, cred); 3665e5b75505Sopenharmony_ci 3666e5b75505Sopenharmony_ci return -1; 3667e5b75505Sopenharmony_ci} 3668e5b75505Sopenharmony_ci 3669e5b75505Sopenharmony_ci 3670e5b75505Sopenharmony_ci#ifdef CONFIG_WPS_NFC 3671e5b75505Sopenharmony_ci 3672e5b75505Sopenharmony_ciint wps_registrar_add_nfc_pw_token(struct wps_registrar *reg, 3673e5b75505Sopenharmony_ci const u8 *pubkey_hash, u16 pw_id, 3674e5b75505Sopenharmony_ci const u8 *dev_pw, size_t dev_pw_len, 3675e5b75505Sopenharmony_ci int pk_hash_provided_oob) 3676e5b75505Sopenharmony_ci{ 3677e5b75505Sopenharmony_ci struct wps_nfc_pw_token *token; 3678e5b75505Sopenharmony_ci 3679e5b75505Sopenharmony_ci if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN) 3680e5b75505Sopenharmony_ci return -1; 3681e5b75505Sopenharmony_ci 3682e5b75505Sopenharmony_ci if (pw_id == DEV_PW_NFC_CONNECTION_HANDOVER && 3683e5b75505Sopenharmony_ci (pubkey_hash == NULL || !pk_hash_provided_oob)) { 3684e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Unexpected NFC Password Token " 3685e5b75505Sopenharmony_ci "addition - missing public key hash"); 3686e5b75505Sopenharmony_ci return -1; 3687e5b75505Sopenharmony_ci } 3688e5b75505Sopenharmony_ci 3689e5b75505Sopenharmony_ci wps_free_nfc_pw_tokens(®->nfc_pw_tokens, pw_id); 3690e5b75505Sopenharmony_ci 3691e5b75505Sopenharmony_ci token = os_zalloc(sizeof(*token)); 3692e5b75505Sopenharmony_ci if (token == NULL) 3693e5b75505Sopenharmony_ci return -1; 3694e5b75505Sopenharmony_ci 3695e5b75505Sopenharmony_ci token->peer_pk_hash_known = pubkey_hash != NULL; 3696e5b75505Sopenharmony_ci if (pubkey_hash) 3697e5b75505Sopenharmony_ci os_memcpy(token->pubkey_hash, pubkey_hash, 3698e5b75505Sopenharmony_ci WPS_OOB_PUBKEY_HASH_LEN); 3699e5b75505Sopenharmony_ci token->pw_id = pw_id; 3700e5b75505Sopenharmony_ci token->pk_hash_provided_oob = pk_hash_provided_oob; 3701e5b75505Sopenharmony_ci if (dev_pw) { 3702e5b75505Sopenharmony_ci wpa_snprintf_hex_uppercase((char *) token->dev_pw, 3703e5b75505Sopenharmony_ci sizeof(token->dev_pw), 3704e5b75505Sopenharmony_ci dev_pw, dev_pw_len); 3705e5b75505Sopenharmony_ci token->dev_pw_len = dev_pw_len * 2; 3706e5b75505Sopenharmony_ci } 3707e5b75505Sopenharmony_ci 3708e5b75505Sopenharmony_ci dl_list_add(®->nfc_pw_tokens, &token->list); 3709e5b75505Sopenharmony_ci 3710e5b75505Sopenharmony_ci reg->selected_registrar = 1; 3711e5b75505Sopenharmony_ci reg->pbc = 0; 3712e5b75505Sopenharmony_ci wps_registrar_add_authorized_mac(reg, 3713e5b75505Sopenharmony_ci (u8 *) "\xff\xff\xff\xff\xff\xff"); 3714e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, pw_id); 3715e5b75505Sopenharmony_ci eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); 3716e5b75505Sopenharmony_ci eloop_register_timeout(WPS_PBC_WALK_TIME, 0, 3717e5b75505Sopenharmony_ci wps_registrar_set_selected_timeout, 3718e5b75505Sopenharmony_ci reg, NULL); 3719e5b75505Sopenharmony_ci 3720e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar", 3721e5b75505Sopenharmony_ci pw_id); 3722e5b75505Sopenharmony_ci 3723e5b75505Sopenharmony_ci return 0; 3724e5b75505Sopenharmony_ci} 3725e5b75505Sopenharmony_ci 3726e5b75505Sopenharmony_ci 3727e5b75505Sopenharmony_ciint wps_registrar_add_nfc_password_token(struct wps_registrar *reg, 3728e5b75505Sopenharmony_ci const u8 *oob_dev_pw, 3729e5b75505Sopenharmony_ci size_t oob_dev_pw_len) 3730e5b75505Sopenharmony_ci{ 3731e5b75505Sopenharmony_ci const u8 *pos, *hash, *dev_pw; 3732e5b75505Sopenharmony_ci u16 id; 3733e5b75505Sopenharmony_ci size_t dev_pw_len; 3734e5b75505Sopenharmony_ci 3735e5b75505Sopenharmony_ci if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 || 3736e5b75505Sopenharmony_ci oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 + 3737e5b75505Sopenharmony_ci WPS_OOB_DEVICE_PASSWORD_LEN) 3738e5b75505Sopenharmony_ci return -1; 3739e5b75505Sopenharmony_ci 3740e5b75505Sopenharmony_ci hash = oob_dev_pw; 3741e5b75505Sopenharmony_ci pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN; 3742e5b75505Sopenharmony_ci id = WPA_GET_BE16(pos); 3743e5b75505Sopenharmony_ci dev_pw = pos + 2; 3744e5b75505Sopenharmony_ci dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw; 3745e5b75505Sopenharmony_ci 3746e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u", 3747e5b75505Sopenharmony_ci id); 3748e5b75505Sopenharmony_ci 3749e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash", 3750e5b75505Sopenharmony_ci hash, WPS_OOB_PUBKEY_HASH_LEN); 3751e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len); 3752e5b75505Sopenharmony_ci 3753e5b75505Sopenharmony_ci return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw, 3754e5b75505Sopenharmony_ci dev_pw_len, 0); 3755e5b75505Sopenharmony_ci} 3756e5b75505Sopenharmony_ci 3757e5b75505Sopenharmony_ci 3758e5b75505Sopenharmony_civoid wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg, 3759e5b75505Sopenharmony_ci struct wps_nfc_pw_token *token) 3760e5b75505Sopenharmony_ci{ 3761e5b75505Sopenharmony_ci wps_registrar_remove_authorized_mac(reg, 3762e5b75505Sopenharmony_ci (u8 *) "\xff\xff\xff\xff\xff\xff"); 3763e5b75505Sopenharmony_ci wps_registrar_selected_registrar_changed(reg, 0); 3764e5b75505Sopenharmony_ci 3765e5b75505Sopenharmony_ci /* 3766e5b75505Sopenharmony_ci * Free the NFC password token if it was used only for a single protocol 3767e5b75505Sopenharmony_ci * run. The static handover case uses the same password token multiple 3768e5b75505Sopenharmony_ci * times, so do not free that case here. 3769e5b75505Sopenharmony_ci */ 3770e5b75505Sopenharmony_ci if (token->peer_pk_hash_known) 3771e5b75505Sopenharmony_ci os_free(token); 3772e5b75505Sopenharmony_ci} 3773e5b75505Sopenharmony_ci 3774e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_NFC */ 3775