139beb93cSSam Leffler /*
239beb93cSSam Leffler * Wi-Fi Protected Setup - Registrar
3780fb4a2SCy Schubert * Copyright (c) 2008-2016, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
9e28a4053SRui Paulo #include "utils/includes.h"
1039beb93cSSam Leffler
11e28a4053SRui Paulo #include "utils/common.h"
12e28a4053SRui Paulo #include "utils/base64.h"
13e28a4053SRui Paulo #include "utils/eloop.h"
14e28a4053SRui Paulo #include "utils/uuid.h"
15e28a4053SRui Paulo #include "utils/list.h"
16e28a4053SRui Paulo #include "crypto/crypto.h"
17e28a4053SRui Paulo #include "crypto/sha256.h"
18f05cddf9SRui Paulo #include "crypto/random.h"
19e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
20c1d255d3SCy Schubert #include "common/wpa_common.h"
2139beb93cSSam Leffler #include "wps_i.h"
2239beb93cSSam Leffler #include "wps_dev_attr.h"
2339beb93cSSam Leffler #include "wps_upnp.h"
24e28a4053SRui Paulo #include "wps_upnp_i.h"
2539beb93cSSam Leffler
26f05cddf9SRui Paulo #ifndef CONFIG_WPS_STRICT
273157ba21SRui Paulo #define WPS_WORKAROUNDS
28f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
29f05cddf9SRui Paulo
30f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
31f05cddf9SRui Paulo
32f05cddf9SRui Paulo struct wps_nfc_pw_token {
33f05cddf9SRui Paulo struct dl_list list;
34f05cddf9SRui Paulo u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
355b9c547cSRui Paulo unsigned int peer_pk_hash_known:1;
36f05cddf9SRui Paulo u16 pw_id;
375b9c547cSRui Paulo u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1];
38f05cddf9SRui Paulo size_t dev_pw_len;
395b9c547cSRui Paulo int pk_hash_provided_oob; /* whether own PK hash was provided OOB */
40f05cddf9SRui Paulo };
41f05cddf9SRui Paulo
42f05cddf9SRui Paulo
wps_remove_nfc_pw_token(struct wps_nfc_pw_token * token)43f05cddf9SRui Paulo static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token)
44f05cddf9SRui Paulo {
45f05cddf9SRui Paulo dl_list_del(&token->list);
465b9c547cSRui Paulo bin_clear_free(token, sizeof(*token));
47f05cddf9SRui Paulo }
48f05cddf9SRui Paulo
49f05cddf9SRui Paulo
wps_free_nfc_pw_tokens(struct dl_list * tokens,u16 pw_id)50f05cddf9SRui Paulo static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id)
51f05cddf9SRui Paulo {
52f05cddf9SRui Paulo struct wps_nfc_pw_token *token, *prev;
53f05cddf9SRui Paulo dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token,
54f05cddf9SRui Paulo list) {
55f05cddf9SRui Paulo if (pw_id == 0 || pw_id == token->pw_id)
56f05cddf9SRui Paulo wps_remove_nfc_pw_token(token);
57f05cddf9SRui Paulo }
58f05cddf9SRui Paulo }
59f05cddf9SRui Paulo
60f05cddf9SRui Paulo
wps_get_nfc_pw_token(struct dl_list * tokens,u16 pw_id)61f05cddf9SRui Paulo static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens,
62f05cddf9SRui Paulo u16 pw_id)
63f05cddf9SRui Paulo {
64f05cddf9SRui Paulo struct wps_nfc_pw_token *token;
65f05cddf9SRui Paulo dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) {
66f05cddf9SRui Paulo if (pw_id == token->pw_id)
67f05cddf9SRui Paulo return token;
68f05cddf9SRui Paulo }
69f05cddf9SRui Paulo return NULL;
70f05cddf9SRui Paulo }
71f05cddf9SRui Paulo
72f05cddf9SRui Paulo #else /* CONFIG_WPS_NFC */
73f05cddf9SRui Paulo
74f05cddf9SRui Paulo #define wps_free_nfc_pw_tokens(t, p) do { } while (0)
75f05cddf9SRui Paulo
76f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
77f05cddf9SRui Paulo
7839beb93cSSam Leffler
7939beb93cSSam Leffler struct wps_uuid_pin {
80e28a4053SRui Paulo struct dl_list list;
8139beb93cSSam Leffler u8 uuid[WPS_UUID_LEN];
8239beb93cSSam Leffler int wildcard_uuid;
8339beb93cSSam Leffler u8 *pin;
8439beb93cSSam Leffler size_t pin_len;
853157ba21SRui Paulo #define PIN_LOCKED BIT(0)
863157ba21SRui Paulo #define PIN_EXPIRES BIT(1)
873157ba21SRui Paulo int flags;
885b9c547cSRui Paulo struct os_reltime expiration;
89f05cddf9SRui Paulo u8 enrollee_addr[ETH_ALEN];
9039beb93cSSam Leffler };
9139beb93cSSam Leffler
9239beb93cSSam Leffler
wps_free_pin(struct wps_uuid_pin * pin)9339beb93cSSam Leffler static void wps_free_pin(struct wps_uuid_pin *pin)
9439beb93cSSam Leffler {
955b9c547cSRui Paulo bin_clear_free(pin->pin, pin->pin_len);
9639beb93cSSam Leffler os_free(pin);
9739beb93cSSam Leffler }
9839beb93cSSam Leffler
9939beb93cSSam Leffler
wps_remove_pin(struct wps_uuid_pin * pin)100e28a4053SRui Paulo static void wps_remove_pin(struct wps_uuid_pin *pin)
101e28a4053SRui Paulo {
102e28a4053SRui Paulo dl_list_del(&pin->list);
103e28a4053SRui Paulo wps_free_pin(pin);
104e28a4053SRui Paulo }
105e28a4053SRui Paulo
106e28a4053SRui Paulo
wps_free_pins(struct dl_list * pins)107e28a4053SRui Paulo static void wps_free_pins(struct dl_list *pins)
10839beb93cSSam Leffler {
10939beb93cSSam Leffler struct wps_uuid_pin *pin, *prev;
110e28a4053SRui Paulo dl_list_for_each_safe(pin, prev, pins, struct wps_uuid_pin, list)
111e28a4053SRui Paulo wps_remove_pin(pin);
11239beb93cSSam Leffler }
11339beb93cSSam Leffler
11439beb93cSSam Leffler
11539beb93cSSam Leffler struct wps_pbc_session {
11639beb93cSSam Leffler struct wps_pbc_session *next;
11739beb93cSSam Leffler u8 addr[ETH_ALEN];
11839beb93cSSam Leffler u8 uuid_e[WPS_UUID_LEN];
1195b9c547cSRui Paulo struct os_reltime timestamp;
12039beb93cSSam Leffler };
12139beb93cSSam Leffler
12239beb93cSSam Leffler
wps_free_pbc_sessions(struct wps_pbc_session * pbc)12339beb93cSSam Leffler static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)
12439beb93cSSam Leffler {
12539beb93cSSam Leffler struct wps_pbc_session *prev;
12639beb93cSSam Leffler
12739beb93cSSam Leffler while (pbc) {
12839beb93cSSam Leffler prev = pbc;
12939beb93cSSam Leffler pbc = pbc->next;
13039beb93cSSam Leffler os_free(prev);
13139beb93cSSam Leffler }
13239beb93cSSam Leffler }
13339beb93cSSam Leffler
13439beb93cSSam Leffler
135e28a4053SRui Paulo struct wps_registrar_device {
136e28a4053SRui Paulo struct wps_registrar_device *next;
137e28a4053SRui Paulo struct wps_device_data dev;
138e28a4053SRui Paulo u8 uuid[WPS_UUID_LEN];
139e28a4053SRui Paulo };
140e28a4053SRui Paulo
141e28a4053SRui Paulo
14239beb93cSSam Leffler struct wps_registrar {
14339beb93cSSam Leffler struct wps_context *wps;
14439beb93cSSam Leffler
14539beb93cSSam Leffler int pbc;
14639beb93cSSam Leffler int selected_registrar;
14739beb93cSSam Leffler
1485b9c547cSRui Paulo int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *p2p_dev_addr,
1495b9c547cSRui Paulo const u8 *psk, size_t psk_len);
150e28a4053SRui Paulo int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
151e28a4053SRui Paulo struct wpabuf *probe_resp_ie);
15239beb93cSSam Leffler void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
15339beb93cSSam Leffler const struct wps_device_data *dev);
15439beb93cSSam Leffler void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
155f05cddf9SRui Paulo const u8 *uuid_e, const u8 *dev_pw,
156f05cddf9SRui Paulo size_t dev_pw_len);
157e28a4053SRui Paulo void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
158e28a4053SRui Paulo u16 sel_reg_config_methods);
159e28a4053SRui Paulo void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
160e28a4053SRui Paulo const u8 *pri_dev_type, u16 config_methods,
161e28a4053SRui Paulo u16 dev_password_id, u8 request_type,
162e28a4053SRui Paulo const char *dev_name);
163c1d255d3SCy Schubert int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk);
16439beb93cSSam Leffler void *cb_ctx;
16539beb93cSSam Leffler
166e28a4053SRui Paulo struct dl_list pins;
167f05cddf9SRui Paulo struct dl_list nfc_pw_tokens;
16839beb93cSSam Leffler struct wps_pbc_session *pbc_sessions;
16939beb93cSSam Leffler
17039beb93cSSam Leffler int skip_cred_build;
17139beb93cSSam Leffler struct wpabuf *extra_cred;
17239beb93cSSam Leffler int disable_auto_conf;
173e28a4053SRui Paulo int sel_reg_union;
17439beb93cSSam Leffler int sel_reg_dev_password_id_override;
17539beb93cSSam Leffler int sel_reg_config_methods_override;
176f05cddf9SRui Paulo int dualband;
1775b9c547cSRui Paulo int force_per_enrollee_psk;
1783157ba21SRui Paulo
179e28a4053SRui Paulo struct wps_registrar_device *devices;
180e28a4053SRui Paulo
1813157ba21SRui Paulo int force_pbc_overlap;
182f05cddf9SRui Paulo
183f05cddf9SRui Paulo u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
184f05cddf9SRui Paulo u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
185f05cddf9SRui Paulo
186f05cddf9SRui Paulo u8 p2p_dev_addr[ETH_ALEN];
187f05cddf9SRui Paulo
188f05cddf9SRui Paulo u8 pbc_ignore_uuid[WPS_UUID_LEN];
1895b9c547cSRui Paulo #ifdef WPS_WORKAROUNDS
1905b9c547cSRui Paulo struct os_reltime pbc_ignore_start;
1915b9c547cSRui Paulo #endif /* WPS_WORKAROUNDS */
1924bc52338SCy Schubert
1934bc52338SCy Schubert /**
1944bc52338SCy Schubert * multi_ap_backhaul_ssid - SSID to supply to a Multi-AP backhaul
1954bc52338SCy Schubert * enrollee
1964bc52338SCy Schubert *
1974bc52338SCy Schubert * This SSID is used by the Registrar to fill in information for
1984bc52338SCy Schubert * Credentials when the enrollee advertises it is a Multi-AP backhaul
1994bc52338SCy Schubert * STA.
2004bc52338SCy Schubert */
2014bc52338SCy Schubert u8 multi_ap_backhaul_ssid[SSID_MAX_LEN];
2024bc52338SCy Schubert
2034bc52338SCy Schubert /**
2044bc52338SCy Schubert * multi_ap_backhaul_ssid_len - Length of multi_ap_backhaul_ssid in
2054bc52338SCy Schubert * octets
2064bc52338SCy Schubert */
2074bc52338SCy Schubert size_t multi_ap_backhaul_ssid_len;
2084bc52338SCy Schubert
2094bc52338SCy Schubert /**
2104bc52338SCy Schubert * multi_ap_backhaul_network_key - The Network Key (PSK) for the
2114bc52338SCy Schubert * Multi-AP backhaul enrollee.
2124bc52338SCy Schubert *
2134bc52338SCy Schubert * This key can be either the ASCII passphrase (8..63 characters) or the
2144bc52338SCy Schubert * 32-octet PSK (64 hex characters).
2154bc52338SCy Schubert */
2164bc52338SCy Schubert u8 *multi_ap_backhaul_network_key;
2174bc52338SCy Schubert
2184bc52338SCy Schubert /**
2194bc52338SCy Schubert * multi_ap_backhaul_network_key_len - Length of
2204bc52338SCy Schubert * multi_ap_backhaul_network_key in octets
2214bc52338SCy Schubert */
2224bc52338SCy Schubert size_t multi_ap_backhaul_network_key_len;
22339beb93cSSam Leffler };
22439beb93cSSam Leffler
22539beb93cSSam Leffler
22639beb93cSSam Leffler static int wps_set_ie(struct wps_registrar *reg);
22739beb93cSSam Leffler static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
22839beb93cSSam Leffler static void wps_registrar_set_selected_timeout(void *eloop_ctx,
22939beb93cSSam Leffler void *timeout_ctx);
230f05cddf9SRui Paulo static void wps_registrar_remove_pin(struct wps_registrar *reg,
231f05cddf9SRui Paulo struct wps_uuid_pin *pin);
232f05cddf9SRui Paulo
233f05cddf9SRui Paulo
wps_registrar_add_authorized_mac(struct wps_registrar * reg,const u8 * addr)234f05cddf9SRui Paulo static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
235f05cddf9SRui Paulo const u8 *addr)
236f05cddf9SRui Paulo {
237f05cddf9SRui Paulo int i;
238f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR,
239f05cddf9SRui Paulo MAC2STR(addr));
240f05cddf9SRui Paulo for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
241*a90b9d01SCy Schubert if (ether_addr_equal(reg->authorized_macs[i], addr)) {
242f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was "
243f05cddf9SRui Paulo "already in the list");
244f05cddf9SRui Paulo return; /* already in list */
245f05cddf9SRui Paulo }
246f05cddf9SRui Paulo for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
247f05cddf9SRui Paulo os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
248f05cddf9SRui Paulo ETH_ALEN);
249f05cddf9SRui Paulo os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
250f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
251f05cddf9SRui Paulo (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
252f05cddf9SRui Paulo }
253f05cddf9SRui Paulo
254f05cddf9SRui Paulo
wps_registrar_remove_authorized_mac(struct wps_registrar * reg,const u8 * addr)255f05cddf9SRui Paulo static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
256f05cddf9SRui Paulo const u8 *addr)
257f05cddf9SRui Paulo {
258f05cddf9SRui Paulo int i;
259f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR,
260f05cddf9SRui Paulo MAC2STR(addr));
261f05cddf9SRui Paulo for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
262*a90b9d01SCy Schubert if (ether_addr_equal(reg->authorized_macs[i], addr))
263f05cddf9SRui Paulo break;
264f05cddf9SRui Paulo }
265f05cddf9SRui Paulo if (i == WPS_MAX_AUTHORIZED_MACS) {
266f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was not in the "
267f05cddf9SRui Paulo "list");
268f05cddf9SRui Paulo return; /* not in the list */
269f05cddf9SRui Paulo }
270f05cddf9SRui Paulo for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
271f05cddf9SRui Paulo os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
272f05cddf9SRui Paulo ETH_ALEN);
273f05cddf9SRui Paulo os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
274f05cddf9SRui Paulo ETH_ALEN);
275f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs",
276f05cddf9SRui Paulo (u8 *) reg->authorized_macs, sizeof(reg->authorized_macs));
277f05cddf9SRui Paulo }
27839beb93cSSam Leffler
27939beb93cSSam Leffler
wps_free_devices(struct wps_registrar_device * dev)280e28a4053SRui Paulo static void wps_free_devices(struct wps_registrar_device *dev)
281e28a4053SRui Paulo {
282e28a4053SRui Paulo struct wps_registrar_device *prev;
283e28a4053SRui Paulo
284e28a4053SRui Paulo while (dev) {
285e28a4053SRui Paulo prev = dev;
286e28a4053SRui Paulo dev = dev->next;
287e28a4053SRui Paulo wps_device_data_free(&prev->dev);
288e28a4053SRui Paulo os_free(prev);
289e28a4053SRui Paulo }
290e28a4053SRui Paulo }
291e28a4053SRui Paulo
292e28a4053SRui Paulo
wps_device_get(struct wps_registrar * reg,const u8 * addr)293e28a4053SRui Paulo static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg,
294e28a4053SRui Paulo const u8 *addr)
295e28a4053SRui Paulo {
296e28a4053SRui Paulo struct wps_registrar_device *dev;
297e28a4053SRui Paulo
298e28a4053SRui Paulo for (dev = reg->devices; dev; dev = dev->next) {
299*a90b9d01SCy Schubert if (ether_addr_equal(dev->dev.mac_addr, addr))
300e28a4053SRui Paulo return dev;
301e28a4053SRui Paulo }
302e28a4053SRui Paulo return NULL;
303e28a4053SRui Paulo }
304e28a4053SRui Paulo
305e28a4053SRui Paulo
wps_device_clone_data(struct wps_device_data * dst,struct wps_device_data * src)306e28a4053SRui Paulo static void wps_device_clone_data(struct wps_device_data *dst,
307e28a4053SRui Paulo struct wps_device_data *src)
308e28a4053SRui Paulo {
309e28a4053SRui Paulo os_memcpy(dst->mac_addr, src->mac_addr, ETH_ALEN);
310e28a4053SRui Paulo os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
311e28a4053SRui Paulo
312e28a4053SRui Paulo #define WPS_STRDUP(n) \
313e28a4053SRui Paulo os_free(dst->n); \
314e28a4053SRui Paulo dst->n = src->n ? os_strdup(src->n) : NULL
315e28a4053SRui Paulo
316e28a4053SRui Paulo WPS_STRDUP(device_name);
317e28a4053SRui Paulo WPS_STRDUP(manufacturer);
318e28a4053SRui Paulo WPS_STRDUP(model_name);
319e28a4053SRui Paulo WPS_STRDUP(model_number);
320e28a4053SRui Paulo WPS_STRDUP(serial_number);
321e28a4053SRui Paulo #undef WPS_STRDUP
322e28a4053SRui Paulo }
323e28a4053SRui Paulo
324e28a4053SRui Paulo
wps_device_store(struct wps_registrar * reg,struct wps_device_data * dev,const u8 * uuid)325e28a4053SRui Paulo int wps_device_store(struct wps_registrar *reg,
326e28a4053SRui Paulo struct wps_device_data *dev, const u8 *uuid)
327e28a4053SRui Paulo {
328e28a4053SRui Paulo struct wps_registrar_device *d;
329e28a4053SRui Paulo
330e28a4053SRui Paulo d = wps_device_get(reg, dev->mac_addr);
331e28a4053SRui Paulo if (d == NULL) {
332e28a4053SRui Paulo d = os_zalloc(sizeof(*d));
333e28a4053SRui Paulo if (d == NULL)
334e28a4053SRui Paulo return -1;
335e28a4053SRui Paulo d->next = reg->devices;
336e28a4053SRui Paulo reg->devices = d;
337e28a4053SRui Paulo }
338e28a4053SRui Paulo
339e28a4053SRui Paulo wps_device_clone_data(&d->dev, dev);
340e28a4053SRui Paulo os_memcpy(d->uuid, uuid, WPS_UUID_LEN);
341e28a4053SRui Paulo
342e28a4053SRui Paulo return 0;
343e28a4053SRui Paulo }
344e28a4053SRui Paulo
345e28a4053SRui Paulo
wps_registrar_add_pbc_session(struct wps_registrar * reg,const u8 * addr,const u8 * uuid_e)34639beb93cSSam Leffler static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
34739beb93cSSam Leffler const u8 *addr, const u8 *uuid_e)
34839beb93cSSam Leffler {
34939beb93cSSam Leffler struct wps_pbc_session *pbc, *prev = NULL;
3505b9c547cSRui Paulo struct os_reltime now;
35139beb93cSSam Leffler
3525b9c547cSRui Paulo os_get_reltime(&now);
35339beb93cSSam Leffler
35439beb93cSSam Leffler pbc = reg->pbc_sessions;
35539beb93cSSam Leffler while (pbc) {
356*a90b9d01SCy Schubert if (ether_addr_equal(pbc->addr, addr) &&
35739beb93cSSam Leffler os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
35839beb93cSSam Leffler if (prev)
35939beb93cSSam Leffler prev->next = pbc->next;
36039beb93cSSam Leffler else
36139beb93cSSam Leffler reg->pbc_sessions = pbc->next;
36239beb93cSSam Leffler break;
36339beb93cSSam Leffler }
36439beb93cSSam Leffler prev = pbc;
36539beb93cSSam Leffler pbc = pbc->next;
36639beb93cSSam Leffler }
36739beb93cSSam Leffler
36839beb93cSSam Leffler if (!pbc) {
36939beb93cSSam Leffler pbc = os_zalloc(sizeof(*pbc));
37039beb93cSSam Leffler if (pbc == NULL)
37139beb93cSSam Leffler return;
37239beb93cSSam Leffler os_memcpy(pbc->addr, addr, ETH_ALEN);
37339beb93cSSam Leffler if (uuid_e)
37439beb93cSSam Leffler os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN);
37539beb93cSSam Leffler }
37639beb93cSSam Leffler
37739beb93cSSam Leffler pbc->next = reg->pbc_sessions;
37839beb93cSSam Leffler reg->pbc_sessions = pbc;
37939beb93cSSam Leffler pbc->timestamp = now;
38039beb93cSSam Leffler
38139beb93cSSam Leffler /* remove entries that have timed out */
38239beb93cSSam Leffler prev = pbc;
38339beb93cSSam Leffler pbc = pbc->next;
38439beb93cSSam Leffler
38539beb93cSSam Leffler while (pbc) {
3865b9c547cSRui Paulo if (os_reltime_expired(&now, &pbc->timestamp,
3875b9c547cSRui Paulo WPS_PBC_WALK_TIME)) {
38839beb93cSSam Leffler prev->next = NULL;
38939beb93cSSam Leffler wps_free_pbc_sessions(pbc);
39039beb93cSSam Leffler break;
39139beb93cSSam Leffler }
39239beb93cSSam Leffler prev = pbc;
39339beb93cSSam Leffler pbc = pbc->next;
39439beb93cSSam Leffler }
39539beb93cSSam Leffler }
39639beb93cSSam Leffler
39739beb93cSSam Leffler
wps_registrar_remove_pbc_session(struct wps_registrar * reg,const u8 * uuid_e,const u8 * p2p_dev_addr)39839beb93cSSam Leffler static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
399f05cddf9SRui Paulo const u8 *uuid_e,
400f05cddf9SRui Paulo const u8 *p2p_dev_addr)
40139beb93cSSam Leffler {
402f05cddf9SRui Paulo struct wps_pbc_session *pbc, *prev = NULL, *tmp;
40339beb93cSSam Leffler
40439beb93cSSam Leffler pbc = reg->pbc_sessions;
40539beb93cSSam Leffler while (pbc) {
406f05cddf9SRui Paulo if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
407f05cddf9SRui Paulo (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
408*a90b9d01SCy Schubert ether_addr_equal(reg->p2p_dev_addr, p2p_dev_addr))) {
40939beb93cSSam Leffler if (prev)
41039beb93cSSam Leffler prev->next = pbc->next;
41139beb93cSSam Leffler else
41239beb93cSSam Leffler reg->pbc_sessions = pbc->next;
413f05cddf9SRui Paulo tmp = pbc;
414f05cddf9SRui Paulo pbc = pbc->next;
415f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Removing PBC session for "
416f05cddf9SRui Paulo "addr=" MACSTR, MAC2STR(tmp->addr));
417f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Removed UUID-E",
418f05cddf9SRui Paulo tmp->uuid_e, WPS_UUID_LEN);
419f05cddf9SRui Paulo os_free(tmp);
420f05cddf9SRui Paulo continue;
42139beb93cSSam Leffler }
42239beb93cSSam Leffler prev = pbc;
42339beb93cSSam Leffler pbc = pbc->next;
42439beb93cSSam Leffler }
42539beb93cSSam Leffler }
42639beb93cSSam Leffler
42739beb93cSSam Leffler
wps_registrar_pbc_overlap(struct wps_registrar * reg,const u8 * addr,const u8 * uuid_e)428f05cddf9SRui Paulo int wps_registrar_pbc_overlap(struct wps_registrar *reg,
42939beb93cSSam Leffler const u8 *addr, const u8 *uuid_e)
43039beb93cSSam Leffler {
43139beb93cSSam Leffler int count = 0;
43239beb93cSSam Leffler struct wps_pbc_session *pbc;
433f05cddf9SRui Paulo struct wps_pbc_session *first = NULL;
4345b9c547cSRui Paulo struct os_reltime now;
43539beb93cSSam Leffler
4365b9c547cSRui Paulo os_get_reltime(&now);
43739beb93cSSam Leffler
438f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Checking active PBC sessions for overlap");
439f05cddf9SRui Paulo
440f05cddf9SRui Paulo if (uuid_e) {
441f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add one for the requested UUID");
442f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Requested UUID",
443f05cddf9SRui Paulo uuid_e, WPS_UUID_LEN);
44439beb93cSSam Leffler count++;
44539beb93cSSam Leffler }
44639beb93cSSam Leffler
447f05cddf9SRui Paulo for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
448f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Consider PBC session with " MACSTR,
449f05cddf9SRui Paulo MAC2STR(pbc->addr));
450f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID-E",
451f05cddf9SRui Paulo pbc->uuid_e, WPS_UUID_LEN);
4525b9c547cSRui Paulo if (os_reltime_expired(&now, &pbc->timestamp,
4535b9c547cSRui Paulo WPS_PBC_WALK_TIME)) {
4545b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: PBC walk time has expired");
455f05cddf9SRui Paulo break;
456f05cddf9SRui Paulo }
457f05cddf9SRui Paulo if (first &&
458f05cddf9SRui Paulo os_memcmp(pbc->uuid_e, first->uuid_e, WPS_UUID_LEN) == 0) {
459f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Same Enrollee");
460f05cddf9SRui Paulo continue; /* same Enrollee */
461f05cddf9SRui Paulo }
462f05cddf9SRui Paulo if (uuid_e == NULL ||
463f05cddf9SRui Paulo os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN)) {
464f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: New Enrollee");
46539beb93cSSam Leffler count++;
466f05cddf9SRui Paulo }
467f05cddf9SRui Paulo if (first == NULL)
468f05cddf9SRui Paulo first = pbc;
469f05cddf9SRui Paulo }
470f05cddf9SRui Paulo
471f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: %u active PBC session(s) found", count);
47239beb93cSSam Leffler
47339beb93cSSam Leffler return count > 1 ? 1 : 0;
47439beb93cSSam Leffler }
47539beb93cSSam Leffler
47639beb93cSSam Leffler
wps_build_wps_state(struct wps_context * wps,struct wpabuf * msg)47739beb93cSSam Leffler static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
47839beb93cSSam Leffler {
47939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)",
48039beb93cSSam Leffler wps->wps_state);
48139beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_WPS_STATE);
48239beb93cSSam Leffler wpabuf_put_be16(msg, 1);
48339beb93cSSam Leffler wpabuf_put_u8(msg, wps->wps_state);
48439beb93cSSam Leffler return 0;
48539beb93cSSam Leffler }
48639beb93cSSam Leffler
48739beb93cSSam Leffler
48839beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
wps_registrar_free_pending_m2(struct wps_context * wps)48939beb93cSSam Leffler static void wps_registrar_free_pending_m2(struct wps_context *wps)
49039beb93cSSam Leffler {
49139beb93cSSam Leffler struct upnp_pending_message *p, *p2, *prev = NULL;
49239beb93cSSam Leffler p = wps->upnp_msgs;
49339beb93cSSam Leffler while (p) {
49439beb93cSSam Leffler if (p->type == WPS_M2 || p->type == WPS_M2D) {
49539beb93cSSam Leffler if (prev == NULL)
49639beb93cSSam Leffler wps->upnp_msgs = p->next;
49739beb93cSSam Leffler else
49839beb93cSSam Leffler prev->next = p->next;
49939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
50039beb93cSSam Leffler p2 = p;
50139beb93cSSam Leffler p = p->next;
50239beb93cSSam Leffler wpabuf_free(p2->msg);
50339beb93cSSam Leffler os_free(p2);
50439beb93cSSam Leffler continue;
50539beb93cSSam Leffler }
50639beb93cSSam Leffler prev = p;
50739beb93cSSam Leffler p = p->next;
50839beb93cSSam Leffler }
50939beb93cSSam Leffler }
51039beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
51139beb93cSSam Leffler
51239beb93cSSam Leffler
wps_build_ap_setup_locked(struct wps_context * wps,struct wpabuf * msg)51339beb93cSSam Leffler static int wps_build_ap_setup_locked(struct wps_context *wps,
51439beb93cSSam Leffler struct wpabuf *msg)
51539beb93cSSam Leffler {
516f05cddf9SRui Paulo if (wps->ap_setup_locked && wps->ap_setup_locked != 2) {
51739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * AP Setup Locked");
51839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
51939beb93cSSam Leffler wpabuf_put_be16(msg, 1);
52039beb93cSSam Leffler wpabuf_put_u8(msg, 1);
52139beb93cSSam Leffler }
52239beb93cSSam Leffler return 0;
52339beb93cSSam Leffler }
52439beb93cSSam Leffler
52539beb93cSSam Leffler
wps_build_selected_registrar(struct wps_registrar * reg,struct wpabuf * msg)52639beb93cSSam Leffler static int wps_build_selected_registrar(struct wps_registrar *reg,
52739beb93cSSam Leffler struct wpabuf *msg)
52839beb93cSSam Leffler {
529e28a4053SRui Paulo if (!reg->sel_reg_union)
53039beb93cSSam Leffler return 0;
53139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar");
53239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
53339beb93cSSam Leffler wpabuf_put_be16(msg, 1);
53439beb93cSSam Leffler wpabuf_put_u8(msg, 1);
53539beb93cSSam Leffler return 0;
53639beb93cSSam Leffler }
53739beb93cSSam Leffler
53839beb93cSSam Leffler
wps_build_sel_reg_dev_password_id(struct wps_registrar * reg,struct wpabuf * msg)53939beb93cSSam Leffler static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
54039beb93cSSam Leffler struct wpabuf *msg)
54139beb93cSSam Leffler {
54239beb93cSSam Leffler u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
543e28a4053SRui Paulo if (!reg->sel_reg_union)
54439beb93cSSam Leffler return 0;
54539beb93cSSam Leffler if (reg->sel_reg_dev_password_id_override >= 0)
54639beb93cSSam Leffler id = reg->sel_reg_dev_password_id_override;
54739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id);
54839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
54939beb93cSSam Leffler wpabuf_put_be16(msg, 2);
55039beb93cSSam Leffler wpabuf_put_be16(msg, id);
55139beb93cSSam Leffler return 0;
55239beb93cSSam Leffler }
55339beb93cSSam Leffler
55439beb93cSSam Leffler
wps_build_sel_pbc_reg_uuid_e(struct wps_registrar * reg,struct wpabuf * msg)555f05cddf9SRui Paulo static int wps_build_sel_pbc_reg_uuid_e(struct wps_registrar *reg,
556f05cddf9SRui Paulo struct wpabuf *msg)
557f05cddf9SRui Paulo {
558f05cddf9SRui Paulo u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
559f05cddf9SRui Paulo if (!reg->sel_reg_union)
560f05cddf9SRui Paulo return 0;
561f05cddf9SRui Paulo if (reg->sel_reg_dev_password_id_override >= 0)
562f05cddf9SRui Paulo id = reg->sel_reg_dev_password_id_override;
563f05cddf9SRui Paulo if (id != DEV_PW_PUSHBUTTON || !reg->dualband)
564f05cddf9SRui Paulo return 0;
565f05cddf9SRui Paulo return wps_build_uuid_e(msg, reg->wps->uuid);
566f05cddf9SRui Paulo }
567f05cddf9SRui Paulo
568f05cddf9SRui Paulo
wps_set_pushbutton(u16 * methods,u16 conf_methods)569f05cddf9SRui Paulo static void wps_set_pushbutton(u16 *methods, u16 conf_methods)
570f05cddf9SRui Paulo {
571f05cddf9SRui Paulo *methods |= WPS_CONFIG_PUSHBUTTON;
572f05cddf9SRui Paulo if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) ==
573f05cddf9SRui Paulo WPS_CONFIG_VIRT_PUSHBUTTON)
574f05cddf9SRui Paulo *methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
575f05cddf9SRui Paulo if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) ==
576f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON)
577f05cddf9SRui Paulo *methods |= WPS_CONFIG_PHY_PUSHBUTTON;
578f05cddf9SRui Paulo if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
579f05cddf9SRui Paulo WPS_CONFIG_VIRT_PUSHBUTTON &&
580f05cddf9SRui Paulo (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
581f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON) {
582f05cddf9SRui Paulo /*
583f05cddf9SRui Paulo * Required to include virtual/physical flag, but we were not
584f05cddf9SRui Paulo * configured with push button type, so have to default to one
585f05cddf9SRui Paulo * of them.
586f05cddf9SRui Paulo */
587f05cddf9SRui Paulo *methods |= WPS_CONFIG_PHY_PUSHBUTTON;
588f05cddf9SRui Paulo }
589f05cddf9SRui Paulo }
590f05cddf9SRui Paulo
591f05cddf9SRui Paulo
wps_build_sel_reg_config_methods(struct wps_registrar * reg,struct wpabuf * msg)59239beb93cSSam Leffler static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
59339beb93cSSam Leffler struct wpabuf *msg)
59439beb93cSSam Leffler {
59539beb93cSSam Leffler u16 methods;
596e28a4053SRui Paulo if (!reg->sel_reg_union)
59739beb93cSSam Leffler return 0;
598f05cddf9SRui Paulo methods = reg->wps->config_methods;
599f05cddf9SRui Paulo methods &= ~WPS_CONFIG_PUSHBUTTON;
600f05cddf9SRui Paulo methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
601f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON);
60239beb93cSSam Leffler if (reg->pbc)
603f05cddf9SRui Paulo wps_set_pushbutton(&methods, reg->wps->config_methods);
60439beb93cSSam Leffler if (reg->sel_reg_config_methods_override >= 0)
60539beb93cSSam Leffler methods = reg->sel_reg_config_methods_override;
60639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Selected Registrar Config Methods (%x)",
60739beb93cSSam Leffler methods);
60839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
60939beb93cSSam Leffler wpabuf_put_be16(msg, 2);
61039beb93cSSam Leffler wpabuf_put_be16(msg, methods);
61139beb93cSSam Leffler return 0;
61239beb93cSSam Leffler }
61339beb93cSSam Leffler
61439beb93cSSam Leffler
wps_build_probe_config_methods(struct wps_registrar * reg,struct wpabuf * msg)61539beb93cSSam Leffler static int wps_build_probe_config_methods(struct wps_registrar *reg,
61639beb93cSSam Leffler struct wpabuf *msg)
61739beb93cSSam Leffler {
61839beb93cSSam Leffler u16 methods;
619e28a4053SRui Paulo /*
620e28a4053SRui Paulo * These are the methods that the AP supports as an Enrollee for adding
621e28a4053SRui Paulo * external Registrars.
622e28a4053SRui Paulo */
623e28a4053SRui Paulo methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
624f05cddf9SRui Paulo methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
625f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON);
62639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods);
62739beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
62839beb93cSSam Leffler wpabuf_put_be16(msg, 2);
62939beb93cSSam Leffler wpabuf_put_be16(msg, methods);
63039beb93cSSam Leffler return 0;
63139beb93cSSam Leffler }
63239beb93cSSam Leffler
63339beb93cSSam Leffler
wps_build_config_methods_r(struct wps_registrar * reg,struct wpabuf * msg)63439beb93cSSam Leffler static int wps_build_config_methods_r(struct wps_registrar *reg,
63539beb93cSSam Leffler struct wpabuf *msg)
63639beb93cSSam Leffler {
637f05cddf9SRui Paulo return wps_build_config_methods(msg, reg->wps->config_methods);
638f05cddf9SRui Paulo }
639f05cddf9SRui Paulo
640f05cddf9SRui Paulo
wps_authorized_macs(struct wps_registrar * reg,size_t * count)641f05cddf9SRui Paulo const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count)
642f05cddf9SRui Paulo {
643f05cddf9SRui Paulo *count = 0;
644f05cddf9SRui Paulo
645f05cddf9SRui Paulo while (*count < WPS_MAX_AUTHORIZED_MACS) {
646f05cddf9SRui Paulo if (is_zero_ether_addr(reg->authorized_macs_union[*count]))
647f05cddf9SRui Paulo break;
648f05cddf9SRui Paulo (*count)++;
649f05cddf9SRui Paulo }
650f05cddf9SRui Paulo
651f05cddf9SRui Paulo return (const u8 *) reg->authorized_macs_union;
65239beb93cSSam Leffler }
65339beb93cSSam Leffler
65439beb93cSSam Leffler
65539beb93cSSam Leffler /**
65639beb93cSSam Leffler * wps_registrar_init - Initialize WPS Registrar data
65739beb93cSSam Leffler * @wps: Pointer to longterm WPS context
65839beb93cSSam Leffler * @cfg: Registrar configuration
65939beb93cSSam Leffler * Returns: Pointer to allocated Registrar data or %NULL on failure
66039beb93cSSam Leffler *
66139beb93cSSam Leffler * This function is used to initialize WPS Registrar functionality. It can be
66239beb93cSSam Leffler * used for a single Registrar run (e.g., when run in a supplicant) or multiple
66339beb93cSSam Leffler * runs (e.g., when run as an internal Registrar in an AP). Caller is
66439beb93cSSam Leffler * responsible for freeing the returned data with wps_registrar_deinit() when
66539beb93cSSam Leffler * Registrar functionality is not needed anymore.
66639beb93cSSam Leffler */
66739beb93cSSam Leffler struct wps_registrar *
wps_registrar_init(struct wps_context * wps,const struct wps_registrar_config * cfg)66839beb93cSSam Leffler wps_registrar_init(struct wps_context *wps,
66939beb93cSSam Leffler const struct wps_registrar_config *cfg)
67039beb93cSSam Leffler {
67139beb93cSSam Leffler struct wps_registrar *reg = os_zalloc(sizeof(*reg));
67239beb93cSSam Leffler if (reg == NULL)
67339beb93cSSam Leffler return NULL;
67439beb93cSSam Leffler
675e28a4053SRui Paulo dl_list_init(®->pins);
676f05cddf9SRui Paulo dl_list_init(®->nfc_pw_tokens);
67739beb93cSSam Leffler reg->wps = wps;
67839beb93cSSam Leffler reg->new_psk_cb = cfg->new_psk_cb;
67939beb93cSSam Leffler reg->set_ie_cb = cfg->set_ie_cb;
68039beb93cSSam Leffler reg->pin_needed_cb = cfg->pin_needed_cb;
68139beb93cSSam Leffler reg->reg_success_cb = cfg->reg_success_cb;
682e28a4053SRui Paulo reg->set_sel_reg_cb = cfg->set_sel_reg_cb;
683e28a4053SRui Paulo reg->enrollee_seen_cb = cfg->enrollee_seen_cb;
684c1d255d3SCy Schubert reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb;
68539beb93cSSam Leffler reg->cb_ctx = cfg->cb_ctx;
68639beb93cSSam Leffler reg->skip_cred_build = cfg->skip_cred_build;
68739beb93cSSam Leffler if (cfg->extra_cred) {
68839beb93cSSam Leffler reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred,
68939beb93cSSam Leffler cfg->extra_cred_len);
69039beb93cSSam Leffler if (reg->extra_cred == NULL) {
69139beb93cSSam Leffler os_free(reg);
69239beb93cSSam Leffler return NULL;
69339beb93cSSam Leffler }
69439beb93cSSam Leffler }
69539beb93cSSam Leffler reg->disable_auto_conf = cfg->disable_auto_conf;
69639beb93cSSam Leffler reg->sel_reg_dev_password_id_override = -1;
69739beb93cSSam Leffler reg->sel_reg_config_methods_override = -1;
698f05cddf9SRui Paulo reg->dualband = cfg->dualband;
6995b9c547cSRui Paulo reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk;
70039beb93cSSam Leffler
7014bc52338SCy Schubert if (cfg->multi_ap_backhaul_ssid) {
7024bc52338SCy Schubert os_memcpy(reg->multi_ap_backhaul_ssid,
7034bc52338SCy Schubert cfg->multi_ap_backhaul_ssid,
7044bc52338SCy Schubert cfg->multi_ap_backhaul_ssid_len);
7054bc52338SCy Schubert reg->multi_ap_backhaul_ssid_len =
7064bc52338SCy Schubert cfg->multi_ap_backhaul_ssid_len;
7074bc52338SCy Schubert }
7084bc52338SCy Schubert if (cfg->multi_ap_backhaul_network_key) {
7094bc52338SCy Schubert reg->multi_ap_backhaul_network_key =
7104bc52338SCy Schubert os_memdup(cfg->multi_ap_backhaul_network_key,
7114bc52338SCy Schubert cfg->multi_ap_backhaul_network_key_len);
7124bc52338SCy Schubert if (reg->multi_ap_backhaul_network_key)
7134bc52338SCy Schubert reg->multi_ap_backhaul_network_key_len =
7144bc52338SCy Schubert cfg->multi_ap_backhaul_network_key_len;
7154bc52338SCy Schubert }
7164bc52338SCy Schubert
71739beb93cSSam Leffler if (wps_set_ie(reg)) {
71839beb93cSSam Leffler wps_registrar_deinit(reg);
71939beb93cSSam Leffler return NULL;
72039beb93cSSam Leffler }
72139beb93cSSam Leffler
72239beb93cSSam Leffler return reg;
72339beb93cSSam Leffler }
72439beb93cSSam Leffler
72539beb93cSSam Leffler
wps_registrar_flush(struct wps_registrar * reg)7265b9c547cSRui Paulo void wps_registrar_flush(struct wps_registrar *reg)
7275b9c547cSRui Paulo {
7285b9c547cSRui Paulo if (reg == NULL)
7295b9c547cSRui Paulo return;
7305b9c547cSRui Paulo wps_free_pins(®->pins);
7315b9c547cSRui Paulo wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0);
7325b9c547cSRui Paulo wps_free_pbc_sessions(reg->pbc_sessions);
7335b9c547cSRui Paulo reg->pbc_sessions = NULL;
7345b9c547cSRui Paulo wps_free_devices(reg->devices);
7355b9c547cSRui Paulo reg->devices = NULL;
7365b9c547cSRui Paulo #ifdef WPS_WORKAROUNDS
7375b9c547cSRui Paulo reg->pbc_ignore_start.sec = 0;
7385b9c547cSRui Paulo #endif /* WPS_WORKAROUNDS */
7395b9c547cSRui Paulo }
7405b9c547cSRui Paulo
7415b9c547cSRui Paulo
74239beb93cSSam Leffler /**
74339beb93cSSam Leffler * wps_registrar_deinit - Deinitialize WPS Registrar data
74439beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
74539beb93cSSam Leffler */
wps_registrar_deinit(struct wps_registrar * reg)74639beb93cSSam Leffler void wps_registrar_deinit(struct wps_registrar *reg)
74739beb93cSSam Leffler {
74839beb93cSSam Leffler if (reg == NULL)
74939beb93cSSam Leffler return;
75039beb93cSSam Leffler eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
75139beb93cSSam Leffler eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
7525b9c547cSRui Paulo wps_registrar_flush(reg);
753780fb4a2SCy Schubert wpabuf_clear_free(reg->extra_cred);
7544bc52338SCy Schubert bin_clear_free(reg->multi_ap_backhaul_network_key,
7554bc52338SCy Schubert reg->multi_ap_backhaul_network_key_len);
75639beb93cSSam Leffler os_free(reg);
75739beb93cSSam Leffler }
75839beb93cSSam Leffler
75939beb93cSSam Leffler
wps_registrar_invalidate_unused(struct wps_registrar * reg)760f05cddf9SRui Paulo static void wps_registrar_invalidate_unused(struct wps_registrar *reg)
761f05cddf9SRui Paulo {
762f05cddf9SRui Paulo struct wps_uuid_pin *pin;
763f05cddf9SRui Paulo
764f05cddf9SRui Paulo dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) {
765f05cddf9SRui Paulo if (pin->wildcard_uuid == 1 && !(pin->flags & PIN_LOCKED)) {
766f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalidate previously "
767f05cddf9SRui Paulo "configured wildcard PIN");
768f05cddf9SRui Paulo wps_registrar_remove_pin(reg, pin);
769f05cddf9SRui Paulo break;
770f05cddf9SRui Paulo }
771f05cddf9SRui Paulo }
772f05cddf9SRui Paulo }
773f05cddf9SRui Paulo
774f05cddf9SRui Paulo
77539beb93cSSam Leffler /**
77639beb93cSSam Leffler * wps_registrar_add_pin - Configure a new PIN for Registrar
77739beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
778f05cddf9SRui Paulo * @addr: Enrollee MAC address or %NULL if not known
77939beb93cSSam Leffler * @uuid: UUID-E or %NULL for wildcard (any UUID)
78039beb93cSSam Leffler * @pin: PIN (Device Password)
78139beb93cSSam Leffler * @pin_len: Length of pin in octets
7823157ba21SRui Paulo * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
78339beb93cSSam Leffler * Returns: 0 on success, -1 on failure
78439beb93cSSam Leffler */
wps_registrar_add_pin(struct wps_registrar * reg,const u8 * addr,const u8 * uuid,const u8 * pin,size_t pin_len,int timeout)785f05cddf9SRui Paulo int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
786f05cddf9SRui Paulo const u8 *uuid, const u8 *pin, size_t pin_len,
787f05cddf9SRui Paulo int timeout)
78839beb93cSSam Leffler {
78939beb93cSSam Leffler struct wps_uuid_pin *p;
79039beb93cSSam Leffler
79139beb93cSSam Leffler p = os_zalloc(sizeof(*p));
79239beb93cSSam Leffler if (p == NULL)
79339beb93cSSam Leffler return -1;
794f05cddf9SRui Paulo if (addr)
795f05cddf9SRui Paulo os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
79639beb93cSSam Leffler if (uuid == NULL)
79739beb93cSSam Leffler p->wildcard_uuid = 1;
79839beb93cSSam Leffler else
79939beb93cSSam Leffler os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
80085732ac8SCy Schubert p->pin = os_memdup(pin, pin_len);
80139beb93cSSam Leffler if (p->pin == NULL) {
80239beb93cSSam Leffler os_free(p);
80339beb93cSSam Leffler return -1;
80439beb93cSSam Leffler }
80539beb93cSSam Leffler p->pin_len = pin_len;
80639beb93cSSam Leffler
8073157ba21SRui Paulo if (timeout) {
8083157ba21SRui Paulo p->flags |= PIN_EXPIRES;
8095b9c547cSRui Paulo os_get_reltime(&p->expiration);
8103157ba21SRui Paulo p->expiration.sec += timeout;
8113157ba21SRui Paulo }
8123157ba21SRui Paulo
813f05cddf9SRui Paulo if (p->wildcard_uuid)
814f05cddf9SRui Paulo wps_registrar_invalidate_unused(reg);
815f05cddf9SRui Paulo
816e28a4053SRui Paulo dl_list_add(®->pins, &p->list);
81739beb93cSSam Leffler
8183157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
8193157ba21SRui Paulo timeout);
82039beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
82139beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
82239beb93cSSam Leffler reg->selected_registrar = 1;
82339beb93cSSam Leffler reg->pbc = 0;
824f05cddf9SRui Paulo if (addr)
825f05cddf9SRui Paulo wps_registrar_add_authorized_mac(reg, addr);
826f05cddf9SRui Paulo else
827f05cddf9SRui Paulo wps_registrar_add_authorized_mac(
828f05cddf9SRui Paulo reg, (u8 *) "\xff\xff\xff\xff\xff\xff");
8295b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
8303157ba21SRui Paulo eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
8313157ba21SRui Paulo eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
8323157ba21SRui Paulo wps_registrar_set_selected_timeout,
8333157ba21SRui Paulo reg, NULL);
83439beb93cSSam Leffler
83539beb93cSSam Leffler return 0;
83639beb93cSSam Leffler }
83739beb93cSSam Leffler
83839beb93cSSam Leffler
wps_registrar_remove_pin(struct wps_registrar * reg,struct wps_uuid_pin * pin)839f05cddf9SRui Paulo static void wps_registrar_remove_pin(struct wps_registrar *reg,
840f05cddf9SRui Paulo struct wps_uuid_pin *pin)
841f05cddf9SRui Paulo {
842f05cddf9SRui Paulo u8 *addr;
843f05cddf9SRui Paulo u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
844f05cddf9SRui Paulo
845f05cddf9SRui Paulo if (is_zero_ether_addr(pin->enrollee_addr))
846f05cddf9SRui Paulo addr = bcast;
847f05cddf9SRui Paulo else
848f05cddf9SRui Paulo addr = pin->enrollee_addr;
849f05cddf9SRui Paulo wps_registrar_remove_authorized_mac(reg, addr);
850f05cddf9SRui Paulo wps_remove_pin(pin);
8515b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
852f05cddf9SRui Paulo }
853f05cddf9SRui Paulo
854f05cddf9SRui Paulo
wps_registrar_expire_pins(struct wps_registrar * reg)8553157ba21SRui Paulo static void wps_registrar_expire_pins(struct wps_registrar *reg)
8563157ba21SRui Paulo {
857e28a4053SRui Paulo struct wps_uuid_pin *pin, *prev;
8585b9c547cSRui Paulo struct os_reltime now;
8593157ba21SRui Paulo
8605b9c547cSRui Paulo os_get_reltime(&now);
861e28a4053SRui Paulo dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list)
862e28a4053SRui Paulo {
8633157ba21SRui Paulo if ((pin->flags & PIN_EXPIRES) &&
8645b9c547cSRui Paulo os_reltime_before(&pin->expiration, &now)) {
8653157ba21SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
866e28a4053SRui Paulo pin->uuid, WPS_UUID_LEN);
867f05cddf9SRui Paulo wps_registrar_remove_pin(reg, pin);
8683157ba21SRui Paulo }
8693157ba21SRui Paulo }
8703157ba21SRui Paulo }
8713157ba21SRui Paulo
8723157ba21SRui Paulo
87339beb93cSSam Leffler /**
874f05cddf9SRui Paulo * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN
875f05cddf9SRui Paulo * @reg: Registrar data from wps_registrar_init()
876f05cddf9SRui Paulo * @dev_pw: PIN to search for or %NULL to match any
877f05cddf9SRui Paulo * @dev_pw_len: Length of dev_pw in octets
878f05cddf9SRui Paulo * Returns: 0 on success, -1 if not wildcard PIN is enabled
879f05cddf9SRui Paulo */
wps_registrar_invalidate_wildcard_pin(struct wps_registrar * reg,const u8 * dev_pw,size_t dev_pw_len)880f05cddf9SRui Paulo static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg,
881f05cddf9SRui Paulo const u8 *dev_pw,
882f05cddf9SRui Paulo size_t dev_pw_len)
883f05cddf9SRui Paulo {
884f05cddf9SRui Paulo struct wps_uuid_pin *pin, *prev;
885f05cddf9SRui Paulo
886f05cddf9SRui Paulo dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list)
887f05cddf9SRui Paulo {
888f05cddf9SRui Paulo if (dev_pw && pin->pin &&
889f05cddf9SRui Paulo (dev_pw_len != pin->pin_len ||
8905b9c547cSRui Paulo os_memcmp_const(dev_pw, pin->pin, dev_pw_len) != 0))
891f05cddf9SRui Paulo continue; /* different PIN */
892f05cddf9SRui Paulo if (pin->wildcard_uuid) {
893f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
894f05cddf9SRui Paulo pin->uuid, WPS_UUID_LEN);
895f05cddf9SRui Paulo wps_registrar_remove_pin(reg, pin);
896f05cddf9SRui Paulo return 0;
897f05cddf9SRui Paulo }
898f05cddf9SRui Paulo }
899f05cddf9SRui Paulo
900f05cddf9SRui Paulo return -1;
901f05cddf9SRui Paulo }
902f05cddf9SRui Paulo
903f05cddf9SRui Paulo
904f05cddf9SRui Paulo /**
90539beb93cSSam Leffler * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
90639beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
90739beb93cSSam Leffler * @uuid: UUID-E
90839beb93cSSam Leffler * Returns: 0 on success, -1 on failure (e.g., PIN not found)
90939beb93cSSam Leffler */
wps_registrar_invalidate_pin(struct wps_registrar * reg,const u8 * uuid)91039beb93cSSam Leffler int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
91139beb93cSSam Leffler {
91239beb93cSSam Leffler struct wps_uuid_pin *pin, *prev;
91339beb93cSSam Leffler
914e28a4053SRui Paulo dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list)
915e28a4053SRui Paulo {
91639beb93cSSam Leffler if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
91739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
91839beb93cSSam Leffler pin->uuid, WPS_UUID_LEN);
919f05cddf9SRui Paulo wps_registrar_remove_pin(reg, pin);
92039beb93cSSam Leffler return 0;
92139beb93cSSam Leffler }
92239beb93cSSam Leffler }
92339beb93cSSam Leffler
92439beb93cSSam Leffler return -1;
92539beb93cSSam Leffler }
92639beb93cSSam Leffler
92739beb93cSSam Leffler
wps_registrar_get_pin(struct wps_registrar * reg,const u8 * uuid,size_t * pin_len)92839beb93cSSam Leffler static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
92939beb93cSSam Leffler const u8 *uuid, size_t *pin_len)
93039beb93cSSam Leffler {
931e28a4053SRui Paulo struct wps_uuid_pin *pin, *found = NULL;
93285732ac8SCy Schubert int wildcard = 0;
93339beb93cSSam Leffler
9343157ba21SRui Paulo wps_registrar_expire_pins(reg);
9353157ba21SRui Paulo
936e28a4053SRui Paulo dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) {
93739beb93cSSam Leffler if (!pin->wildcard_uuid &&
938e28a4053SRui Paulo os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
939e28a4053SRui Paulo found = pin;
94039beb93cSSam Leffler break;
941e28a4053SRui Paulo }
94239beb93cSSam Leffler }
94339beb93cSSam Leffler
944e28a4053SRui Paulo if (!found) {
94539beb93cSSam Leffler /* Check for wildcard UUIDs since none of the UUID-specific
94639beb93cSSam Leffler * PINs matched */
947e28a4053SRui Paulo dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) {
948f05cddf9SRui Paulo if (pin->wildcard_uuid == 1 ||
949f05cddf9SRui Paulo pin->wildcard_uuid == 2) {
95039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
95139beb93cSSam Leffler "PIN. Assigned it for this UUID-E");
95285732ac8SCy Schubert wildcard = 1;
95339beb93cSSam Leffler os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
954e28a4053SRui Paulo found = pin;
95539beb93cSSam Leffler break;
95639beb93cSSam Leffler }
95739beb93cSSam Leffler }
95839beb93cSSam Leffler }
95939beb93cSSam Leffler
960e28a4053SRui Paulo if (!found)
96139beb93cSSam Leffler return NULL;
96239beb93cSSam Leffler
96339beb93cSSam Leffler /*
96439beb93cSSam Leffler * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
96539beb93cSSam Leffler * that could otherwise avoid PIN invalidations.
96639beb93cSSam Leffler */
967e28a4053SRui Paulo if (found->flags & PIN_LOCKED) {
96839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
96939beb93cSSam Leffler "allow concurrent re-use");
97039beb93cSSam Leffler return NULL;
97139beb93cSSam Leffler }
972e28a4053SRui Paulo *pin_len = found->pin_len;
973e28a4053SRui Paulo found->flags |= PIN_LOCKED;
97485732ac8SCy Schubert if (wildcard)
97585732ac8SCy Schubert found->wildcard_uuid++;
976e28a4053SRui Paulo return found->pin;
97739beb93cSSam Leffler }
97839beb93cSSam Leffler
97939beb93cSSam Leffler
98039beb93cSSam Leffler /**
98139beb93cSSam Leffler * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E
98239beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
98339beb93cSSam Leffler * @uuid: UUID-E
98439beb93cSSam Leffler * Returns: 0 on success, -1 on failure
98539beb93cSSam Leffler *
98639beb93cSSam Leffler * PINs are locked to enforce only one concurrent use. This function unlocks a
98739beb93cSSam Leffler * PIN to allow it to be used again. If the specified PIN was configured using
98839beb93cSSam Leffler * a wildcard UUID, it will be removed instead of allowing multiple uses.
98939beb93cSSam Leffler */
wps_registrar_unlock_pin(struct wps_registrar * reg,const u8 * uuid)99039beb93cSSam Leffler int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
99139beb93cSSam Leffler {
99239beb93cSSam Leffler struct wps_uuid_pin *pin;
99339beb93cSSam Leffler
994e28a4053SRui Paulo dl_list_for_each(pin, ®->pins, struct wps_uuid_pin, list) {
99539beb93cSSam Leffler if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
996f05cddf9SRui Paulo if (pin->wildcard_uuid == 3) {
99739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
99839beb93cSSam Leffler "wildcard PIN");
99939beb93cSSam Leffler return wps_registrar_invalidate_pin(reg, uuid);
100039beb93cSSam Leffler }
10013157ba21SRui Paulo pin->flags &= ~PIN_LOCKED;
100239beb93cSSam Leffler return 0;
100339beb93cSSam Leffler }
100439beb93cSSam Leffler }
100539beb93cSSam Leffler
100639beb93cSSam Leffler return -1;
100739beb93cSSam Leffler }
100839beb93cSSam Leffler
100939beb93cSSam Leffler
wps_registrar_stop_pbc(struct wps_registrar * reg)101039beb93cSSam Leffler static void wps_registrar_stop_pbc(struct wps_registrar *reg)
101139beb93cSSam Leffler {
101239beb93cSSam Leffler reg->selected_registrar = 0;
101339beb93cSSam Leffler reg->pbc = 0;
1014f05cddf9SRui Paulo os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
1015f05cddf9SRui Paulo wps_registrar_remove_authorized_mac(reg,
1016f05cddf9SRui Paulo (u8 *) "\xff\xff\xff\xff\xff\xff");
10175b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
101839beb93cSSam Leffler }
101939beb93cSSam Leffler
102039beb93cSSam Leffler
wps_registrar_pbc_timeout(void * eloop_ctx,void * timeout_ctx)102139beb93cSSam Leffler static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
102239beb93cSSam Leffler {
102339beb93cSSam Leffler struct wps_registrar *reg = eloop_ctx;
102439beb93cSSam Leffler
102539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
10263157ba21SRui Paulo wps_pbc_timeout_event(reg->wps);
102739beb93cSSam Leffler wps_registrar_stop_pbc(reg);
102839beb93cSSam Leffler }
102939beb93cSSam Leffler
103039beb93cSSam Leffler
103139beb93cSSam Leffler /**
103239beb93cSSam Leffler * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
103339beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
1034f05cddf9SRui Paulo * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL
1035f05cddf9SRui Paulo * indicates no such filtering
1036f05cddf9SRui Paulo * Returns: 0 on success, -1 on failure, -2 on session overlap
103739beb93cSSam Leffler *
103839beb93cSSam Leffler * This function is called on an AP when a push button is pushed to activate
103939beb93cSSam Leffler * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
1040f05cddf9SRui Paulo * or when a PBC registration is completed. If more than one Enrollee in active
1041f05cddf9SRui Paulo * PBC mode has been detected during the monitor time (previous 2 minutes), the
1042f05cddf9SRui Paulo * PBC mode is not activated and -2 is returned to indicate session overlap.
1043f05cddf9SRui Paulo * This is skipped if a specific Enrollee is selected.
104439beb93cSSam Leffler */
wps_registrar_button_pushed(struct wps_registrar * reg,const u8 * p2p_dev_addr)1045f05cddf9SRui Paulo int wps_registrar_button_pushed(struct wps_registrar *reg,
1046f05cddf9SRui Paulo const u8 *p2p_dev_addr)
104739beb93cSSam Leffler {
1048f05cddf9SRui Paulo if (p2p_dev_addr == NULL &&
1049f05cddf9SRui Paulo wps_registrar_pbc_overlap(reg, NULL, NULL)) {
105039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
105139beb93cSSam Leffler "mode");
10523157ba21SRui Paulo wps_pbc_overlap_event(reg->wps);
1053f05cddf9SRui Paulo return -2;
105439beb93cSSam Leffler }
105539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
10563157ba21SRui Paulo reg->force_pbc_overlap = 0;
105739beb93cSSam Leffler reg->selected_registrar = 1;
105839beb93cSSam Leffler reg->pbc = 1;
1059f05cddf9SRui Paulo if (p2p_dev_addr)
1060f05cddf9SRui Paulo os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
1061f05cddf9SRui Paulo else
1062f05cddf9SRui Paulo os_memset(reg->p2p_dev_addr, 0, ETH_ALEN);
1063f05cddf9SRui Paulo wps_registrar_add_authorized_mac(reg,
1064f05cddf9SRui Paulo (u8 *) "\xff\xff\xff\xff\xff\xff");
10655b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
106639beb93cSSam Leffler
10675b9c547cSRui Paulo wps_pbc_active_event(reg->wps);
1068f05cddf9SRui Paulo eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
106939beb93cSSam Leffler eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
107039beb93cSSam Leffler eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
107139beb93cSSam Leffler reg, NULL);
107239beb93cSSam Leffler return 0;
107339beb93cSSam Leffler }
107439beb93cSSam Leffler
107539beb93cSSam Leffler
wps_registrar_pbc_completed(struct wps_registrar * reg)107639beb93cSSam Leffler static void wps_registrar_pbc_completed(struct wps_registrar *reg)
107739beb93cSSam Leffler {
107839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
107939beb93cSSam Leffler eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
108039beb93cSSam Leffler wps_registrar_stop_pbc(reg);
10815b9c547cSRui Paulo wps_pbc_disable_event(reg->wps);
108239beb93cSSam Leffler }
108339beb93cSSam Leffler
1084e28a4053SRui Paulo
wps_registrar_pin_completed(struct wps_registrar * reg)10853157ba21SRui Paulo static void wps_registrar_pin_completed(struct wps_registrar *reg)
10863157ba21SRui Paulo {
10873157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
10883157ba21SRui Paulo eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
10893157ba21SRui Paulo reg->selected_registrar = 0;
10905b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
10913157ba21SRui Paulo }
10923157ba21SRui Paulo
109339beb93cSSam Leffler
wps_registrar_complete(struct wps_registrar * registrar,const u8 * uuid_e,const u8 * dev_pw,size_t dev_pw_len)1094f05cddf9SRui Paulo void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
1095f05cddf9SRui Paulo const u8 *dev_pw, size_t dev_pw_len)
1096f05cddf9SRui Paulo {
1097f05cddf9SRui Paulo if (registrar->pbc) {
1098f05cddf9SRui Paulo wps_registrar_remove_pbc_session(registrar,
1099f05cddf9SRui Paulo uuid_e, NULL);
1100f05cddf9SRui Paulo wps_registrar_pbc_completed(registrar);
11015b9c547cSRui Paulo #ifdef WPS_WORKAROUNDS
11025b9c547cSRui Paulo os_get_reltime(®istrar->pbc_ignore_start);
11035b9c547cSRui Paulo #endif /* WPS_WORKAROUNDS */
1104f05cddf9SRui Paulo os_memcpy(registrar->pbc_ignore_uuid, uuid_e, WPS_UUID_LEN);
1105f05cddf9SRui Paulo } else {
1106f05cddf9SRui Paulo wps_registrar_pin_completed(registrar);
1107f05cddf9SRui Paulo }
1108f05cddf9SRui Paulo
1109f05cddf9SRui Paulo if (dev_pw &&
1110f05cddf9SRui Paulo wps_registrar_invalidate_wildcard_pin(registrar, dev_pw,
1111f05cddf9SRui Paulo dev_pw_len) == 0) {
1112f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN",
1113f05cddf9SRui Paulo dev_pw, dev_pw_len);
1114f05cddf9SRui Paulo }
1115f05cddf9SRui Paulo }
1116f05cddf9SRui Paulo
1117f05cddf9SRui Paulo
wps_registrar_wps_cancel(struct wps_registrar * reg)1118f05cddf9SRui Paulo int wps_registrar_wps_cancel(struct wps_registrar *reg)
1119f05cddf9SRui Paulo {
1120f05cddf9SRui Paulo if (reg->pbc) {
1121f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: PBC is set - cancelling it");
1122f05cddf9SRui Paulo wps_registrar_pbc_timeout(reg, NULL);
1123f05cddf9SRui Paulo eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
1124f05cddf9SRui Paulo return 1;
1125f05cddf9SRui Paulo } else if (reg->selected_registrar) {
1126f05cddf9SRui Paulo /* PIN Method */
1127f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it");
1128f05cddf9SRui Paulo wps_registrar_pin_completed(reg);
1129f05cddf9SRui Paulo wps_registrar_invalidate_wildcard_pin(reg, NULL, 0);
1130f05cddf9SRui Paulo return 1;
1131f05cddf9SRui Paulo }
1132f05cddf9SRui Paulo return 0;
1133f05cddf9SRui Paulo }
1134f05cddf9SRui Paulo
1135f05cddf9SRui Paulo
113639beb93cSSam Leffler /**
113739beb93cSSam Leffler * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
113839beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
113939beb93cSSam Leffler * @addr: MAC address of the Probe Request sender
114039beb93cSSam Leffler * @wps_data: WPS IE contents
114139beb93cSSam Leffler *
114239beb93cSSam Leffler * This function is called on an AP when a Probe Request with WPS IE is
114339beb93cSSam Leffler * received. This is used to track PBC mode use and to detect possible overlap
114439beb93cSSam Leffler * situation with other WPS APs.
114539beb93cSSam Leffler */
wps_registrar_probe_req_rx(struct wps_registrar * reg,const u8 * addr,const struct wpabuf * wps_data,int p2p_wildcard)114639beb93cSSam Leffler void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
1147f05cddf9SRui Paulo const struct wpabuf *wps_data,
1148f05cddf9SRui Paulo int p2p_wildcard)
114939beb93cSSam Leffler {
115039beb93cSSam Leffler struct wps_parse_attr attr;
1151f05cddf9SRui Paulo int skip_add = 0;
115239beb93cSSam Leffler
115339beb93cSSam Leffler wpa_hexdump_buf(MSG_MSGDUMP,
115439beb93cSSam Leffler "WPS: Probe Request with WPS data received",
115539beb93cSSam Leffler wps_data);
115639beb93cSSam Leffler
115739beb93cSSam Leffler if (wps_parse_msg(wps_data, &attr) < 0)
115839beb93cSSam Leffler return;
115939beb93cSSam Leffler
116039beb93cSSam Leffler if (attr.config_methods == NULL) {
116139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
116239beb93cSSam Leffler "Probe Request");
116339beb93cSSam Leffler return;
116439beb93cSSam Leffler }
116539beb93cSSam Leffler
1166e28a4053SRui Paulo if (attr.dev_password_id == NULL) {
1167e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: No Device Password Id attribute "
1168e28a4053SRui Paulo "in Probe Request");
1169e28a4053SRui Paulo return;
1170e28a4053SRui Paulo }
1171e28a4053SRui Paulo
1172e28a4053SRui Paulo if (reg->enrollee_seen_cb && attr.uuid_e &&
1173f05cddf9SRui Paulo attr.primary_dev_type && attr.request_type && !p2p_wildcard) {
1174e28a4053SRui Paulo char *dev_name = NULL;
1175e28a4053SRui Paulo if (attr.dev_name) {
1176e28a4053SRui Paulo dev_name = os_zalloc(attr.dev_name_len + 1);
1177e28a4053SRui Paulo if (dev_name) {
1178e28a4053SRui Paulo os_memcpy(dev_name, attr.dev_name,
1179e28a4053SRui Paulo attr.dev_name_len);
1180e28a4053SRui Paulo }
1181e28a4053SRui Paulo }
1182e28a4053SRui Paulo reg->enrollee_seen_cb(reg->cb_ctx, addr, attr.uuid_e,
1183e28a4053SRui Paulo attr.primary_dev_type,
1184e28a4053SRui Paulo WPA_GET_BE16(attr.config_methods),
1185e28a4053SRui Paulo WPA_GET_BE16(attr.dev_password_id),
1186e28a4053SRui Paulo *attr.request_type, dev_name);
1187e28a4053SRui Paulo os_free(dev_name);
1188e28a4053SRui Paulo }
1189e28a4053SRui Paulo
1190e28a4053SRui Paulo if (WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
119139beb93cSSam Leffler return; /* Not PBC */
119239beb93cSSam Leffler
119339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
119439beb93cSSam Leffler MACSTR, MAC2STR(addr));
11953157ba21SRui Paulo if (attr.uuid_e == NULL) {
11963157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No "
11973157ba21SRui Paulo "UUID-E included");
11983157ba21SRui Paulo return;
11993157ba21SRui Paulo }
1200f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: UUID-E from Probe Request", attr.uuid_e,
1201f05cddf9SRui Paulo WPS_UUID_LEN);
120239beb93cSSam Leffler
1203f05cddf9SRui Paulo #ifdef WPS_WORKAROUNDS
1204f05cddf9SRui Paulo if (reg->pbc_ignore_start.sec &&
1205f05cddf9SRui Paulo os_memcmp(attr.uuid_e, reg->pbc_ignore_uuid, WPS_UUID_LEN) == 0) {
12065b9c547cSRui Paulo struct os_reltime now, dur;
12075b9c547cSRui Paulo os_get_reltime(&now);
12085b9c547cSRui Paulo os_reltime_sub(&now, ®->pbc_ignore_start, &dur);
1209f05cddf9SRui Paulo if (dur.sec >= 0 && dur.sec < 5) {
1210f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Ignore PBC activation "
1211f05cddf9SRui Paulo "based on Probe Request from the Enrollee "
1212f05cddf9SRui Paulo "that just completed PBC provisioning");
1213f05cddf9SRui Paulo skip_add = 1;
1214f05cddf9SRui Paulo } else
1215f05cddf9SRui Paulo reg->pbc_ignore_start.sec = 0;
1216f05cddf9SRui Paulo }
1217f05cddf9SRui Paulo #endif /* WPS_WORKAROUNDS */
1218f05cddf9SRui Paulo
1219f05cddf9SRui Paulo if (!skip_add)
122039beb93cSSam Leffler wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
12213157ba21SRui Paulo if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
12223157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
12233157ba21SRui Paulo reg->force_pbc_overlap = 1;
12243157ba21SRui Paulo wps_pbc_overlap_event(reg->wps);
12253157ba21SRui Paulo }
122639beb93cSSam Leffler }
122739beb93cSSam Leffler
122839beb93cSSam Leffler
wps_cb_new_psk(struct wps_registrar * reg,const u8 * mac_addr,const u8 * p2p_dev_addr,const u8 * psk,size_t psk_len)12295b9c547cSRui Paulo int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
12305b9c547cSRui Paulo const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len)
123139beb93cSSam Leffler {
123239beb93cSSam Leffler if (reg->new_psk_cb == NULL)
123339beb93cSSam Leffler return 0;
123439beb93cSSam Leffler
12355b9c547cSRui Paulo return reg->new_psk_cb(reg->cb_ctx, mac_addr, p2p_dev_addr, psk,
12365b9c547cSRui Paulo psk_len);
123739beb93cSSam Leffler }
123839beb93cSSam Leffler
123939beb93cSSam Leffler
wps_cb_pin_needed(struct wps_registrar * reg,const u8 * uuid_e,const struct wps_device_data * dev)124039beb93cSSam Leffler static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
124139beb93cSSam Leffler const struct wps_device_data *dev)
124239beb93cSSam Leffler {
124339beb93cSSam Leffler if (reg->pin_needed_cb == NULL)
124439beb93cSSam Leffler return;
124539beb93cSSam Leffler
124639beb93cSSam Leffler reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
124739beb93cSSam Leffler }
124839beb93cSSam Leffler
124939beb93cSSam Leffler
wps_cb_reg_success(struct wps_registrar * reg,const u8 * mac_addr,const u8 * uuid_e,const u8 * dev_pw,size_t dev_pw_len)125039beb93cSSam Leffler static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr,
1251f05cddf9SRui Paulo const u8 *uuid_e, const u8 *dev_pw,
1252f05cddf9SRui Paulo size_t dev_pw_len)
125339beb93cSSam Leffler {
125439beb93cSSam Leffler if (reg->reg_success_cb == NULL)
125539beb93cSSam Leffler return;
125639beb93cSSam Leffler
1257f05cddf9SRui Paulo reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len);
125839beb93cSSam Leffler }
125939beb93cSSam Leffler
126039beb93cSSam Leffler
wps_cb_set_ie(struct wps_registrar * reg,struct wpabuf * beacon_ie,struct wpabuf * probe_resp_ie)1261e28a4053SRui Paulo static int wps_cb_set_ie(struct wps_registrar *reg, struct wpabuf *beacon_ie,
1262e28a4053SRui Paulo struct wpabuf *probe_resp_ie)
126339beb93cSSam Leffler {
1264e28a4053SRui Paulo return reg->set_ie_cb(reg->cb_ctx, beacon_ie, probe_resp_ie);
1265e28a4053SRui Paulo }
126639beb93cSSam Leffler
1267e28a4053SRui Paulo
wps_cb_set_sel_reg(struct wps_registrar * reg)1268e28a4053SRui Paulo static void wps_cb_set_sel_reg(struct wps_registrar *reg)
1269e28a4053SRui Paulo {
1270e28a4053SRui Paulo u16 methods = 0;
1271e28a4053SRui Paulo if (reg->set_sel_reg_cb == NULL)
1272e28a4053SRui Paulo return;
1273e28a4053SRui Paulo
1274e28a4053SRui Paulo if (reg->selected_registrar) {
1275e28a4053SRui Paulo methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
1276f05cddf9SRui Paulo methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
1277f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON);
1278e28a4053SRui Paulo if (reg->pbc)
1279f05cddf9SRui Paulo wps_set_pushbutton(&methods, reg->wps->config_methods);
1280e28a4053SRui Paulo }
1281e28a4053SRui Paulo
1282f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: wps_cb_set_sel_reg: sel_reg=%d "
1283f05cddf9SRui Paulo "config_methods=0x%x pbc=%d methods=0x%x",
1284f05cddf9SRui Paulo reg->selected_registrar, reg->wps->config_methods,
1285f05cddf9SRui Paulo reg->pbc, methods);
1286f05cddf9SRui Paulo
1287e28a4053SRui Paulo reg->set_sel_reg_cb(reg->cb_ctx, reg->selected_registrar,
1288e28a4053SRui Paulo reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT,
1289e28a4053SRui Paulo methods);
129039beb93cSSam Leffler }
129139beb93cSSam Leffler
129239beb93cSSam Leffler
wps_cp_lookup_pskfile(struct wps_registrar * reg,const u8 * mac_addr,const u8 ** psk)1293c1d255d3SCy Schubert static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr,
1294c1d255d3SCy Schubert const u8 **psk)
1295c1d255d3SCy Schubert {
1296c1d255d3SCy Schubert if (!reg->lookup_pskfile_cb)
1297c1d255d3SCy Schubert return 0;
1298c1d255d3SCy Schubert return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk);
1299c1d255d3SCy Schubert }
1300c1d255d3SCy Schubert
1301c1d255d3SCy Schubert
wps_set_ie(struct wps_registrar * reg)130239beb93cSSam Leffler static int wps_set_ie(struct wps_registrar *reg)
130339beb93cSSam Leffler {
130439beb93cSSam Leffler struct wpabuf *beacon;
130539beb93cSSam Leffler struct wpabuf *probe;
1306f05cddf9SRui Paulo const u8 *auth_macs;
1307f05cddf9SRui Paulo size_t count;
1308f05cddf9SRui Paulo size_t vendor_len = 0;
1309f05cddf9SRui Paulo int i;
1310e28a4053SRui Paulo
1311e28a4053SRui Paulo if (reg->set_ie_cb == NULL)
1312e28a4053SRui Paulo return 0;
131339beb93cSSam Leffler
1314f05cddf9SRui Paulo for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
1315f05cddf9SRui Paulo if (reg->wps->dev.vendor_ext[i]) {
1316f05cddf9SRui Paulo vendor_len += 2 + 2;
1317f05cddf9SRui Paulo vendor_len += wpabuf_len(reg->wps->dev.vendor_ext[i]);
1318f05cddf9SRui Paulo }
1319f05cddf9SRui Paulo }
132039beb93cSSam Leffler
1321f05cddf9SRui Paulo beacon = wpabuf_alloc(400 + vendor_len);
1322f05cddf9SRui Paulo probe = wpabuf_alloc(500 + vendor_len);
1323c1d255d3SCy Schubert if (!beacon || !probe)
1324c1d255d3SCy Schubert goto fail;
132539beb93cSSam Leffler
1326f05cddf9SRui Paulo auth_macs = wps_authorized_macs(reg, &count);
1327f05cddf9SRui Paulo
1328f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
1329f05cddf9SRui Paulo
133039beb93cSSam Leffler if (wps_build_version(beacon) ||
133139beb93cSSam Leffler wps_build_wps_state(reg->wps, beacon) ||
133239beb93cSSam Leffler wps_build_ap_setup_locked(reg->wps, beacon) ||
133339beb93cSSam Leffler wps_build_selected_registrar(reg, beacon) ||
133439beb93cSSam Leffler wps_build_sel_reg_dev_password_id(reg, beacon) ||
133539beb93cSSam Leffler wps_build_sel_reg_config_methods(reg, beacon) ||
1336f05cddf9SRui Paulo wps_build_sel_pbc_reg_uuid_e(reg, beacon) ||
13375b9c547cSRui Paulo (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) ||
13384bc52338SCy Schubert wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) ||
1339c1d255d3SCy Schubert wps_build_vendor_ext(®->wps->dev, beacon) ||
1340c1d255d3SCy Schubert wps_build_application_ext(®->wps->dev, beacon))
1341c1d255d3SCy Schubert goto fail;
1342f05cddf9SRui Paulo
1343f05cddf9SRui Paulo #ifdef CONFIG_P2P
1344f05cddf9SRui Paulo if (wps_build_dev_name(®->wps->dev, beacon) ||
1345c1d255d3SCy Schubert wps_build_primary_dev_type(®->wps->dev, beacon))
1346c1d255d3SCy Schubert goto fail;
1347f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1348f05cddf9SRui Paulo
1349f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
1350f05cddf9SRui Paulo
1351f05cddf9SRui Paulo if (wps_build_version(probe) ||
135239beb93cSSam Leffler wps_build_wps_state(reg->wps, probe) ||
135339beb93cSSam Leffler wps_build_ap_setup_locked(reg->wps, probe) ||
135439beb93cSSam Leffler wps_build_selected_registrar(reg, probe) ||
135539beb93cSSam Leffler wps_build_sel_reg_dev_password_id(reg, probe) ||
135639beb93cSSam Leffler wps_build_sel_reg_config_methods(reg, probe) ||
1357e28a4053SRui Paulo wps_build_resp_type(probe, reg->wps->ap ? WPS_RESP_AP :
1358e28a4053SRui Paulo WPS_RESP_REGISTRAR) ||
135939beb93cSSam Leffler wps_build_uuid_e(probe, reg->wps->uuid) ||
136039beb93cSSam Leffler wps_build_device_attrs(®->wps->dev, probe) ||
136139beb93cSSam Leffler wps_build_probe_config_methods(reg, probe) ||
13625b9c547cSRui Paulo (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) ||
13634bc52338SCy Schubert wps_build_wfa_ext(probe, 0, auth_macs, count, 0) ||
1364c1d255d3SCy Schubert wps_build_vendor_ext(®->wps->dev, probe) ||
1365c1d255d3SCy Schubert wps_build_application_ext(®->wps->dev, probe))
1366c1d255d3SCy Schubert goto fail;
136739beb93cSSam Leffler
136839beb93cSSam Leffler beacon = wps_ie_encapsulate(beacon);
136939beb93cSSam Leffler probe = wps_ie_encapsulate(probe);
137039beb93cSSam Leffler
1371c1d255d3SCy Schubert if (!beacon || !probe)
1372c1d255d3SCy Schubert goto fail;
1373c1d255d3SCy Schubert
1374c1d255d3SCy Schubert return wps_cb_set_ie(reg, beacon, probe);
1375c1d255d3SCy Schubert fail:
137639beb93cSSam Leffler wpabuf_free(beacon);
137739beb93cSSam Leffler wpabuf_free(probe);
137839beb93cSSam Leffler return -1;
137939beb93cSSam Leffler }
138039beb93cSSam Leffler
138139beb93cSSam Leffler
wps_get_dev_password(struct wps_data * wps)138239beb93cSSam Leffler static int wps_get_dev_password(struct wps_data *wps)
138339beb93cSSam Leffler {
138439beb93cSSam Leffler const u8 *pin;
138539beb93cSSam Leffler size_t pin_len = 0;
138639beb93cSSam Leffler
13875b9c547cSRui Paulo bin_clear_free(wps->dev_password, wps->dev_password_len);
138839beb93cSSam Leffler wps->dev_password = NULL;
138939beb93cSSam Leffler
139039beb93cSSam Leffler if (wps->pbc) {
139139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
139239beb93cSSam Leffler pin = (const u8 *) "00000000";
139339beb93cSSam Leffler pin_len = 8;
1394f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
1395f05cddf9SRui Paulo } else if (wps->nfc_pw_token) {
13965b9c547cSRui Paulo if (wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
13975b9c547cSRui Paulo {
13985b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Using NFC connection "
13995b9c547cSRui Paulo "handover and abbreviated WPS handshake "
14005b9c547cSRui Paulo "without Device Password");
14015b9c547cSRui Paulo return 0;
14025b9c547cSRui Paulo }
1403f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
1404f05cddf9SRui Paulo "Password Token");
1405f05cddf9SRui Paulo pin = wps->nfc_pw_token->dev_pw;
1406f05cddf9SRui Paulo pin_len = wps->nfc_pw_token->dev_pw_len;
14075b9c547cSRui Paulo } else if (wps->dev_pw_id >= 0x10 &&
14085b9c547cSRui Paulo wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
14095b9c547cSRui Paulo wps->wps->ap_nfc_dev_pw) {
14105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from own NFC Password Token");
14115b9c547cSRui Paulo pin = wpabuf_head(wps->wps->ap_nfc_dev_pw);
14125b9c547cSRui Paulo pin_len = wpabuf_len(wps->wps->ap_nfc_dev_pw);
1413f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
141439beb93cSSam Leffler } else {
141539beb93cSSam Leffler pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
141639beb93cSSam Leffler &pin_len);
14175b9c547cSRui Paulo if (pin && wps->dev_pw_id >= 0x10) {
14185b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: No match for OOB Device "
14195b9c547cSRui Paulo "Password ID, but PIN found");
14205b9c547cSRui Paulo /*
14215b9c547cSRui Paulo * See whether Enrollee is willing to use PIN instead.
14225b9c547cSRui Paulo */
14235b9c547cSRui Paulo wps->dev_pw_id = DEV_PW_DEFAULT;
14245b9c547cSRui Paulo }
142539beb93cSSam Leffler }
142639beb93cSSam Leffler if (pin == NULL) {
142739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
14285b9c547cSRui Paulo "the Enrollee (context %p registrar %p)",
14295b9c547cSRui Paulo wps->wps, wps->wps->registrar);
143039beb93cSSam Leffler wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
143139beb93cSSam Leffler &wps->peer_dev);
143239beb93cSSam Leffler return -1;
143339beb93cSSam Leffler }
143439beb93cSSam Leffler
143585732ac8SCy Schubert wps->dev_password = os_memdup(pin, pin_len);
143639beb93cSSam Leffler if (wps->dev_password == NULL)
143739beb93cSSam Leffler return -1;
143839beb93cSSam Leffler wps->dev_password_len = pin_len;
143939beb93cSSam Leffler
144039beb93cSSam Leffler return 0;
144139beb93cSSam Leffler }
144239beb93cSSam Leffler
144339beb93cSSam Leffler
wps_build_uuid_r(struct wps_data * wps,struct wpabuf * msg)144439beb93cSSam Leffler static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)
144539beb93cSSam Leffler {
144639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * UUID-R");
144739beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_UUID_R);
144839beb93cSSam Leffler wpabuf_put_be16(msg, WPS_UUID_LEN);
144939beb93cSSam Leffler wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN);
145039beb93cSSam Leffler return 0;
145139beb93cSSam Leffler }
145239beb93cSSam Leffler
145339beb93cSSam Leffler
wps_build_r_hash(struct wps_data * wps,struct wpabuf * msg)145439beb93cSSam Leffler static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
145539beb93cSSam Leffler {
145639beb93cSSam Leffler u8 *hash;
145739beb93cSSam Leffler const u8 *addr[4];
145839beb93cSSam Leffler size_t len[4];
145939beb93cSSam Leffler
1460f05cddf9SRui Paulo if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
146139beb93cSSam Leffler return -1;
146239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
146339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
146439beb93cSSam Leffler wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
146539beb93cSSam Leffler
146639beb93cSSam Leffler if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
146739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
146839beb93cSSam Leffler "R-Hash derivation");
146939beb93cSSam Leffler return -1;
147039beb93cSSam Leffler }
147139beb93cSSam Leffler
147239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * R-Hash1");
147339beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_R_HASH1);
147439beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN);
147539beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN);
147639beb93cSSam Leffler /* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
147739beb93cSSam Leffler addr[0] = wps->snonce;
147839beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
147939beb93cSSam Leffler addr[1] = wps->psk1;
148039beb93cSSam Leffler len[1] = WPS_PSK_LEN;
148139beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
148239beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
148339beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
148439beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
148539beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
148639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN);
148739beb93cSSam Leffler
148839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * R-Hash2");
148939beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_R_HASH2);
149039beb93cSSam Leffler wpabuf_put_be16(msg, SHA256_MAC_LEN);
149139beb93cSSam Leffler hash = wpabuf_put(msg, SHA256_MAC_LEN);
149239beb93cSSam Leffler /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
149339beb93cSSam Leffler addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
149439beb93cSSam Leffler addr[1] = wps->psk2;
149539beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
149639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN);
149739beb93cSSam Leffler
149839beb93cSSam Leffler return 0;
149939beb93cSSam Leffler }
150039beb93cSSam Leffler
150139beb93cSSam Leffler
wps_build_r_snonce1(struct wps_data * wps,struct wpabuf * msg)150239beb93cSSam Leffler static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)
150339beb93cSSam Leffler {
150439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * R-SNonce1");
150539beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_R_SNONCE1);
150639beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
150739beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
150839beb93cSSam Leffler return 0;
150939beb93cSSam Leffler }
151039beb93cSSam Leffler
151139beb93cSSam Leffler
wps_build_r_snonce2(struct wps_data * wps,struct wpabuf * msg)151239beb93cSSam Leffler static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
151339beb93cSSam Leffler {
151439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * R-SNonce2");
151539beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_R_SNONCE2);
151639beb93cSSam Leffler wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
151739beb93cSSam Leffler wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
151839beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
151939beb93cSSam Leffler return 0;
152039beb93cSSam Leffler }
152139beb93cSSam Leffler
152239beb93cSSam Leffler
wps_build_cred_network_idx(struct wpabuf * msg,const struct wps_credential * cred)152339beb93cSSam Leffler static int wps_build_cred_network_idx(struct wpabuf *msg,
1524e28a4053SRui Paulo const struct wps_credential *cred)
152539beb93cSSam Leffler {
1526f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Network Index (1)");
152739beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
152839beb93cSSam Leffler wpabuf_put_be16(msg, 1);
152939beb93cSSam Leffler wpabuf_put_u8(msg, 1);
153039beb93cSSam Leffler return 0;
153139beb93cSSam Leffler }
153239beb93cSSam Leffler
153339beb93cSSam Leffler
wps_build_cred_ssid(struct wpabuf * msg,const struct wps_credential * cred)153439beb93cSSam Leffler static int wps_build_cred_ssid(struct wpabuf *msg,
1535e28a4053SRui Paulo const struct wps_credential *cred)
153639beb93cSSam Leffler {
153739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * SSID");
1538f05cddf9SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID for Credential",
1539f05cddf9SRui Paulo cred->ssid, cred->ssid_len);
154039beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_SSID);
154139beb93cSSam Leffler wpabuf_put_be16(msg, cred->ssid_len);
154239beb93cSSam Leffler wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
154339beb93cSSam Leffler return 0;
154439beb93cSSam Leffler }
154539beb93cSSam Leffler
154639beb93cSSam Leffler
wps_build_cred_auth_type(struct wpabuf * msg,const struct wps_credential * cred)154739beb93cSSam Leffler static int wps_build_cred_auth_type(struct wpabuf *msg,
1548e28a4053SRui Paulo const struct wps_credential *cred)
154939beb93cSSam Leffler {
155039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Authentication Type (0x%x)",
155139beb93cSSam Leffler cred->auth_type);
155239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
155339beb93cSSam Leffler wpabuf_put_be16(msg, 2);
155439beb93cSSam Leffler wpabuf_put_be16(msg, cred->auth_type);
155539beb93cSSam Leffler return 0;
155639beb93cSSam Leffler }
155739beb93cSSam Leffler
155839beb93cSSam Leffler
wps_build_cred_encr_type(struct wpabuf * msg,const struct wps_credential * cred)155939beb93cSSam Leffler static int wps_build_cred_encr_type(struct wpabuf *msg,
1560e28a4053SRui Paulo const struct wps_credential *cred)
156139beb93cSSam Leffler {
156239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Encryption Type (0x%x)",
156339beb93cSSam Leffler cred->encr_type);
156439beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
156539beb93cSSam Leffler wpabuf_put_be16(msg, 2);
156639beb93cSSam Leffler wpabuf_put_be16(msg, cred->encr_type);
156739beb93cSSam Leffler return 0;
156839beb93cSSam Leffler }
156939beb93cSSam Leffler
157039beb93cSSam Leffler
wps_build_cred_network_key(struct wpabuf * msg,const struct wps_credential * cred)157139beb93cSSam Leffler static int wps_build_cred_network_key(struct wpabuf *msg,
1572e28a4053SRui Paulo const struct wps_credential *cred)
157339beb93cSSam Leffler {
1574e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%d)",
1575e28a4053SRui Paulo (int) cred->key_len);
1576f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
1577f05cddf9SRui Paulo cred->key, cred->key_len);
157839beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
157939beb93cSSam Leffler wpabuf_put_be16(msg, cred->key_len);
158039beb93cSSam Leffler wpabuf_put_data(msg, cred->key, cred->key_len);
158139beb93cSSam Leffler return 0;
158239beb93cSSam Leffler }
158339beb93cSSam Leffler
158439beb93cSSam Leffler
wps_build_credential(struct wpabuf * msg,const struct wps_credential * cred)158539beb93cSSam Leffler static int wps_build_credential(struct wpabuf *msg,
1586e28a4053SRui Paulo const struct wps_credential *cred)
158739beb93cSSam Leffler {
158839beb93cSSam Leffler if (wps_build_cred_network_idx(msg, cred) ||
158939beb93cSSam Leffler wps_build_cred_ssid(msg, cred) ||
159039beb93cSSam Leffler wps_build_cred_auth_type(msg, cred) ||
159139beb93cSSam Leffler wps_build_cred_encr_type(msg, cred) ||
159239beb93cSSam Leffler wps_build_cred_network_key(msg, cred) ||
15935b9c547cSRui Paulo wps_build_mac_addr(msg, cred->mac_addr))
159439beb93cSSam Leffler return -1;
159539beb93cSSam Leffler return 0;
159639beb93cSSam Leffler }
159739beb93cSSam Leffler
159839beb93cSSam Leffler
wps_build_credential_wrap(struct wpabuf * msg,const struct wps_credential * cred)1599f05cddf9SRui Paulo int wps_build_credential_wrap(struct wpabuf *msg,
1600f05cddf9SRui Paulo const struct wps_credential *cred)
1601f05cddf9SRui Paulo {
1602f05cddf9SRui Paulo struct wpabuf *wbuf;
1603f05cddf9SRui Paulo wbuf = wpabuf_alloc(200);
1604f05cddf9SRui Paulo if (wbuf == NULL)
1605f05cddf9SRui Paulo return -1;
1606f05cddf9SRui Paulo if (wps_build_credential(wbuf, cred)) {
1607780fb4a2SCy Schubert wpabuf_clear_free(wbuf);
1608f05cddf9SRui Paulo return -1;
1609f05cddf9SRui Paulo }
1610f05cddf9SRui Paulo wpabuf_put_be16(msg, ATTR_CRED);
1611f05cddf9SRui Paulo wpabuf_put_be16(msg, wpabuf_len(wbuf));
1612f05cddf9SRui Paulo wpabuf_put_buf(msg, wbuf);
1613780fb4a2SCy Schubert wpabuf_clear_free(wbuf);
1614f05cddf9SRui Paulo return 0;
1615f05cddf9SRui Paulo }
1616f05cddf9SRui Paulo
1617f05cddf9SRui Paulo
wps_build_cred(struct wps_data * wps,struct wpabuf * msg)1618e28a4053SRui Paulo int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
161939beb93cSSam Leffler {
162039beb93cSSam Leffler struct wpabuf *cred;
16214bc52338SCy Schubert struct wps_registrar *reg = wps->wps->registrar;
1622c1d255d3SCy Schubert const u8 *pskfile_psk;
1623c1d255d3SCy Schubert char hex[65];
162439beb93cSSam Leffler
162539beb93cSSam Leffler if (wps->wps->registrar->skip_cred_build)
162639beb93cSSam Leffler goto skip_cred_build;
162739beb93cSSam Leffler
162839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Credential");
1629e28a4053SRui Paulo if (wps->use_cred) {
1630e28a4053SRui Paulo os_memcpy(&wps->cred, wps->use_cred, sizeof(wps->cred));
1631e28a4053SRui Paulo goto use_provided;
1632e28a4053SRui Paulo }
163339beb93cSSam Leffler os_memset(&wps->cred, 0, sizeof(wps->cred));
163439beb93cSSam Leffler
16354bc52338SCy Schubert if (wps->peer_dev.multi_ap_ext == MULTI_AP_BACKHAUL_STA &&
16364bc52338SCy Schubert reg->multi_ap_backhaul_ssid_len) {
16374bc52338SCy Schubert wpa_printf(MSG_DEBUG, "WPS: Use backhaul STA credentials");
16384bc52338SCy Schubert os_memcpy(wps->cred.ssid, reg->multi_ap_backhaul_ssid,
16394bc52338SCy Schubert reg->multi_ap_backhaul_ssid_len);
16404bc52338SCy Schubert wps->cred.ssid_len = reg->multi_ap_backhaul_ssid_len;
16414bc52338SCy Schubert /* Backhaul is always WPA2PSK */
16424bc52338SCy Schubert wps->cred.auth_type = WPS_AUTH_WPA2PSK;
16434bc52338SCy Schubert wps->cred.encr_type = WPS_ENCR_AES;
16444bc52338SCy Schubert /* Set MAC address in the Credential to be the Enrollee's MAC
16454bc52338SCy Schubert * address
16464bc52338SCy Schubert */
16474bc52338SCy Schubert os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
16484bc52338SCy Schubert if (reg->multi_ap_backhaul_network_key) {
16494bc52338SCy Schubert os_memcpy(wps->cred.key,
16504bc52338SCy Schubert reg->multi_ap_backhaul_network_key,
16514bc52338SCy Schubert reg->multi_ap_backhaul_network_key_len);
16524bc52338SCy Schubert wps->cred.key_len =
16534bc52338SCy Schubert reg->multi_ap_backhaul_network_key_len;
16544bc52338SCy Schubert }
16554bc52338SCy Schubert goto use_provided;
16564bc52338SCy Schubert }
16574bc52338SCy Schubert
165839beb93cSSam Leffler os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
165939beb93cSSam Leffler wps->cred.ssid_len = wps->wps->ssid_len;
166039beb93cSSam Leffler
166139beb93cSSam Leffler /* Select the best authentication and encryption type */
1662780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
1663780fb4a2SCy Schubert "WPS: Own auth types 0x%x - masked Enrollee auth types 0x%x",
1664780fb4a2SCy Schubert wps->wps->auth_types, wps->auth_type);
166539beb93cSSam Leffler if (wps->auth_type & WPS_AUTH_WPA2PSK)
166639beb93cSSam Leffler wps->auth_type = WPS_AUTH_WPA2PSK;
1667c1d255d3SCy Schubert #ifndef CONFIG_NO_TKIP
166839beb93cSSam Leffler else if (wps->auth_type & WPS_AUTH_WPAPSK)
166939beb93cSSam Leffler wps->auth_type = WPS_AUTH_WPAPSK;
1670c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
167139beb93cSSam Leffler else if (wps->auth_type & WPS_AUTH_OPEN)
167239beb93cSSam Leffler wps->auth_type = WPS_AUTH_OPEN;
167339beb93cSSam Leffler else {
167439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
167539beb93cSSam Leffler wps->auth_type);
167639beb93cSSam Leffler return -1;
167739beb93cSSam Leffler }
167839beb93cSSam Leffler wps->cred.auth_type = wps->auth_type;
167939beb93cSSam Leffler
1680780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
1681780fb4a2SCy Schubert "WPS: Own encr types 0x%x (rsn: 0x%x, wpa: 0x%x) - masked Enrollee encr types 0x%x",
1682780fb4a2SCy Schubert wps->wps->encr_types, wps->wps->encr_types_rsn,
1683780fb4a2SCy Schubert wps->wps->encr_types_wpa, wps->encr_type);
1684780fb4a2SCy Schubert if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPA2PSK)
1685780fb4a2SCy Schubert wps->encr_type &= wps->wps->encr_types_rsn;
1686780fb4a2SCy Schubert else if (wps->wps->ap && wps->auth_type == WPS_AUTH_WPAPSK)
1687780fb4a2SCy Schubert wps->encr_type &= wps->wps->encr_types_wpa;
168839beb93cSSam Leffler if (wps->auth_type == WPS_AUTH_WPA2PSK ||
168939beb93cSSam Leffler wps->auth_type == WPS_AUTH_WPAPSK) {
169039beb93cSSam Leffler if (wps->encr_type & WPS_ENCR_AES)
169139beb93cSSam Leffler wps->encr_type = WPS_ENCR_AES;
1692c1d255d3SCy Schubert #ifndef CONFIG_NO_TKIP
169339beb93cSSam Leffler else if (wps->encr_type & WPS_ENCR_TKIP)
169439beb93cSSam Leffler wps->encr_type = WPS_ENCR_TKIP;
1695c1d255d3SCy Schubert #endif /* CONFIG_NO_TKIP */
169639beb93cSSam Leffler else {
169739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
169839beb93cSSam Leffler "type for WPA/WPA2");
169939beb93cSSam Leffler return -1;
170039beb93cSSam Leffler }
170139beb93cSSam Leffler } else {
17025b9c547cSRui Paulo if (wps->encr_type & WPS_ENCR_NONE)
170339beb93cSSam Leffler wps->encr_type = WPS_ENCR_NONE;
17045b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
17055b9c547cSRui Paulo else if (wps->encr_type & WPS_ENCR_WEP)
17065b9c547cSRui Paulo wps->encr_type = WPS_ENCR_WEP;
17075b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
170839beb93cSSam Leffler else {
170939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
171039beb93cSSam Leffler "type for non-WPA/WPA2 mode");
171139beb93cSSam Leffler return -1;
171239beb93cSSam Leffler }
171339beb93cSSam Leffler }
171439beb93cSSam Leffler wps->cred.encr_type = wps->encr_type;
17153157ba21SRui Paulo /*
17163157ba21SRui Paulo * Set MAC address in the Credential to be the Enrollee's MAC address
17173157ba21SRui Paulo */
17183157ba21SRui Paulo os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
171939beb93cSSam Leffler
172039beb93cSSam Leffler if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
172139beb93cSSam Leffler !wps->wps->registrar->disable_auto_conf) {
172239beb93cSSam Leffler u8 r[16];
172339beb93cSSam Leffler /* Generate a random passphrase */
17245b9c547cSRui Paulo if (random_pool_ready() != 1 ||
17255b9c547cSRui Paulo random_get_bytes(r, sizeof(r)) < 0) {
17265b9c547cSRui Paulo wpa_printf(MSG_INFO,
17275b9c547cSRui Paulo "WPS: Could not generate random PSK");
172839beb93cSSam Leffler return -1;
17295b9c547cSRui Paulo }
173039beb93cSSam Leffler os_free(wps->new_psk);
1731c1d255d3SCy Schubert wps->new_psk = (u8 *) base64_encode(r, sizeof(r),
1732c1d255d3SCy Schubert &wps->new_psk_len);
173339beb93cSSam Leffler if (wps->new_psk == NULL)
173439beb93cSSam Leffler return -1;
173539beb93cSSam Leffler wps->new_psk_len--; /* remove newline */
173639beb93cSSam Leffler while (wps->new_psk_len &&
173739beb93cSSam Leffler wps->new_psk[wps->new_psk_len - 1] == '=')
173839beb93cSSam Leffler wps->new_psk_len--;
173939beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
174039beb93cSSam Leffler wps->new_psk, wps->new_psk_len);
174139beb93cSSam Leffler os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
174239beb93cSSam Leffler wps->cred.key_len = wps->new_psk_len;
1743c1d255d3SCy Schubert } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) {
1744c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file",
1745c1d255d3SCy Schubert pskfile_psk, PMK_LEN);
1746c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN);
1747c1d255d3SCy Schubert os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
1748c1d255d3SCy Schubert wps->cred.key_len = PMK_LEN * 2;
17495b9c547cSRui Paulo } else if (!wps->wps->registrar->force_per_enrollee_psk &&
17505b9c547cSRui Paulo wps->use_psk_key && wps->wps->psk_set) {
1751e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key");
1752c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN);
1753c1d255d3SCy Schubert os_memcpy(wps->cred.key, hex, PMK_LEN * 2);
1754c1d255d3SCy Schubert wps->cred.key_len = PMK_LEN * 2;
1755c1d255d3SCy Schubert } else if ((!wps->wps->registrar->force_per_enrollee_psk ||
1756c1d255d3SCy Schubert wps->wps->use_passphrase) && wps->wps->network_key) {
1757c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1758c1d255d3SCy Schubert "WPS: Use passphrase format for Network key");
175939beb93cSSam Leffler os_memcpy(wps->cred.key, wps->wps->network_key,
176039beb93cSSam Leffler wps->wps->network_key_len);
176139beb93cSSam Leffler wps->cred.key_len = wps->wps->network_key_len;
176239beb93cSSam Leffler } else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
176339beb93cSSam Leffler /* Generate a random per-device PSK */
176439beb93cSSam Leffler os_free(wps->new_psk);
1765c1d255d3SCy Schubert wps->new_psk_len = PMK_LEN;
176639beb93cSSam Leffler wps->new_psk = os_malloc(wps->new_psk_len);
176739beb93cSSam Leffler if (wps->new_psk == NULL)
176839beb93cSSam Leffler return -1;
17695b9c547cSRui Paulo if (random_pool_ready() != 1 ||
17705b9c547cSRui Paulo random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) {
17715b9c547cSRui Paulo wpa_printf(MSG_INFO,
17725b9c547cSRui Paulo "WPS: Could not generate random PSK");
177339beb93cSSam Leffler os_free(wps->new_psk);
177439beb93cSSam Leffler wps->new_psk = NULL;
177539beb93cSSam Leffler return -1;
177639beb93cSSam Leffler }
177739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
177839beb93cSSam Leffler wps->new_psk, wps->new_psk_len);
177939beb93cSSam Leffler wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
178039beb93cSSam Leffler wps->new_psk_len);
178139beb93cSSam Leffler os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
178239beb93cSSam Leffler wps->cred.key_len = wps->new_psk_len * 2;
178339beb93cSSam Leffler }
178439beb93cSSam Leffler
1785e28a4053SRui Paulo use_provided:
1786f05cddf9SRui Paulo #ifdef CONFIG_WPS_TESTING
17874b72b91aSCy Schubert if (wps_testing_stub_cred)
1788f05cddf9SRui Paulo cred = wpabuf_alloc(200);
1789f05cddf9SRui Paulo else
1790f05cddf9SRui Paulo cred = NULL;
1791f05cddf9SRui Paulo if (cred) {
17924b72b91aSCy Schubert struct wps_credential stub;
17934b72b91aSCy Schubert wpa_printf(MSG_DEBUG, "WPS: Add stub credential");
17944b72b91aSCy Schubert os_memset(&stub, 0, sizeof(stub));
17954b72b91aSCy Schubert os_memcpy(stub.ssid, "stub", 5);
17964b72b91aSCy Schubert stub.ssid_len = 5;
17974b72b91aSCy Schubert stub.auth_type = WPS_AUTH_WPA2PSK;
17984b72b91aSCy Schubert stub.encr_type = WPS_ENCR_AES;
17994b72b91aSCy Schubert os_memcpy(stub.key, "stub psk", 9);
18004b72b91aSCy Schubert stub.key_len = 9;
18014b72b91aSCy Schubert os_memcpy(stub.mac_addr, wps->mac_addr_e, ETH_ALEN);
18024b72b91aSCy Schubert wps_build_credential(cred, &stub);
18034b72b91aSCy Schubert wpa_hexdump_buf(MSG_DEBUG, "WPS: Stub Credential", cred);
1804f05cddf9SRui Paulo
1805f05cddf9SRui Paulo wpabuf_put_be16(msg, ATTR_CRED);
1806f05cddf9SRui Paulo wpabuf_put_be16(msg, wpabuf_len(cred));
1807f05cddf9SRui Paulo wpabuf_put_buf(msg, cred);
1808f05cddf9SRui Paulo
1809f05cddf9SRui Paulo wpabuf_free(cred);
1810f05cddf9SRui Paulo }
1811f05cddf9SRui Paulo #endif /* CONFIG_WPS_TESTING */
1812f05cddf9SRui Paulo
181339beb93cSSam Leffler cred = wpabuf_alloc(200);
181439beb93cSSam Leffler if (cred == NULL)
181539beb93cSSam Leffler return -1;
181639beb93cSSam Leffler
181739beb93cSSam Leffler if (wps_build_credential(cred, &wps->cred)) {
1818780fb4a2SCy Schubert wpabuf_clear_free(cred);
181939beb93cSSam Leffler return -1;
182039beb93cSSam Leffler }
182139beb93cSSam Leffler
182239beb93cSSam Leffler wpabuf_put_be16(msg, ATTR_CRED);
182339beb93cSSam Leffler wpabuf_put_be16(msg, wpabuf_len(cred));
182439beb93cSSam Leffler wpabuf_put_buf(msg, cred);
1825780fb4a2SCy Schubert wpabuf_clear_free(cred);
182639beb93cSSam Leffler
182739beb93cSSam Leffler skip_cred_build:
182839beb93cSSam Leffler if (wps->wps->registrar->extra_cred) {
182939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * Credential (pre-configured)");
183039beb93cSSam Leffler wpabuf_put_buf(msg, wps->wps->registrar->extra_cred);
183139beb93cSSam Leffler }
183239beb93cSSam Leffler
183339beb93cSSam Leffler return 0;
183439beb93cSSam Leffler }
183539beb93cSSam Leffler
183639beb93cSSam Leffler
wps_build_ap_settings(struct wps_data * wps,struct wpabuf * msg)183739beb93cSSam Leffler static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
183839beb93cSSam Leffler {
183939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: * AP Settings");
184039beb93cSSam Leffler
184139beb93cSSam Leffler if (wps_build_credential(msg, &wps->cred))
184239beb93cSSam Leffler return -1;
184339beb93cSSam Leffler
184439beb93cSSam Leffler return 0;
184539beb93cSSam Leffler }
184639beb93cSSam Leffler
184739beb93cSSam Leffler
wps_build_ap_cred(struct wps_data * wps)1848f05cddf9SRui Paulo static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
1849f05cddf9SRui Paulo {
1850f05cddf9SRui Paulo struct wpabuf *msg, *plain;
1851f05cddf9SRui Paulo
1852f05cddf9SRui Paulo msg = wpabuf_alloc(1000);
1853f05cddf9SRui Paulo if (msg == NULL)
1854f05cddf9SRui Paulo return NULL;
1855f05cddf9SRui Paulo
1856f05cddf9SRui Paulo plain = wpabuf_alloc(200);
1857f05cddf9SRui Paulo if (plain == NULL) {
1858f05cddf9SRui Paulo wpabuf_free(msg);
1859f05cddf9SRui Paulo return NULL;
1860f05cddf9SRui Paulo }
1861f05cddf9SRui Paulo
1862f05cddf9SRui Paulo if (wps_build_ap_settings(wps, plain)) {
1863780fb4a2SCy Schubert wpabuf_clear_free(plain);
1864f05cddf9SRui Paulo wpabuf_free(msg);
1865f05cddf9SRui Paulo return NULL;
1866f05cddf9SRui Paulo }
1867f05cddf9SRui Paulo
1868f05cddf9SRui Paulo wpabuf_put_be16(msg, ATTR_CRED);
1869f05cddf9SRui Paulo wpabuf_put_be16(msg, wpabuf_len(plain));
1870f05cddf9SRui Paulo wpabuf_put_buf(msg, plain);
1871780fb4a2SCy Schubert wpabuf_clear_free(plain);
1872f05cddf9SRui Paulo
1873f05cddf9SRui Paulo return msg;
1874f05cddf9SRui Paulo }
1875f05cddf9SRui Paulo
1876f05cddf9SRui Paulo
wps_build_m2(struct wps_data * wps)187739beb93cSSam Leffler static struct wpabuf * wps_build_m2(struct wps_data *wps)
187839beb93cSSam Leffler {
187939beb93cSSam Leffler struct wpabuf *msg;
18805b9c547cSRui Paulo int config_in_m2 = 0;
188139beb93cSSam Leffler
1882f05cddf9SRui Paulo if (random_get_bytes(wps->nonce_r, WPS_NONCE_LEN) < 0)
188339beb93cSSam Leffler return NULL;
188439beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
188539beb93cSSam Leffler wps->nonce_r, WPS_NONCE_LEN);
188639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
188739beb93cSSam Leffler
188839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M2");
188939beb93cSSam Leffler msg = wpabuf_alloc(1000);
189039beb93cSSam Leffler if (msg == NULL)
189139beb93cSSam Leffler return NULL;
189239beb93cSSam Leffler
189339beb93cSSam Leffler if (wps_build_version(msg) ||
189439beb93cSSam Leffler wps_build_msg_type(msg, WPS_M2) ||
189539beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
189639beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) ||
189739beb93cSSam Leffler wps_build_uuid_r(wps, msg) ||
189839beb93cSSam Leffler wps_build_public_key(wps, msg) ||
189939beb93cSSam Leffler wps_derive_keys(wps) ||
190039beb93cSSam Leffler wps_build_auth_type_flags(wps, msg) ||
190139beb93cSSam Leffler wps_build_encr_type_flags(wps, msg) ||
190239beb93cSSam Leffler wps_build_conn_type_flags(wps, msg) ||
190339beb93cSSam Leffler wps_build_config_methods_r(wps->wps->registrar, msg) ||
190439beb93cSSam Leffler wps_build_device_attrs(&wps->wps->dev, msg) ||
19055b9c547cSRui Paulo wps_build_rf_bands(&wps->wps->dev, msg,
19065b9c547cSRui Paulo wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
190739beb93cSSam Leffler wps_build_assoc_state(wps, msg) ||
190839beb93cSSam Leffler wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
190939beb93cSSam Leffler wps_build_dev_password_id(msg, wps->dev_pw_id) ||
191039beb93cSSam Leffler wps_build_os_version(&wps->wps->dev, msg) ||
19114bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
19125b9c547cSRui Paulo wpabuf_free(msg);
19135b9c547cSRui Paulo return NULL;
19145b9c547cSRui Paulo }
19155b9c547cSRui Paulo
19165b9c547cSRui Paulo #ifdef CONFIG_WPS_NFC
19175b9c547cSRui Paulo if (wps->nfc_pw_token && wps->nfc_pw_token->pk_hash_provided_oob &&
19185b9c547cSRui Paulo wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
19195b9c547cSRui Paulo /*
19205b9c547cSRui Paulo * Use abbreviated handshake since public key hash allowed
19215b9c547cSRui Paulo * Enrollee to validate our public key similarly to how Enrollee
19225b9c547cSRui Paulo * public key was validated. There is no need to validate Device
19235b9c547cSRui Paulo * Password in this case.
19245b9c547cSRui Paulo */
19255b9c547cSRui Paulo struct wpabuf *plain = wpabuf_alloc(500);
19265b9c547cSRui Paulo if (plain == NULL ||
19275b9c547cSRui Paulo wps_build_cred(wps, plain) ||
19285b9c547cSRui Paulo wps_build_key_wrap_auth(wps, plain) ||
19295b9c547cSRui Paulo wps_build_encr_settings(wps, msg, plain)) {
19305b9c547cSRui Paulo wpabuf_free(msg);
1931780fb4a2SCy Schubert wpabuf_clear_free(plain);
19325b9c547cSRui Paulo return NULL;
19335b9c547cSRui Paulo }
1934780fb4a2SCy Schubert wpabuf_clear_free(plain);
19355b9c547cSRui Paulo config_in_m2 = 1;
19365b9c547cSRui Paulo }
19375b9c547cSRui Paulo #endif /* CONFIG_WPS_NFC */
19385b9c547cSRui Paulo
19395b9c547cSRui Paulo if (wps_build_authenticator(wps, msg)) {
194039beb93cSSam Leffler wpabuf_free(msg);
194139beb93cSSam Leffler return NULL;
194239beb93cSSam Leffler }
194339beb93cSSam Leffler
1944e28a4053SRui Paulo wps->int_reg = 1;
19455b9c547cSRui Paulo wps->state = config_in_m2 ? RECV_DONE : RECV_M3;
194639beb93cSSam Leffler return msg;
194739beb93cSSam Leffler }
194839beb93cSSam Leffler
194939beb93cSSam Leffler
wps_build_m2d(struct wps_data * wps)195039beb93cSSam Leffler static struct wpabuf * wps_build_m2d(struct wps_data *wps)
195139beb93cSSam Leffler {
195239beb93cSSam Leffler struct wpabuf *msg;
19533157ba21SRui Paulo u16 err = wps->config_error;
195439beb93cSSam Leffler
195539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
195639beb93cSSam Leffler msg = wpabuf_alloc(1000);
195739beb93cSSam Leffler if (msg == NULL)
195839beb93cSSam Leffler return NULL;
195939beb93cSSam Leffler
19603157ba21SRui Paulo if (wps->wps->ap && wps->wps->ap_setup_locked &&
19613157ba21SRui Paulo err == WPS_CFG_NO_ERROR)
196239beb93cSSam Leffler err = WPS_CFG_SETUP_LOCKED;
196339beb93cSSam Leffler
196439beb93cSSam Leffler if (wps_build_version(msg) ||
196539beb93cSSam Leffler wps_build_msg_type(msg, WPS_M2D) ||
196639beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
196739beb93cSSam Leffler wps_build_registrar_nonce(wps, msg) ||
196839beb93cSSam Leffler wps_build_uuid_r(wps, msg) ||
196939beb93cSSam Leffler wps_build_auth_type_flags(wps, msg) ||
197039beb93cSSam Leffler wps_build_encr_type_flags(wps, msg) ||
197139beb93cSSam Leffler wps_build_conn_type_flags(wps, msg) ||
197239beb93cSSam Leffler wps_build_config_methods_r(wps->wps->registrar, msg) ||
197339beb93cSSam Leffler wps_build_device_attrs(&wps->wps->dev, msg) ||
19745b9c547cSRui Paulo wps_build_rf_bands(&wps->wps->dev, msg,
19755b9c547cSRui Paulo wps->wps->rf_band_cb(wps->wps->cb_ctx)) ||
197639beb93cSSam Leffler wps_build_assoc_state(wps, msg) ||
197739beb93cSSam Leffler wps_build_config_error(msg, err) ||
1978f05cddf9SRui Paulo wps_build_os_version(&wps->wps->dev, msg) ||
19794bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0)) {
198039beb93cSSam Leffler wpabuf_free(msg);
198139beb93cSSam Leffler return NULL;
198239beb93cSSam Leffler }
198339beb93cSSam Leffler
198439beb93cSSam Leffler wps->state = RECV_M2D_ACK;
198539beb93cSSam Leffler return msg;
198639beb93cSSam Leffler }
198739beb93cSSam Leffler
198839beb93cSSam Leffler
wps_build_m4(struct wps_data * wps)198939beb93cSSam Leffler static struct wpabuf * wps_build_m4(struct wps_data *wps)
199039beb93cSSam Leffler {
199139beb93cSSam Leffler struct wpabuf *msg, *plain;
199239beb93cSSam Leffler
199339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
199439beb93cSSam Leffler
1995780fb4a2SCy Schubert if (wps_derive_psk(wps, wps->dev_password, wps->dev_password_len) < 0)
1996780fb4a2SCy Schubert return NULL;
199739beb93cSSam Leffler
199839beb93cSSam Leffler plain = wpabuf_alloc(200);
199939beb93cSSam Leffler if (plain == NULL)
200039beb93cSSam Leffler return NULL;
200139beb93cSSam Leffler
200239beb93cSSam Leffler msg = wpabuf_alloc(1000);
200339beb93cSSam Leffler if (msg == NULL) {
200439beb93cSSam Leffler wpabuf_free(plain);
200539beb93cSSam Leffler return NULL;
200639beb93cSSam Leffler }
200739beb93cSSam Leffler
200839beb93cSSam Leffler if (wps_build_version(msg) ||
200939beb93cSSam Leffler wps_build_msg_type(msg, WPS_M4) ||
201039beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
201139beb93cSSam Leffler wps_build_r_hash(wps, msg) ||
201239beb93cSSam Leffler wps_build_r_snonce1(wps, plain) ||
201339beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) ||
201439beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) ||
20154bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
201639beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
2017780fb4a2SCy Schubert wpabuf_clear_free(plain);
201839beb93cSSam Leffler wpabuf_free(msg);
201939beb93cSSam Leffler return NULL;
202039beb93cSSam Leffler }
2021780fb4a2SCy Schubert wpabuf_clear_free(plain);
202239beb93cSSam Leffler
202339beb93cSSam Leffler wps->state = RECV_M5;
202439beb93cSSam Leffler return msg;
202539beb93cSSam Leffler }
202639beb93cSSam Leffler
202739beb93cSSam Leffler
wps_build_m6(struct wps_data * wps)202839beb93cSSam Leffler static struct wpabuf * wps_build_m6(struct wps_data *wps)
202939beb93cSSam Leffler {
203039beb93cSSam Leffler struct wpabuf *msg, *plain;
203139beb93cSSam Leffler
203239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M6");
203339beb93cSSam Leffler
203439beb93cSSam Leffler plain = wpabuf_alloc(200);
203539beb93cSSam Leffler if (plain == NULL)
203639beb93cSSam Leffler return NULL;
203739beb93cSSam Leffler
203839beb93cSSam Leffler msg = wpabuf_alloc(1000);
203939beb93cSSam Leffler if (msg == NULL) {
204039beb93cSSam Leffler wpabuf_free(plain);
204139beb93cSSam Leffler return NULL;
204239beb93cSSam Leffler }
204339beb93cSSam Leffler
204439beb93cSSam Leffler if (wps_build_version(msg) ||
204539beb93cSSam Leffler wps_build_msg_type(msg, WPS_M6) ||
204639beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
204739beb93cSSam Leffler wps_build_r_snonce2(wps, plain) ||
204839beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) ||
204939beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) ||
20504bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
205139beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
2052780fb4a2SCy Schubert wpabuf_clear_free(plain);
205339beb93cSSam Leffler wpabuf_free(msg);
205439beb93cSSam Leffler return NULL;
205539beb93cSSam Leffler }
2056780fb4a2SCy Schubert wpabuf_clear_free(plain);
205739beb93cSSam Leffler
205839beb93cSSam Leffler wps->wps_pin_revealed = 1;
205939beb93cSSam Leffler wps->state = RECV_M7;
206039beb93cSSam Leffler return msg;
206139beb93cSSam Leffler }
206239beb93cSSam Leffler
206339beb93cSSam Leffler
wps_build_m8(struct wps_data * wps)206439beb93cSSam Leffler static struct wpabuf * wps_build_m8(struct wps_data *wps)
206539beb93cSSam Leffler {
206639beb93cSSam Leffler struct wpabuf *msg, *plain;
206739beb93cSSam Leffler
206839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
206939beb93cSSam Leffler
207039beb93cSSam Leffler plain = wpabuf_alloc(500);
207139beb93cSSam Leffler if (plain == NULL)
207239beb93cSSam Leffler return NULL;
207339beb93cSSam Leffler
207439beb93cSSam Leffler msg = wpabuf_alloc(1000);
207539beb93cSSam Leffler if (msg == NULL) {
207639beb93cSSam Leffler wpabuf_free(plain);
207739beb93cSSam Leffler return NULL;
207839beb93cSSam Leffler }
207939beb93cSSam Leffler
208039beb93cSSam Leffler if (wps_build_version(msg) ||
208139beb93cSSam Leffler wps_build_msg_type(msg, WPS_M8) ||
208239beb93cSSam Leffler wps_build_enrollee_nonce(wps, msg) ||
2083e28a4053SRui Paulo ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) ||
2084e28a4053SRui Paulo (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) ||
208539beb93cSSam Leffler wps_build_key_wrap_auth(wps, plain) ||
208639beb93cSSam Leffler wps_build_encr_settings(wps, msg, plain) ||
20874bc52338SCy Schubert wps_build_wfa_ext(msg, 0, NULL, 0, 0) ||
208839beb93cSSam Leffler wps_build_authenticator(wps, msg)) {
2089780fb4a2SCy Schubert wpabuf_clear_free(plain);
2090780fb4a2SCy Schubert wpabuf_clear_free(msg);
209139beb93cSSam Leffler return NULL;
209239beb93cSSam Leffler }
2093780fb4a2SCy Schubert wpabuf_clear_free(plain);
209439beb93cSSam Leffler
209539beb93cSSam Leffler wps->state = RECV_DONE;
209639beb93cSSam Leffler return msg;
209739beb93cSSam Leffler }
209839beb93cSSam Leffler
209939beb93cSSam Leffler
wps_registrar_get_msg(struct wps_data * wps,enum wsc_op_code * op_code)210039beb93cSSam Leffler struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
210139beb93cSSam Leffler enum wsc_op_code *op_code)
210239beb93cSSam Leffler {
210339beb93cSSam Leffler struct wpabuf *msg;
210439beb93cSSam Leffler
210539beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
2106e28a4053SRui Paulo if (!wps->int_reg && wps->wps->wps_upnp) {
210739beb93cSSam Leffler struct upnp_pending_message *p, *prev = NULL;
210839beb93cSSam Leffler if (wps->ext_reg > 1)
210939beb93cSSam Leffler wps_registrar_free_pending_m2(wps->wps);
211039beb93cSSam Leffler p = wps->wps->upnp_msgs;
211139beb93cSSam Leffler /* TODO: check pending message MAC address */
211239beb93cSSam Leffler while (p && p->next) {
211339beb93cSSam Leffler prev = p;
211439beb93cSSam Leffler p = p->next;
211539beb93cSSam Leffler }
211639beb93cSSam Leffler if (p) {
211739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
211839beb93cSSam Leffler "UPnP");
211939beb93cSSam Leffler if (prev)
212039beb93cSSam Leffler prev->next = NULL;
212139beb93cSSam Leffler else
212239beb93cSSam Leffler wps->wps->upnp_msgs = NULL;
212339beb93cSSam Leffler msg = p->msg;
21243157ba21SRui Paulo switch (p->type) {
21253157ba21SRui Paulo case WPS_WSC_ACK:
21263157ba21SRui Paulo *op_code = WSC_ACK;
21273157ba21SRui Paulo break;
21283157ba21SRui Paulo case WPS_WSC_NACK:
21293157ba21SRui Paulo *op_code = WSC_NACK;
21303157ba21SRui Paulo break;
21313157ba21SRui Paulo default:
213239beb93cSSam Leffler *op_code = WSC_MSG;
21333157ba21SRui Paulo break;
21343157ba21SRui Paulo }
21353157ba21SRui Paulo os_free(p);
213639beb93cSSam Leffler if (wps->ext_reg == 0)
213739beb93cSSam Leffler wps->ext_reg = 1;
213839beb93cSSam Leffler return msg;
213939beb93cSSam Leffler }
214039beb93cSSam Leffler }
214139beb93cSSam Leffler if (wps->ext_reg) {
214239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
214339beb93cSSam Leffler "pending message available");
214439beb93cSSam Leffler return NULL;
214539beb93cSSam Leffler }
214639beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
214739beb93cSSam Leffler
214839beb93cSSam Leffler switch (wps->state) {
214939beb93cSSam Leffler case SEND_M2:
215039beb93cSSam Leffler if (wps_get_dev_password(wps) < 0)
215139beb93cSSam Leffler msg = wps_build_m2d(wps);
215239beb93cSSam Leffler else
215339beb93cSSam Leffler msg = wps_build_m2(wps);
215439beb93cSSam Leffler *op_code = WSC_MSG;
215539beb93cSSam Leffler break;
215639beb93cSSam Leffler case SEND_M2D:
215739beb93cSSam Leffler msg = wps_build_m2d(wps);
215839beb93cSSam Leffler *op_code = WSC_MSG;
215939beb93cSSam Leffler break;
216039beb93cSSam Leffler case SEND_M4:
216139beb93cSSam Leffler msg = wps_build_m4(wps);
216239beb93cSSam Leffler *op_code = WSC_MSG;
216339beb93cSSam Leffler break;
216439beb93cSSam Leffler case SEND_M6:
216539beb93cSSam Leffler msg = wps_build_m6(wps);
216639beb93cSSam Leffler *op_code = WSC_MSG;
216739beb93cSSam Leffler break;
216839beb93cSSam Leffler case SEND_M8:
216939beb93cSSam Leffler msg = wps_build_m8(wps);
217039beb93cSSam Leffler *op_code = WSC_MSG;
217139beb93cSSam Leffler break;
217239beb93cSSam Leffler case RECV_DONE:
217339beb93cSSam Leffler msg = wps_build_wsc_ack(wps);
217439beb93cSSam Leffler *op_code = WSC_ACK;
217539beb93cSSam Leffler break;
217639beb93cSSam Leffler case SEND_WSC_NACK:
217739beb93cSSam Leffler msg = wps_build_wsc_nack(wps);
217839beb93cSSam Leffler *op_code = WSC_NACK;
217939beb93cSSam Leffler break;
218039beb93cSSam Leffler default:
218139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
218239beb93cSSam Leffler "a message", wps->state);
218339beb93cSSam Leffler msg = NULL;
218439beb93cSSam Leffler break;
218539beb93cSSam Leffler }
218639beb93cSSam Leffler
218739beb93cSSam Leffler if (*op_code == WSC_MSG && msg) {
218839beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation
218939beb93cSSam Leffler */
219039beb93cSSam Leffler wpabuf_free(wps->last_msg);
219139beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg);
219239beb93cSSam Leffler }
219339beb93cSSam Leffler
219439beb93cSSam Leffler return msg;
219539beb93cSSam Leffler }
219639beb93cSSam Leffler
219739beb93cSSam Leffler
wps_process_enrollee_nonce(struct wps_data * wps,const u8 * e_nonce)219839beb93cSSam Leffler static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
219939beb93cSSam Leffler {
220039beb93cSSam Leffler if (e_nonce == NULL) {
220139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
220239beb93cSSam Leffler return -1;
220339beb93cSSam Leffler }
220439beb93cSSam Leffler
220539beb93cSSam Leffler os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN);
220639beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
220739beb93cSSam Leffler wps->nonce_e, WPS_NONCE_LEN);
220839beb93cSSam Leffler
220939beb93cSSam Leffler return 0;
221039beb93cSSam Leffler }
221139beb93cSSam Leffler
221239beb93cSSam Leffler
wps_process_registrar_nonce(struct wps_data * wps,const u8 * r_nonce)221339beb93cSSam Leffler static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
221439beb93cSSam Leffler {
221539beb93cSSam Leffler if (r_nonce == NULL) {
221639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
221739beb93cSSam Leffler return -1;
221839beb93cSSam Leffler }
221939beb93cSSam Leffler
222039beb93cSSam Leffler if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) {
222139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received");
222239beb93cSSam Leffler return -1;
222339beb93cSSam Leffler }
222439beb93cSSam Leffler
222539beb93cSSam Leffler return 0;
222639beb93cSSam Leffler }
222739beb93cSSam Leffler
222839beb93cSSam Leffler
wps_process_uuid_e(struct wps_data * wps,const u8 * uuid_e)222939beb93cSSam Leffler static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)
223039beb93cSSam Leffler {
223139beb93cSSam Leffler if (uuid_e == NULL) {
223239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No UUID-E received");
223339beb93cSSam Leffler return -1;
223439beb93cSSam Leffler }
223539beb93cSSam Leffler
223639beb93cSSam Leffler os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN);
223739beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN);
223839beb93cSSam Leffler
223939beb93cSSam Leffler return 0;
224039beb93cSSam Leffler }
224139beb93cSSam Leffler
224239beb93cSSam Leffler
wps_process_dev_password_id(struct wps_data * wps,const u8 * pw_id)224339beb93cSSam Leffler static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)
224439beb93cSSam Leffler {
224539beb93cSSam Leffler if (pw_id == NULL) {
224639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received");
224739beb93cSSam Leffler return -1;
224839beb93cSSam Leffler }
224939beb93cSSam Leffler
225039beb93cSSam Leffler wps->dev_pw_id = WPA_GET_BE16(pw_id);
225139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id);
225239beb93cSSam Leffler
225339beb93cSSam Leffler return 0;
225439beb93cSSam Leffler }
225539beb93cSSam Leffler
225639beb93cSSam Leffler
wps_process_e_hash1(struct wps_data * wps,const u8 * e_hash1)225739beb93cSSam Leffler static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)
225839beb93cSSam Leffler {
225939beb93cSSam Leffler if (e_hash1 == NULL) {
226039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received");
226139beb93cSSam Leffler return -1;
226239beb93cSSam Leffler }
226339beb93cSSam Leffler
226439beb93cSSam Leffler os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN);
226539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN);
226639beb93cSSam Leffler
226739beb93cSSam Leffler return 0;
226839beb93cSSam Leffler }
226939beb93cSSam Leffler
227039beb93cSSam Leffler
wps_process_e_hash2(struct wps_data * wps,const u8 * e_hash2)227139beb93cSSam Leffler static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)
227239beb93cSSam Leffler {
227339beb93cSSam Leffler if (e_hash2 == NULL) {
227439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received");
227539beb93cSSam Leffler return -1;
227639beb93cSSam Leffler }
227739beb93cSSam Leffler
227839beb93cSSam Leffler os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN);
227939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN);
228039beb93cSSam Leffler
228139beb93cSSam Leffler return 0;
228239beb93cSSam Leffler }
228339beb93cSSam Leffler
228439beb93cSSam Leffler
wps_process_e_snonce1(struct wps_data * wps,const u8 * e_snonce1)228539beb93cSSam Leffler static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
228639beb93cSSam Leffler {
228739beb93cSSam Leffler u8 hash[SHA256_MAC_LEN];
228839beb93cSSam Leffler const u8 *addr[4];
228939beb93cSSam Leffler size_t len[4];
229039beb93cSSam Leffler
229139beb93cSSam Leffler if (e_snonce1 == NULL) {
229239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received");
229339beb93cSSam Leffler return -1;
229439beb93cSSam Leffler }
229539beb93cSSam Leffler
229639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1,
229739beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
229839beb93cSSam Leffler
229939beb93cSSam Leffler /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
230039beb93cSSam Leffler addr[0] = e_snonce1;
230139beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
230239beb93cSSam Leffler addr[1] = wps->psk1;
230339beb93cSSam Leffler len[1] = WPS_PSK_LEN;
230439beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
230539beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
230639beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
230739beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
230839beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
230939beb93cSSam Leffler
23105b9c547cSRui Paulo if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
231139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
231239beb93cSSam Leffler "not match with the pre-committed value");
231339beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
23145b9c547cSRui Paulo wps_pwd_auth_fail_event(wps->wps, 0, 1, wps->mac_addr_e);
231539beb93cSSam Leffler return -1;
231639beb93cSSam Leffler }
231739beb93cSSam Leffler
231839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first "
231939beb93cSSam Leffler "half of the device password");
232039beb93cSSam Leffler
232139beb93cSSam Leffler return 0;
232239beb93cSSam Leffler }
232339beb93cSSam Leffler
232439beb93cSSam Leffler
wps_process_e_snonce2(struct wps_data * wps,const u8 * e_snonce2)232539beb93cSSam Leffler static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
232639beb93cSSam Leffler {
232739beb93cSSam Leffler u8 hash[SHA256_MAC_LEN];
232839beb93cSSam Leffler const u8 *addr[4];
232939beb93cSSam Leffler size_t len[4];
233039beb93cSSam Leffler
233139beb93cSSam Leffler if (e_snonce2 == NULL) {
233239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received");
233339beb93cSSam Leffler return -1;
233439beb93cSSam Leffler }
233539beb93cSSam Leffler
233639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2,
233739beb93cSSam Leffler WPS_SECRET_NONCE_LEN);
233839beb93cSSam Leffler
233939beb93cSSam Leffler /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
234039beb93cSSam Leffler addr[0] = e_snonce2;
234139beb93cSSam Leffler len[0] = WPS_SECRET_NONCE_LEN;
234239beb93cSSam Leffler addr[1] = wps->psk2;
234339beb93cSSam Leffler len[1] = WPS_PSK_LEN;
234439beb93cSSam Leffler addr[2] = wpabuf_head(wps->dh_pubkey_e);
234539beb93cSSam Leffler len[2] = wpabuf_len(wps->dh_pubkey_e);
234639beb93cSSam Leffler addr[3] = wpabuf_head(wps->dh_pubkey_r);
234739beb93cSSam Leffler len[3] = wpabuf_len(wps->dh_pubkey_r);
234839beb93cSSam Leffler hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
234939beb93cSSam Leffler
23505b9c547cSRui Paulo if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
235139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
235239beb93cSSam Leffler "not match with the pre-committed value");
235339beb93cSSam Leffler wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
235439beb93cSSam Leffler wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
23555b9c547cSRui Paulo wps_pwd_auth_fail_event(wps->wps, 0, 2, wps->mac_addr_e);
235639beb93cSSam Leffler return -1;
235739beb93cSSam Leffler }
235839beb93cSSam Leffler
235939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second "
236039beb93cSSam Leffler "half of the device password");
236139beb93cSSam Leffler wps->wps_pin_revealed = 0;
236239beb93cSSam Leffler wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e);
236339beb93cSSam Leffler
2364f05cddf9SRui Paulo /*
2365f05cddf9SRui Paulo * In case wildcard PIN is used and WPS handshake succeeds in the first
2366f05cddf9SRui Paulo * attempt, wps_registrar_unlock_pin() would not free the PIN, so make
2367f05cddf9SRui Paulo * sure the PIN gets invalidated here.
2368f05cddf9SRui Paulo */
2369f05cddf9SRui Paulo wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
2370f05cddf9SRui Paulo
237139beb93cSSam Leffler return 0;
237239beb93cSSam Leffler }
237339beb93cSSam Leffler
237439beb93cSSam Leffler
wps_process_mac_addr(struct wps_data * wps,const u8 * mac_addr)237539beb93cSSam Leffler static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)
237639beb93cSSam Leffler {
237739beb93cSSam Leffler if (mac_addr == NULL) {
237839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No MAC Address received");
237939beb93cSSam Leffler return -1;
238039beb93cSSam Leffler }
238139beb93cSSam Leffler
238239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR,
238339beb93cSSam Leffler MAC2STR(mac_addr));
238439beb93cSSam Leffler os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN);
238539beb93cSSam Leffler os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN);
238639beb93cSSam Leffler
238739beb93cSSam Leffler return 0;
238839beb93cSSam Leffler }
238939beb93cSSam Leffler
239039beb93cSSam Leffler
wps_process_pubkey(struct wps_data * wps,const u8 * pk,size_t pk_len)239139beb93cSSam Leffler static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
239239beb93cSSam Leffler size_t pk_len)
239339beb93cSSam Leffler {
239439beb93cSSam Leffler if (pk == NULL || pk_len == 0) {
239539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
239639beb93cSSam Leffler return -1;
239739beb93cSSam Leffler }
239839beb93cSSam Leffler
239939beb93cSSam Leffler wpabuf_free(wps->dh_pubkey_e);
240039beb93cSSam Leffler wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
240139beb93cSSam Leffler if (wps->dh_pubkey_e == NULL)
240239beb93cSSam Leffler return -1;
240339beb93cSSam Leffler
240439beb93cSSam Leffler return 0;
240539beb93cSSam Leffler }
240639beb93cSSam Leffler
240739beb93cSSam Leffler
wps_process_auth_type_flags(struct wps_data * wps,const u8 * auth)240839beb93cSSam Leffler static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
240939beb93cSSam Leffler {
241039beb93cSSam Leffler u16 auth_types;
241139beb93cSSam Leffler
241239beb93cSSam Leffler if (auth == NULL) {
241339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags "
241439beb93cSSam Leffler "received");
241539beb93cSSam Leffler return -1;
241639beb93cSSam Leffler }
241739beb93cSSam Leffler
241839beb93cSSam Leffler auth_types = WPA_GET_BE16(auth);
241939beb93cSSam Leffler
242039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
242139beb93cSSam Leffler auth_types);
2422780fb4a2SCy Schubert #ifdef WPS_WORKAROUNDS
2423780fb4a2SCy Schubert /*
2424780fb4a2SCy Schubert * Some deployed implementations seem to advertise incorrect information
2425780fb4a2SCy Schubert * in this attribute. A value of 0x1b (WPA2 + WPA + WPAPSK + OPEN, but
2426780fb4a2SCy Schubert * no WPA2PSK) has been reported to be used. Add WPA2PSK to the list to
2427780fb4a2SCy Schubert * avoid issues with building Credentials that do not use the strongest
2428780fb4a2SCy Schubert * actually supported authentication option (that device does support
2429780fb4a2SCy Schubert * WPA2PSK even when it does not claim it here).
2430780fb4a2SCy Schubert */
2431780fb4a2SCy Schubert if ((auth_types &
2432780fb4a2SCy Schubert (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) ==
2433780fb4a2SCy Schubert (WPS_AUTH_WPA2 | WPS_AUTH_WPAPSK)) {
2434780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
2435780fb4a2SCy Schubert "WPS: Workaround - assume Enrollee supports WPA2PSK based on claimed WPA2 support");
2436780fb4a2SCy Schubert auth_types |= WPS_AUTH_WPA2PSK;
2437780fb4a2SCy Schubert }
2438780fb4a2SCy Schubert #endif /* WPS_WORKAROUNDS */
243939beb93cSSam Leffler wps->auth_type = wps->wps->auth_types & auth_types;
244039beb93cSSam Leffler if (wps->auth_type == 0) {
244139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No match in supported "
244239beb93cSSam Leffler "authentication types (own 0x%x Enrollee 0x%x)",
244339beb93cSSam Leffler wps->wps->auth_types, auth_types);
24443157ba21SRui Paulo #ifdef WPS_WORKAROUNDS
24453157ba21SRui Paulo /*
24463157ba21SRui Paulo * Some deployed implementations seem to advertise incorrect
24473157ba21SRui Paulo * information in this attribute. For example, Linksys WRT350N
24483157ba21SRui Paulo * seems to have a byteorder bug that breaks this negotiation.
24493157ba21SRui Paulo * In order to interoperate with existing implementations,
24503157ba21SRui Paulo * assume that the Enrollee supports everything we do.
24513157ba21SRui Paulo */
24523157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
24533157ba21SRui Paulo "does not advertise supported authentication types "
24543157ba21SRui Paulo "correctly");
24553157ba21SRui Paulo wps->auth_type = wps->wps->auth_types;
24563157ba21SRui Paulo #else /* WPS_WORKAROUNDS */
245739beb93cSSam Leffler return -1;
24583157ba21SRui Paulo #endif /* WPS_WORKAROUNDS */
245939beb93cSSam Leffler }
246039beb93cSSam Leffler
246139beb93cSSam Leffler return 0;
246239beb93cSSam Leffler }
246339beb93cSSam Leffler
246439beb93cSSam Leffler
wps_process_encr_type_flags(struct wps_data * wps,const u8 * encr)246539beb93cSSam Leffler static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
246639beb93cSSam Leffler {
246739beb93cSSam Leffler u16 encr_types;
246839beb93cSSam Leffler
246939beb93cSSam Leffler if (encr == NULL) {
247039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags "
247139beb93cSSam Leffler "received");
247239beb93cSSam Leffler return -1;
247339beb93cSSam Leffler }
247439beb93cSSam Leffler
247539beb93cSSam Leffler encr_types = WPA_GET_BE16(encr);
247639beb93cSSam Leffler
247739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x",
247839beb93cSSam Leffler encr_types);
247939beb93cSSam Leffler wps->encr_type = wps->wps->encr_types & encr_types;
248039beb93cSSam Leffler if (wps->encr_type == 0) {
248139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No match in supported "
24823157ba21SRui Paulo "encryption types (own 0x%x Enrollee 0x%x)",
24833157ba21SRui Paulo wps->wps->encr_types, encr_types);
24843157ba21SRui Paulo #ifdef WPS_WORKAROUNDS
24853157ba21SRui Paulo /*
24863157ba21SRui Paulo * Some deployed implementations seem to advertise incorrect
24873157ba21SRui Paulo * information in this attribute. For example, Linksys WRT350N
24883157ba21SRui Paulo * seems to have a byteorder bug that breaks this negotiation.
24893157ba21SRui Paulo * In order to interoperate with existing implementations,
24903157ba21SRui Paulo * assume that the Enrollee supports everything we do.
24913157ba21SRui Paulo */
24923157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
24933157ba21SRui Paulo "does not advertise supported encryption types "
24943157ba21SRui Paulo "correctly");
24953157ba21SRui Paulo wps->encr_type = wps->wps->encr_types;
24963157ba21SRui Paulo #else /* WPS_WORKAROUNDS */
249739beb93cSSam Leffler return -1;
24983157ba21SRui Paulo #endif /* WPS_WORKAROUNDS */
249939beb93cSSam Leffler }
250039beb93cSSam Leffler
250139beb93cSSam Leffler return 0;
250239beb93cSSam Leffler }
250339beb93cSSam Leffler
250439beb93cSSam Leffler
wps_process_conn_type_flags(struct wps_data * wps,const u8 * conn)250539beb93cSSam Leffler static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)
250639beb93cSSam Leffler {
250739beb93cSSam Leffler if (conn == NULL) {
250839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags "
250939beb93cSSam Leffler "received");
251039beb93cSSam Leffler return -1;
251139beb93cSSam Leffler }
251239beb93cSSam Leffler
251339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x",
251439beb93cSSam Leffler *conn);
251539beb93cSSam Leffler
251639beb93cSSam Leffler return 0;
251739beb93cSSam Leffler }
251839beb93cSSam Leffler
251939beb93cSSam Leffler
wps_process_config_methods(struct wps_data * wps,const u8 * methods)252039beb93cSSam Leffler static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)
252139beb93cSSam Leffler {
252239beb93cSSam Leffler u16 m;
252339beb93cSSam Leffler
252439beb93cSSam Leffler if (methods == NULL) {
252539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Config Methods received");
252639beb93cSSam Leffler return -1;
252739beb93cSSam Leffler }
252839beb93cSSam Leffler
252939beb93cSSam Leffler m = WPA_GET_BE16(methods);
253039beb93cSSam Leffler
2531e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x"
2532e28a4053SRui Paulo "%s%s%s%s%s%s%s%s%s", m,
2533e28a4053SRui Paulo m & WPS_CONFIG_USBA ? " [USBA]" : "",
2534e28a4053SRui Paulo m & WPS_CONFIG_ETHERNET ? " [Ethernet]" : "",
2535e28a4053SRui Paulo m & WPS_CONFIG_LABEL ? " [Label]" : "",
2536e28a4053SRui Paulo m & WPS_CONFIG_DISPLAY ? " [Display]" : "",
2537e28a4053SRui Paulo m & WPS_CONFIG_EXT_NFC_TOKEN ? " [Ext NFC Token]" : "",
2538e28a4053SRui Paulo m & WPS_CONFIG_INT_NFC_TOKEN ? " [Int NFC Token]" : "",
2539e28a4053SRui Paulo m & WPS_CONFIG_NFC_INTERFACE ? " [NFC]" : "",
2540e28a4053SRui Paulo m & WPS_CONFIG_PUSHBUTTON ? " [PBC]" : "",
2541e28a4053SRui Paulo m & WPS_CONFIG_KEYPAD ? " [Keypad]" : "");
2542e28a4053SRui Paulo
2543e28a4053SRui Paulo if (!(m & WPS_CONFIG_DISPLAY) && !wps->use_psk_key) {
2544e28a4053SRui Paulo /*
2545e28a4053SRui Paulo * The Enrollee does not have a display so it is unlikely to be
2546e28a4053SRui Paulo * able to show the passphrase to a user and as such, could
2547e28a4053SRui Paulo * benefit from receiving PSK to reduce key derivation time.
2548e28a4053SRui Paulo */
2549e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Prefer PSK format key due to "
2550e28a4053SRui Paulo "Enrollee not supporting display");
2551e28a4053SRui Paulo wps->use_psk_key = 1;
2552e28a4053SRui Paulo }
255339beb93cSSam Leffler
255439beb93cSSam Leffler return 0;
255539beb93cSSam Leffler }
255639beb93cSSam Leffler
255739beb93cSSam Leffler
wps_process_wps_state(struct wps_data * wps,const u8 * state)255839beb93cSSam Leffler static int wps_process_wps_state(struct wps_data *wps, const u8 *state)
255939beb93cSSam Leffler {
256039beb93cSSam Leffler if (state == NULL) {
256139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State "
256239beb93cSSam Leffler "received");
256339beb93cSSam Leffler return -1;
256439beb93cSSam Leffler }
256539beb93cSSam Leffler
256639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d",
256739beb93cSSam Leffler *state);
256839beb93cSSam Leffler
256939beb93cSSam Leffler return 0;
257039beb93cSSam Leffler }
257139beb93cSSam Leffler
257239beb93cSSam Leffler
wps_process_assoc_state(struct wps_data * wps,const u8 * assoc)257339beb93cSSam Leffler static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
257439beb93cSSam Leffler {
257539beb93cSSam Leffler u16 a;
257639beb93cSSam Leffler
257739beb93cSSam Leffler if (assoc == NULL) {
257839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Association State received");
257939beb93cSSam Leffler return -1;
258039beb93cSSam Leffler }
258139beb93cSSam Leffler
258239beb93cSSam Leffler a = WPA_GET_BE16(assoc);
258339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a);
258439beb93cSSam Leffler
258539beb93cSSam Leffler return 0;
258639beb93cSSam Leffler }
258739beb93cSSam Leffler
258839beb93cSSam Leffler
wps_process_config_error(struct wps_data * wps,const u8 * err)258939beb93cSSam Leffler static int wps_process_config_error(struct wps_data *wps, const u8 *err)
259039beb93cSSam Leffler {
259139beb93cSSam Leffler u16 e;
259239beb93cSSam Leffler
259339beb93cSSam Leffler if (err == NULL) {
259439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received");
259539beb93cSSam Leffler return -1;
259639beb93cSSam Leffler }
259739beb93cSSam Leffler
259839beb93cSSam Leffler e = WPA_GET_BE16(err);
259939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e);
260039beb93cSSam Leffler
260139beb93cSSam Leffler return 0;
260239beb93cSSam Leffler }
260339beb93cSSam Leffler
260439beb93cSSam Leffler
wps_registrar_p2p_dev_addr_match(struct wps_data * wps)2605f05cddf9SRui Paulo static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps)
2606f05cddf9SRui Paulo {
2607f05cddf9SRui Paulo #ifdef CONFIG_P2P
2608f05cddf9SRui Paulo struct wps_registrar *reg = wps->wps->registrar;
2609f05cddf9SRui Paulo
2610f05cddf9SRui Paulo if (is_zero_ether_addr(reg->p2p_dev_addr))
2611f05cddf9SRui Paulo return 1; /* no filtering in use */
2612f05cddf9SRui Paulo
2613*a90b9d01SCy Schubert if (!ether_addr_equal(reg->p2p_dev_addr, wps->p2p_dev_addr)) {
2614f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address "
2615f05cddf9SRui Paulo "filtering for PBC: expected " MACSTR " was "
2616f05cddf9SRui Paulo MACSTR " - indicate PBC session overlap",
2617f05cddf9SRui Paulo MAC2STR(reg->p2p_dev_addr),
2618f05cddf9SRui Paulo MAC2STR(wps->p2p_dev_addr));
2619f05cddf9SRui Paulo return 0;
2620f05cddf9SRui Paulo }
2621f05cddf9SRui Paulo #endif /* CONFIG_P2P */
2622f05cddf9SRui Paulo return 1;
2623f05cddf9SRui Paulo }
2624f05cddf9SRui Paulo
2625f05cddf9SRui Paulo
wps_registrar_skip_overlap(struct wps_data * wps)2626f05cddf9SRui Paulo static int wps_registrar_skip_overlap(struct wps_data *wps)
2627f05cddf9SRui Paulo {
2628f05cddf9SRui Paulo #ifdef CONFIG_P2P
2629f05cddf9SRui Paulo struct wps_registrar *reg = wps->wps->registrar;
2630f05cddf9SRui Paulo
2631f05cddf9SRui Paulo if (is_zero_ether_addr(reg->p2p_dev_addr))
2632f05cddf9SRui Paulo return 0; /* no specific Enrollee selected */
2633f05cddf9SRui Paulo
2634*a90b9d01SCy Schubert if (ether_addr_equal(reg->p2p_dev_addr, wps->p2p_dev_addr)) {
2635f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected "
2636f05cddf9SRui Paulo "Enrollee match");
2637f05cddf9SRui Paulo return 1;
2638f05cddf9SRui Paulo }
2639f05cddf9SRui Paulo #endif /* CONFIG_P2P */
2640f05cddf9SRui Paulo return 0;
2641f05cddf9SRui Paulo }
2642f05cddf9SRui Paulo
2643f05cddf9SRui Paulo
wps_process_m1(struct wps_data * wps,struct wps_parse_attr * attr)264439beb93cSSam Leffler static enum wps_process_res wps_process_m1(struct wps_data *wps,
264539beb93cSSam Leffler struct wps_parse_attr *attr)
264639beb93cSSam Leffler {
264739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M1");
264839beb93cSSam Leffler
264939beb93cSSam Leffler if (wps->state != RECV_M1) {
265039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
265139beb93cSSam Leffler "receiving M1", wps->state);
265239beb93cSSam Leffler return WPS_FAILURE;
265339beb93cSSam Leffler }
265439beb93cSSam Leffler
265539beb93cSSam Leffler if (wps_process_uuid_e(wps, attr->uuid_e) ||
265639beb93cSSam Leffler wps_process_mac_addr(wps, attr->mac_addr) ||
265739beb93cSSam Leffler wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
265839beb93cSSam Leffler wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
265939beb93cSSam Leffler wps_process_auth_type_flags(wps, attr->auth_type_flags) ||
266039beb93cSSam Leffler wps_process_encr_type_flags(wps, attr->encr_type_flags) ||
266139beb93cSSam Leffler wps_process_conn_type_flags(wps, attr->conn_type_flags) ||
266239beb93cSSam Leffler wps_process_config_methods(wps, attr->config_methods) ||
266339beb93cSSam Leffler wps_process_wps_state(wps, attr->wps_state) ||
266439beb93cSSam Leffler wps_process_device_attrs(&wps->peer_dev, attr) ||
266539beb93cSSam Leffler wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) ||
266639beb93cSSam Leffler wps_process_assoc_state(wps, attr->assoc_state) ||
266739beb93cSSam Leffler wps_process_dev_password_id(wps, attr->dev_password_id) ||
266839beb93cSSam Leffler wps_process_config_error(wps, attr->config_error) ||
266939beb93cSSam Leffler wps_process_os_version(&wps->peer_dev, attr->os_version))
267039beb93cSSam Leffler return WPS_FAILURE;
267139beb93cSSam Leffler
2672e28a4053SRui Paulo if (wps->dev_pw_id < 0x10 &&
2673e28a4053SRui Paulo wps->dev_pw_id != DEV_PW_DEFAULT &&
26745b9c547cSRui Paulo wps->dev_pw_id != DEV_PW_P2PS_DEFAULT &&
267539beb93cSSam Leffler wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
267639beb93cSSam Leffler wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
267739beb93cSSam Leffler wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
26785b9c547cSRui Paulo #ifdef CONFIG_WPS_NFC
26795b9c547cSRui Paulo wps->dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
26805b9c547cSRui Paulo #endif /* CONFIG_WPS_NFC */
268139beb93cSSam Leffler (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
268239beb93cSSam Leffler !wps->wps->registrar->pbc)) {
268339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
268439beb93cSSam Leffler wps->dev_pw_id);
268539beb93cSSam Leffler wps->state = SEND_M2D;
268639beb93cSSam Leffler return WPS_CONTINUE;
268739beb93cSSam Leffler }
268839beb93cSSam Leffler
2689f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
26905b9c547cSRui Paulo if (wps->dev_pw_id >= 0x10 ||
26915b9c547cSRui Paulo wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
2692f05cddf9SRui Paulo struct wps_nfc_pw_token *token;
2693f05cddf9SRui Paulo const u8 *addr[1];
2694f05cddf9SRui Paulo u8 hash[WPS_HASH_LEN];
2695f05cddf9SRui Paulo
26965b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Searching for NFC token match for id=%d (ctx %p registrar %p)",
26975b9c547cSRui Paulo wps->dev_pw_id, wps->wps, wps->wps->registrar);
2698f05cddf9SRui Paulo token = wps_get_nfc_pw_token(
2699f05cddf9SRui Paulo &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id);
27005b9c547cSRui Paulo if (token && token->peer_pk_hash_known) {
2701325151a3SRui Paulo size_t len;
2702325151a3SRui Paulo
2703f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
2704f05cddf9SRui Paulo "Password Token");
2705f05cddf9SRui Paulo dl_list_del(&token->list);
2706f05cddf9SRui Paulo wps->nfc_pw_token = token;
2707f05cddf9SRui Paulo
2708f05cddf9SRui Paulo addr[0] = attr->public_key;
2709325151a3SRui Paulo len = attr->public_key_len;
2710325151a3SRui Paulo sha256_vector(1, addr, &len, hash);
27115b9c547cSRui Paulo if (os_memcmp_const(hash,
27125b9c547cSRui Paulo wps->nfc_pw_token->pubkey_hash,
2713f05cddf9SRui Paulo WPS_OOB_PUBKEY_HASH_LEN) != 0) {
2714f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "WPS: Public Key hash "
2715f05cddf9SRui Paulo "mismatch");
27165b9c547cSRui Paulo wps->state = SEND_M2D;
27175b9c547cSRui Paulo wps->config_error =
27185b9c547cSRui Paulo WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
27195b9c547cSRui Paulo return WPS_CONTINUE;
2720e28a4053SRui Paulo }
27215b9c547cSRui Paulo } else if (token) {
27225b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Found matching NFC "
27235b9c547cSRui Paulo "Password Token (no peer PK hash)");
27245b9c547cSRui Paulo wps->nfc_pw_token = token;
27255b9c547cSRui Paulo } else if (wps->dev_pw_id >= 0x10 &&
27265b9c547cSRui Paulo wps->wps->ap_nfc_dev_pw_id == wps->dev_pw_id &&
27275b9c547cSRui Paulo wps->wps->ap_nfc_dev_pw) {
27285b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Found match with own NFC Password Token");
2729f05cddf9SRui Paulo }
2730f05cddf9SRui Paulo }
2731f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
2732e28a4053SRui Paulo
273339beb93cSSam Leffler if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
2734f05cddf9SRui Paulo if ((wps->wps->registrar->force_pbc_overlap ||
27353157ba21SRui Paulo wps_registrar_pbc_overlap(wps->wps->registrar,
2736f05cddf9SRui Paulo wps->mac_addr_e, wps->uuid_e) ||
2737f05cddf9SRui Paulo !wps_registrar_p2p_dev_addr_match(wps)) &&
2738f05cddf9SRui Paulo !wps_registrar_skip_overlap(wps)) {
273939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
274039beb93cSSam Leffler "negotiation");
274139beb93cSSam Leffler wps->state = SEND_M2D;
27423157ba21SRui Paulo wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
27433157ba21SRui Paulo wps_pbc_overlap_event(wps->wps);
2744f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M1,
2745f05cddf9SRui Paulo WPS_CFG_MULTIPLE_PBC_DETECTED,
27465b9c547cSRui Paulo WPS_EI_NO_ERROR, wps->mac_addr_e);
27473157ba21SRui Paulo wps->wps->registrar->force_pbc_overlap = 1;
274839beb93cSSam Leffler return WPS_CONTINUE;
274939beb93cSSam Leffler }
275039beb93cSSam Leffler wps_registrar_add_pbc_session(wps->wps->registrar,
275139beb93cSSam Leffler wps->mac_addr_e, wps->uuid_e);
275239beb93cSSam Leffler wps->pbc = 1;
275339beb93cSSam Leffler }
275439beb93cSSam Leffler
2755e28a4053SRui Paulo #ifdef WPS_WORKAROUNDS
2756e28a4053SRui Paulo /*
2757e28a4053SRui Paulo * It looks like Mac OS X 10.6.3 and 10.6.4 do not like Network Key in
2758e28a4053SRui Paulo * passphrase format. To avoid interop issues, force PSK format to be
2759e28a4053SRui Paulo * used.
2760e28a4053SRui Paulo */
2761e28a4053SRui Paulo if (!wps->use_psk_key &&
2762e28a4053SRui Paulo wps->peer_dev.manufacturer &&
2763e28a4053SRui Paulo os_strncmp(wps->peer_dev.manufacturer, "Apple ", 6) == 0 &&
2764e28a4053SRui Paulo wps->peer_dev.model_name &&
2765e28a4053SRui Paulo os_strcmp(wps->peer_dev.model_name, "AirPort") == 0) {
2766e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Workaround - Force Network Key in "
2767e28a4053SRui Paulo "PSK format");
2768e28a4053SRui Paulo wps->use_psk_key = 1;
2769e28a4053SRui Paulo }
2770e28a4053SRui Paulo #endif /* WPS_WORKAROUNDS */
27714bc52338SCy Schubert wps_process_vendor_ext_m1(&wps->peer_dev, attr->multi_ap_ext);
2772e28a4053SRui Paulo
277339beb93cSSam Leffler wps->state = SEND_M2;
277439beb93cSSam Leffler return WPS_CONTINUE;
277539beb93cSSam Leffler }
277639beb93cSSam Leffler
277739beb93cSSam Leffler
wps_process_m3(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)277839beb93cSSam Leffler static enum wps_process_res wps_process_m3(struct wps_data *wps,
277939beb93cSSam Leffler const struct wpabuf *msg,
278039beb93cSSam Leffler struct wps_parse_attr *attr)
278139beb93cSSam Leffler {
278239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M3");
278339beb93cSSam Leffler
278439beb93cSSam Leffler if (wps->state != RECV_M3) {
278539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
278639beb93cSSam Leffler "receiving M3", wps->state);
278739beb93cSSam Leffler wps->state = SEND_WSC_NACK;
278839beb93cSSam Leffler return WPS_CONTINUE;
278939beb93cSSam Leffler }
279039beb93cSSam Leffler
2791f05cddf9SRui Paulo if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
2792f05cddf9SRui Paulo !wps_registrar_skip_overlap(wps)) {
27933157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
27943157ba21SRui Paulo "session overlap");
27953157ba21SRui Paulo wps->state = SEND_WSC_NACK;
27963157ba21SRui Paulo wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
27973157ba21SRui Paulo return WPS_CONTINUE;
27983157ba21SRui Paulo }
27993157ba21SRui Paulo
280039beb93cSSam Leffler if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
280139beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg) ||
280239beb93cSSam Leffler wps_process_e_hash1(wps, attr->e_hash1) ||
280339beb93cSSam Leffler wps_process_e_hash2(wps, attr->e_hash2)) {
280439beb93cSSam Leffler wps->state = SEND_WSC_NACK;
280539beb93cSSam Leffler return WPS_CONTINUE;
280639beb93cSSam Leffler }
280739beb93cSSam Leffler
280839beb93cSSam Leffler wps->state = SEND_M4;
280939beb93cSSam Leffler return WPS_CONTINUE;
281039beb93cSSam Leffler }
281139beb93cSSam Leffler
281239beb93cSSam Leffler
wps_process_m5(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)281339beb93cSSam Leffler static enum wps_process_res wps_process_m5(struct wps_data *wps,
281439beb93cSSam Leffler const struct wpabuf *msg,
281539beb93cSSam Leffler struct wps_parse_attr *attr)
281639beb93cSSam Leffler {
281739beb93cSSam Leffler struct wpabuf *decrypted;
281839beb93cSSam Leffler struct wps_parse_attr eattr;
281939beb93cSSam Leffler
282039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M5");
282139beb93cSSam Leffler
282239beb93cSSam Leffler if (wps->state != RECV_M5) {
282339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
282439beb93cSSam Leffler "receiving M5", wps->state);
282539beb93cSSam Leffler wps->state = SEND_WSC_NACK;
282639beb93cSSam Leffler return WPS_CONTINUE;
282739beb93cSSam Leffler }
282839beb93cSSam Leffler
2829f05cddf9SRui Paulo if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
2830f05cddf9SRui Paulo !wps_registrar_skip_overlap(wps)) {
28313157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
28323157ba21SRui Paulo "session overlap");
28333157ba21SRui Paulo wps->state = SEND_WSC_NACK;
28343157ba21SRui Paulo wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
28353157ba21SRui Paulo return WPS_CONTINUE;
28363157ba21SRui Paulo }
28373157ba21SRui Paulo
283839beb93cSSam Leffler if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
283939beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) {
284039beb93cSSam Leffler wps->state = SEND_WSC_NACK;
284139beb93cSSam Leffler return WPS_CONTINUE;
284239beb93cSSam Leffler }
284339beb93cSSam Leffler
284439beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
284539beb93cSSam Leffler attr->encr_settings_len);
284639beb93cSSam Leffler if (decrypted == NULL) {
284739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
284839beb93cSSam Leffler "Settings attribute");
284939beb93cSSam Leffler wps->state = SEND_WSC_NACK;
285039beb93cSSam Leffler return WPS_CONTINUE;
285139beb93cSSam Leffler }
285239beb93cSSam Leffler
2853f05cddf9SRui Paulo if (wps_validate_m5_encr(decrypted, attr->version2 != NULL) < 0) {
2854780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
2855f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
2856f05cddf9SRui Paulo return WPS_CONTINUE;
2857f05cddf9SRui Paulo }
2858f05cddf9SRui Paulo
285939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
286039beb93cSSam Leffler "attribute");
286139beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 ||
286239beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
286339beb93cSSam Leffler wps_process_e_snonce1(wps, eattr.e_snonce1)) {
2864780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
286539beb93cSSam Leffler wps->state = SEND_WSC_NACK;
286639beb93cSSam Leffler return WPS_CONTINUE;
286739beb93cSSam Leffler }
2868780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
286939beb93cSSam Leffler
287039beb93cSSam Leffler wps->state = SEND_M6;
287139beb93cSSam Leffler return WPS_CONTINUE;
287239beb93cSSam Leffler }
287339beb93cSSam Leffler
287439beb93cSSam Leffler
wps_sta_cred_cb(struct wps_data * wps)28753157ba21SRui Paulo static void wps_sta_cred_cb(struct wps_data *wps)
28763157ba21SRui Paulo {
28773157ba21SRui Paulo /*
28783157ba21SRui Paulo * Update credential to only include a single authentication and
28793157ba21SRui Paulo * encryption type in case the AP configuration includes more than one
28803157ba21SRui Paulo * option.
28813157ba21SRui Paulo */
28823157ba21SRui Paulo if (wps->cred.auth_type & WPS_AUTH_WPA2PSK)
28833157ba21SRui Paulo wps->cred.auth_type = WPS_AUTH_WPA2PSK;
28843157ba21SRui Paulo else if (wps->cred.auth_type & WPS_AUTH_WPAPSK)
28853157ba21SRui Paulo wps->cred.auth_type = WPS_AUTH_WPAPSK;
28863157ba21SRui Paulo if (wps->cred.encr_type & WPS_ENCR_AES)
28873157ba21SRui Paulo wps->cred.encr_type = WPS_ENCR_AES;
28883157ba21SRui Paulo else if (wps->cred.encr_type & WPS_ENCR_TKIP)
28893157ba21SRui Paulo wps->cred.encr_type = WPS_ENCR_TKIP;
28903157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the "
28913157ba21SRui Paulo "AP configuration");
28923157ba21SRui Paulo if (wps->wps->cred_cb)
28933157ba21SRui Paulo wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
28943157ba21SRui Paulo }
28953157ba21SRui Paulo
28963157ba21SRui Paulo
wps_cred_update(struct wps_credential * dst,struct wps_credential * src)2897e28a4053SRui Paulo static void wps_cred_update(struct wps_credential *dst,
2898e28a4053SRui Paulo struct wps_credential *src)
2899e28a4053SRui Paulo {
2900e28a4053SRui Paulo os_memcpy(dst->ssid, src->ssid, sizeof(dst->ssid));
2901e28a4053SRui Paulo dst->ssid_len = src->ssid_len;
2902e28a4053SRui Paulo dst->auth_type = src->auth_type;
2903e28a4053SRui Paulo dst->encr_type = src->encr_type;
2904e28a4053SRui Paulo dst->key_idx = src->key_idx;
2905e28a4053SRui Paulo os_memcpy(dst->key, src->key, sizeof(dst->key));
2906e28a4053SRui Paulo dst->key_len = src->key_len;
2907e28a4053SRui Paulo }
2908e28a4053SRui Paulo
2909e28a4053SRui Paulo
wps_process_ap_settings_r(struct wps_data * wps,struct wps_parse_attr * attr)291039beb93cSSam Leffler static int wps_process_ap_settings_r(struct wps_data *wps,
291139beb93cSSam Leffler struct wps_parse_attr *attr)
291239beb93cSSam Leffler {
2913f05cddf9SRui Paulo struct wpabuf *msg;
2914f05cddf9SRui Paulo
2915e28a4053SRui Paulo if (wps->wps->ap || wps->er)
291639beb93cSSam Leffler return 0;
291739beb93cSSam Leffler
291839beb93cSSam Leffler /* AP Settings Attributes in M7 when Enrollee is an AP */
291939beb93cSSam Leffler if (wps_process_ap_settings(attr, &wps->cred) < 0)
292039beb93cSSam Leffler return -1;
292139beb93cSSam Leffler
292239beb93cSSam Leffler wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
292339beb93cSSam Leffler
2924e28a4053SRui Paulo if (wps->new_ap_settings) {
2925e28a4053SRui Paulo wpa_printf(MSG_INFO, "WPS: Update AP configuration based on "
2926e28a4053SRui Paulo "new settings");
2927e28a4053SRui Paulo wps_cred_update(&wps->cred, wps->new_ap_settings);
292839beb93cSSam Leffler return 0;
2929e28a4053SRui Paulo } else {
29303157ba21SRui Paulo /*
2931e28a4053SRui Paulo * Use the AP PIN only to receive the current AP settings, not
2932e28a4053SRui Paulo * to reconfigure the AP.
29333157ba21SRui Paulo */
2934f05cddf9SRui Paulo
2935f05cddf9SRui Paulo /*
2936f05cddf9SRui Paulo * Clear selected registrar here since we do not get to
2937f05cddf9SRui Paulo * WSC_Done in this protocol run.
2938f05cddf9SRui Paulo */
2939f05cddf9SRui Paulo wps_registrar_pin_completed(wps->wps->registrar);
2940f05cddf9SRui Paulo
2941f05cddf9SRui Paulo msg = wps_build_ap_cred(wps);
2942f05cddf9SRui Paulo if (msg == NULL)
2943f05cddf9SRui Paulo return -1;
2944f05cddf9SRui Paulo wps->cred.cred_attr = wpabuf_head(msg);
2945f05cddf9SRui Paulo wps->cred.cred_attr_len = wpabuf_len(msg);
2946f05cddf9SRui Paulo
2947e28a4053SRui Paulo if (wps->ap_settings_cb) {
2948e28a4053SRui Paulo wps->ap_settings_cb(wps->ap_settings_cb_ctx,
2949e28a4053SRui Paulo &wps->cred);
2950f05cddf9SRui Paulo wpabuf_free(msg);
2951e28a4053SRui Paulo return 1;
2952e28a4053SRui Paulo }
29533157ba21SRui Paulo wps_sta_cred_cb(wps);
2954f05cddf9SRui Paulo
2955f05cddf9SRui Paulo wps->cred.cred_attr = NULL;
2956f05cddf9SRui Paulo wps->cred.cred_attr_len = 0;
2957f05cddf9SRui Paulo wpabuf_free(msg);
2958f05cddf9SRui Paulo
29593157ba21SRui Paulo return 1;
2960e28a4053SRui Paulo }
296139beb93cSSam Leffler }
296239beb93cSSam Leffler
296339beb93cSSam Leffler
wps_process_m7(struct wps_data * wps,const struct wpabuf * msg,struct wps_parse_attr * attr)296439beb93cSSam Leffler static enum wps_process_res wps_process_m7(struct wps_data *wps,
296539beb93cSSam Leffler const struct wpabuf *msg,
296639beb93cSSam Leffler struct wps_parse_attr *attr)
296739beb93cSSam Leffler {
296839beb93cSSam Leffler struct wpabuf *decrypted;
296939beb93cSSam Leffler struct wps_parse_attr eattr;
297039beb93cSSam Leffler
297139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received M7");
297239beb93cSSam Leffler
297339beb93cSSam Leffler if (wps->state != RECV_M7) {
297439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
297539beb93cSSam Leffler "receiving M7", wps->state);
297639beb93cSSam Leffler wps->state = SEND_WSC_NACK;
297739beb93cSSam Leffler return WPS_CONTINUE;
297839beb93cSSam Leffler }
297939beb93cSSam Leffler
2980f05cddf9SRui Paulo if (wps->pbc && wps->wps->registrar->force_pbc_overlap &&
2981f05cddf9SRui Paulo !wps_registrar_skip_overlap(wps)) {
29823157ba21SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
29833157ba21SRui Paulo "session overlap");
29843157ba21SRui Paulo wps->state = SEND_WSC_NACK;
29853157ba21SRui Paulo wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
29863157ba21SRui Paulo return WPS_CONTINUE;
29873157ba21SRui Paulo }
29883157ba21SRui Paulo
298939beb93cSSam Leffler if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
299039beb93cSSam Leffler wps_process_authenticator(wps, attr->authenticator, msg)) {
299139beb93cSSam Leffler wps->state = SEND_WSC_NACK;
299239beb93cSSam Leffler return WPS_CONTINUE;
299339beb93cSSam Leffler }
299439beb93cSSam Leffler
299539beb93cSSam Leffler decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
299639beb93cSSam Leffler attr->encr_settings_len);
299739beb93cSSam Leffler if (decrypted == NULL) {
2998e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Failed to decrypt Encrypted "
299939beb93cSSam Leffler "Settings attribute");
300039beb93cSSam Leffler wps->state = SEND_WSC_NACK;
300139beb93cSSam Leffler return WPS_CONTINUE;
300239beb93cSSam Leffler }
300339beb93cSSam Leffler
3004f05cddf9SRui Paulo if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er,
3005f05cddf9SRui Paulo attr->version2 != NULL) < 0) {
3006780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
3007f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
3008f05cddf9SRui Paulo return WPS_CONTINUE;
3009f05cddf9SRui Paulo }
3010f05cddf9SRui Paulo
301139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
301239beb93cSSam Leffler "attribute");
301339beb93cSSam Leffler if (wps_parse_msg(decrypted, &eattr) < 0 ||
301439beb93cSSam Leffler wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
301539beb93cSSam Leffler wps_process_e_snonce2(wps, eattr.e_snonce2) ||
301639beb93cSSam Leffler wps_process_ap_settings_r(wps, &eattr)) {
3017780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
301839beb93cSSam Leffler wps->state = SEND_WSC_NACK;
301939beb93cSSam Leffler return WPS_CONTINUE;
302039beb93cSSam Leffler }
302139beb93cSSam Leffler
3022780fb4a2SCy Schubert wpabuf_clear_free(decrypted);
302339beb93cSSam Leffler
302439beb93cSSam Leffler wps->state = SEND_M8;
302539beb93cSSam Leffler return WPS_CONTINUE;
302639beb93cSSam Leffler }
302739beb93cSSam Leffler
302839beb93cSSam Leffler
wps_process_wsc_msg(struct wps_data * wps,const struct wpabuf * msg)302939beb93cSSam Leffler static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
303039beb93cSSam Leffler const struct wpabuf *msg)
303139beb93cSSam Leffler {
303239beb93cSSam Leffler struct wps_parse_attr attr;
303339beb93cSSam Leffler enum wps_process_res ret = WPS_CONTINUE;
303439beb93cSSam Leffler
303539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
303639beb93cSSam Leffler
303739beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
303839beb93cSSam Leffler return WPS_FAILURE;
303939beb93cSSam Leffler
304039beb93cSSam Leffler if (attr.msg_type == NULL) {
304139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
3042f05cddf9SRui Paulo wps->state = SEND_WSC_NACK;
3043f05cddf9SRui Paulo return WPS_CONTINUE;
304439beb93cSSam Leffler }
304539beb93cSSam Leffler
304639beb93cSSam Leffler if (*attr.msg_type != WPS_M1 &&
304739beb93cSSam Leffler (attr.registrar_nonce == NULL ||
304839beb93cSSam Leffler os_memcmp(wps->nonce_r, attr.registrar_nonce,
3049f05cddf9SRui Paulo WPS_NONCE_LEN) != 0)) {
305039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
305139beb93cSSam Leffler return WPS_FAILURE;
305239beb93cSSam Leffler }
305339beb93cSSam Leffler
305439beb93cSSam Leffler switch (*attr.msg_type) {
305539beb93cSSam Leffler case WPS_M1:
3056f05cddf9SRui Paulo if (wps_validate_m1(msg) < 0)
3057f05cddf9SRui Paulo return WPS_FAILURE;
305839beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
305939beb93cSSam Leffler if (wps->wps->wps_upnp && attr.mac_addr) {
306039beb93cSSam Leffler /* Remove old pending messages when starting new run */
306139beb93cSSam Leffler wps_free_pending_msgs(wps->wps->upnp_msgs);
306239beb93cSSam Leffler wps->wps->upnp_msgs = NULL;
306339beb93cSSam Leffler
306439beb93cSSam Leffler upnp_wps_device_send_wlan_event(
306539beb93cSSam Leffler wps->wps->wps_upnp, attr.mac_addr,
306639beb93cSSam Leffler UPNP_WPS_WLANEVENT_TYPE_EAP, msg);
306739beb93cSSam Leffler }
306839beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
306939beb93cSSam Leffler ret = wps_process_m1(wps, &attr);
307039beb93cSSam Leffler break;
307139beb93cSSam Leffler case WPS_M3:
3072f05cddf9SRui Paulo if (wps_validate_m3(msg) < 0)
3073f05cddf9SRui Paulo return WPS_FAILURE;
307439beb93cSSam Leffler ret = wps_process_m3(wps, msg, &attr);
307539beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
3076f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M3, wps->config_error,
30775b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
307839beb93cSSam Leffler break;
307939beb93cSSam Leffler case WPS_M5:
3080f05cddf9SRui Paulo if (wps_validate_m5(msg) < 0)
3081f05cddf9SRui Paulo return WPS_FAILURE;
308239beb93cSSam Leffler ret = wps_process_m5(wps, msg, &attr);
308339beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
3084f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M5, wps->config_error,
30855b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
308639beb93cSSam Leffler break;
308739beb93cSSam Leffler case WPS_M7:
3088f05cddf9SRui Paulo if (wps_validate_m7(msg) < 0)
3089f05cddf9SRui Paulo return WPS_FAILURE;
309039beb93cSSam Leffler ret = wps_process_m7(wps, msg, &attr);
309139beb93cSSam Leffler if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
3092f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M7, wps->config_error,
30935b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
309439beb93cSSam Leffler break;
309539beb93cSSam Leffler default:
309639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
309739beb93cSSam Leffler *attr.msg_type);
309839beb93cSSam Leffler return WPS_FAILURE;
309939beb93cSSam Leffler }
310039beb93cSSam Leffler
310139beb93cSSam Leffler if (ret == WPS_CONTINUE) {
310239beb93cSSam Leffler /* Save a copy of the last message for Authenticator derivation
310339beb93cSSam Leffler */
310439beb93cSSam Leffler wpabuf_free(wps->last_msg);
310539beb93cSSam Leffler wps->last_msg = wpabuf_dup(msg);
310639beb93cSSam Leffler }
310739beb93cSSam Leffler
310839beb93cSSam Leffler return ret;
310939beb93cSSam Leffler }
311039beb93cSSam Leffler
311139beb93cSSam Leffler
wps_process_wsc_ack(struct wps_data * wps,const struct wpabuf * msg)311239beb93cSSam Leffler static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
311339beb93cSSam Leffler const struct wpabuf *msg)
311439beb93cSSam Leffler {
311539beb93cSSam Leffler struct wps_parse_attr attr;
311639beb93cSSam Leffler
311739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
311839beb93cSSam Leffler
311939beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
312039beb93cSSam Leffler return WPS_FAILURE;
312139beb93cSSam Leffler
312239beb93cSSam Leffler if (attr.msg_type == NULL) {
312339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
312439beb93cSSam Leffler return WPS_FAILURE;
312539beb93cSSam Leffler }
312639beb93cSSam Leffler
312739beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_ACK) {
312839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
312939beb93cSSam Leffler *attr.msg_type);
313039beb93cSSam Leffler return WPS_FAILURE;
313139beb93cSSam Leffler }
313239beb93cSSam Leffler
313339beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
313439beb93cSSam Leffler if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
313539beb93cSSam Leffler upnp_wps_subscribers(wps->wps->wps_upnp)) {
313639beb93cSSam Leffler if (wps->wps->upnp_msgs)
313739beb93cSSam Leffler return WPS_CONTINUE;
313839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
313939beb93cSSam Leffler "external Registrar");
314039beb93cSSam Leffler return WPS_PENDING;
314139beb93cSSam Leffler }
314239beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
314339beb93cSSam Leffler
314439beb93cSSam Leffler if (attr.registrar_nonce == NULL ||
3145f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
314639beb93cSSam Leffler {
314739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
314839beb93cSSam Leffler return WPS_FAILURE;
314939beb93cSSam Leffler }
315039beb93cSSam Leffler
315139beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
3152f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
315339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
315439beb93cSSam Leffler return WPS_FAILURE;
315539beb93cSSam Leffler }
315639beb93cSSam Leffler
315739beb93cSSam Leffler if (wps->state == RECV_M2D_ACK) {
315839beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
315939beb93cSSam Leffler if (wps->wps->wps_upnp &&
316039beb93cSSam Leffler upnp_wps_subscribers(wps->wps->wps_upnp)) {
316139beb93cSSam Leffler if (wps->wps->upnp_msgs)
316239beb93cSSam Leffler return WPS_CONTINUE;
316339beb93cSSam Leffler if (wps->ext_reg == 0)
316439beb93cSSam Leffler wps->ext_reg = 1;
316539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
316639beb93cSSam Leffler "external Registrar");
316739beb93cSSam Leffler return WPS_PENDING;
316839beb93cSSam Leffler }
316939beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
317039beb93cSSam Leffler
317139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
317239beb93cSSam Leffler "terminate negotiation");
317339beb93cSSam Leffler }
317439beb93cSSam Leffler
317539beb93cSSam Leffler return WPS_FAILURE;
317639beb93cSSam Leffler }
317739beb93cSSam Leffler
317839beb93cSSam Leffler
wps_process_wsc_nack(struct wps_data * wps,const struct wpabuf * msg)317939beb93cSSam Leffler static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
318039beb93cSSam Leffler const struct wpabuf *msg)
318139beb93cSSam Leffler {
318239beb93cSSam Leffler struct wps_parse_attr attr;
318339beb93cSSam Leffler int old_state;
3184f05cddf9SRui Paulo u16 config_error;
318539beb93cSSam Leffler
318639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
318739beb93cSSam Leffler
318839beb93cSSam Leffler old_state = wps->state;
318939beb93cSSam Leffler wps->state = SEND_WSC_NACK;
319039beb93cSSam Leffler
319139beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
319239beb93cSSam Leffler return WPS_FAILURE;
319339beb93cSSam Leffler
319439beb93cSSam Leffler if (attr.msg_type == NULL) {
319539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
319639beb93cSSam Leffler return WPS_FAILURE;
319739beb93cSSam Leffler }
319839beb93cSSam Leffler
319939beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_NACK) {
320039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
320139beb93cSSam Leffler *attr.msg_type);
320239beb93cSSam Leffler return WPS_FAILURE;
320339beb93cSSam Leffler }
320439beb93cSSam Leffler
320539beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
320639beb93cSSam Leffler if (wps->wps->wps_upnp && wps->ext_reg) {
320739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
320839beb93cSSam Leffler "Registrar terminated by the Enrollee");
320939beb93cSSam Leffler return WPS_FAILURE;
321039beb93cSSam Leffler }
321139beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
321239beb93cSSam Leffler
321339beb93cSSam Leffler if (attr.registrar_nonce == NULL ||
3214f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
321539beb93cSSam Leffler {
321639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
321739beb93cSSam Leffler return WPS_FAILURE;
321839beb93cSSam Leffler }
321939beb93cSSam Leffler
322039beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
3221f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
322239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
322339beb93cSSam Leffler return WPS_FAILURE;
322439beb93cSSam Leffler }
322539beb93cSSam Leffler
322639beb93cSSam Leffler if (attr.config_error == NULL) {
322739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
322839beb93cSSam Leffler "in WSC_NACK");
322939beb93cSSam Leffler return WPS_FAILURE;
323039beb93cSSam Leffler }
323139beb93cSSam Leffler
3232f05cddf9SRui Paulo config_error = WPA_GET_BE16(attr.config_error);
323339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
3234f05cddf9SRui Paulo "Configuration Error %d", config_error);
323539beb93cSSam Leffler
323639beb93cSSam Leffler switch (old_state) {
323739beb93cSSam Leffler case RECV_M3:
3238f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M2, config_error,
32395b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
324039beb93cSSam Leffler break;
324139beb93cSSam Leffler case RECV_M5:
3242f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M4, config_error,
32435b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
324439beb93cSSam Leffler break;
324539beb93cSSam Leffler case RECV_M7:
3246f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M6, config_error,
32475b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
324839beb93cSSam Leffler break;
324939beb93cSSam Leffler case RECV_DONE:
3250f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_M8, config_error,
32515b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
325239beb93cSSam Leffler break;
325339beb93cSSam Leffler default:
325439beb93cSSam Leffler break;
325539beb93cSSam Leffler }
325639beb93cSSam Leffler
325739beb93cSSam Leffler return WPS_FAILURE;
325839beb93cSSam Leffler }
325939beb93cSSam Leffler
326039beb93cSSam Leffler
wps_process_wsc_done(struct wps_data * wps,const struct wpabuf * msg)326139beb93cSSam Leffler static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
326239beb93cSSam Leffler const struct wpabuf *msg)
326339beb93cSSam Leffler {
326439beb93cSSam Leffler struct wps_parse_attr attr;
326539beb93cSSam Leffler
326639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
326739beb93cSSam Leffler
326839beb93cSSam Leffler if (wps->state != RECV_DONE &&
326939beb93cSSam Leffler (!wps->wps->wps_upnp || !wps->ext_reg)) {
327039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
327139beb93cSSam Leffler "receiving WSC_Done", wps->state);
327239beb93cSSam Leffler return WPS_FAILURE;
327339beb93cSSam Leffler }
327439beb93cSSam Leffler
327539beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0)
327639beb93cSSam Leffler return WPS_FAILURE;
327739beb93cSSam Leffler
327839beb93cSSam Leffler if (attr.msg_type == NULL) {
327939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
328039beb93cSSam Leffler return WPS_FAILURE;
328139beb93cSSam Leffler }
328239beb93cSSam Leffler
328339beb93cSSam Leffler if (*attr.msg_type != WPS_WSC_DONE) {
328439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
328539beb93cSSam Leffler *attr.msg_type);
328639beb93cSSam Leffler return WPS_FAILURE;
328739beb93cSSam Leffler }
328839beb93cSSam Leffler
328939beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
329039beb93cSSam Leffler if (wps->wps->wps_upnp && wps->ext_reg) {
329139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Negotiation using external "
329239beb93cSSam Leffler "Registrar completed successfully");
3293e28a4053SRui Paulo wps_device_store(wps->wps->registrar, &wps->peer_dev,
3294e28a4053SRui Paulo wps->uuid_e);
329539beb93cSSam Leffler return WPS_DONE;
329639beb93cSSam Leffler }
329739beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
329839beb93cSSam Leffler
329939beb93cSSam Leffler if (attr.registrar_nonce == NULL ||
3300f05cddf9SRui Paulo os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
330139beb93cSSam Leffler {
330239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
330339beb93cSSam Leffler return WPS_FAILURE;
330439beb93cSSam Leffler }
330539beb93cSSam Leffler
330639beb93cSSam Leffler if (attr.enrollee_nonce == NULL ||
3307f05cddf9SRui Paulo os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
330839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
330939beb93cSSam Leffler return WPS_FAILURE;
331039beb93cSSam Leffler }
331139beb93cSSam Leffler
331239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
3313e28a4053SRui Paulo wps_device_store(wps->wps->registrar, &wps->peer_dev,
3314e28a4053SRui Paulo wps->uuid_e);
331539beb93cSSam Leffler
331639beb93cSSam Leffler if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
331739beb93cSSam Leffler wps->wps->ap && !wps->wps->registrar->disable_auto_conf) {
331839beb93cSSam Leffler struct wps_credential cred;
331939beb93cSSam Leffler
332039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
332139beb93cSSam Leffler "on first Enrollee connection");
332239beb93cSSam Leffler
332339beb93cSSam Leffler os_memset(&cred, 0, sizeof(cred));
332439beb93cSSam Leffler os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
332539beb93cSSam Leffler cred.ssid_len = wps->wps->ssid_len;
3326325151a3SRui Paulo if (wps->wps->rf_band_cb(wps->wps->cb_ctx) == WPS_RF_60GHZ) {
3327325151a3SRui Paulo cred.auth_type = WPS_AUTH_WPA2PSK;
3328325151a3SRui Paulo cred.encr_type = WPS_ENCR_AES;
3329325151a3SRui Paulo } else {
333039beb93cSSam Leffler cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
333139beb93cSSam Leffler cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
3332325151a3SRui Paulo }
333339beb93cSSam Leffler os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
333439beb93cSSam Leffler cred.key_len = wps->new_psk_len;
333539beb93cSSam Leffler
333639beb93cSSam Leffler wps->wps->wps_state = WPS_STATE_CONFIGURED;
333739beb93cSSam Leffler wpa_hexdump_ascii_key(MSG_DEBUG,
333839beb93cSSam Leffler "WPS: Generated random passphrase",
333939beb93cSSam Leffler wps->new_psk, wps->new_psk_len);
334039beb93cSSam Leffler if (wps->wps->cred_cb)
334139beb93cSSam Leffler wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
334239beb93cSSam Leffler
334339beb93cSSam Leffler os_free(wps->new_psk);
334439beb93cSSam Leffler wps->new_psk = NULL;
334539beb93cSSam Leffler }
334639beb93cSSam Leffler
3347e28a4053SRui Paulo if (!wps->wps->ap && !wps->er)
33483157ba21SRui Paulo wps_sta_cred_cb(wps);
334939beb93cSSam Leffler
335039beb93cSSam Leffler if (wps->new_psk) {
335139beb93cSSam Leffler if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
33525b9c547cSRui Paulo wps->p2p_dev_addr, wps->new_psk,
33535b9c547cSRui Paulo wps->new_psk_len)) {
335439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
335539beb93cSSam Leffler "new PSK");
335639beb93cSSam Leffler }
335739beb93cSSam Leffler os_free(wps->new_psk);
335839beb93cSSam Leffler wps->new_psk = NULL;
335939beb93cSSam Leffler }
336039beb93cSSam Leffler
3361f05cddf9SRui Paulo wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e,
3362f05cddf9SRui Paulo wps->dev_password, wps->dev_password_len);
336339beb93cSSam Leffler
336439beb93cSSam Leffler if (wps->pbc) {
336539beb93cSSam Leffler wps_registrar_remove_pbc_session(wps->wps->registrar,
3366f05cddf9SRui Paulo wps->uuid_e,
3367f05cddf9SRui Paulo wps->p2p_dev_addr);
336839beb93cSSam Leffler wps_registrar_pbc_completed(wps->wps->registrar);
33695b9c547cSRui Paulo #ifdef WPS_WORKAROUNDS
33705b9c547cSRui Paulo os_get_reltime(&wps->wps->registrar->pbc_ignore_start);
33715b9c547cSRui Paulo #endif /* WPS_WORKAROUNDS */
3372f05cddf9SRui Paulo os_memcpy(wps->wps->registrar->pbc_ignore_uuid, wps->uuid_e,
3373f05cddf9SRui Paulo WPS_UUID_LEN);
33743157ba21SRui Paulo } else {
33753157ba21SRui Paulo wps_registrar_pin_completed(wps->wps->registrar);
337639beb93cSSam Leffler }
3377f05cddf9SRui Paulo /* TODO: maintain AuthorizedMACs somewhere separately for each ER and
3378f05cddf9SRui Paulo * merge them into APs own list.. */
337939beb93cSSam Leffler
33805b9c547cSRui Paulo wps_success_event(wps->wps, wps->mac_addr_e);
338139beb93cSSam Leffler
338239beb93cSSam Leffler return WPS_DONE;
338339beb93cSSam Leffler }
338439beb93cSSam Leffler
338539beb93cSSam Leffler
wps_registrar_process_msg(struct wps_data * wps,enum wsc_op_code op_code,const struct wpabuf * msg)338639beb93cSSam Leffler enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
338739beb93cSSam Leffler enum wsc_op_code op_code,
338839beb93cSSam Leffler const struct wpabuf *msg)
338939beb93cSSam Leffler {
339039beb93cSSam Leffler enum wps_process_res ret;
339139beb93cSSam Leffler
339239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
339339beb93cSSam Leffler "op_code=%d)",
339439beb93cSSam Leffler (unsigned long) wpabuf_len(msg), op_code);
339539beb93cSSam Leffler
339639beb93cSSam Leffler #ifdef CONFIG_WPS_UPNP
339739beb93cSSam Leffler if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
339839beb93cSSam Leffler struct wps_parse_attr attr;
339939beb93cSSam Leffler if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
340039beb93cSSam Leffler *attr.msg_type == WPS_M3)
340139beb93cSSam Leffler wps->ext_reg = 2; /* past M2/M2D phase */
340239beb93cSSam Leffler }
340339beb93cSSam Leffler if (wps->ext_reg > 1)
340439beb93cSSam Leffler wps_registrar_free_pending_m2(wps->wps);
340539beb93cSSam Leffler if (wps->wps->wps_upnp && wps->ext_reg &&
340639beb93cSSam Leffler wps->wps->upnp_msgs == NULL &&
34073157ba21SRui Paulo (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK))
34083157ba21SRui Paulo {
340939beb93cSSam Leffler struct wps_parse_attr attr;
341039beb93cSSam Leffler int type;
341139beb93cSSam Leffler if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
341239beb93cSSam Leffler type = -1;
341339beb93cSSam Leffler else
341439beb93cSSam Leffler type = *attr.msg_type;
341539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Sending received message (type %d)"
341639beb93cSSam Leffler " to external Registrar for processing", type);
341739beb93cSSam Leffler upnp_wps_device_send_wlan_event(wps->wps->wps_upnp,
341839beb93cSSam Leffler wps->mac_addr_e,
341939beb93cSSam Leffler UPNP_WPS_WLANEVENT_TYPE_EAP,
342039beb93cSSam Leffler msg);
342139beb93cSSam Leffler if (op_code == WSC_MSG)
342239beb93cSSam Leffler return WPS_PENDING;
342339beb93cSSam Leffler } else if (wps->wps->wps_upnp && wps->ext_reg && op_code == WSC_MSG) {
342439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Skip internal processing - using "
342539beb93cSSam Leffler "external Registrar");
342639beb93cSSam Leffler return WPS_CONTINUE;
342739beb93cSSam Leffler }
342839beb93cSSam Leffler #endif /* CONFIG_WPS_UPNP */
342939beb93cSSam Leffler
343039beb93cSSam Leffler switch (op_code) {
343139beb93cSSam Leffler case WSC_MSG:
343239beb93cSSam Leffler return wps_process_wsc_msg(wps, msg);
343339beb93cSSam Leffler case WSC_ACK:
3434f05cddf9SRui Paulo if (wps_validate_wsc_ack(msg) < 0)
3435f05cddf9SRui Paulo return WPS_FAILURE;
343639beb93cSSam Leffler return wps_process_wsc_ack(wps, msg);
343739beb93cSSam Leffler case WSC_NACK:
3438f05cddf9SRui Paulo if (wps_validate_wsc_nack(msg) < 0)
3439f05cddf9SRui Paulo return WPS_FAILURE;
344039beb93cSSam Leffler return wps_process_wsc_nack(wps, msg);
344139beb93cSSam Leffler case WSC_Done:
3442f05cddf9SRui Paulo if (wps_validate_wsc_done(msg) < 0)
3443f05cddf9SRui Paulo return WPS_FAILURE;
344439beb93cSSam Leffler ret = wps_process_wsc_done(wps, msg);
344539beb93cSSam Leffler if (ret == WPS_FAILURE) {
344639beb93cSSam Leffler wps->state = SEND_WSC_NACK;
3447f05cddf9SRui Paulo wps_fail_event(wps->wps, WPS_WSC_DONE,
3448f05cddf9SRui Paulo wps->config_error,
34495b9c547cSRui Paulo wps->error_indication, wps->mac_addr_e);
345039beb93cSSam Leffler }
345139beb93cSSam Leffler return ret;
345239beb93cSSam Leffler default:
345339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
345439beb93cSSam Leffler return WPS_FAILURE;
345539beb93cSSam Leffler }
345639beb93cSSam Leffler }
345739beb93cSSam Leffler
345839beb93cSSam Leffler
wps_registrar_update_ie(struct wps_registrar * reg)345939beb93cSSam Leffler int wps_registrar_update_ie(struct wps_registrar *reg)
346039beb93cSSam Leffler {
346139beb93cSSam Leffler return wps_set_ie(reg);
346239beb93cSSam Leffler }
346339beb93cSSam Leffler
346439beb93cSSam Leffler
wps_registrar_set_selected_timeout(void * eloop_ctx,void * timeout_ctx)346539beb93cSSam Leffler static void wps_registrar_set_selected_timeout(void *eloop_ctx,
346639beb93cSSam Leffler void *timeout_ctx)
346739beb93cSSam Leffler {
346839beb93cSSam Leffler struct wps_registrar *reg = eloop_ctx;
346939beb93cSSam Leffler
3470e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - "
3471e28a4053SRui Paulo "unselect internal Registrar");
347239beb93cSSam Leffler reg->selected_registrar = 0;
347339beb93cSSam Leffler reg->pbc = 0;
3474c1d255d3SCy Schubert wps_registrar_expire_pins(reg);
34755b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
3476e28a4053SRui Paulo }
3477e28a4053SRui Paulo
3478e28a4053SRui Paulo
3479e28a4053SRui Paulo #ifdef CONFIG_WPS_UPNP
wps_registrar_sel_reg_add(struct wps_registrar * reg,struct subscription * s)3480e28a4053SRui Paulo static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
3481e28a4053SRui Paulo struct subscription *s)
3482e28a4053SRui Paulo {
3483f05cddf9SRui Paulo int i, j;
3484e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
3485e28a4053SRui Paulo "config_methods=0x%x)",
3486e28a4053SRui Paulo s->dev_password_id, s->config_methods);
3487e28a4053SRui Paulo reg->sel_reg_union = 1;
3488e28a4053SRui Paulo if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON)
3489e28a4053SRui Paulo reg->sel_reg_dev_password_id_override = s->dev_password_id;
3490e28a4053SRui Paulo if (reg->sel_reg_config_methods_override == -1)
3491e28a4053SRui Paulo reg->sel_reg_config_methods_override = 0;
3492e28a4053SRui Paulo reg->sel_reg_config_methods_override |= s->config_methods;
3493f05cddf9SRui Paulo for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
3494f05cddf9SRui Paulo if (is_zero_ether_addr(reg->authorized_macs_union[i]))
3495f05cddf9SRui Paulo break;
3496f05cddf9SRui Paulo for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
3497f05cddf9SRui Paulo j++) {
3498f05cddf9SRui Paulo if (is_zero_ether_addr(s->authorized_macs[j]))
3499f05cddf9SRui Paulo break;
3500f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC into union: "
3501f05cddf9SRui Paulo MACSTR, MAC2STR(s->authorized_macs[j]));
3502f05cddf9SRui Paulo os_memcpy(reg->authorized_macs_union[i],
3503f05cddf9SRui Paulo s->authorized_macs[j], ETH_ALEN);
3504f05cddf9SRui Paulo i++;
3505f05cddf9SRui Paulo }
3506f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union",
3507f05cddf9SRui Paulo (u8 *) reg->authorized_macs_union,
3508f05cddf9SRui Paulo sizeof(reg->authorized_macs_union));
3509e28a4053SRui Paulo }
3510e28a4053SRui Paulo #endif /* CONFIG_WPS_UPNP */
3511e28a4053SRui Paulo
3512e28a4053SRui Paulo
wps_registrar_sel_reg_union(struct wps_registrar * reg)3513e28a4053SRui Paulo static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
3514e28a4053SRui Paulo {
3515e28a4053SRui Paulo #ifdef CONFIG_WPS_UPNP
3516e28a4053SRui Paulo struct subscription *s;
3517e28a4053SRui Paulo
3518e28a4053SRui Paulo if (reg->wps->wps_upnp == NULL)
3519e28a4053SRui Paulo return;
3520e28a4053SRui Paulo
3521e28a4053SRui Paulo dl_list_for_each(s, ®->wps->wps_upnp->subscriptions,
3522e28a4053SRui Paulo struct subscription, list) {
3523e28a4053SRui Paulo struct subscr_addr *sa;
3524e28a4053SRui Paulo sa = dl_list_first(&s->addr_list, struct subscr_addr, list);
3525e28a4053SRui Paulo if (sa) {
3526e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d",
3527e28a4053SRui Paulo inet_ntoa(sa->saddr.sin_addr),
3528e28a4053SRui Paulo ntohs(sa->saddr.sin_port));
3529e28a4053SRui Paulo }
3530e28a4053SRui Paulo if (s->selected_registrar)
3531e28a4053SRui Paulo wps_registrar_sel_reg_add(reg, s);
3532e28a4053SRui Paulo else
3533e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: External Registrar not "
3534e28a4053SRui Paulo "selected");
3535e28a4053SRui Paulo }
3536e28a4053SRui Paulo #endif /* CONFIG_WPS_UPNP */
353739beb93cSSam Leffler }
353839beb93cSSam Leffler
353939beb93cSSam Leffler
354039beb93cSSam Leffler /**
3541e28a4053SRui Paulo * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change
354239beb93cSSam Leffler * @reg: Registrar data from wps_registrar_init()
354339beb93cSSam Leffler *
3544e28a4053SRui Paulo * This function is called when selected registrar state changes, e.g., when an
3545e28a4053SRui Paulo * AP receives a SetSelectedRegistrar UPnP message.
354639beb93cSSam Leffler */
wps_registrar_selected_registrar_changed(struct wps_registrar * reg,u16 dev_pw_id)35475b9c547cSRui Paulo void wps_registrar_selected_registrar_changed(struct wps_registrar *reg,
35485b9c547cSRui Paulo u16 dev_pw_id)
354939beb93cSSam Leffler {
3550e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
355139beb93cSSam Leffler
3552e28a4053SRui Paulo reg->sel_reg_union = reg->selected_registrar;
3553e28a4053SRui Paulo reg->sel_reg_dev_password_id_override = -1;
3554e28a4053SRui Paulo reg->sel_reg_config_methods_override = -1;
3555f05cddf9SRui Paulo os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
3556f05cddf9SRui Paulo WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
3557f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Authorized MACs union (start with own)",
3558f05cddf9SRui Paulo (u8 *) reg->authorized_macs_union,
3559f05cddf9SRui Paulo sizeof(reg->authorized_macs_union));
3560e28a4053SRui Paulo if (reg->selected_registrar) {
3561f05cddf9SRui Paulo u16 methods;
3562f05cddf9SRui Paulo
3563f05cddf9SRui Paulo methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
3564f05cddf9SRui Paulo methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
3565f05cddf9SRui Paulo WPS_CONFIG_PHY_PUSHBUTTON);
3566e28a4053SRui Paulo if (reg->pbc) {
3567e28a4053SRui Paulo reg->sel_reg_dev_password_id_override =
3568e28a4053SRui Paulo DEV_PW_PUSHBUTTON;
3569f05cddf9SRui Paulo wps_set_pushbutton(&methods, reg->wps->config_methods);
35705b9c547cSRui Paulo } else if (dev_pw_id)
35715b9c547cSRui Paulo reg->sel_reg_dev_password_id_override = dev_pw_id;
3572e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
3573e28a4053SRui Paulo "(pbc=%d)", reg->pbc);
3574f05cddf9SRui Paulo reg->sel_reg_config_methods_override = methods;
3575e28a4053SRui Paulo } else
3576e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
357739beb93cSSam Leffler
3578e28a4053SRui Paulo wps_registrar_sel_reg_union(reg);
357939beb93cSSam Leffler
358039beb93cSSam Leffler wps_set_ie(reg);
3581e28a4053SRui Paulo wps_cb_set_sel_reg(reg);
3582e28a4053SRui Paulo }
358339beb93cSSam Leffler
3584e28a4053SRui Paulo
wps_registrar_get_info(struct wps_registrar * reg,const u8 * addr,char * buf,size_t buflen)3585e28a4053SRui Paulo int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
3586e28a4053SRui Paulo char *buf, size_t buflen)
3587e28a4053SRui Paulo {
3588e28a4053SRui Paulo struct wps_registrar_device *d;
3589e28a4053SRui Paulo int len = 0, ret;
3590e28a4053SRui Paulo char uuid[40];
3591e28a4053SRui Paulo char devtype[WPS_DEV_TYPE_BUFSIZE];
3592e28a4053SRui Paulo
3593e28a4053SRui Paulo d = wps_device_get(reg, addr);
3594e28a4053SRui Paulo if (d == NULL)
359539beb93cSSam Leffler return 0;
3596e28a4053SRui Paulo if (uuid_bin2str(d->uuid, uuid, sizeof(uuid)))
3597e28a4053SRui Paulo return 0;
3598e28a4053SRui Paulo
3599e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len,
3600e28a4053SRui Paulo "wpsUuid=%s\n"
3601e28a4053SRui Paulo "wpsPrimaryDeviceType=%s\n"
3602e28a4053SRui Paulo "wpsDeviceName=%s\n"
3603e28a4053SRui Paulo "wpsManufacturer=%s\n"
3604e28a4053SRui Paulo "wpsModelName=%s\n"
3605e28a4053SRui Paulo "wpsModelNumber=%s\n"
3606e28a4053SRui Paulo "wpsSerialNumber=%s\n",
3607e28a4053SRui Paulo uuid,
3608e28a4053SRui Paulo wps_dev_type_bin2str(d->dev.pri_dev_type, devtype,
3609e28a4053SRui Paulo sizeof(devtype)),
3610e28a4053SRui Paulo d->dev.device_name ? d->dev.device_name : "",
3611e28a4053SRui Paulo d->dev.manufacturer ? d->dev.manufacturer : "",
3612e28a4053SRui Paulo d->dev.model_name ? d->dev.model_name : "",
3613e28a4053SRui Paulo d->dev.model_number ? d->dev.model_number : "",
3614e28a4053SRui Paulo d->dev.serial_number ? d->dev.serial_number : "");
36155b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret))
3616e28a4053SRui Paulo return len;
3617e28a4053SRui Paulo len += ret;
3618e28a4053SRui Paulo
3619e28a4053SRui Paulo return len;
362039beb93cSSam Leffler }
3621f05cddf9SRui Paulo
3622f05cddf9SRui Paulo
wps_registrar_config_ap(struct wps_registrar * reg,struct wps_credential * cred)3623f05cddf9SRui Paulo int wps_registrar_config_ap(struct wps_registrar *reg,
3624f05cddf9SRui Paulo struct wps_credential *cred)
3625f05cddf9SRui Paulo {
36265b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: encr_type=0x%x", cred->encr_type);
3627f05cddf9SRui Paulo if (!(cred->encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP |
3628f05cddf9SRui Paulo WPS_ENCR_AES))) {
3629f05cddf9SRui Paulo if (cred->encr_type & WPS_ENCR_WEP) {
3630f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
3631f05cddf9SRui Paulo "due to WEP configuration");
3632f05cddf9SRui Paulo return -1;
3633f05cddf9SRui Paulo }
3634f05cddf9SRui Paulo
3635f05cddf9SRui Paulo wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
3636f05cddf9SRui Paulo "invalid encr_type 0x%x", cred->encr_type);
3637f05cddf9SRui Paulo return -1;
3638f05cddf9SRui Paulo }
3639f05cddf9SRui Paulo
3640f05cddf9SRui Paulo if ((cred->encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
3641f05cddf9SRui Paulo WPS_ENCR_TKIP) {
3642f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
3643f05cddf9SRui Paulo "TKIP+AES");
3644f05cddf9SRui Paulo cred->encr_type |= WPS_ENCR_AES;
3645f05cddf9SRui Paulo }
3646f05cddf9SRui Paulo
3647f05cddf9SRui Paulo if ((cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
3648f05cddf9SRui Paulo WPS_AUTH_WPAPSK) {
3649f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
3650f05cddf9SRui Paulo "WPAPSK+WPA2PSK");
3651f05cddf9SRui Paulo cred->auth_type |= WPS_AUTH_WPA2PSK;
3652f05cddf9SRui Paulo }
3653f05cddf9SRui Paulo
3654f05cddf9SRui Paulo if (reg->wps->cred_cb)
3655f05cddf9SRui Paulo return reg->wps->cred_cb(reg->wps->cb_ctx, cred);
3656f05cddf9SRui Paulo
3657f05cddf9SRui Paulo return -1;
3658f05cddf9SRui Paulo }
3659f05cddf9SRui Paulo
3660f05cddf9SRui Paulo
wps_registrar_update_multi_ap(struct wps_registrar * reg,const u8 * multi_ap_backhaul_ssid,size_t multi_ap_backhaul_ssid_len,const u8 * multi_ap_backhaul_network_key,size_t multi_ap_backhaul_network_key_len)3661c1d255d3SCy Schubert int wps_registrar_update_multi_ap(struct wps_registrar *reg,
3662c1d255d3SCy Schubert const u8 *multi_ap_backhaul_ssid,
3663c1d255d3SCy Schubert size_t multi_ap_backhaul_ssid_len,
3664c1d255d3SCy Schubert const u8 *multi_ap_backhaul_network_key,
3665c1d255d3SCy Schubert size_t multi_ap_backhaul_network_key_len)
3666c1d255d3SCy Schubert {
3667c1d255d3SCy Schubert if (multi_ap_backhaul_ssid) {
3668c1d255d3SCy Schubert os_memcpy(reg->multi_ap_backhaul_ssid,
3669c1d255d3SCy Schubert multi_ap_backhaul_ssid, multi_ap_backhaul_ssid_len);
3670c1d255d3SCy Schubert reg->multi_ap_backhaul_ssid_len = multi_ap_backhaul_ssid_len;
3671c1d255d3SCy Schubert }
3672c1d255d3SCy Schubert
3673c1d255d3SCy Schubert os_free(reg->multi_ap_backhaul_network_key);
3674c1d255d3SCy Schubert reg->multi_ap_backhaul_network_key = NULL;
3675c1d255d3SCy Schubert reg->multi_ap_backhaul_network_key_len = 0;
3676c1d255d3SCy Schubert if (multi_ap_backhaul_network_key) {
3677c1d255d3SCy Schubert reg->multi_ap_backhaul_network_key =
3678c1d255d3SCy Schubert os_memdup(multi_ap_backhaul_network_key,
3679c1d255d3SCy Schubert multi_ap_backhaul_network_key_len);
3680c1d255d3SCy Schubert if (!reg->multi_ap_backhaul_network_key)
3681c1d255d3SCy Schubert return -1;
3682c1d255d3SCy Schubert reg->multi_ap_backhaul_network_key_len =
3683c1d255d3SCy Schubert multi_ap_backhaul_network_key_len;
3684c1d255d3SCy Schubert }
3685c1d255d3SCy Schubert
3686c1d255d3SCy Schubert return 0;
3687c1d255d3SCy Schubert }
3688c1d255d3SCy Schubert
3689c1d255d3SCy Schubert
3690f05cddf9SRui Paulo #ifdef CONFIG_WPS_NFC
3691f05cddf9SRui Paulo
wps_registrar_add_nfc_pw_token(struct wps_registrar * reg,const u8 * pubkey_hash,u16 pw_id,const u8 * dev_pw,size_t dev_pw_len,int pk_hash_provided_oob)3692f05cddf9SRui Paulo int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
3693f05cddf9SRui Paulo const u8 *pubkey_hash, u16 pw_id,
36945b9c547cSRui Paulo const u8 *dev_pw, size_t dev_pw_len,
36955b9c547cSRui Paulo int pk_hash_provided_oob)
3696f05cddf9SRui Paulo {
3697f05cddf9SRui Paulo struct wps_nfc_pw_token *token;
3698f05cddf9SRui Paulo
3699f05cddf9SRui Paulo if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN)
3700f05cddf9SRui Paulo return -1;
3701f05cddf9SRui Paulo
37025b9c547cSRui Paulo if (pw_id == DEV_PW_NFC_CONNECTION_HANDOVER &&
37035b9c547cSRui Paulo (pubkey_hash == NULL || !pk_hash_provided_oob)) {
37045b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Unexpected NFC Password Token "
37055b9c547cSRui Paulo "addition - missing public key hash");
37065b9c547cSRui Paulo return -1;
37075b9c547cSRui Paulo }
37085b9c547cSRui Paulo
3709f05cddf9SRui Paulo wps_free_nfc_pw_tokens(®->nfc_pw_tokens, pw_id);
3710f05cddf9SRui Paulo
3711f05cddf9SRui Paulo token = os_zalloc(sizeof(*token));
3712f05cddf9SRui Paulo if (token == NULL)
3713f05cddf9SRui Paulo return -1;
3714f05cddf9SRui Paulo
37155b9c547cSRui Paulo token->peer_pk_hash_known = pubkey_hash != NULL;
37165b9c547cSRui Paulo if (pubkey_hash)
37175b9c547cSRui Paulo os_memcpy(token->pubkey_hash, pubkey_hash,
37185b9c547cSRui Paulo WPS_OOB_PUBKEY_HASH_LEN);
3719f05cddf9SRui Paulo token->pw_id = pw_id;
37205b9c547cSRui Paulo token->pk_hash_provided_oob = pk_hash_provided_oob;
37215b9c547cSRui Paulo if (dev_pw) {
37225b9c547cSRui Paulo wpa_snprintf_hex_uppercase((char *) token->dev_pw,
37235b9c547cSRui Paulo sizeof(token->dev_pw),
37245b9c547cSRui Paulo dev_pw, dev_pw_len);
37255b9c547cSRui Paulo token->dev_pw_len = dev_pw_len * 2;
37265b9c547cSRui Paulo }
3727f05cddf9SRui Paulo
3728f05cddf9SRui Paulo dl_list_add(®->nfc_pw_tokens, &token->list);
3729f05cddf9SRui Paulo
3730f05cddf9SRui Paulo reg->selected_registrar = 1;
3731f05cddf9SRui Paulo reg->pbc = 0;
3732f05cddf9SRui Paulo wps_registrar_add_authorized_mac(reg,
3733f05cddf9SRui Paulo (u8 *) "\xff\xff\xff\xff\xff\xff");
37345b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, pw_id);
3735f05cddf9SRui Paulo eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
3736f05cddf9SRui Paulo eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
3737f05cddf9SRui Paulo wps_registrar_set_selected_timeout,
3738f05cddf9SRui Paulo reg, NULL);
3739f05cddf9SRui Paulo
37405b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WPS: Added NFC Device Password %u to Registrar",
37415b9c547cSRui Paulo pw_id);
37425b9c547cSRui Paulo
3743f05cddf9SRui Paulo return 0;
3744f05cddf9SRui Paulo }
3745f05cddf9SRui Paulo
3746f05cddf9SRui Paulo
wps_registrar_add_nfc_password_token(struct wps_registrar * reg,const u8 * oob_dev_pw,size_t oob_dev_pw_len)3747f05cddf9SRui Paulo int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
3748f05cddf9SRui Paulo const u8 *oob_dev_pw,
3749f05cddf9SRui Paulo size_t oob_dev_pw_len)
3750f05cddf9SRui Paulo {
3751f05cddf9SRui Paulo const u8 *pos, *hash, *dev_pw;
3752f05cddf9SRui Paulo u16 id;
3753f05cddf9SRui Paulo size_t dev_pw_len;
3754f05cddf9SRui Paulo
37555b9c547cSRui Paulo if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
3756f05cddf9SRui Paulo oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
3757f05cddf9SRui Paulo WPS_OOB_DEVICE_PASSWORD_LEN)
3758f05cddf9SRui Paulo return -1;
3759f05cddf9SRui Paulo
3760f05cddf9SRui Paulo hash = oob_dev_pw;
3761f05cddf9SRui Paulo pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN;
3762f05cddf9SRui Paulo id = WPA_GET_BE16(pos);
3763f05cddf9SRui Paulo dev_pw = pos + 2;
3764f05cddf9SRui Paulo dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw;
3765f05cddf9SRui Paulo
3766f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u",
3767f05cddf9SRui Paulo id);
3768f05cddf9SRui Paulo
3769f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash",
3770f05cddf9SRui Paulo hash, WPS_OOB_PUBKEY_HASH_LEN);
3771f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len);
3772f05cddf9SRui Paulo
3773f05cddf9SRui Paulo return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw,
37745b9c547cSRui Paulo dev_pw_len, 0);
3775f05cddf9SRui Paulo }
3776f05cddf9SRui Paulo
3777f05cddf9SRui Paulo
wps_registrar_remove_nfc_pw_token(struct wps_registrar * reg,struct wps_nfc_pw_token * token)3778f05cddf9SRui Paulo void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
3779f05cddf9SRui Paulo struct wps_nfc_pw_token *token)
3780f05cddf9SRui Paulo {
3781f05cddf9SRui Paulo wps_registrar_remove_authorized_mac(reg,
3782f05cddf9SRui Paulo (u8 *) "\xff\xff\xff\xff\xff\xff");
37835b9c547cSRui Paulo wps_registrar_selected_registrar_changed(reg, 0);
37845b9c547cSRui Paulo
37855b9c547cSRui Paulo /*
37865b9c547cSRui Paulo * Free the NFC password token if it was used only for a single protocol
37875b9c547cSRui Paulo * run. The static handover case uses the same password token multiple
37885b9c547cSRui Paulo * times, so do not free that case here.
37895b9c547cSRui Paulo */
37905b9c547cSRui Paulo if (token->peer_pk_hash_known)
37915b9c547cSRui Paulo os_free(token);
3792f05cddf9SRui Paulo }
3793f05cddf9SRui Paulo
3794f05cddf9SRui Paulo #endif /* CONFIG_WPS_NFC */
3795