xref: /freebsd-src/contrib/wpa/src/common/dpp.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
185732ac8SCy Schubert /*
285732ac8SCy Schubert  * DPP functionality shared between hostapd and wpa_supplicant
385732ac8SCy Schubert  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert  * Copyright (c) 2018-2020, The Linux Foundation
5*a90b9d01SCy Schubert  * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
685732ac8SCy Schubert  *
785732ac8SCy Schubert  * This software may be distributed under the terms of the BSD license.
885732ac8SCy Schubert  * See README for more details.
985732ac8SCy Schubert  */
1085732ac8SCy Schubert 
1185732ac8SCy Schubert #include "utils/includes.h"
1285732ac8SCy Schubert 
1385732ac8SCy Schubert #include "utils/common.h"
1485732ac8SCy Schubert #include "utils/base64.h"
1585732ac8SCy Schubert #include "utils/json.h"
16*a90b9d01SCy Schubert #include "utils/ip_addr.h"
1785732ac8SCy Schubert #include "common/ieee802_11_common.h"
1885732ac8SCy Schubert #include "common/wpa_ctrl.h"
194bc52338SCy Schubert #include "common/gas.h"
20c1d255d3SCy Schubert #include "eap_common/eap_defs.h"
2185732ac8SCy Schubert #include "crypto/crypto.h"
2285732ac8SCy Schubert #include "crypto/random.h"
2385732ac8SCy Schubert #include "crypto/aes.h"
2485732ac8SCy Schubert #include "crypto/aes_siv.h"
2585732ac8SCy Schubert #include "drivers/driver.h"
2685732ac8SCy Schubert #include "dpp.h"
27c1d255d3SCy Schubert #include "dpp_i.h"
2885732ac8SCy Schubert 
2985732ac8SCy Schubert 
3085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
3132a95656SCy Schubert #ifdef CONFIG_DPP3
3232a95656SCy Schubert int dpp_version_override = 3;
3332a95656SCy Schubert #elif defined(CONFIG_DPP2)
34c1d255d3SCy Schubert int dpp_version_override = 2;
35c1d255d3SCy Schubert #else
36c1d255d3SCy Schubert int dpp_version_override = 1;
37c1d255d3SCy Schubert #endif
3885732ac8SCy Schubert enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
3985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
4085732ac8SCy Schubert 
4185732ac8SCy Schubert 
42c1d255d3SCy Schubert void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
4385732ac8SCy Schubert {
4485732ac8SCy Schubert 	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
4585732ac8SCy Schubert }
4685732ac8SCy Schubert 
4785732ac8SCy Schubert 
4885732ac8SCy Schubert struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
4985732ac8SCy Schubert 			      size_t len)
5085732ac8SCy Schubert {
5185732ac8SCy Schubert 	struct wpabuf *msg;
5285732ac8SCy Schubert 
5385732ac8SCy Schubert 	msg = wpabuf_alloc(8 + len);
5485732ac8SCy Schubert 	if (!msg)
5585732ac8SCy Schubert 		return NULL;
5685732ac8SCy Schubert 	wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
5785732ac8SCy Schubert 	wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
5885732ac8SCy Schubert 	wpabuf_put_be24(msg, OUI_WFA);
5985732ac8SCy Schubert 	wpabuf_put_u8(msg, DPP_OUI_TYPE);
6085732ac8SCy Schubert 	wpabuf_put_u8(msg, 1); /* Crypto Suite */
6185732ac8SCy Schubert 	wpabuf_put_u8(msg, type);
6285732ac8SCy Schubert 	return msg;
6385732ac8SCy Schubert }
6485732ac8SCy Schubert 
6585732ac8SCy Schubert 
6685732ac8SCy Schubert const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
6785732ac8SCy Schubert {
6885732ac8SCy Schubert 	u16 id, alen;
6985732ac8SCy Schubert 	const u8 *pos = buf, *end = buf + len;
7085732ac8SCy Schubert 
7185732ac8SCy Schubert 	while (end - pos >= 4) {
7285732ac8SCy Schubert 		id = WPA_GET_LE16(pos);
7385732ac8SCy Schubert 		pos += 2;
7485732ac8SCy Schubert 		alen = WPA_GET_LE16(pos);
7585732ac8SCy Schubert 		pos += 2;
7685732ac8SCy Schubert 		if (alen > end - pos)
7785732ac8SCy Schubert 			return NULL;
7885732ac8SCy Schubert 		if (id == req_id) {
7985732ac8SCy Schubert 			*ret_len = alen;
8085732ac8SCy Schubert 			return pos;
8185732ac8SCy Schubert 		}
8285732ac8SCy Schubert 		pos += alen;
8385732ac8SCy Schubert 	}
8485732ac8SCy Schubert 
8585732ac8SCy Schubert 	return NULL;
8685732ac8SCy Schubert }
8785732ac8SCy Schubert 
8885732ac8SCy Schubert 
89c1d255d3SCy Schubert static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
90c1d255d3SCy Schubert 				    u16 req_id, u16 *ret_len)
91c1d255d3SCy Schubert {
92c1d255d3SCy Schubert 	u16 id, alen;
93c1d255d3SCy Schubert 	const u8 *pos, *end = buf + len;
94c1d255d3SCy Schubert 
95c1d255d3SCy Schubert 	if (!prev)
96c1d255d3SCy Schubert 		pos = buf;
97c1d255d3SCy Schubert 	else
98c1d255d3SCy Schubert 		pos = prev + WPA_GET_LE16(prev - 2);
99c1d255d3SCy Schubert 	while (end - pos >= 4) {
100c1d255d3SCy Schubert 		id = WPA_GET_LE16(pos);
101c1d255d3SCy Schubert 		pos += 2;
102c1d255d3SCy Schubert 		alen = WPA_GET_LE16(pos);
103c1d255d3SCy Schubert 		pos += 2;
104c1d255d3SCy Schubert 		if (alen > end - pos)
105c1d255d3SCy Schubert 			return NULL;
106c1d255d3SCy Schubert 		if (id == req_id) {
107c1d255d3SCy Schubert 			*ret_len = alen;
108c1d255d3SCy Schubert 			return pos;
109c1d255d3SCy Schubert 		}
110c1d255d3SCy Schubert 		pos += alen;
111c1d255d3SCy Schubert 	}
112c1d255d3SCy Schubert 
113c1d255d3SCy Schubert 	return NULL;
114c1d255d3SCy Schubert }
115c1d255d3SCy Schubert 
116c1d255d3SCy Schubert 
11785732ac8SCy Schubert int dpp_check_attrs(const u8 *buf, size_t len)
11885732ac8SCy Schubert {
11985732ac8SCy Schubert 	const u8 *pos, *end;
12085732ac8SCy Schubert 	int wrapped_data = 0;
12185732ac8SCy Schubert 
12285732ac8SCy Schubert 	pos = buf;
12385732ac8SCy Schubert 	end = buf + len;
12485732ac8SCy Schubert 	while (end - pos >= 4) {
12585732ac8SCy Schubert 		u16 id, alen;
12685732ac8SCy Schubert 
12785732ac8SCy Schubert 		id = WPA_GET_LE16(pos);
12885732ac8SCy Schubert 		pos += 2;
12985732ac8SCy Schubert 		alen = WPA_GET_LE16(pos);
13085732ac8SCy Schubert 		pos += 2;
13185732ac8SCy Schubert 		wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
13285732ac8SCy Schubert 			   id, alen);
13385732ac8SCy Schubert 		if (alen > end - pos) {
13485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
13585732ac8SCy Schubert 				   "DPP: Truncated message - not enough room for the attribute - dropped");
13685732ac8SCy Schubert 			return -1;
13785732ac8SCy Schubert 		}
13885732ac8SCy Schubert 		if (wrapped_data) {
13985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
14085732ac8SCy Schubert 				   "DPP: An unexpected attribute included after the Wrapped Data attribute");
14185732ac8SCy Schubert 			return -1;
14285732ac8SCy Schubert 		}
14385732ac8SCy Schubert 		if (id == DPP_ATTR_WRAPPED_DATA)
14485732ac8SCy Schubert 			wrapped_data = 1;
14585732ac8SCy Schubert 		pos += alen;
14685732ac8SCy Schubert 	}
14785732ac8SCy Schubert 
14885732ac8SCy Schubert 	if (end != pos) {
14985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
15085732ac8SCy Schubert 			   "DPP: Unexpected octets (%d) after the last attribute",
15185732ac8SCy Schubert 			   (int) (end - pos));
15285732ac8SCy Schubert 		return -1;
15385732ac8SCy Schubert 	}
15485732ac8SCy Schubert 
15585732ac8SCy Schubert 	return 0;
15685732ac8SCy Schubert }
15785732ac8SCy Schubert 
15885732ac8SCy Schubert 
15985732ac8SCy Schubert void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
16085732ac8SCy Schubert {
16185732ac8SCy Schubert 	if (!info)
16285732ac8SCy Schubert 		return;
16385732ac8SCy Schubert 	os_free(info->uri);
16485732ac8SCy Schubert 	os_free(info->info);
165c1d255d3SCy Schubert 	os_free(info->chan);
166*a90b9d01SCy Schubert 	os_free(info->host);
167c1d255d3SCy Schubert 	os_free(info->pk);
1684b72b91aSCy Schubert 	crypto_ec_key_deinit(info->pubkey);
169c1d255d3SCy Schubert 	str_clear_free(info->configurator_params);
17085732ac8SCy Schubert 	os_free(info);
17185732ac8SCy Schubert }
17285732ac8SCy Schubert 
17385732ac8SCy Schubert 
17485732ac8SCy Schubert const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
17585732ac8SCy Schubert {
17685732ac8SCy Schubert 	switch (type) {
17785732ac8SCy Schubert 	case DPP_BOOTSTRAP_QR_CODE:
17885732ac8SCy Schubert 		return "QRCODE";
17985732ac8SCy Schubert 	case DPP_BOOTSTRAP_PKEX:
18085732ac8SCy Schubert 		return "PKEX";
181c1d255d3SCy Schubert 	case DPP_BOOTSTRAP_NFC_URI:
182c1d255d3SCy Schubert 		return "NFC-URI";
18385732ac8SCy Schubert 	}
18485732ac8SCy Schubert 	return "??";
18585732ac8SCy Schubert }
18685732ac8SCy Schubert 
18785732ac8SCy Schubert 
18885732ac8SCy Schubert static int dpp_uri_valid_info(const char *info)
18985732ac8SCy Schubert {
19085732ac8SCy Schubert 	while (*info) {
19185732ac8SCy Schubert 		unsigned char val = *info++;
19285732ac8SCy Schubert 
19385732ac8SCy Schubert 		if (val < 0x20 || val > 0x7e || val == 0x3b)
19485732ac8SCy Schubert 			return 0;
19585732ac8SCy Schubert 	}
19685732ac8SCy Schubert 
19785732ac8SCy Schubert 	return 1;
19885732ac8SCy Schubert }
19985732ac8SCy Schubert 
20085732ac8SCy Schubert 
20185732ac8SCy Schubert static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
20285732ac8SCy Schubert {
20385732ac8SCy Schubert 	bi->uri = os_strdup(uri);
20485732ac8SCy Schubert 	return bi->uri ? 0 : -1;
20585732ac8SCy Schubert }
20685732ac8SCy Schubert 
20785732ac8SCy Schubert 
20885732ac8SCy Schubert int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
20985732ac8SCy Schubert 			    const char *chan_list)
21085732ac8SCy Schubert {
211206b73d0SCy Schubert 	const char *pos = chan_list, *pos2;
212206b73d0SCy Schubert 	int opclass = -1, channel, freq;
21385732ac8SCy Schubert 
21485732ac8SCy Schubert 	while (pos && *pos && *pos != ';') {
215206b73d0SCy Schubert 		pos2 = pos;
216206b73d0SCy Schubert 		while (*pos2 >= '0' && *pos2 <= '9')
217206b73d0SCy Schubert 			pos2++;
218206b73d0SCy Schubert 		if (*pos2 == '/') {
21985732ac8SCy Schubert 			opclass = atoi(pos);
220206b73d0SCy Schubert 			pos = pos2 + 1;
221206b73d0SCy Schubert 		}
22285732ac8SCy Schubert 		if (opclass <= 0)
22385732ac8SCy Schubert 			goto fail;
22485732ac8SCy Schubert 		channel = atoi(pos);
22585732ac8SCy Schubert 		if (channel <= 0)
22685732ac8SCy Schubert 			goto fail;
22785732ac8SCy Schubert 		while (*pos >= '0' && *pos <= '9')
22885732ac8SCy Schubert 			pos++;
22985732ac8SCy Schubert 		freq = ieee80211_chan_to_freq(NULL, opclass, channel);
23085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
23185732ac8SCy Schubert 			   "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
23285732ac8SCy Schubert 			   opclass, channel, freq);
233c1d255d3SCy Schubert 		bi->channels_listed = true;
23485732ac8SCy Schubert 		if (freq < 0) {
23585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
23685732ac8SCy Schubert 				   "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
23785732ac8SCy Schubert 				   opclass, channel);
23885732ac8SCy Schubert 		} else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
23985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
24085732ac8SCy Schubert 				   "DPP: Too many channels in URI channel-list - ignore list");
24185732ac8SCy Schubert 			bi->num_freq = 0;
24285732ac8SCy Schubert 			break;
24385732ac8SCy Schubert 		} else {
24485732ac8SCy Schubert 			bi->freq[bi->num_freq++] = freq;
24585732ac8SCy Schubert 		}
24685732ac8SCy Schubert 
24785732ac8SCy Schubert 		if (*pos == ';' || *pos == '\0')
24885732ac8SCy Schubert 			break;
24985732ac8SCy Schubert 		if (*pos != ',')
25085732ac8SCy Schubert 			goto fail;
25185732ac8SCy Schubert 		pos++;
25285732ac8SCy Schubert 	}
25385732ac8SCy Schubert 
25485732ac8SCy Schubert 	return 0;
25585732ac8SCy Schubert fail:
25685732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
25785732ac8SCy Schubert 	return -1;
25885732ac8SCy Schubert }
25985732ac8SCy Schubert 
26085732ac8SCy Schubert 
26185732ac8SCy Schubert int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
26285732ac8SCy Schubert {
26385732ac8SCy Schubert 	if (!mac)
26485732ac8SCy Schubert 		return 0;
26585732ac8SCy Schubert 
26685732ac8SCy Schubert 	if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
26785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
26885732ac8SCy Schubert 		return -1;
26985732ac8SCy Schubert 	}
27085732ac8SCy Schubert 
27185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
27285732ac8SCy Schubert 
27385732ac8SCy Schubert 	return 0;
27485732ac8SCy Schubert }
27585732ac8SCy Schubert 
27685732ac8SCy Schubert 
27785732ac8SCy Schubert int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
27885732ac8SCy Schubert {
27985732ac8SCy Schubert 	const char *end;
28085732ac8SCy Schubert 
28185732ac8SCy Schubert 	if (!info)
28285732ac8SCy Schubert 		return 0;
28385732ac8SCy Schubert 
28485732ac8SCy Schubert 	end = os_strchr(info, ';');
28585732ac8SCy Schubert 	if (!end)
28685732ac8SCy Schubert 		end = info + os_strlen(info);
28785732ac8SCy Schubert 	bi->info = os_malloc(end - info + 1);
28885732ac8SCy Schubert 	if (!bi->info)
28985732ac8SCy Schubert 		return -1;
29085732ac8SCy Schubert 	os_memcpy(bi->info, info, end - info);
29185732ac8SCy Schubert 	bi->info[end - info] = '\0';
29285732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
29385732ac8SCy Schubert 	if (!dpp_uri_valid_info(bi->info)) {
29485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
29585732ac8SCy Schubert 		return -1;
29685732ac8SCy Schubert 	}
29785732ac8SCy Schubert 
29885732ac8SCy Schubert 	return 0;
29985732ac8SCy Schubert }
30085732ac8SCy Schubert 
30185732ac8SCy Schubert 
302c1d255d3SCy Schubert int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
30385732ac8SCy Schubert {
304c1d255d3SCy Schubert #ifdef CONFIG_DPP2
305c1d255d3SCy Schubert 	if (!version || DPP_VERSION < 2)
306c1d255d3SCy Schubert 		return 0;
30785732ac8SCy Schubert 
308c1d255d3SCy Schubert 	if (*version == '1')
309c1d255d3SCy Schubert 		bi->version = 1;
310c1d255d3SCy Schubert 	else if (*version == '2')
311c1d255d3SCy Schubert 		bi->version = 2;
31232a95656SCy Schubert 	else if (*version == '3')
31332a95656SCy Schubert 		bi->version = 3;
314c1d255d3SCy Schubert 	else
315c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
31685732ac8SCy Schubert 
317c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
318c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
31985732ac8SCy Schubert 
320c1d255d3SCy Schubert 	return 0;
32185732ac8SCy Schubert }
32285732ac8SCy Schubert 
32385732ac8SCy Schubert 
32485732ac8SCy Schubert static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
32585732ac8SCy Schubert {
32685732ac8SCy Schubert 	u8 *data;
32785732ac8SCy Schubert 	size_t data_len;
32885732ac8SCy Schubert 	int res;
329c1d255d3SCy Schubert 	const char *end;
33085732ac8SCy Schubert 
33185732ac8SCy Schubert 	end = os_strchr(info, ';');
33285732ac8SCy Schubert 	if (!end)
33385732ac8SCy Schubert 		return -1;
33485732ac8SCy Schubert 
335c1d255d3SCy Schubert 	data = base64_decode(info, end - info, &data_len);
33685732ac8SCy Schubert 	if (!data) {
33785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
33885732ac8SCy Schubert 			   "DPP: Invalid base64 encoding on URI public-key");
33985732ac8SCy Schubert 		return -1;
34085732ac8SCy Schubert 	}
34185732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
34285732ac8SCy Schubert 		    data, data_len);
34385732ac8SCy Schubert 
344c1d255d3SCy Schubert 	res = dpp_get_subject_public_key(bi, data, data_len);
34585732ac8SCy Schubert 	os_free(data);
346c1d255d3SCy Schubert 	return res;
34785732ac8SCy Schubert }
34885732ac8SCy Schubert 
34985732ac8SCy Schubert 
350*a90b9d01SCy Schubert static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
351*a90b9d01SCy Schubert 					  const char *txt)
352*a90b9d01SCy Schubert {
353*a90b9d01SCy Schubert 	int val;
354*a90b9d01SCy Schubert 
355*a90b9d01SCy Schubert 	if (!txt)
356*a90b9d01SCy Schubert 		return 0;
357*a90b9d01SCy Schubert 
358*a90b9d01SCy Schubert 	val = hex2num(txt[0]);
359*a90b9d01SCy Schubert 	if (val < 0)
360*a90b9d01SCy Schubert 		return -1;
361*a90b9d01SCy Schubert 	bi->supported_curves = val;
362*a90b9d01SCy Schubert 
363*a90b9d01SCy Schubert 	val = hex2num(txt[1]);
364*a90b9d01SCy Schubert 	if (val > 0)
365*a90b9d01SCy Schubert 		bi->supported_curves |= val << 4;
366*a90b9d01SCy Schubert 
367*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
368*a90b9d01SCy Schubert 		   bi->supported_curves);
369*a90b9d01SCy Schubert 
370*a90b9d01SCy Schubert 	return 0;
371*a90b9d01SCy Schubert }
372*a90b9d01SCy Schubert 
373*a90b9d01SCy Schubert 
374*a90b9d01SCy Schubert static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
375*a90b9d01SCy Schubert {
376*a90b9d01SCy Schubert 	const char *end;
377*a90b9d01SCy Schubert 	char *port;
378*a90b9d01SCy Schubert 	struct hostapd_ip_addr addr;
379*a90b9d01SCy Schubert 	char buf[100], *pos;
380*a90b9d01SCy Schubert 
381*a90b9d01SCy Schubert 	if (!txt)
382*a90b9d01SCy Schubert 		return 0;
383*a90b9d01SCy Schubert 
384*a90b9d01SCy Schubert 	end = os_strchr(txt, ';');
385*a90b9d01SCy Schubert 	if (!end)
386*a90b9d01SCy Schubert 		end = txt + os_strlen(txt);
387*a90b9d01SCy Schubert 	if (end - txt > (int) sizeof(buf) - 1)
388*a90b9d01SCy Schubert 		return -1;
389*a90b9d01SCy Schubert 	os_memcpy(buf, txt, end - txt);
390*a90b9d01SCy Schubert 	buf[end - txt] = '\0';
391*a90b9d01SCy Schubert 
392*a90b9d01SCy Schubert 	bi->port = DPP_TCP_PORT;
393*a90b9d01SCy Schubert 
394*a90b9d01SCy Schubert 	pos = buf;
395*a90b9d01SCy Schubert 	if (*pos == '[') {
396*a90b9d01SCy Schubert 		pos = &buf[1];
397*a90b9d01SCy Schubert 		port = os_strchr(pos, ']');
398*a90b9d01SCy Schubert 		if (!port)
399*a90b9d01SCy Schubert 			return -1;
400*a90b9d01SCy Schubert 		*port++ = '\0';
401*a90b9d01SCy Schubert 		if (*port == ':')
402*a90b9d01SCy Schubert 			bi->port = atoi(port + 1);
403*a90b9d01SCy Schubert 	}
404*a90b9d01SCy Schubert 
405*a90b9d01SCy Schubert 	if (hostapd_parse_ip_addr(pos, &addr) < 0) {
406*a90b9d01SCy Schubert 		if (buf[0] != '[') {
407*a90b9d01SCy Schubert 			port = os_strrchr(pos, ':');
408*a90b9d01SCy Schubert 			if (port) {
409*a90b9d01SCy Schubert 				*port++ = '\0';
410*a90b9d01SCy Schubert 				bi->port = atoi(port);
411*a90b9d01SCy Schubert 			}
412*a90b9d01SCy Schubert 		}
413*a90b9d01SCy Schubert 		if (hostapd_parse_ip_addr(pos, &addr) < 0) {
414*a90b9d01SCy Schubert 			wpa_printf(MSG_INFO,
415*a90b9d01SCy Schubert 				   "DPP: Invalid IP address in URI host entry: %s",
416*a90b9d01SCy Schubert 				   pos);
417*a90b9d01SCy Schubert 			return -1;
418*a90b9d01SCy Schubert 		}
419*a90b9d01SCy Schubert 	}
420*a90b9d01SCy Schubert 	os_free(bi->host);
421*a90b9d01SCy Schubert 	bi->host = os_memdup(&addr, sizeof(addr));
422*a90b9d01SCy Schubert 	if (!bi->host)
423*a90b9d01SCy Schubert 		return -1;
424*a90b9d01SCy Schubert 
425*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
426*a90b9d01SCy Schubert 		   hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
427*a90b9d01SCy Schubert 
428*a90b9d01SCy Schubert 	return 0;
429*a90b9d01SCy Schubert }
430*a90b9d01SCy Schubert 
431*a90b9d01SCy Schubert 
43285732ac8SCy Schubert static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
43385732ac8SCy Schubert {
43485732ac8SCy Schubert 	const char *pos = uri;
43585732ac8SCy Schubert 	const char *end;
43685732ac8SCy Schubert 	const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
437*a90b9d01SCy Schubert 	const char *version = NULL, *supported_curves = NULL, *host = NULL;
43885732ac8SCy Schubert 	struct dpp_bootstrap_info *bi;
43985732ac8SCy Schubert 
44085732ac8SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
44185732ac8SCy Schubert 
44285732ac8SCy Schubert 	if (os_strncmp(pos, "DPP:", 4) != 0) {
44385732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
44485732ac8SCy Schubert 		return NULL;
44585732ac8SCy Schubert 	}
44685732ac8SCy Schubert 	pos += 4;
44785732ac8SCy Schubert 
44885732ac8SCy Schubert 	for (;;) {
44985732ac8SCy Schubert 		end = os_strchr(pos, ';');
45085732ac8SCy Schubert 		if (!end)
45185732ac8SCy Schubert 			break;
45285732ac8SCy Schubert 
45385732ac8SCy Schubert 		if (end == pos) {
45485732ac8SCy Schubert 			/* Handle terminating ";;" and ignore unexpected ";"
45585732ac8SCy Schubert 			 * for parsing robustness. */
45685732ac8SCy Schubert 			pos++;
45785732ac8SCy Schubert 			continue;
45885732ac8SCy Schubert 		}
45985732ac8SCy Schubert 
46085732ac8SCy Schubert 		if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
46185732ac8SCy Schubert 			chan_list = pos + 2;
46285732ac8SCy Schubert 		else if (pos[0] == 'M' && pos[1] == ':' && !mac)
46385732ac8SCy Schubert 			mac = pos + 2;
46485732ac8SCy Schubert 		else if (pos[0] == 'I' && pos[1] == ':' && !info)
46585732ac8SCy Schubert 			info = pos + 2;
46685732ac8SCy Schubert 		else if (pos[0] == 'K' && pos[1] == ':' && !pk)
46785732ac8SCy Schubert 			pk = pos + 2;
468c1d255d3SCy Schubert 		else if (pos[0] == 'V' && pos[1] == ':' && !version)
469c1d255d3SCy Schubert 			version = pos + 2;
470*a90b9d01SCy Schubert 		else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
471*a90b9d01SCy Schubert 			supported_curves = pos + 2;
472*a90b9d01SCy Schubert 		else if (pos[0] == 'H' && pos[1] == ':' && !host)
473*a90b9d01SCy Schubert 			host = pos + 2;
47485732ac8SCy Schubert 		else
47585732ac8SCy Schubert 			wpa_hexdump_ascii(MSG_DEBUG,
47685732ac8SCy Schubert 					  "DPP: Ignore unrecognized URI parameter",
47785732ac8SCy Schubert 					  pos, end - pos);
47885732ac8SCy Schubert 		pos = end + 1;
47985732ac8SCy Schubert 	}
48085732ac8SCy Schubert 
48185732ac8SCy Schubert 	if (!pk) {
48285732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: URI missing public-key");
48385732ac8SCy Schubert 		return NULL;
48485732ac8SCy Schubert 	}
48585732ac8SCy Schubert 
48685732ac8SCy Schubert 	bi = os_zalloc(sizeof(*bi));
48785732ac8SCy Schubert 	if (!bi)
48885732ac8SCy Schubert 		return NULL;
48985732ac8SCy Schubert 
49085732ac8SCy Schubert 	if (dpp_clone_uri(bi, uri) < 0 ||
49185732ac8SCy Schubert 	    dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
49285732ac8SCy Schubert 	    dpp_parse_uri_mac(bi, mac) < 0 ||
49385732ac8SCy Schubert 	    dpp_parse_uri_info(bi, info) < 0 ||
494c1d255d3SCy Schubert 	    dpp_parse_uri_version(bi, version) < 0 ||
495*a90b9d01SCy Schubert 	    dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
496*a90b9d01SCy Schubert 	    dpp_parse_uri_host(bi, host) < 0 ||
49785732ac8SCy Schubert 	    dpp_parse_uri_pk(bi, pk) < 0) {
49885732ac8SCy Schubert 		dpp_bootstrap_info_free(bi);
49985732ac8SCy Schubert 		bi = NULL;
50085732ac8SCy Schubert 	}
50185732ac8SCy Schubert 
50285732ac8SCy Schubert 	return bi;
50385732ac8SCy Schubert }
50485732ac8SCy Schubert 
50585732ac8SCy Schubert 
506c1d255d3SCy Schubert void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
50785732ac8SCy Schubert {
50885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
50985732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
51085732ac8SCy Schubert 	wpabuf_put_le16(msg, 1);
51185732ac8SCy Schubert 	wpabuf_put_u8(msg, status);
51285732ac8SCy Schubert }
51385732ac8SCy Schubert 
51485732ac8SCy Schubert 
515c1d255d3SCy Schubert void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
51685732ac8SCy Schubert {
51785732ac8SCy Schubert 	if (hash) {
51885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
51985732ac8SCy Schubert 		wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
52085732ac8SCy Schubert 		wpabuf_put_le16(msg, SHA256_MAC_LEN);
52185732ac8SCy Schubert 		wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
52285732ac8SCy Schubert 	}
52385732ac8SCy Schubert }
52485732ac8SCy Schubert 
52585732ac8SCy Schubert 
52685732ac8SCy Schubert static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
52785732ac8SCy Schubert 			       u16 num_modes, unsigned int freq)
52885732ac8SCy Schubert {
52985732ac8SCy Schubert 	u16 m;
53085732ac8SCy Schubert 	int c, flag;
53185732ac8SCy Schubert 
53285732ac8SCy Schubert 	if (!own_modes || !num_modes)
53385732ac8SCy Schubert 		return 1;
53485732ac8SCy Schubert 
53585732ac8SCy Schubert 	for (m = 0; m < num_modes; m++) {
53685732ac8SCy Schubert 		for (c = 0; c < own_modes[m].num_channels; c++) {
53785732ac8SCy Schubert 			if ((unsigned int) own_modes[m].channels[c].freq !=
53885732ac8SCy Schubert 			    freq)
53985732ac8SCy Schubert 				continue;
54085732ac8SCy Schubert 			flag = own_modes[m].channels[c].flag;
54185732ac8SCy Schubert 			if (!(flag & (HOSTAPD_CHAN_DISABLED |
54285732ac8SCy Schubert 				      HOSTAPD_CHAN_NO_IR |
54385732ac8SCy Schubert 				      HOSTAPD_CHAN_RADAR)))
54485732ac8SCy Schubert 				return 1;
54585732ac8SCy Schubert 		}
54685732ac8SCy Schubert 	}
54785732ac8SCy Schubert 
54885732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
54985732ac8SCy Schubert 	return 0;
55085732ac8SCy Schubert }
55185732ac8SCy Schubert 
55285732ac8SCy Schubert 
55385732ac8SCy Schubert static int freq_included(const unsigned int freqs[], unsigned int num,
55485732ac8SCy Schubert 			 unsigned int freq)
55585732ac8SCy Schubert {
55685732ac8SCy Schubert 	while (num > 0) {
55785732ac8SCy Schubert 		if (freqs[--num] == freq)
55885732ac8SCy Schubert 			return 1;
55985732ac8SCy Schubert 	}
56085732ac8SCy Schubert 	return 0;
56185732ac8SCy Schubert }
56285732ac8SCy Schubert 
56385732ac8SCy Schubert 
56485732ac8SCy Schubert static void freq_to_start(unsigned int freqs[], unsigned int num,
56585732ac8SCy Schubert 			  unsigned int freq)
56685732ac8SCy Schubert {
56785732ac8SCy Schubert 	unsigned int i;
56885732ac8SCy Schubert 
56985732ac8SCy Schubert 	for (i = 0; i < num; i++) {
57085732ac8SCy Schubert 		if (freqs[i] == freq)
57185732ac8SCy Schubert 			break;
57285732ac8SCy Schubert 	}
57385732ac8SCy Schubert 	if (i == 0 || i >= num)
57485732ac8SCy Schubert 		return;
57585732ac8SCy Schubert 	os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
57685732ac8SCy Schubert 	freqs[0] = freq;
57785732ac8SCy Schubert }
57885732ac8SCy Schubert 
57985732ac8SCy Schubert 
58085732ac8SCy Schubert static int dpp_channel_intersect(struct dpp_authentication *auth,
58185732ac8SCy Schubert 				 struct hostapd_hw_modes *own_modes,
58285732ac8SCy Schubert 				 u16 num_modes)
58385732ac8SCy Schubert {
58485732ac8SCy Schubert 	struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
58585732ac8SCy Schubert 	unsigned int i, freq;
58685732ac8SCy Schubert 
58785732ac8SCy Schubert 	for (i = 0; i < peer_bi->num_freq; i++) {
58885732ac8SCy Schubert 		freq = peer_bi->freq[i];
58985732ac8SCy Schubert 		if (freq_included(auth->freq, auth->num_freq, freq))
59085732ac8SCy Schubert 			continue;
59185732ac8SCy Schubert 		if (dpp_channel_ok_init(own_modes, num_modes, freq))
59285732ac8SCy Schubert 			auth->freq[auth->num_freq++] = freq;
59385732ac8SCy Schubert 	}
59485732ac8SCy Schubert 	if (!auth->num_freq) {
59585732ac8SCy Schubert 		wpa_printf(MSG_INFO,
59685732ac8SCy Schubert 			   "DPP: No available channels for initiating DPP Authentication");
59785732ac8SCy Schubert 		return -1;
59885732ac8SCy Schubert 	}
59985732ac8SCy Schubert 	auth->curr_freq = auth->freq[0];
60085732ac8SCy Schubert 	return 0;
60185732ac8SCy Schubert }
60285732ac8SCy Schubert 
60385732ac8SCy Schubert 
60485732ac8SCy Schubert static int dpp_channel_local_list(struct dpp_authentication *auth,
60585732ac8SCy Schubert 				  struct hostapd_hw_modes *own_modes,
60685732ac8SCy Schubert 				  u16 num_modes)
60785732ac8SCy Schubert {
60885732ac8SCy Schubert 	u16 m;
60985732ac8SCy Schubert 	int c, flag;
61085732ac8SCy Schubert 	unsigned int freq;
61185732ac8SCy Schubert 
61285732ac8SCy Schubert 	auth->num_freq = 0;
61385732ac8SCy Schubert 
61485732ac8SCy Schubert 	if (!own_modes || !num_modes) {
61585732ac8SCy Schubert 		auth->freq[0] = 2412;
61685732ac8SCy Schubert 		auth->freq[1] = 2437;
61785732ac8SCy Schubert 		auth->freq[2] = 2462;
61885732ac8SCy Schubert 		auth->num_freq = 3;
61985732ac8SCy Schubert 		return 0;
62085732ac8SCy Schubert 	}
62185732ac8SCy Schubert 
62285732ac8SCy Schubert 	for (m = 0; m < num_modes; m++) {
62385732ac8SCy Schubert 		for (c = 0; c < own_modes[m].num_channels; c++) {
62485732ac8SCy Schubert 			freq = own_modes[m].channels[c].freq;
62585732ac8SCy Schubert 			flag = own_modes[m].channels[c].flag;
62685732ac8SCy Schubert 			if (flag & (HOSTAPD_CHAN_DISABLED |
62785732ac8SCy Schubert 				    HOSTAPD_CHAN_NO_IR |
62885732ac8SCy Schubert 				    HOSTAPD_CHAN_RADAR))
62985732ac8SCy Schubert 				continue;
63085732ac8SCy Schubert 			if (freq_included(auth->freq, auth->num_freq, freq))
63185732ac8SCy Schubert 				continue;
63285732ac8SCy Schubert 			auth->freq[auth->num_freq++] = freq;
63385732ac8SCy Schubert 			if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
63485732ac8SCy Schubert 				m = num_modes;
63585732ac8SCy Schubert 				break;
63685732ac8SCy Schubert 			}
63785732ac8SCy Schubert 		}
63885732ac8SCy Schubert 	}
63985732ac8SCy Schubert 
64085732ac8SCy Schubert 	return auth->num_freq == 0 ? -1 : 0;
64185732ac8SCy Schubert }
64285732ac8SCy Schubert 
64385732ac8SCy Schubert 
644c1d255d3SCy Schubert int dpp_prepare_channel_list(struct dpp_authentication *auth,
645c1d255d3SCy Schubert 			     unsigned int neg_freq,
646c1d255d3SCy Schubert 			     struct hostapd_hw_modes *own_modes, u16 num_modes)
64785732ac8SCy Schubert {
64885732ac8SCy Schubert 	int res;
64985732ac8SCy Schubert 	char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
65085732ac8SCy Schubert 	unsigned int i;
65185732ac8SCy Schubert 
652c1d255d3SCy Schubert 	if (!own_modes) {
653c1d255d3SCy Schubert 		if (!neg_freq)
654c1d255d3SCy Schubert 			return -1;
655c1d255d3SCy Schubert 		auth->num_freq = 1;
656c1d255d3SCy Schubert 		auth->freq[0] = neg_freq;
657c1d255d3SCy Schubert 		auth->curr_freq = neg_freq;
658c1d255d3SCy Schubert 		return 0;
659c1d255d3SCy Schubert 	}
660c1d255d3SCy Schubert 
66185732ac8SCy Schubert 	if (auth->peer_bi->num_freq > 0)
66285732ac8SCy Schubert 		res = dpp_channel_intersect(auth, own_modes, num_modes);
66385732ac8SCy Schubert 	else
66485732ac8SCy Schubert 		res = dpp_channel_local_list(auth, own_modes, num_modes);
66585732ac8SCy Schubert 	if (res < 0)
66685732ac8SCy Schubert 		return res;
66785732ac8SCy Schubert 
66885732ac8SCy Schubert 	/* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
66985732ac8SCy Schubert 	 * likely channels first. */
67085732ac8SCy Schubert 	freq_to_start(auth->freq, auth->num_freq, 2462);
67185732ac8SCy Schubert 	freq_to_start(auth->freq, auth->num_freq, 2412);
67285732ac8SCy Schubert 	freq_to_start(auth->freq, auth->num_freq, 2437);
67385732ac8SCy Schubert 
67485732ac8SCy Schubert 	auth->freq_idx = 0;
67585732ac8SCy Schubert 	auth->curr_freq = auth->freq[0];
67685732ac8SCy Schubert 
67785732ac8SCy Schubert 	pos = freqs;
67885732ac8SCy Schubert 	end = pos + sizeof(freqs);
67985732ac8SCy Schubert 	for (i = 0; i < auth->num_freq; i++) {
68085732ac8SCy Schubert 		res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
68185732ac8SCy Schubert 		if (os_snprintf_error(end - pos, res))
68285732ac8SCy Schubert 			break;
68385732ac8SCy Schubert 		pos += res;
68485732ac8SCy Schubert 	}
68585732ac8SCy Schubert 	*pos = '\0';
68685732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
68785732ac8SCy Schubert 		   freqs);
68885732ac8SCy Schubert 
68985732ac8SCy Schubert 	return 0;
69085732ac8SCy Schubert }
69185732ac8SCy Schubert 
69285732ac8SCy Schubert 
693c1d255d3SCy Schubert int dpp_gen_uri(struct dpp_bootstrap_info *bi)
69485732ac8SCy Schubert {
695c1d255d3SCy Schubert 	char macstr[ETH_ALEN * 2 + 10];
69685732ac8SCy Schubert 	size_t len;
697*a90b9d01SCy Schubert 	char supp_curves[10];
698*a90b9d01SCy Schubert 	char host[100];
69985732ac8SCy Schubert 
70085732ac8SCy Schubert 	len = 4; /* "DPP:" */
701c1d255d3SCy Schubert 	if (bi->chan)
702c1d255d3SCy Schubert 		len += 3 + os_strlen(bi->chan); /* C:...; */
703c1d255d3SCy Schubert 	if (is_zero_ether_addr(bi->mac_addr))
704c1d255d3SCy Schubert 		macstr[0] = '\0';
705c1d255d3SCy Schubert 	else
706c1d255d3SCy Schubert 		os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
707c1d255d3SCy Schubert 			    MAC2STR(bi->mac_addr));
708c1d255d3SCy Schubert 	len += os_strlen(macstr); /* M:...; */
709c1d255d3SCy Schubert 	if (bi->info)
710c1d255d3SCy Schubert 		len += 3 + os_strlen(bi->info); /* I:...; */
711c1d255d3SCy Schubert #ifdef CONFIG_DPP2
712c1d255d3SCy Schubert 	len += 4; /* V:2; */
713c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
714c1d255d3SCy Schubert 	len += 4 + os_strlen(bi->pk); /* K:...;; */
715c1d255d3SCy Schubert 
716*a90b9d01SCy Schubert 	if (bi->supported_curves) {
717*a90b9d01SCy Schubert 		u8 val = bi->supported_curves;
718*a90b9d01SCy Schubert 
719*a90b9d01SCy Schubert 		if (val & 0xf0) {
720*a90b9d01SCy Schubert 			val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
721*a90b9d01SCy Schubert 			len += os_snprintf(supp_curves, sizeof(supp_curves),
722*a90b9d01SCy Schubert 					   "B:%02x;", val);
723*a90b9d01SCy Schubert 		} else {
724*a90b9d01SCy Schubert 			len += os_snprintf(supp_curves, sizeof(supp_curves),
725*a90b9d01SCy Schubert 					   "B:%x;", val);
726*a90b9d01SCy Schubert 		}
727*a90b9d01SCy Schubert 	} else {
728*a90b9d01SCy Schubert 		supp_curves[0] = '\0';
729*a90b9d01SCy Schubert 	}
730*a90b9d01SCy Schubert 
731*a90b9d01SCy Schubert 	host[0] = '\0';
732*a90b9d01SCy Schubert 	if (bi->host) {
733*a90b9d01SCy Schubert 		char buf[100];
734*a90b9d01SCy Schubert 		const char *addr;
735*a90b9d01SCy Schubert 
736*a90b9d01SCy Schubert 		addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
737*a90b9d01SCy Schubert 		if (!addr)
738*a90b9d01SCy Schubert 			return -1;
739*a90b9d01SCy Schubert 		if (bi->port == DPP_TCP_PORT)
740*a90b9d01SCy Schubert 			len += os_snprintf(host, sizeof(host), "H:%s;", addr);
741*a90b9d01SCy Schubert 		else if (bi->host->af == AF_INET)
742*a90b9d01SCy Schubert 			len += os_snprintf(host, sizeof(host), "H:%s:%u;",
743*a90b9d01SCy Schubert 					   addr, bi->port);
744*a90b9d01SCy Schubert 		else
745*a90b9d01SCy Schubert 			len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
746*a90b9d01SCy Schubert 					   addr, bi->port);
747*a90b9d01SCy Schubert 	}
748*a90b9d01SCy Schubert 
749c1d255d3SCy Schubert 	os_free(bi->uri);
75085732ac8SCy Schubert 	bi->uri = os_malloc(len + 1);
75185732ac8SCy Schubert 	if (!bi->uri)
75285732ac8SCy Schubert 		return -1;
753*a90b9d01SCy Schubert 	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
754c1d255d3SCy Schubert 		    bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
755c1d255d3SCy Schubert 		    bi->chan ? ";" : "",
756c1d255d3SCy Schubert 		    macstr,
757c1d255d3SCy Schubert 		    bi->info ? "I:" : "", bi->info ? bi->info : "",
758c1d255d3SCy Schubert 		    bi->info ? ";" : "",
75932a95656SCy Schubert 		    DPP_VERSION == 3 ? "V:3;" :
76032a95656SCy Schubert 		    (DPP_VERSION == 2 ? "V:2;" : ""),
761*a90b9d01SCy Schubert 		    supp_curves,
762*a90b9d01SCy Schubert 		    host,
763c1d255d3SCy Schubert 		    bi->pk);
764c1d255d3SCy Schubert 	return 0;
76585732ac8SCy Schubert }
76685732ac8SCy Schubert 
76785732ac8SCy Schubert 
768c1d255d3SCy Schubert struct dpp_authentication *
769c1d255d3SCy Schubert dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
77085732ac8SCy Schubert {
77185732ac8SCy Schubert 	struct dpp_authentication *auth;
77285732ac8SCy Schubert 
77385732ac8SCy Schubert 	auth = os_zalloc(sizeof(*auth));
77485732ac8SCy Schubert 	if (!auth)
77585732ac8SCy Schubert 		return NULL;
776c1d255d3SCy Schubert 	auth->global = dpp;
77785732ac8SCy Schubert 	auth->msg_ctx = msg_ctx;
778c1d255d3SCy Schubert 	auth->conf_resp_status = 255;
77985732ac8SCy Schubert 	return auth;
78085732ac8SCy Schubert }
78185732ac8SCy Schubert 
78285732ac8SCy Schubert 
7834bc52338SCy Schubert static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
78485732ac8SCy Schubert 					       const char *json)
78585732ac8SCy Schubert {
78685732ac8SCy Schubert 	size_t nonce_len;
78785732ac8SCy Schubert 	size_t json_len, clear_len;
788*a90b9d01SCy Schubert 	struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
78985732ac8SCy Schubert 	u8 *wrapped;
79085732ac8SCy Schubert 	size_t attr_len;
791*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
792*a90b9d01SCy Schubert 	u8 auth_i[DPP_MAX_HASH_LEN];
793*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
79485732ac8SCy Schubert 
79585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
79685732ac8SCy Schubert 
79785732ac8SCy Schubert 	nonce_len = auth->curve->nonce_len;
79885732ac8SCy Schubert 	if (random_get_bytes(auth->e_nonce, nonce_len)) {
79985732ac8SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
80085732ac8SCy Schubert 		goto fail;
80185732ac8SCy Schubert 	}
80285732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
80385732ac8SCy Schubert 	json_len = os_strlen(json);
804c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
80585732ac8SCy Schubert 
80685732ac8SCy Schubert 	/* { E-nonce, configAttrib }ke */
80785732ac8SCy Schubert 	clear_len = 4 + nonce_len + 4 + json_len;
808*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
809*a90b9d01SCy Schubert 	if (auth->waiting_new_key) {
810*a90b9d01SCy Schubert 		pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
811*a90b9d01SCy Schubert 		if (!pe)
812*a90b9d01SCy Schubert 			goto fail;
813*a90b9d01SCy Schubert 		clear_len += 4 + wpabuf_len(pe);
814*a90b9d01SCy Schubert 
815*a90b9d01SCy Schubert 		if (dpp_derive_auth_i(auth, auth_i) < 0)
816*a90b9d01SCy Schubert 			goto fail;
817*a90b9d01SCy Schubert 		clear_len += 4 + auth->curve->hash_len;
818*a90b9d01SCy Schubert 	}
819*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
82085732ac8SCy Schubert 	clear = wpabuf_alloc(clear_len);
82185732ac8SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
82285732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
82385732ac8SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
82485732ac8SCy Schubert 		attr_len += 5;
82585732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
82685732ac8SCy Schubert 	msg = wpabuf_alloc(attr_len);
82785732ac8SCy Schubert 	if (!clear || !msg)
82885732ac8SCy Schubert 		goto fail;
82985732ac8SCy Schubert 
83085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
83185732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
83285732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
83385732ac8SCy Schubert 		goto skip_e_nonce;
83485732ac8SCy Schubert 	}
83585732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
83685732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
83785732ac8SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
83885732ac8SCy Schubert 		wpabuf_put_le16(clear, nonce_len - 1);
83985732ac8SCy Schubert 		wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
84085732ac8SCy Schubert 		goto skip_e_nonce;
84185732ac8SCy Schubert 	}
84285732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
84385732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
84485732ac8SCy Schubert 		goto skip_wrapped_data;
84585732ac8SCy Schubert 	}
84685732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
84785732ac8SCy Schubert 
84885732ac8SCy Schubert 	/* E-nonce */
84985732ac8SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
85085732ac8SCy Schubert 	wpabuf_put_le16(clear, nonce_len);
85185732ac8SCy Schubert 	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
85285732ac8SCy Schubert 
85385732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
85485732ac8SCy Schubert skip_e_nonce:
85585732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
85685732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
85785732ac8SCy Schubert 		goto skip_conf_attr_obj;
85885732ac8SCy Schubert 	}
85985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
86085732ac8SCy Schubert 
861*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
862*a90b9d01SCy Schubert 	if (pe) {
863*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Pe");
864*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
865*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, wpabuf_len(pe));
866*a90b9d01SCy Schubert 		wpabuf_put_buf(clear, pe);
867*a90b9d01SCy Schubert 	}
868*a90b9d01SCy Schubert 	if (auth->waiting_new_key) {
869*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
870*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
871*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, auth->curve->hash_len);
872*a90b9d01SCy Schubert 		wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
873*a90b9d01SCy Schubert 	}
874*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
875*a90b9d01SCy Schubert 
87685732ac8SCy Schubert 	/* configAttrib */
87785732ac8SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
87885732ac8SCy Schubert 	wpabuf_put_le16(clear, json_len);
87985732ac8SCy Schubert 	wpabuf_put_data(clear, json, json_len);
88085732ac8SCy Schubert 
88185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
88285732ac8SCy Schubert skip_conf_attr_obj:
88385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
88485732ac8SCy Schubert 
88585732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
88685732ac8SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
88785732ac8SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
88885732ac8SCy Schubert 
88985732ac8SCy Schubert 	/* No AES-SIV AD */
89085732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
89185732ac8SCy Schubert 	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
89285732ac8SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
89385732ac8SCy Schubert 			    0, NULL, NULL, wrapped) < 0)
89485732ac8SCy Schubert 		goto fail;
89585732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
89685732ac8SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
89785732ac8SCy Schubert 
89885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
89985732ac8SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
90085732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
90185732ac8SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
90285732ac8SCy Schubert 	}
90385732ac8SCy Schubert skip_wrapped_data:
90485732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
90585732ac8SCy Schubert 
90685732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG,
90785732ac8SCy Schubert 			"DPP: Configuration Request frame attributes", msg);
908*a90b9d01SCy Schubert out:
90985732ac8SCy Schubert 	wpabuf_free(clear);
910*a90b9d01SCy Schubert 	wpabuf_free(pe);
91185732ac8SCy Schubert 	return msg;
91285732ac8SCy Schubert 
91385732ac8SCy Schubert fail:
91485732ac8SCy Schubert 	wpabuf_free(msg);
915*a90b9d01SCy Schubert 	msg = NULL;
916*a90b9d01SCy Schubert 	goto out;
91785732ac8SCy Schubert }
91885732ac8SCy Schubert 
91985732ac8SCy Schubert 
920c1d255d3SCy Schubert void dpp_write_adv_proto(struct wpabuf *buf)
9214bc52338SCy Schubert {
9224bc52338SCy Schubert 	/* Advertisement Protocol IE */
9234bc52338SCy Schubert 	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
9244bc52338SCy Schubert 	wpabuf_put_u8(buf, 8); /* Length */
9254bc52338SCy Schubert 	wpabuf_put_u8(buf, 0x7f);
9264bc52338SCy Schubert 	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
9274bc52338SCy Schubert 	wpabuf_put_u8(buf, 5);
9284bc52338SCy Schubert 	wpabuf_put_be24(buf, OUI_WFA);
9294bc52338SCy Schubert 	wpabuf_put_u8(buf, DPP_OUI_TYPE);
9304bc52338SCy Schubert 	wpabuf_put_u8(buf, 0x01);
9314bc52338SCy Schubert }
9324bc52338SCy Schubert 
9334bc52338SCy Schubert 
934c1d255d3SCy Schubert void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
9354bc52338SCy Schubert {
9364bc52338SCy Schubert 	/* GAS Query */
9374bc52338SCy Schubert 	wpabuf_put_le16(buf, wpabuf_len(query));
9384bc52338SCy Schubert 	wpabuf_put_buf(buf, query);
9394bc52338SCy Schubert }
9404bc52338SCy Schubert 
9414bc52338SCy Schubert 
9424bc52338SCy Schubert struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
9434bc52338SCy Schubert 				   const char *json)
9444bc52338SCy Schubert {
9454bc52338SCy Schubert 	struct wpabuf *buf, *conf_req;
9464bc52338SCy Schubert 
9474bc52338SCy Schubert 	conf_req = dpp_build_conf_req_attr(auth, json);
9484bc52338SCy Schubert 	if (!conf_req) {
9494bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
9504bc52338SCy Schubert 			   "DPP: No configuration request data available");
9514bc52338SCy Schubert 		return NULL;
9524bc52338SCy Schubert 	}
9534bc52338SCy Schubert 
9544bc52338SCy Schubert 	buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
9554bc52338SCy Schubert 	if (!buf) {
9564bc52338SCy Schubert 		wpabuf_free(conf_req);
9574bc52338SCy Schubert 		return NULL;
9584bc52338SCy Schubert 	}
9594bc52338SCy Schubert 
9604bc52338SCy Schubert 	dpp_write_adv_proto(buf);
9614bc52338SCy Schubert 	dpp_write_gas_query(buf, conf_req);
9624bc52338SCy Schubert 	wpabuf_free(conf_req);
9634bc52338SCy Schubert 	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
9644bc52338SCy Schubert 
9654bc52338SCy Schubert 	return buf;
9664bc52338SCy Schubert }
9674bc52338SCy Schubert 
9684bc52338SCy Schubert 
969c1d255d3SCy Schubert struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
970c1d255d3SCy Schubert 					  const char *name,
971c1d255d3SCy Schubert 					  enum dpp_netrole netrole,
972*a90b9d01SCy Schubert 					  const char *mud_url, int *opclasses,
973*a90b9d01SCy Schubert 					  const char *extra_name,
974*a90b9d01SCy Schubert 					  const char *extra_value)
97585732ac8SCy Schubert {
976c1d255d3SCy Schubert 	size_t len, name_len;
977c1d255d3SCy Schubert 	const char *tech = "infra";
978c1d255d3SCy Schubert 	const char *dpp_name;
979*a90b9d01SCy Schubert 	struct wpabuf *buf = NULL, *json = NULL;
980c1d255d3SCy Schubert 	char *csr = NULL;
98185732ac8SCy Schubert 
98285732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
983c1d255d3SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
984c1d255d3SCy Schubert 		static const char *bogus_tech = "knfra";
98585732ac8SCy Schubert 
986c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
987c1d255d3SCy Schubert 		tech = bogus_tech;
98885732ac8SCy Schubert 	}
98985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
99085732ac8SCy Schubert 
991c1d255d3SCy Schubert 	dpp_name = name ? name : "Test";
992c1d255d3SCy Schubert 	name_len = os_strlen(dpp_name);
99385732ac8SCy Schubert 
994c1d255d3SCy Schubert 	len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
995c1d255d3SCy Schubert 	if (mud_url && mud_url[0])
996c1d255d3SCy Schubert 		len += 10 + os_strlen(mud_url);
997*a90b9d01SCy Schubert 	if (extra_name && extra_value && extra_name[0] && extra_value[0])
998*a90b9d01SCy Schubert 		len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
9994bc52338SCy Schubert #ifdef CONFIG_DPP2
1000c1d255d3SCy Schubert 	if (auth->csr) {
1001c1d255d3SCy Schubert 		size_t csr_len;
100285732ac8SCy Schubert 
1003c1d255d3SCy Schubert 		csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1004c1d255d3SCy Schubert 					  wpabuf_len(auth->csr), &csr_len);
1005c1d255d3SCy Schubert 		if (!csr)
1006*a90b9d01SCy Schubert 			goto fail;
1007c1d255d3SCy Schubert 		len += 30 + csr_len;
10084bc52338SCy Schubert 	}
10094bc52338SCy Schubert #endif /* CONFIG_DPP2 */
1010c1d255d3SCy Schubert 	json = wpabuf_alloc(len);
1011c1d255d3SCy Schubert 	if (!json)
1012*a90b9d01SCy Schubert 		goto fail;
10134bc52338SCy Schubert 
1014c1d255d3SCy Schubert 	json_start_object(json, NULL);
1015*a90b9d01SCy Schubert 	if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1016*a90b9d01SCy Schubert 		goto fail;
1017c1d255d3SCy Schubert 	json_value_sep(json);
1018c1d255d3SCy Schubert 	json_add_string(json, "wi-fi_tech", tech);
1019c1d255d3SCy Schubert 	json_value_sep(json);
1020c1d255d3SCy Schubert 	json_add_string(json, "netRole", dpp_netrole_str(netrole));
1021c1d255d3SCy Schubert 	if (mud_url && mud_url[0]) {
1022c1d255d3SCy Schubert 		json_value_sep(json);
1023c1d255d3SCy Schubert 		json_add_string(json, "mudurl", mud_url);
102485732ac8SCy Schubert 	}
1025c1d255d3SCy Schubert 	if (opclasses) {
1026c1d255d3SCy Schubert 		int i;
102785732ac8SCy Schubert 
1028c1d255d3SCy Schubert 		json_value_sep(json);
1029c1d255d3SCy Schubert 		json_start_array(json, "bandSupport");
1030c1d255d3SCy Schubert 		for (i = 0; opclasses[i]; i++)
1031c1d255d3SCy Schubert 			wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
1032c1d255d3SCy Schubert 		json_end_array(json);
103385732ac8SCy Schubert 	}
1034c1d255d3SCy Schubert 	if (csr) {
1035c1d255d3SCy Schubert 		json_value_sep(json);
1036c1d255d3SCy Schubert 		json_add_string(json, "pkcs10", csr);
103785732ac8SCy Schubert 	}
1038*a90b9d01SCy Schubert 	if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1039*a90b9d01SCy Schubert 		json_value_sep(json);
1040*a90b9d01SCy Schubert 		wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1041*a90b9d01SCy Schubert 	}
1042c1d255d3SCy Schubert 	json_end_object(json);
104385732ac8SCy Schubert 
1044c1d255d3SCy Schubert 	buf = dpp_build_conf_req(auth, wpabuf_head(json));
1045*a90b9d01SCy Schubert fail:
1046c1d255d3SCy Schubert 	wpabuf_free(json);
1047c1d255d3SCy Schubert 	os_free(csr);
104885732ac8SCy Schubert 
1049c1d255d3SCy Schubert 	return buf;
105085732ac8SCy Schubert }
105185732ac8SCy Schubert 
105285732ac8SCy Schubert 
10534bc52338SCy Schubert static int bin_str_eq(const char *val, size_t len, const char *cmp)
10544bc52338SCy Schubert {
10554bc52338SCy Schubert 	return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
10564bc52338SCy Schubert }
10574bc52338SCy Schubert 
10584bc52338SCy Schubert 
10594bc52338SCy Schubert struct dpp_configuration * dpp_configuration_alloc(const char *type)
10604bc52338SCy Schubert {
10614bc52338SCy Schubert 	struct dpp_configuration *conf;
10624bc52338SCy Schubert 	const char *end;
10634bc52338SCy Schubert 	size_t len;
10644bc52338SCy Schubert 
10654bc52338SCy Schubert 	conf = os_zalloc(sizeof(*conf));
10664bc52338SCy Schubert 	if (!conf)
10674bc52338SCy Schubert 		goto fail;
10684bc52338SCy Schubert 
10694bc52338SCy Schubert 	end = os_strchr(type, ' ');
10704bc52338SCy Schubert 	if (end)
10714bc52338SCy Schubert 		len = end - type;
10724bc52338SCy Schubert 	else
10734bc52338SCy Schubert 		len = os_strlen(type);
10744bc52338SCy Schubert 
10754bc52338SCy Schubert 	if (bin_str_eq(type, len, "psk"))
10764bc52338SCy Schubert 		conf->akm = DPP_AKM_PSK;
10774bc52338SCy Schubert 	else if (bin_str_eq(type, len, "sae"))
10784bc52338SCy Schubert 		conf->akm = DPP_AKM_SAE;
10794bc52338SCy Schubert 	else if (bin_str_eq(type, len, "psk-sae") ||
10804bc52338SCy Schubert 		 bin_str_eq(type, len, "psk+sae"))
10814bc52338SCy Schubert 		conf->akm = DPP_AKM_PSK_SAE;
10824bc52338SCy Schubert 	else if (bin_str_eq(type, len, "sae-dpp") ||
10834bc52338SCy Schubert 		 bin_str_eq(type, len, "dpp+sae"))
10844bc52338SCy Schubert 		conf->akm = DPP_AKM_SAE_DPP;
10854bc52338SCy Schubert 	else if (bin_str_eq(type, len, "psk-sae-dpp") ||
10864bc52338SCy Schubert 		 bin_str_eq(type, len, "dpp+psk+sae"))
10874bc52338SCy Schubert 		conf->akm = DPP_AKM_PSK_SAE_DPP;
10884bc52338SCy Schubert 	else if (bin_str_eq(type, len, "dpp"))
10894bc52338SCy Schubert 		conf->akm = DPP_AKM_DPP;
1090c1d255d3SCy Schubert 	else if (bin_str_eq(type, len, "dot1x"))
1091c1d255d3SCy Schubert 		conf->akm = DPP_AKM_DOT1X;
10924bc52338SCy Schubert 	else
10934bc52338SCy Schubert 		goto fail;
10944bc52338SCy Schubert 
10954bc52338SCy Schubert 	return conf;
10964bc52338SCy Schubert fail:
10974bc52338SCy Schubert 	dpp_configuration_free(conf);
10984bc52338SCy Schubert 	return NULL;
10994bc52338SCy Schubert }
11004bc52338SCy Schubert 
11014bc52338SCy Schubert 
11024bc52338SCy Schubert int dpp_akm_psk(enum dpp_akm akm)
11034bc52338SCy Schubert {
11044bc52338SCy Schubert 	return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
11054bc52338SCy Schubert 		akm == DPP_AKM_PSK_SAE_DPP;
11064bc52338SCy Schubert }
11074bc52338SCy Schubert 
11084bc52338SCy Schubert 
11094bc52338SCy Schubert int dpp_akm_sae(enum dpp_akm akm)
11104bc52338SCy Schubert {
11114bc52338SCy Schubert 	return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
11124bc52338SCy Schubert 		akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
11134bc52338SCy Schubert }
11144bc52338SCy Schubert 
11154bc52338SCy Schubert 
11164bc52338SCy Schubert int dpp_akm_legacy(enum dpp_akm akm)
11174bc52338SCy Schubert {
11184bc52338SCy Schubert 	return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
11194bc52338SCy Schubert 		akm == DPP_AKM_SAE;
11204bc52338SCy Schubert }
11214bc52338SCy Schubert 
11224bc52338SCy Schubert 
11234bc52338SCy Schubert int dpp_akm_dpp(enum dpp_akm akm)
11244bc52338SCy Schubert {
11254bc52338SCy Schubert 	return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
11264bc52338SCy Schubert 		akm == DPP_AKM_PSK_SAE_DPP;
11274bc52338SCy Schubert }
11284bc52338SCy Schubert 
11294bc52338SCy Schubert 
11304bc52338SCy Schubert int dpp_akm_ver2(enum dpp_akm akm)
11314bc52338SCy Schubert {
11324bc52338SCy Schubert 	return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
11334bc52338SCy Schubert }
11344bc52338SCy Schubert 
11354bc52338SCy Schubert 
11364bc52338SCy Schubert int dpp_configuration_valid(const struct dpp_configuration *conf)
11374bc52338SCy Schubert {
11384bc52338SCy Schubert 	if (conf->ssid_len == 0)
11394bc52338SCy Schubert 		return 0;
11404bc52338SCy Schubert 	if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
11414bc52338SCy Schubert 		return 0;
11424bc52338SCy Schubert 	if (dpp_akm_sae(conf->akm) && !conf->passphrase)
11434bc52338SCy Schubert 		return 0;
11444bc52338SCy Schubert 	return 1;
11454bc52338SCy Schubert }
11464bc52338SCy Schubert 
11474bc52338SCy Schubert 
114885732ac8SCy Schubert void dpp_configuration_free(struct dpp_configuration *conf)
114985732ac8SCy Schubert {
115085732ac8SCy Schubert 	if (!conf)
115185732ac8SCy Schubert 		return;
115285732ac8SCy Schubert 	str_clear_free(conf->passphrase);
115385732ac8SCy Schubert 	os_free(conf->group_id);
1154c1d255d3SCy Schubert 	os_free(conf->csrattrs);
1155*a90b9d01SCy Schubert 	os_free(conf->extra_name);
1156*a90b9d01SCy Schubert 	os_free(conf->extra_value);
115785732ac8SCy Schubert 	bin_clear_free(conf, sizeof(*conf));
115885732ac8SCy Schubert }
115985732ac8SCy Schubert 
116085732ac8SCy Schubert 
1161c1d255d3SCy Schubert static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1162c1d255d3SCy Schubert 					  const char *cmd, int idx)
11634bc52338SCy Schubert {
11644bc52338SCy Schubert 	const char *pos, *end;
11654bc52338SCy Schubert 	struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
11664bc52338SCy Schubert 	struct dpp_configuration *conf = NULL;
1167c1d255d3SCy Schubert 	size_t len;
11684bc52338SCy Schubert 
11694bc52338SCy Schubert 	pos = os_strstr(cmd, " conf=sta-");
11704bc52338SCy Schubert 	if (pos) {
11714bc52338SCy Schubert 		conf_sta = dpp_configuration_alloc(pos + 10);
11724bc52338SCy Schubert 		if (!conf_sta)
11734bc52338SCy Schubert 			goto fail;
1174c1d255d3SCy Schubert 		conf_sta->netrole = DPP_NETROLE_STA;
11754bc52338SCy Schubert 		conf = conf_sta;
11764bc52338SCy Schubert 	}
11774bc52338SCy Schubert 
11784bc52338SCy Schubert 	pos = os_strstr(cmd, " conf=ap-");
11794bc52338SCy Schubert 	if (pos) {
11804bc52338SCy Schubert 		conf_ap = dpp_configuration_alloc(pos + 9);
11814bc52338SCy Schubert 		if (!conf_ap)
11824bc52338SCy Schubert 			goto fail;
1183c1d255d3SCy Schubert 		conf_ap->netrole = DPP_NETROLE_AP;
11844bc52338SCy Schubert 		conf = conf_ap;
11854bc52338SCy Schubert 	}
11864bc52338SCy Schubert 
1187c1d255d3SCy Schubert 	pos = os_strstr(cmd, " conf=configurator");
1188c1d255d3SCy Schubert 	if (pos)
1189c1d255d3SCy Schubert 		auth->provision_configurator = 1;
1190c1d255d3SCy Schubert 
11914bc52338SCy Schubert 	if (!conf)
11924bc52338SCy Schubert 		return 0;
11934bc52338SCy Schubert 
11944bc52338SCy Schubert 	pos = os_strstr(cmd, " ssid=");
11954bc52338SCy Schubert 	if (pos) {
11964bc52338SCy Schubert 		pos += 6;
11974bc52338SCy Schubert 		end = os_strchr(pos, ' ');
11984bc52338SCy Schubert 		conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
11994bc52338SCy Schubert 		conf->ssid_len /= 2;
12004bc52338SCy Schubert 		if (conf->ssid_len > sizeof(conf->ssid) ||
12014bc52338SCy Schubert 		    hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
12024bc52338SCy Schubert 			goto fail;
12034bc52338SCy Schubert 	} else {
12044bc52338SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
12054bc52338SCy Schubert 		/* use a default SSID for legacy testing reasons */
12064bc52338SCy Schubert 		os_memcpy(conf->ssid, "test", 4);
12074bc52338SCy Schubert 		conf->ssid_len = 4;
12084bc52338SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
12094bc52338SCy Schubert 		goto fail;
12104bc52338SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
12114bc52338SCy Schubert 	}
12124bc52338SCy Schubert 
1213c1d255d3SCy Schubert 	pos = os_strstr(cmd, " ssid_charset=");
1214c1d255d3SCy Schubert 	if (pos) {
1215c1d255d3SCy Schubert 		if (conf_ap) {
1216c1d255d3SCy Schubert 			wpa_printf(MSG_INFO,
1217c1d255d3SCy Schubert 				   "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1218c1d255d3SCy Schubert 			goto fail;
1219c1d255d3SCy Schubert 		}
1220c1d255d3SCy Schubert 		conf->ssid_charset = atoi(pos + 14);
1221c1d255d3SCy Schubert 	}
1222c1d255d3SCy Schubert 
12234bc52338SCy Schubert 	pos = os_strstr(cmd, " pass=");
12244bc52338SCy Schubert 	if (pos) {
12254bc52338SCy Schubert 		size_t pass_len;
12264bc52338SCy Schubert 
12274bc52338SCy Schubert 		pos += 6;
12284bc52338SCy Schubert 		end = os_strchr(pos, ' ');
12294bc52338SCy Schubert 		pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
12304bc52338SCy Schubert 		pass_len /= 2;
12314bc52338SCy Schubert 		if (pass_len > 63 || pass_len < 8)
12324bc52338SCy Schubert 			goto fail;
12334bc52338SCy Schubert 		conf->passphrase = os_zalloc(pass_len + 1);
12344bc52338SCy Schubert 		if (!conf->passphrase ||
12354bc52338SCy Schubert 		    hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
12364bc52338SCy Schubert 			goto fail;
12374bc52338SCy Schubert 	}
12384bc52338SCy Schubert 
12394bc52338SCy Schubert 	pos = os_strstr(cmd, " psk=");
12404bc52338SCy Schubert 	if (pos) {
12414bc52338SCy Schubert 		pos += 5;
12424bc52338SCy Schubert 		if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
12434bc52338SCy Schubert 			goto fail;
12444bc52338SCy Schubert 		conf->psk_set = 1;
12454bc52338SCy Schubert 	}
12464bc52338SCy Schubert 
12474bc52338SCy Schubert 	pos = os_strstr(cmd, " group_id=");
12484bc52338SCy Schubert 	if (pos) {
12494bc52338SCy Schubert 		size_t group_id_len;
12504bc52338SCy Schubert 
12514bc52338SCy Schubert 		pos += 10;
12524bc52338SCy Schubert 		end = os_strchr(pos, ' ');
12534bc52338SCy Schubert 		group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
12544bc52338SCy Schubert 		conf->group_id = os_malloc(group_id_len + 1);
12554bc52338SCy Schubert 		if (!conf->group_id)
12564bc52338SCy Schubert 			goto fail;
12574bc52338SCy Schubert 		os_memcpy(conf->group_id, pos, group_id_len);
12584bc52338SCy Schubert 		conf->group_id[group_id_len] = '\0';
12594bc52338SCy Schubert 	}
12604bc52338SCy Schubert 
12614bc52338SCy Schubert 	pos = os_strstr(cmd, " expiry=");
12624bc52338SCy Schubert 	if (pos) {
12634bc52338SCy Schubert 		long int val;
12644bc52338SCy Schubert 
12654bc52338SCy Schubert 		pos += 8;
12664bc52338SCy Schubert 		val = strtol(pos, NULL, 0);
12674bc52338SCy Schubert 		if (val <= 0)
12684bc52338SCy Schubert 			goto fail;
12694bc52338SCy Schubert 		conf->netaccesskey_expiry = val;
12704bc52338SCy Schubert 	}
12714bc52338SCy Schubert 
1272c1d255d3SCy Schubert 	pos = os_strstr(cmd, " csrattrs=");
1273c1d255d3SCy Schubert 	if (pos) {
1274c1d255d3SCy Schubert 		pos += 10;
1275c1d255d3SCy Schubert 		end = os_strchr(pos, ' ');
1276c1d255d3SCy Schubert 		len = end ? (size_t) (end - pos) : os_strlen(pos);
1277c1d255d3SCy Schubert 		conf->csrattrs = os_zalloc(len + 1);
1278c1d255d3SCy Schubert 		if (!conf->csrattrs)
1279c1d255d3SCy Schubert 			goto fail;
1280c1d255d3SCy Schubert 		os_memcpy(conf->csrattrs, pos, len);
1281c1d255d3SCy Schubert 	}
1282c1d255d3SCy Schubert 
1283*a90b9d01SCy Schubert 	pos = os_strstr(cmd, " conf_extra_name=");
1284*a90b9d01SCy Schubert 	if (pos) {
1285*a90b9d01SCy Schubert 		pos += 17;
1286*a90b9d01SCy Schubert 		end = os_strchr(pos, ' ');
1287*a90b9d01SCy Schubert 		len = end ? (size_t) (end - pos) : os_strlen(pos);
1288*a90b9d01SCy Schubert 		conf->extra_name = os_zalloc(len + 1);
1289*a90b9d01SCy Schubert 		if (!conf->extra_name)
1290*a90b9d01SCy Schubert 			goto fail;
1291*a90b9d01SCy Schubert 		os_memcpy(conf->extra_name, pos, len);
1292*a90b9d01SCy Schubert 	}
1293*a90b9d01SCy Schubert 
1294*a90b9d01SCy Schubert 	pos = os_strstr(cmd, " conf_extra_value=");
1295*a90b9d01SCy Schubert 	if (pos) {
1296*a90b9d01SCy Schubert 		pos += 18;
1297*a90b9d01SCy Schubert 		end = os_strchr(pos, ' ');
1298*a90b9d01SCy Schubert 		len = end ? (size_t) (end - pos) : os_strlen(pos);
1299*a90b9d01SCy Schubert 		len /= 2;
1300*a90b9d01SCy Schubert 		conf->extra_value = os_zalloc(len + 1);
1301*a90b9d01SCy Schubert 		if (!conf->extra_value ||
1302*a90b9d01SCy Schubert 		    hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1303*a90b9d01SCy Schubert 			goto fail;
1304*a90b9d01SCy Schubert 	}
1305*a90b9d01SCy Schubert 
13064bc52338SCy Schubert 	if (!dpp_configuration_valid(conf))
13074bc52338SCy Schubert 		goto fail;
13084bc52338SCy Schubert 
1309c1d255d3SCy Schubert 	if (idx == 0) {
13104bc52338SCy Schubert 		auth->conf_sta = conf_sta;
13114bc52338SCy Schubert 		auth->conf_ap = conf_ap;
1312c1d255d3SCy Schubert 	} else if (idx == 1) {
1313*a90b9d01SCy Schubert 		if (!auth->conf_sta)
1314*a90b9d01SCy Schubert 			auth->conf_sta = conf_sta;
1315*a90b9d01SCy Schubert 		else
1316c1d255d3SCy Schubert 			auth->conf2_sta = conf_sta;
1317*a90b9d01SCy Schubert 		if (!auth->conf_ap)
1318*a90b9d01SCy Schubert 			auth->conf_ap = conf_ap;
1319*a90b9d01SCy Schubert 		else
1320c1d255d3SCy Schubert 			auth->conf2_ap = conf_ap;
1321c1d255d3SCy Schubert 	} else {
1322c1d255d3SCy Schubert 		goto fail;
1323c1d255d3SCy Schubert 	}
13244bc52338SCy Schubert 	return 0;
13254bc52338SCy Schubert 
13264bc52338SCy Schubert fail:
13274bc52338SCy Schubert 	dpp_configuration_free(conf_sta);
13284bc52338SCy Schubert 	dpp_configuration_free(conf_ap);
13294bc52338SCy Schubert 	return -1;
13304bc52338SCy Schubert }
13314bc52338SCy Schubert 
13324bc52338SCy Schubert 
1333c1d255d3SCy Schubert static int dpp_configuration_parse(struct dpp_authentication *auth,
1334c1d255d3SCy Schubert 				   const char *cmd)
1335c1d255d3SCy Schubert {
1336c1d255d3SCy Schubert 	const char *pos;
1337c1d255d3SCy Schubert 	char *tmp;
1338c1d255d3SCy Schubert 	size_t len;
1339c1d255d3SCy Schubert 	int res;
1340c1d255d3SCy Schubert 
1341c1d255d3SCy Schubert 	pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1342c1d255d3SCy Schubert 	if (!pos)
1343c1d255d3SCy Schubert 		return dpp_configuration_parse_helper(auth, cmd, 0);
1344c1d255d3SCy Schubert 
1345c1d255d3SCy Schubert 	len = pos - cmd;
1346c1d255d3SCy Schubert 	tmp = os_malloc(len + 1);
1347c1d255d3SCy Schubert 	if (!tmp)
1348c1d255d3SCy Schubert 		goto fail;
1349c1d255d3SCy Schubert 	os_memcpy(tmp, cmd, len);
1350c1d255d3SCy Schubert 	tmp[len] = '\0';
1351*a90b9d01SCy Schubert 	res = dpp_configuration_parse_helper(auth, tmp, 0);
1352c1d255d3SCy Schubert 	str_clear_free(tmp);
1353c1d255d3SCy Schubert 	if (res)
1354c1d255d3SCy Schubert 		goto fail;
1355c1d255d3SCy Schubert 	res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1356c1d255d3SCy Schubert 	if (res)
1357c1d255d3SCy Schubert 		goto fail;
1358c1d255d3SCy Schubert 	return 0;
1359c1d255d3SCy Schubert fail:
1360c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf_sta);
1361c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf2_sta);
1362c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf_ap);
1363c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf2_ap);
1364c1d255d3SCy Schubert 	return -1;
1365c1d255d3SCy Schubert }
1366c1d255d3SCy Schubert 
1367c1d255d3SCy Schubert 
13684bc52338SCy Schubert static struct dpp_configurator *
13694bc52338SCy Schubert dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
13704bc52338SCy Schubert {
13714bc52338SCy Schubert 	struct dpp_configurator *conf;
13724bc52338SCy Schubert 
13734bc52338SCy Schubert 	if (!dpp)
13744bc52338SCy Schubert 		return NULL;
13754bc52338SCy Schubert 
13764bc52338SCy Schubert 	dl_list_for_each(conf, &dpp->configurator,
13774bc52338SCy Schubert 			 struct dpp_configurator, list) {
13784bc52338SCy Schubert 		if (conf->id == id)
13794bc52338SCy Schubert 			return conf;
13804bc52338SCy Schubert 	}
13814bc52338SCy Schubert 	return NULL;
13824bc52338SCy Schubert }
13834bc52338SCy Schubert 
13844bc52338SCy Schubert 
1385c1d255d3SCy Schubert int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
13864bc52338SCy Schubert {
13874bc52338SCy Schubert 	const char *pos;
1388c1d255d3SCy Schubert 	char *tmp = NULL;
1389c1d255d3SCy Schubert 	int ret = -1;
13904bc52338SCy Schubert 
1391c1d255d3SCy Schubert 	if (!cmd || auth->configurator_set)
13924bc52338SCy Schubert 		return 0;
1393c1d255d3SCy Schubert 	auth->configurator_set = 1;
1394c1d255d3SCy Schubert 
1395c1d255d3SCy Schubert 	if (cmd[0] != ' ') {
1396c1d255d3SCy Schubert 		size_t len;
1397c1d255d3SCy Schubert 
1398c1d255d3SCy Schubert 		len = os_strlen(cmd);
1399c1d255d3SCy Schubert 		tmp = os_malloc(len + 2);
1400c1d255d3SCy Schubert 		if (!tmp)
1401c1d255d3SCy Schubert 			goto fail;
1402c1d255d3SCy Schubert 		tmp[0] = ' ';
1403c1d255d3SCy Schubert 		os_memcpy(tmp + 1, cmd, len + 1);
1404c1d255d3SCy Schubert 		cmd = tmp;
1405c1d255d3SCy Schubert 	}
14064bc52338SCy Schubert 
14074bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
14084bc52338SCy Schubert 
1409*a90b9d01SCy Schubert 	if (os_strstr(cmd, " conf=query")) {
1410*a90b9d01SCy Schubert 		auth->configurator_set = 0;
1411*a90b9d01SCy Schubert 		auth->use_config_query = true;
1412*a90b9d01SCy Schubert 		ret = 0;
1413*a90b9d01SCy Schubert 		goto fail;
1414*a90b9d01SCy Schubert 	}
1415*a90b9d01SCy Schubert 
14164bc52338SCy Schubert 	pos = os_strstr(cmd, " configurator=");
1417c1d255d3SCy Schubert 	if (!auth->conf && pos) {
14184bc52338SCy Schubert 		pos += 14;
1419c1d255d3SCy Schubert 		auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
14204bc52338SCy Schubert 		if (!auth->conf) {
14214bc52338SCy Schubert 			wpa_printf(MSG_INFO,
14224bc52338SCy Schubert 				   "DPP: Could not find the specified configurator");
1423c1d255d3SCy Schubert 			goto fail;
14244bc52338SCy Schubert 		}
14254bc52338SCy Schubert 	}
14264bc52338SCy Schubert 
1427c1d255d3SCy Schubert 	pos = os_strstr(cmd, " conn_status=");
1428c1d255d3SCy Schubert 	if (pos) {
1429c1d255d3SCy Schubert 		pos += 13;
1430c1d255d3SCy Schubert 		auth->send_conn_status = atoi(pos);
14314bc52338SCy Schubert 	}
1432c1d255d3SCy Schubert 
1433c1d255d3SCy Schubert 	pos = os_strstr(cmd, " akm_use_selector=");
1434c1d255d3SCy Schubert 	if (pos) {
1435c1d255d3SCy Schubert 		pos += 18;
1436c1d255d3SCy Schubert 		auth->akm_use_selector = atoi(pos);
1437c1d255d3SCy Schubert 	}
1438c1d255d3SCy Schubert 
1439c1d255d3SCy Schubert 	if (dpp_configuration_parse(auth, cmd) < 0) {
1440c1d255d3SCy Schubert 		wpa_msg(auth->msg_ctx, MSG_INFO,
1441c1d255d3SCy Schubert 			"DPP: Failed to set configurator parameters");
1442c1d255d3SCy Schubert 		goto fail;
1443c1d255d3SCy Schubert 	}
1444c1d255d3SCy Schubert 	ret = 0;
1445c1d255d3SCy Schubert fail:
1446c1d255d3SCy Schubert 	os_free(tmp);
1447c1d255d3SCy Schubert 	return ret;
14484bc52338SCy Schubert }
14494bc52338SCy Schubert 
14504bc52338SCy Schubert 
145185732ac8SCy Schubert void dpp_auth_deinit(struct dpp_authentication *auth)
145285732ac8SCy Schubert {
1453c1d255d3SCy Schubert 	unsigned int i;
1454c1d255d3SCy Schubert 
145585732ac8SCy Schubert 	if (!auth)
145685732ac8SCy Schubert 		return;
145785732ac8SCy Schubert 	dpp_configuration_free(auth->conf_ap);
1458c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf2_ap);
145985732ac8SCy Schubert 	dpp_configuration_free(auth->conf_sta);
1460c1d255d3SCy Schubert 	dpp_configuration_free(auth->conf2_sta);
14614b72b91aSCy Schubert 	crypto_ec_key_deinit(auth->own_protocol_key);
14624b72b91aSCy Schubert 	crypto_ec_key_deinit(auth->peer_protocol_key);
14634b72b91aSCy Schubert 	crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
146485732ac8SCy Schubert 	wpabuf_free(auth->req_msg);
146585732ac8SCy Schubert 	wpabuf_free(auth->resp_msg);
146685732ac8SCy Schubert 	wpabuf_free(auth->conf_req);
1467c1d255d3SCy Schubert 	wpabuf_free(auth->reconfig_req_msg);
1468c1d255d3SCy Schubert 	wpabuf_free(auth->reconfig_resp_msg);
1469c1d255d3SCy Schubert 	for (i = 0; i < auth->num_conf_obj; i++) {
1470c1d255d3SCy Schubert 		struct dpp_config_obj *conf = &auth->conf_obj[i];
1471c1d255d3SCy Schubert 
1472c1d255d3SCy Schubert 		os_free(conf->connector);
1473c1d255d3SCy Schubert 		wpabuf_free(conf->c_sign_key);
1474c1d255d3SCy Schubert 		wpabuf_free(conf->certbag);
1475c1d255d3SCy Schubert 		wpabuf_free(conf->certs);
1476c1d255d3SCy Schubert 		wpabuf_free(conf->cacert);
1477c1d255d3SCy Schubert 		os_free(conf->server_name);
1478c1d255d3SCy Schubert 		wpabuf_free(conf->pp_key);
1479c1d255d3SCy Schubert 	}
1480c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1481c1d255d3SCy Schubert 	dpp_free_asymmetric_key(auth->conf_key_pkg);
1482c1d255d3SCy Schubert 	os_free(auth->csrattrs);
1483c1d255d3SCy Schubert 	wpabuf_free(auth->csr);
1484c1d255d3SCy Schubert 	wpabuf_free(auth->priv_key);
1485c1d255d3SCy Schubert 	wpabuf_free(auth->cacert);
1486c1d255d3SCy Schubert 	wpabuf_free(auth->certbag);
1487c1d255d3SCy Schubert 	os_free(auth->trusted_eap_server_name);
1488c1d255d3SCy Schubert 	wpabuf_free(auth->conf_resp_tcp);
1489c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
149085732ac8SCy Schubert 	wpabuf_free(auth->net_access_key);
149185732ac8SCy Schubert 	dpp_bootstrap_info_free(auth->tmp_own_bi);
1492c1d255d3SCy Schubert 	if (auth->tmp_peer_bi) {
1493c1d255d3SCy Schubert 		dl_list_del(&auth->tmp_peer_bi->list);
1494c1d255d3SCy Schubert 		dpp_bootstrap_info_free(auth->tmp_peer_bi);
1495c1d255d3SCy Schubert 	}
1496*a90b9d01SCy Schubert 	os_free(auth->e_name);
1497*a90b9d01SCy Schubert 	os_free(auth->e_mud_url);
1498*a90b9d01SCy Schubert 	os_free(auth->e_band_support);
149985732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
150085732ac8SCy Schubert 	os_free(auth->config_obj_override);
150185732ac8SCy Schubert 	os_free(auth->discovery_override);
150285732ac8SCy Schubert 	os_free(auth->groups_override);
150385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
150485732ac8SCy Schubert 	bin_clear_free(auth, sizeof(*auth));
150585732ac8SCy Schubert }
150685732ac8SCy Schubert 
150785732ac8SCy Schubert 
150885732ac8SCy Schubert static struct wpabuf *
150985732ac8SCy Schubert dpp_build_conf_start(struct dpp_authentication *auth,
151085732ac8SCy Schubert 		     struct dpp_configuration *conf, size_t tailroom)
151185732ac8SCy Schubert {
151285732ac8SCy Schubert 	struct wpabuf *buf;
151385732ac8SCy Schubert 
151485732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
151585732ac8SCy Schubert 	if (auth->discovery_override)
151685732ac8SCy Schubert 		tailroom += os_strlen(auth->discovery_override);
151785732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
151885732ac8SCy Schubert 
151985732ac8SCy Schubert 	buf = wpabuf_alloc(200 + tailroom);
152085732ac8SCy Schubert 	if (!buf)
152185732ac8SCy Schubert 		return NULL;
1522c1d255d3SCy Schubert 	json_start_object(buf, NULL);
1523c1d255d3SCy Schubert 	json_add_string(buf, "wi-fi_tech", "infra");
1524c1d255d3SCy Schubert 	json_value_sep(buf);
152585732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
152685732ac8SCy Schubert 	if (auth->discovery_override) {
152785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
152885732ac8SCy Schubert 			   auth->discovery_override);
1529c1d255d3SCy Schubert 		wpabuf_put_str(buf, "\"discovery\":");
153085732ac8SCy Schubert 		wpabuf_put_str(buf, auth->discovery_override);
1531c1d255d3SCy Schubert 		json_value_sep(buf);
153285732ac8SCy Schubert 		return buf;
153385732ac8SCy Schubert 	}
153485732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1535c1d255d3SCy Schubert 	json_start_object(buf, "discovery");
1536c1d255d3SCy Schubert 	if (((!conf->ssid_charset || auth->peer_version < 2) &&
1537c1d255d3SCy Schubert 	     json_add_string_escape(buf, "ssid", conf->ssid,
1538c1d255d3SCy Schubert 				    conf->ssid_len) < 0) ||
1539c1d255d3SCy Schubert 	    ((conf->ssid_charset && auth->peer_version >= 2) &&
1540c1d255d3SCy Schubert 	     json_add_base64url(buf, "ssid64", conf->ssid,
1541c1d255d3SCy Schubert 				conf->ssid_len) < 0)) {
1542c1d255d3SCy Schubert 		wpabuf_free(buf);
1543c1d255d3SCy Schubert 		return NULL;
1544c1d255d3SCy Schubert 	}
1545c1d255d3SCy Schubert 	if (conf->ssid_charset > 0) {
1546c1d255d3SCy Schubert 		json_value_sep(buf);
1547c1d255d3SCy Schubert 		json_add_int(buf, "ssid_charset", conf->ssid_charset);
1548c1d255d3SCy Schubert 	}
1549c1d255d3SCy Schubert 	json_end_object(buf);
1550c1d255d3SCy Schubert 	json_value_sep(buf);
155185732ac8SCy Schubert 
155285732ac8SCy Schubert 	return buf;
155385732ac8SCy Schubert }
155485732ac8SCy Schubert 
155585732ac8SCy Schubert 
15564b72b91aSCy Schubert int dpp_build_jwk(struct wpabuf *buf, const char *name,
15574b72b91aSCy Schubert 		  struct crypto_ec_key *key, const char *kid,
15584b72b91aSCy Schubert 		  const struct dpp_curve_params *curve)
155985732ac8SCy Schubert {
156085732ac8SCy Schubert 	struct wpabuf *pub;
156185732ac8SCy Schubert 	const u8 *pos;
156285732ac8SCy Schubert 	int ret = -1;
156385732ac8SCy Schubert 
15644b72b91aSCy Schubert 	pub = crypto_ec_key_get_pubkey_point(key, 0);
156585732ac8SCy Schubert 	if (!pub)
156685732ac8SCy Schubert 		goto fail;
156785732ac8SCy Schubert 
1568c1d255d3SCy Schubert 	json_start_object(buf, name);
1569c1d255d3SCy Schubert 	json_add_string(buf, "kty", "EC");
1570c1d255d3SCy Schubert 	json_value_sep(buf);
1571c1d255d3SCy Schubert 	json_add_string(buf, "crv", curve->jwk_crv);
1572c1d255d3SCy Schubert 	json_value_sep(buf);
1573c1d255d3SCy Schubert 	pos = wpabuf_head(pub);
1574c1d255d3SCy Schubert 	if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1575c1d255d3SCy Schubert 		goto fail;
1576c1d255d3SCy Schubert 	json_value_sep(buf);
1577c1d255d3SCy Schubert 	pos += curve->prime_len;
1578c1d255d3SCy Schubert 	if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1579c1d255d3SCy Schubert 		goto fail;
158085732ac8SCy Schubert 	if (kid) {
1581c1d255d3SCy Schubert 		json_value_sep(buf);
1582c1d255d3SCy Schubert 		json_add_string(buf, "kid", kid);
158385732ac8SCy Schubert 	}
1584c1d255d3SCy Schubert 	json_end_object(buf);
158585732ac8SCy Schubert 	ret = 0;
158685732ac8SCy Schubert fail:
158785732ac8SCy Schubert 	wpabuf_free(pub);
158885732ac8SCy Schubert 	return ret;
158985732ac8SCy Schubert }
159085732ac8SCy Schubert 
159185732ac8SCy Schubert 
15924bc52338SCy Schubert static void dpp_build_legacy_cred_params(struct wpabuf *buf,
15934bc52338SCy Schubert 					 struct dpp_configuration *conf)
15944bc52338SCy Schubert {
15954bc52338SCy Schubert 	if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
1596c1d255d3SCy Schubert 		json_add_string_escape(buf, "pass", conf->passphrase,
15974bc52338SCy Schubert 				       os_strlen(conf->passphrase));
15984bc52338SCy Schubert 	} else if (conf->psk_set) {
15994bc52338SCy Schubert 		char psk[2 * sizeof(conf->psk) + 1];
16004bc52338SCy Schubert 
16014bc52338SCy Schubert 		wpa_snprintf_hex(psk, sizeof(psk),
16024bc52338SCy Schubert 				 conf->psk, sizeof(conf->psk));
1603c1d255d3SCy Schubert 		json_add_string(buf, "psk_hex", psk);
1604c1d255d3SCy Schubert 		forced_memzero(psk, sizeof(psk));
1605c1d255d3SCy Schubert 	}
1606c1d255d3SCy Schubert }
1607c1d255d3SCy Schubert 
1608c1d255d3SCy Schubert 
1609*a90b9d01SCy Schubert const char * dpp_netrole_str(enum dpp_netrole netrole)
1610c1d255d3SCy Schubert {
1611c1d255d3SCy Schubert 	switch (netrole) {
1612c1d255d3SCy Schubert 	case DPP_NETROLE_STA:
1613c1d255d3SCy Schubert 		return "sta";
1614c1d255d3SCy Schubert 	case DPP_NETROLE_AP:
1615c1d255d3SCy Schubert 		return "ap";
1616c1d255d3SCy Schubert 	case DPP_NETROLE_CONFIGURATOR:
1617c1d255d3SCy Schubert 		return "configurator";
1618c1d255d3SCy Schubert 	default:
1619c1d255d3SCy Schubert 		return "??";
16204bc52338SCy Schubert 	}
16214bc52338SCy Schubert }
16224bc52338SCy Schubert 
16234bc52338SCy Schubert 
1624*a90b9d01SCy Schubert static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1625*a90b9d01SCy Schubert {
1626*a90b9d01SCy Schubert 	enum dpp_bootstrap_supported_curves idx;
1627*a90b9d01SCy Schubert 
1628*a90b9d01SCy Schubert 	if (!bi || !bi->supported_curves)
1629*a90b9d01SCy Schubert 		return true; /* no support indication available */
1630*a90b9d01SCy Schubert 
1631*a90b9d01SCy Schubert 	if (os_strcmp(curve, "prime256v1") == 0)
1632*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_P_256;
1633*a90b9d01SCy Schubert 	else if (os_strcmp(curve, "secp384r1") == 0)
1634*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_P_384;
1635*a90b9d01SCy Schubert 	else if (os_strcmp(curve, "secp521r1") == 0)
1636*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_P_521;
1637*a90b9d01SCy Schubert 	else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1638*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_BP_256;
1639*a90b9d01SCy Schubert 	else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1640*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_BP_384;
1641*a90b9d01SCy Schubert 	else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1642*a90b9d01SCy Schubert 		idx = DPP_BOOTSTRAP_CURVE_BP_512;
1643*a90b9d01SCy Schubert 	else
1644*a90b9d01SCy Schubert 		return true;
1645*a90b9d01SCy Schubert 
1646*a90b9d01SCy Schubert 	return bi->supported_curves & BIT(idx);
1647*a90b9d01SCy Schubert }
1648*a90b9d01SCy Schubert 
1649*a90b9d01SCy Schubert 
165085732ac8SCy Schubert static struct wpabuf *
1651c1d255d3SCy Schubert dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
165285732ac8SCy Schubert 		       struct dpp_configuration *conf)
165385732ac8SCy Schubert {
165485732ac8SCy Schubert 	struct wpabuf *buf = NULL;
1655c1d255d3SCy Schubert 	char *signed_conn = NULL;
165685732ac8SCy Schubert 	size_t tailroom;
1657*a90b9d01SCy Schubert 	const struct dpp_curve_params *curve; /* C-sign-key curve */
1658*a90b9d01SCy Schubert 	const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
165985732ac8SCy Schubert 	struct wpabuf *dppcon = NULL;
166085732ac8SCy Schubert 	size_t extra_len = 1000;
16614bc52338SCy Schubert 	int incl_legacy;
16624bc52338SCy Schubert 	enum dpp_akm akm;
1663c1d255d3SCy Schubert 	const char *akm_str;
166485732ac8SCy Schubert 
166585732ac8SCy Schubert 	if (!auth->conf) {
166685732ac8SCy Schubert 		wpa_printf(MSG_INFO,
166785732ac8SCy Schubert 			   "DPP: No configurator specified - cannot generate DPP config object");
166885732ac8SCy Schubert 		goto fail;
166985732ac8SCy Schubert 	}
167085732ac8SCy Schubert 	curve = auth->conf->curve;
1671*a90b9d01SCy Schubert 	if (dpp_akm_dpp(conf->akm) &&
1672*a90b9d01SCy Schubert 	    !dpp_supports_curve(curve->name, auth->peer_bi)) {
1673*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1674*a90b9d01SCy Schubert 			   "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1675*a90b9d01SCy Schubert 			   curve->name);
1676*a90b9d01SCy Schubert 		goto fail;
1677*a90b9d01SCy Schubert 	}
1678*a90b9d01SCy Schubert 	if (auth->new_curve && auth->new_key_received)
1679*a90b9d01SCy Schubert 		nak_curve = auth->new_curve;
1680*a90b9d01SCy Schubert 	else
1681*a90b9d01SCy Schubert 		nak_curve = auth->curve;
1682*a90b9d01SCy Schubert 	if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1683*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1684*a90b9d01SCy Schubert 			   "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1685*a90b9d01SCy Schubert 			   nak_curve->name);
1686*a90b9d01SCy Schubert 		goto fail;
1687*a90b9d01SCy Schubert 	}
168885732ac8SCy Schubert 
16894bc52338SCy Schubert 	akm = conf->akm;
16904bc52338SCy Schubert 	if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
16914bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
16924bc52338SCy Schubert 			   "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
16934bc52338SCy Schubert 		akm = DPP_AKM_DPP;
16944bc52338SCy Schubert 	}
16954bc52338SCy Schubert 
169685732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
169785732ac8SCy Schubert 	if (auth->groups_override)
169885732ac8SCy Schubert 		extra_len += os_strlen(auth->groups_override);
169985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
170085732ac8SCy Schubert 
170185732ac8SCy Schubert 	if (conf->group_id)
170285732ac8SCy Schubert 		extra_len += os_strlen(conf->group_id);
170385732ac8SCy Schubert 
170485732ac8SCy Schubert 	/* Connector (JSON dppCon object) */
1705*a90b9d01SCy Schubert 	dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
170685732ac8SCy Schubert 	if (!dppcon)
170785732ac8SCy Schubert 		goto fail;
170885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
170985732ac8SCy Schubert 	if (auth->groups_override) {
171085732ac8SCy Schubert 		wpabuf_put_u8(dppcon, '{');
171185732ac8SCy Schubert 		if (auth->groups_override) {
171285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
171385732ac8SCy Schubert 				   "DPP: TESTING - groups override: '%s'",
171485732ac8SCy Schubert 				   auth->groups_override);
171585732ac8SCy Schubert 			wpabuf_put_str(dppcon, "\"groups\":");
171685732ac8SCy Schubert 			wpabuf_put_str(dppcon, auth->groups_override);
1717c1d255d3SCy Schubert 			json_value_sep(dppcon);
171885732ac8SCy Schubert 		}
171985732ac8SCy Schubert 		goto skip_groups;
172085732ac8SCy Schubert 	}
172185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1722c1d255d3SCy Schubert 	json_start_object(dppcon, NULL);
1723c1d255d3SCy Schubert 	json_start_array(dppcon, "groups");
1724c1d255d3SCy Schubert 	json_start_object(dppcon, NULL);
1725c1d255d3SCy Schubert 	json_add_string(dppcon, "groupId",
172685732ac8SCy Schubert 			conf->group_id ? conf->group_id : "*");
1727c1d255d3SCy Schubert 	json_value_sep(dppcon);
1728c1d255d3SCy Schubert 	json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1729c1d255d3SCy Schubert 	json_end_object(dppcon);
1730c1d255d3SCy Schubert 	json_end_array(dppcon);
1731c1d255d3SCy Schubert 	json_value_sep(dppcon);
173285732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
173385732ac8SCy Schubert skip_groups:
173485732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1735*a90b9d01SCy Schubert 	if (!auth->peer_protocol_key) {
1736*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1737*a90b9d01SCy Schubert 			   "DPP: No peer protocol key available to build netAccessKey JWK");
1738*a90b9d01SCy Schubert 		goto fail;
1739*a90b9d01SCy Schubert 	}
1740*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
1741*a90b9d01SCy Schubert 	if (auth->conf->net_access_key_curve &&
1742*a90b9d01SCy Schubert 	    auth->curve != auth->conf->net_access_key_curve &&
1743*a90b9d01SCy Schubert 	    !auth->new_key_received) {
1744*a90b9d01SCy Schubert 		if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1745*a90b9d01SCy Schubert 					auth->peer_bi)) {
1746*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
1747*a90b9d01SCy Schubert 				   "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1748*a90b9d01SCy Schubert 				   auth->conf->net_access_key_curve->name);
1749*a90b9d01SCy Schubert 			goto fail;
1750*a90b9d01SCy Schubert 		}
1751*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1752*a90b9d01SCy Schubert 			   "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1753*a90b9d01SCy Schubert 			   auth->curve->name,
1754*a90b9d01SCy Schubert 			   auth->conf->net_access_key_curve->name,
1755*a90b9d01SCy Schubert 			   auth->waiting_new_key ?
1756*a90b9d01SCy Schubert 			   "the required key not received" :
1757*a90b9d01SCy Schubert 			   "request a new key");
1758*a90b9d01SCy Schubert 		if (auth->waiting_new_key)
1759*a90b9d01SCy Schubert 			auth->waiting_new_key = false; /* failed */
1760*a90b9d01SCy Schubert 		else
1761*a90b9d01SCy Schubert 			auth->waiting_new_key = true;
1762*a90b9d01SCy Schubert 		goto fail;
1763*a90b9d01SCy Schubert 	}
1764*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
1765*a90b9d01SCy Schubert 	if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1766*a90b9d01SCy Schubert 			  nak_curve) < 0) {
176785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
176885732ac8SCy Schubert 		goto fail;
176985732ac8SCy Schubert 	}
177085732ac8SCy Schubert 	if (conf->netaccesskey_expiry) {
177185732ac8SCy Schubert 		struct os_tm tm;
1772c1d255d3SCy Schubert 		char expiry[30];
177385732ac8SCy Schubert 
177485732ac8SCy Schubert 		if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
177585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
177685732ac8SCy Schubert 				   "DPP: Failed to generate expiry string");
177785732ac8SCy Schubert 			goto fail;
177885732ac8SCy Schubert 		}
1779c1d255d3SCy Schubert 		os_snprintf(expiry, sizeof(expiry),
1780c1d255d3SCy Schubert 			    "%04u-%02u-%02uT%02u:%02u:%02uZ",
178185732ac8SCy Schubert 			    tm.year, tm.month, tm.day,
178285732ac8SCy Schubert 			    tm.hour, tm.min, tm.sec);
1783c1d255d3SCy Schubert 		json_value_sep(dppcon);
1784c1d255d3SCy Schubert 		json_add_string(dppcon, "expiry", expiry);
178585732ac8SCy Schubert 	}
178632a95656SCy Schubert #ifdef CONFIG_DPP3
178732a95656SCy Schubert 	json_value_sep(dppcon);
178832a95656SCy Schubert 	json_add_int(dppcon, "version", auth->peer_version);
178932a95656SCy Schubert #endif /* CONFIG_DPP3 */
1790c1d255d3SCy Schubert 	json_end_object(dppcon);
179185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
179285732ac8SCy Schubert 		   (const char *) wpabuf_head(dppcon));
179385732ac8SCy Schubert 
1794c1d255d3SCy Schubert 	signed_conn = dpp_sign_connector(auth->conf, dppcon);
1795c1d255d3SCy Schubert 	if (!signed_conn)
179685732ac8SCy Schubert 		goto fail;
179785732ac8SCy Schubert 
17984bc52338SCy Schubert 	incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
179985732ac8SCy Schubert 	tailroom = 1000;
180085732ac8SCy Schubert 	tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
1801c1d255d3SCy Schubert 	tailroom += os_strlen(signed_conn);
18024bc52338SCy Schubert 	if (incl_legacy)
18034bc52338SCy Schubert 		tailroom += 1000;
1804c1d255d3SCy Schubert 	if (akm == DPP_AKM_DOT1X) {
1805c1d255d3SCy Schubert 		if (auth->certbag)
1806c1d255d3SCy Schubert 			tailroom += 2 * wpabuf_len(auth->certbag);
1807c1d255d3SCy Schubert 		if (auth->cacert)
1808c1d255d3SCy Schubert 			tailroom += 2 * wpabuf_len(auth->cacert);
1809c1d255d3SCy Schubert 		if (auth->trusted_eap_server_name)
1810c1d255d3SCy Schubert 			tailroom += os_strlen(auth->trusted_eap_server_name);
1811c1d255d3SCy Schubert 		tailroom += 1000;
1812c1d255d3SCy Schubert 	}
1813*a90b9d01SCy Schubert 	if (conf->extra_name && conf->extra_value)
1814*a90b9d01SCy Schubert 		tailroom += 10 + os_strlen(conf->extra_name) +
1815*a90b9d01SCy Schubert 			os_strlen(conf->extra_value);
181685732ac8SCy Schubert 	buf = dpp_build_conf_start(auth, conf, tailroom);
181785732ac8SCy Schubert 	if (!buf)
181885732ac8SCy Schubert 		goto fail;
181985732ac8SCy Schubert 
1820c1d255d3SCy Schubert 	if (auth->akm_use_selector && dpp_akm_ver2(akm))
1821c1d255d3SCy Schubert 		akm_str = dpp_akm_selector_str(akm);
1822c1d255d3SCy Schubert 	else
1823c1d255d3SCy Schubert 		akm_str = dpp_akm_str(akm);
1824c1d255d3SCy Schubert 	json_start_object(buf, "cred");
1825c1d255d3SCy Schubert 	json_add_string(buf, "akm", akm_str);
1826c1d255d3SCy Schubert 	json_value_sep(buf);
18274bc52338SCy Schubert 	if (incl_legacy) {
18284bc52338SCy Schubert 		dpp_build_legacy_cred_params(buf, conf);
1829c1d255d3SCy Schubert 		json_value_sep(buf);
1830c1d255d3SCy Schubert 	}
1831c1d255d3SCy Schubert 	if (akm == DPP_AKM_DOT1X) {
1832c1d255d3SCy Schubert 		json_start_object(buf, "entCreds");
1833c1d255d3SCy Schubert 		if (!auth->certbag)
1834c1d255d3SCy Schubert 			goto fail;
1835c1d255d3SCy Schubert 		json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1836c1d255d3SCy Schubert 				wpabuf_len(auth->certbag));
1837c1d255d3SCy Schubert 		if (auth->cacert) {
1838c1d255d3SCy Schubert 			json_value_sep(buf);
1839c1d255d3SCy Schubert 			json_add_base64(buf, "caCert",
1840c1d255d3SCy Schubert 					wpabuf_head(auth->cacert),
1841c1d255d3SCy Schubert 					wpabuf_len(auth->cacert));
1842c1d255d3SCy Schubert 		}
1843c1d255d3SCy Schubert 		if (auth->trusted_eap_server_name) {
1844c1d255d3SCy Schubert 			json_value_sep(buf);
1845c1d255d3SCy Schubert 			json_add_string(buf, "trustedEapServerName",
1846c1d255d3SCy Schubert 					auth->trusted_eap_server_name);
1847c1d255d3SCy Schubert 		}
1848c1d255d3SCy Schubert 		json_value_sep(buf);
1849c1d255d3SCy Schubert 		json_start_array(buf, "eapMethods");
1850c1d255d3SCy Schubert 		wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1851c1d255d3SCy Schubert 		json_end_array(buf);
1852c1d255d3SCy Schubert 		json_end_object(buf);
1853c1d255d3SCy Schubert 		json_value_sep(buf);
18544bc52338SCy Schubert 	}
18554bc52338SCy Schubert 	wpabuf_put_str(buf, "\"signedConnector\":\"");
1856c1d255d3SCy Schubert 	wpabuf_put_str(buf, signed_conn);
1857c1d255d3SCy Schubert 	wpabuf_put_str(buf, "\"");
1858c1d255d3SCy Schubert 	json_value_sep(buf);
185985732ac8SCy Schubert 	if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
186085732ac8SCy Schubert 			  curve) < 0) {
186185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
186285732ac8SCy Schubert 		goto fail;
186385732ac8SCy Schubert 	}
1864c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1865c1d255d3SCy Schubert 	if (auth->peer_version >= 2 && auth->conf->pp_key) {
1866c1d255d3SCy Schubert 		json_value_sep(buf);
1867c1d255d3SCy Schubert 		if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1868c1d255d3SCy Schubert 				  curve) < 0) {
1869c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1870c1d255d3SCy Schubert 			goto fail;
1871c1d255d3SCy Schubert 		}
1872c1d255d3SCy Schubert 	}
1873c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
187485732ac8SCy Schubert 
1875c1d255d3SCy Schubert 	json_end_object(buf);
1876*a90b9d01SCy Schubert 	if (conf->extra_name && conf->extra_value) {
1877*a90b9d01SCy Schubert 		json_value_sep(buf);
1878*a90b9d01SCy Schubert 		wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1879*a90b9d01SCy Schubert 			      conf->extra_value);
1880*a90b9d01SCy Schubert 	}
1881c1d255d3SCy Schubert 	json_end_object(buf);
188285732ac8SCy Schubert 
188385732ac8SCy Schubert 	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
188485732ac8SCy Schubert 			      wpabuf_head(buf), wpabuf_len(buf));
188585732ac8SCy Schubert 
1886*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
1887*a90b9d01SCy Schubert 	if (!auth->conf->net_access_key_curve) {
1888*a90b9d01SCy Schubert 		/* All netAccessKey values used in the network will have to be
1889*a90b9d01SCy Schubert 		 * from the same curve for network introduction to work, so
1890*a90b9d01SCy Schubert 		 * hardcode the first used netAccessKey curve for consecutive
1891*a90b9d01SCy Schubert 		 * operations if there was no explicit configuration of which
1892*a90b9d01SCy Schubert 		 * curve to use. */
1893*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
1894*a90b9d01SCy Schubert 			   "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1895*a90b9d01SCy Schubert 			   nak_curve->name);
1896*a90b9d01SCy Schubert 		auth->conf->net_access_key_curve = nak_curve;
1897*a90b9d01SCy Schubert 	}
1898*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
1899*a90b9d01SCy Schubert 
190085732ac8SCy Schubert out:
1901c1d255d3SCy Schubert 	os_free(signed_conn);
190285732ac8SCy Schubert 	wpabuf_free(dppcon);
190385732ac8SCy Schubert 	return buf;
190485732ac8SCy Schubert fail:
190585732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
190685732ac8SCy Schubert 	wpabuf_free(buf);
190785732ac8SCy Schubert 	buf = NULL;
190885732ac8SCy Schubert 	goto out;
190985732ac8SCy Schubert }
191085732ac8SCy Schubert 
191185732ac8SCy Schubert 
191285732ac8SCy Schubert static struct wpabuf *
1913c1d255d3SCy Schubert dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
191485732ac8SCy Schubert 			  struct dpp_configuration *conf)
191585732ac8SCy Schubert {
191685732ac8SCy Schubert 	struct wpabuf *buf;
1917c1d255d3SCy Schubert 	const char *akm_str;
1918*a90b9d01SCy Schubert 	size_t len = 1000;
191985732ac8SCy Schubert 
1920*a90b9d01SCy Schubert 	if (conf->extra_name && conf->extra_value)
1921*a90b9d01SCy Schubert 		len += 10 + os_strlen(conf->extra_name) +
1922*a90b9d01SCy Schubert 			os_strlen(conf->extra_value);
1923*a90b9d01SCy Schubert 	buf = dpp_build_conf_start(auth, conf, len);
192485732ac8SCy Schubert 	if (!buf)
192585732ac8SCy Schubert 		return NULL;
192685732ac8SCy Schubert 
1927c1d255d3SCy Schubert 	if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1928c1d255d3SCy Schubert 		akm_str = dpp_akm_selector_str(conf->akm);
1929c1d255d3SCy Schubert 	else
1930c1d255d3SCy Schubert 		akm_str = dpp_akm_str(conf->akm);
1931c1d255d3SCy Schubert 	json_start_object(buf, "cred");
1932c1d255d3SCy Schubert 	json_add_string(buf, "akm", akm_str);
1933c1d255d3SCy Schubert 	json_value_sep(buf);
19344bc52338SCy Schubert 	dpp_build_legacy_cred_params(buf, conf);
1935c1d255d3SCy Schubert 	json_end_object(buf);
1936*a90b9d01SCy Schubert 	if (conf->extra_name && conf->extra_value) {
1937*a90b9d01SCy Schubert 		json_value_sep(buf);
1938*a90b9d01SCy Schubert 		wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1939*a90b9d01SCy Schubert 			      conf->extra_value);
1940*a90b9d01SCy Schubert 	}
1941c1d255d3SCy Schubert 	json_end_object(buf);
194285732ac8SCy Schubert 
194385732ac8SCy Schubert 	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
194485732ac8SCy Schubert 			      wpabuf_head(buf), wpabuf_len(buf));
194585732ac8SCy Schubert 
194685732ac8SCy Schubert 	return buf;
194785732ac8SCy Schubert }
194885732ac8SCy Schubert 
194985732ac8SCy Schubert 
1950*a90b9d01SCy Schubert static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1951*a90b9d01SCy Schubert {
1952*a90b9d01SCy Schubert 	struct dpp_bootstrap_info *bi;
1953*a90b9d01SCy Schubert 
1954*a90b9d01SCy Schubert 	if (auth->peer_bi)
1955*a90b9d01SCy Schubert 		return auth->peer_bi->id;
1956*a90b9d01SCy Schubert 	if (auth->tmp_peer_bi)
1957*a90b9d01SCy Schubert 		return auth->tmp_peer_bi->id;
1958*a90b9d01SCy Schubert 
1959*a90b9d01SCy Schubert 	bi = os_zalloc(sizeof(*bi));
1960*a90b9d01SCy Schubert 	if (!bi)
1961*a90b9d01SCy Schubert 		return -1;
1962*a90b9d01SCy Schubert 	bi->id = dpp_next_id(auth->global);
1963*a90b9d01SCy Schubert 	dl_list_add(&auth->global->bootstrap, &bi->list);
1964*a90b9d01SCy Schubert 	auth->tmp_peer_bi = bi;
1965*a90b9d01SCy Schubert 	return bi->id;
1966*a90b9d01SCy Schubert }
1967*a90b9d01SCy Schubert 
1968*a90b9d01SCy Schubert 
196985732ac8SCy Schubert static struct wpabuf *
1970c1d255d3SCy Schubert dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
1971c1d255d3SCy Schubert 		   int idx, bool cert_req)
197285732ac8SCy Schubert {
1973c1d255d3SCy Schubert 	struct dpp_configuration *conf = NULL;
197485732ac8SCy Schubert 
197585732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
197685732ac8SCy Schubert 	if (auth->config_obj_override) {
1977c1d255d3SCy Schubert 		if (idx != 0)
1978c1d255d3SCy Schubert 			return NULL;
197985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
198085732ac8SCy Schubert 		return wpabuf_alloc_copy(auth->config_obj_override,
198185732ac8SCy Schubert 					 os_strlen(auth->config_obj_override));
198285732ac8SCy Schubert 	}
198385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
198485732ac8SCy Schubert 
1985c1d255d3SCy Schubert 	if (idx == 0) {
1986c1d255d3SCy Schubert 		if (netrole == DPP_NETROLE_STA)
1987c1d255d3SCy Schubert 			conf = auth->conf_sta;
1988c1d255d3SCy Schubert 		else if (netrole == DPP_NETROLE_AP)
1989c1d255d3SCy Schubert 			conf = auth->conf_ap;
1990c1d255d3SCy Schubert 	} else if (idx == 1) {
1991c1d255d3SCy Schubert 		if (netrole == DPP_NETROLE_STA)
1992c1d255d3SCy Schubert 			conf = auth->conf2_sta;
1993c1d255d3SCy Schubert 		else if (netrole == DPP_NETROLE_AP)
1994c1d255d3SCy Schubert 			conf = auth->conf2_ap;
1995c1d255d3SCy Schubert 	}
199685732ac8SCy Schubert 	if (!conf) {
1997*a90b9d01SCy Schubert 		if (idx == 0) {
1998*a90b9d01SCy Schubert 			if (auth->use_config_query) {
1999*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
2000*a90b9d01SCy Schubert 					   "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
2001*a90b9d01SCy Schubert 					   dpp_netrole_str(netrole));
2002*a90b9d01SCy Schubert 				auth->waiting_config = true;
2003*a90b9d01SCy Schubert 				dpp_get_peer_bi_id(auth);
2004*a90b9d01SCy Schubert 				return NULL;
2005*a90b9d01SCy Schubert 			}
200685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
200785732ac8SCy Schubert 				   "DPP: No configuration available for Enrollee(%s) - reject configuration request",
2008c1d255d3SCy Schubert 				   dpp_netrole_str(netrole));
2009*a90b9d01SCy Schubert 		}
201085732ac8SCy Schubert 		return NULL;
201185732ac8SCy Schubert 	}
201285732ac8SCy Schubert 
2013c1d255d3SCy Schubert 	if (conf->akm == DPP_AKM_DOT1X) {
2014c1d255d3SCy Schubert 		if (!auth->conf) {
2015c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
2016c1d255d3SCy Schubert 				   "DPP: No Configurator data available");
2017c1d255d3SCy Schubert 			return NULL;
2018c1d255d3SCy Schubert 		}
2019c1d255d3SCy Schubert 		if (!cert_req && !auth->certbag) {
2020c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
2021c1d255d3SCy Schubert 				   "DPP: No certificate data available for dot1x configuration");
2022c1d255d3SCy Schubert 			return NULL;
2023c1d255d3SCy Schubert 		}
2024c1d255d3SCy Schubert 		return dpp_build_conf_obj_dpp(auth, conf);
2025c1d255d3SCy Schubert 	}
2026c1d255d3SCy Schubert 	if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
2027c1d255d3SCy Schubert 		return dpp_build_conf_obj_dpp(auth, conf);
2028c1d255d3SCy Schubert 	return dpp_build_conf_obj_legacy(auth, conf);
202985732ac8SCy Schubert }
203085732ac8SCy Schubert 
203185732ac8SCy Schubert 
2032c1d255d3SCy Schubert struct wpabuf *
203385732ac8SCy Schubert dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
2034c1d255d3SCy Schubert 		    u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
203585732ac8SCy Schubert {
2036*a90b9d01SCy Schubert 	struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
203785732ac8SCy Schubert 	size_t clear_len, attr_len;
203885732ac8SCy Schubert 	struct wpabuf *clear = NULL, *msg = NULL;
203985732ac8SCy Schubert 	u8 *wrapped;
204085732ac8SCy Schubert 	const u8 *addr[1];
204185732ac8SCy Schubert 	size_t len[1];
204285732ac8SCy Schubert 	enum dpp_status_error status;
204385732ac8SCy Schubert 
2044c1d255d3SCy Schubert 	if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2045c1d255d3SCy Schubert 		status = auth->force_conf_resp_status;
2046c1d255d3SCy Schubert 		goto forced_status;
204785732ac8SCy Schubert 	}
2048c1d255d3SCy Schubert 
2049c1d255d3SCy Schubert 	if (netrole == DPP_NETROLE_CONFIGURATOR) {
2050c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2051c1d255d3SCy Schubert 		env_data = dpp_build_enveloped_data(auth);
2052c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
2053c1d255d3SCy Schubert 	} else {
2054c1d255d3SCy Schubert 		conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
2055c1d255d3SCy Schubert 		if (conf) {
2056c1d255d3SCy Schubert 			wpa_hexdump_ascii(MSG_DEBUG,
2057c1d255d3SCy Schubert 					  "DPP: configurationObject JSON",
2058c1d255d3SCy Schubert 					  wpabuf_head(conf), wpabuf_len(conf));
2059c1d255d3SCy Schubert 			conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
2060c1d255d3SCy Schubert 		}
2061c1d255d3SCy Schubert 	}
2062c1d255d3SCy Schubert 
2063*a90b9d01SCy Schubert 	if (!conf && auth->waiting_config)
2064*a90b9d01SCy Schubert 		return NULL;
2065c1d255d3SCy Schubert 	if (conf || env_data)
2066c1d255d3SCy Schubert 		status = DPP_STATUS_OK;
2067c1d255d3SCy Schubert 	else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2068c1d255d3SCy Schubert 		 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2069c1d255d3SCy Schubert 		status = DPP_STATUS_CSR_NEEDED;
2070*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2071*a90b9d01SCy Schubert 	else if (auth->waiting_new_key)
2072*a90b9d01SCy Schubert 		status = DPP_STATUS_NEW_KEY_NEEDED;
2073*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
2074c1d255d3SCy Schubert 	else
2075c1d255d3SCy Schubert 		status = DPP_STATUS_CONFIGURE_FAILURE;
2076c1d255d3SCy Schubert forced_status:
20774bc52338SCy Schubert 	auth->conf_resp_status = status;
207885732ac8SCy Schubert 
2079c1d255d3SCy Schubert 	/* { E-nonce, configurationObject[, sendConnStatus]}ke */
208085732ac8SCy Schubert 	clear_len = 4 + e_nonce_len;
208185732ac8SCy Schubert 	if (conf)
208285732ac8SCy Schubert 		clear_len += 4 + wpabuf_len(conf);
2083c1d255d3SCy Schubert 	if (conf2)
2084c1d255d3SCy Schubert 		clear_len += 4 + wpabuf_len(conf2);
2085c1d255d3SCy Schubert 	if (env_data)
2086c1d255d3SCy Schubert 		clear_len += 4 + wpabuf_len(env_data);
2087c1d255d3SCy Schubert 	if (auth->peer_version >= 2 && auth->send_conn_status &&
2088c1d255d3SCy Schubert 	    netrole == DPP_NETROLE_STA)
2089c1d255d3SCy Schubert 		clear_len += 4;
2090c1d255d3SCy Schubert 	if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2091c1d255d3SCy Schubert 	    auth->conf_sta->csrattrs)
2092c1d255d3SCy Schubert 		clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
2093*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2094*a90b9d01SCy Schubert 	if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2095*a90b9d01SCy Schubert 		struct crypto_ec_key *new_pc;
2096*a90b9d01SCy Schubert 
2097*a90b9d01SCy Schubert 		clear_len += 6; /* Finite Cyclic Group attribute */
2098*a90b9d01SCy Schubert 
2099*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
2100*a90b9d01SCy Schubert 			   "DPP: Generate a new own protocol key for the curve %s",
2101*a90b9d01SCy Schubert 			   auth->conf->net_access_key_curve->name);
2102*a90b9d01SCy Schubert 		new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2103*a90b9d01SCy Schubert 		if (!new_pc) {
2104*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2105*a90b9d01SCy Schubert 			return NULL;
2106*a90b9d01SCy Schubert 		}
2107*a90b9d01SCy Schubert 		pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2108*a90b9d01SCy Schubert 		if (!pc) {
2109*a90b9d01SCy Schubert 			crypto_ec_key_deinit(new_pc);
2110*a90b9d01SCy Schubert 			return NULL;
2111*a90b9d01SCy Schubert 		}
2112*a90b9d01SCy Schubert 		crypto_ec_key_deinit(auth->own_protocol_key);
2113*a90b9d01SCy Schubert 		auth->own_protocol_key = new_pc;
2114*a90b9d01SCy Schubert 		auth->new_curve = auth->conf->net_access_key_curve;
2115*a90b9d01SCy Schubert 		clear_len += 4 + wpabuf_len(pc);
2116*a90b9d01SCy Schubert 	}
2117*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
211885732ac8SCy Schubert 	clear = wpabuf_alloc(clear_len);
211985732ac8SCy Schubert 	attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
212085732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
212185732ac8SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
212285732ac8SCy Schubert 		attr_len += 5;
212385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
212485732ac8SCy Schubert 	msg = wpabuf_alloc(attr_len);
212585732ac8SCy Schubert 	if (!clear || !msg)
212685732ac8SCy Schubert 		goto fail;
212785732ac8SCy Schubert 
212885732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
212985732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
213085732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
213185732ac8SCy Schubert 		goto skip_e_nonce;
213285732ac8SCy Schubert 	}
213385732ac8SCy Schubert 	if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
213485732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
213585732ac8SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
213685732ac8SCy Schubert 		wpabuf_put_le16(clear, e_nonce_len);
213785732ac8SCy Schubert 		wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
213885732ac8SCy Schubert 		wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
213985732ac8SCy Schubert 		goto skip_e_nonce;
214085732ac8SCy Schubert 	}
214185732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
214285732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
214385732ac8SCy Schubert 		goto skip_wrapped_data;
214485732ac8SCy Schubert 	}
214585732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
214685732ac8SCy Schubert 
214785732ac8SCy Schubert 	/* E-nonce */
214885732ac8SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
214985732ac8SCy Schubert 	wpabuf_put_le16(clear, e_nonce_len);
215085732ac8SCy Schubert 	wpabuf_put_data(clear, e_nonce, e_nonce_len);
215185732ac8SCy Schubert 
215285732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
215385732ac8SCy Schubert skip_e_nonce:
215485732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
215585732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
215685732ac8SCy Schubert 		goto skip_config_obj;
215785732ac8SCy Schubert 	}
215885732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
215985732ac8SCy Schubert 
216085732ac8SCy Schubert 	if (conf) {
216185732ac8SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
216285732ac8SCy Schubert 		wpabuf_put_le16(clear, wpabuf_len(conf));
216385732ac8SCy Schubert 		wpabuf_put_buf(clear, conf);
216485732ac8SCy Schubert 	}
2165c1d255d3SCy Schubert 	if (auth->peer_version >= 2 && conf2) {
2166c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2167c1d255d3SCy Schubert 		wpabuf_put_le16(clear, wpabuf_len(conf2));
2168c1d255d3SCy Schubert 		wpabuf_put_buf(clear, conf2);
2169c1d255d3SCy Schubert 	} else if (conf2) {
2170c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2171c1d255d3SCy Schubert 			   "DPP: Second Config Object available, but peer does not support more than one");
2172c1d255d3SCy Schubert 	}
2173c1d255d3SCy Schubert 	if (env_data) {
2174c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2175c1d255d3SCy Schubert 		wpabuf_put_le16(clear, wpabuf_len(env_data));
2176c1d255d3SCy Schubert 		wpabuf_put_buf(clear, env_data);
2177c1d255d3SCy Schubert 	}
2178c1d255d3SCy Schubert 
2179c1d255d3SCy Schubert 	if (auth->peer_version >= 2 && auth->send_conn_status &&
2180c1d255d3SCy Schubert 	    netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
2181c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2182c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2183c1d255d3SCy Schubert 		wpabuf_put_le16(clear, 0);
2184c1d255d3SCy Schubert 	}
2185c1d255d3SCy Schubert 
2186c1d255d3SCy Schubert 	if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2187c1d255d3SCy Schubert 	    auth->conf_sta->csrattrs) {
2188c1d255d3SCy Schubert 		auth->waiting_csr = true;
2189c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2190c1d255d3SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2191c1d255d3SCy Schubert 		wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2192c1d255d3SCy Schubert 		wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2193c1d255d3SCy Schubert 	}
219485732ac8SCy Schubert 
2195*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2196*a90b9d01SCy Schubert 	if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2197*a90b9d01SCy Schubert 	    auth->conf->net_access_key_curve) {
2198*a90b9d01SCy Schubert 		u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2199*a90b9d01SCy Schubert 
2200*a90b9d01SCy Schubert 		/* Finite Cyclic Group attribute */
2201*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2202*a90b9d01SCy Schubert 			   ike_group);
2203*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2204*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, 2);
2205*a90b9d01SCy Schubert 		wpabuf_put_le16(clear, ike_group);
2206*a90b9d01SCy Schubert 
2207*a90b9d01SCy Schubert 		if (pc) {
2208*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Pc");
2209*a90b9d01SCy Schubert 			wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2210*a90b9d01SCy Schubert 			wpabuf_put_le16(clear, wpabuf_len(pc));
2211*a90b9d01SCy Schubert 			wpabuf_put_buf(clear, pc);
2212*a90b9d01SCy Schubert 		}
2213*a90b9d01SCy Schubert 	}
2214*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
2215*a90b9d01SCy Schubert 
221685732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
221785732ac8SCy Schubert skip_config_obj:
221885732ac8SCy Schubert 	if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
221985732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - Status");
222085732ac8SCy Schubert 		goto skip_status;
222185732ac8SCy Schubert 	}
222285732ac8SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
222385732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
222485732ac8SCy Schubert 		status = 255;
222585732ac8SCy Schubert 	}
222685732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
222785732ac8SCy Schubert 
222885732ac8SCy Schubert 	/* DPP Status */
222985732ac8SCy Schubert 	dpp_build_attr_status(msg, status);
223085732ac8SCy Schubert 
223185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
223285732ac8SCy Schubert skip_status:
223385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
223485732ac8SCy Schubert 
223585732ac8SCy Schubert 	addr[0] = wpabuf_head(msg);
223685732ac8SCy Schubert 	len[0] = wpabuf_len(msg);
223785732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
223885732ac8SCy Schubert 
223985732ac8SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
224085732ac8SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
224185732ac8SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
224285732ac8SCy Schubert 
224385732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
224485732ac8SCy Schubert 	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
224585732ac8SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
224685732ac8SCy Schubert 			    1, addr, len, wrapped) < 0)
224785732ac8SCy Schubert 		goto fail;
224885732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
224985732ac8SCy Schubert 		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
225085732ac8SCy Schubert 
225185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
225285732ac8SCy Schubert 	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
225385732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
225485732ac8SCy Schubert 		dpp_build_attr_status(msg, DPP_STATUS_OK);
225585732ac8SCy Schubert 	}
225685732ac8SCy Schubert skip_wrapped_data:
225785732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
225885732ac8SCy Schubert 
225985732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG,
226085732ac8SCy Schubert 			"DPP: Configuration Response attributes", msg);
226185732ac8SCy Schubert out:
2262c1d255d3SCy Schubert 	wpabuf_clear_free(conf);
2263c1d255d3SCy Schubert 	wpabuf_clear_free(conf2);
2264c1d255d3SCy Schubert 	wpabuf_clear_free(env_data);
2265c1d255d3SCy Schubert 	wpabuf_clear_free(clear);
2266*a90b9d01SCy Schubert 	wpabuf_free(pc);
226785732ac8SCy Schubert 
226885732ac8SCy Schubert 	return msg;
226985732ac8SCy Schubert fail:
227085732ac8SCy Schubert 	wpabuf_free(msg);
227185732ac8SCy Schubert 	msg = NULL;
227285732ac8SCy Schubert 	goto out;
227385732ac8SCy Schubert }
227485732ac8SCy Schubert 
227585732ac8SCy Schubert 
227685732ac8SCy Schubert struct wpabuf *
227785732ac8SCy Schubert dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
227885732ac8SCy Schubert 		size_t attr_len)
227985732ac8SCy Schubert {
228085732ac8SCy Schubert 	const u8 *wrapped_data, *e_nonce, *config_attr;
228185732ac8SCy Schubert 	u16 wrapped_data_len, e_nonce_len, config_attr_len;
228285732ac8SCy Schubert 	u8 *unwrapped = NULL;
228385732ac8SCy Schubert 	size_t unwrapped_len = 0;
228485732ac8SCy Schubert 	struct wpabuf *resp = NULL;
228585732ac8SCy Schubert 	struct json_token *root = NULL, *token;
2286c1d255d3SCy Schubert 	enum dpp_netrole netrole;
2287c1d255d3SCy Schubert 	struct wpabuf *cert_req = NULL;
2288*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2289*a90b9d01SCy Schubert 	const u8 *i_proto;
2290*a90b9d01SCy Schubert 	u16 i_proto_len;
2291*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
229285732ac8SCy Schubert 
229385732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
229485732ac8SCy Schubert 	if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
229585732ac8SCy Schubert 		wpa_printf(MSG_INFO,
229685732ac8SCy Schubert 			   "DPP: TESTING - stop at Config Request");
229785732ac8SCy Schubert 		return NULL;
229885732ac8SCy Schubert 	}
229985732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
230085732ac8SCy Schubert 
230185732ac8SCy Schubert 	if (dpp_check_attrs(attr_start, attr_len) < 0) {
230285732ac8SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in config request");
230385732ac8SCy Schubert 		return NULL;
230485732ac8SCy Schubert 	}
230585732ac8SCy Schubert 
230685732ac8SCy Schubert 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
230785732ac8SCy Schubert 				    &wrapped_data_len);
230885732ac8SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
230985732ac8SCy Schubert 		dpp_auth_fail(auth,
231085732ac8SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
231185732ac8SCy Schubert 		return NULL;
231285732ac8SCy Schubert 	}
231385732ac8SCy Schubert 
231485732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
231585732ac8SCy Schubert 		    wrapped_data, wrapped_data_len);
231685732ac8SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
231785732ac8SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
231885732ac8SCy Schubert 	if (!unwrapped)
231985732ac8SCy Schubert 		return NULL;
232085732ac8SCy Schubert 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
232185732ac8SCy Schubert 			    wrapped_data, wrapped_data_len,
232285732ac8SCy Schubert 			    0, NULL, NULL, unwrapped) < 0) {
232385732ac8SCy Schubert 		dpp_auth_fail(auth, "AES-SIV decryption failed");
232485732ac8SCy Schubert 		goto fail;
232585732ac8SCy Schubert 	}
232685732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
232785732ac8SCy Schubert 		    unwrapped, unwrapped_len);
232885732ac8SCy Schubert 
232985732ac8SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
233085732ac8SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
233185732ac8SCy Schubert 		goto fail;
233285732ac8SCy Schubert 	}
233385732ac8SCy Schubert 
233485732ac8SCy Schubert 	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
233585732ac8SCy Schubert 			       DPP_ATTR_ENROLLEE_NONCE,
233685732ac8SCy Schubert 			       &e_nonce_len);
233785732ac8SCy Schubert 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
233885732ac8SCy Schubert 		dpp_auth_fail(auth,
233985732ac8SCy Schubert 			      "Missing or invalid Enrollee Nonce attribute");
234085732ac8SCy Schubert 		goto fail;
234185732ac8SCy Schubert 	}
234285732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
23434bc52338SCy Schubert 	os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
234485732ac8SCy Schubert 
2345*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
2346*a90b9d01SCy Schubert 	i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2347*a90b9d01SCy Schubert 			       DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2348*a90b9d01SCy Schubert 	if (i_proto && !auth->waiting_new_key) {
2349*a90b9d01SCy Schubert 		dpp_auth_fail(auth,
2350*a90b9d01SCy Schubert 			      "Enrollee included a new protocol key even though one was not expected");
2351*a90b9d01SCy Schubert 		goto fail;
2352*a90b9d01SCy Schubert 	}
2353*a90b9d01SCy Schubert 	if (i_proto) {
2354*a90b9d01SCy Schubert 		struct crypto_ec_key *pe;
2355*a90b9d01SCy Schubert 		u8 auth_i[DPP_MAX_HASH_LEN];
2356*a90b9d01SCy Schubert 		const u8 *rx_auth_i;
2357*a90b9d01SCy Schubert 		u16 rx_auth_i_len;
2358*a90b9d01SCy Schubert 
2359*a90b9d01SCy Schubert 		wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2360*a90b9d01SCy Schubert 			    i_proto, i_proto_len);
2361*a90b9d01SCy Schubert 
2362*a90b9d01SCy Schubert 		pe = dpp_set_pubkey_point(auth->own_protocol_key,
2363*a90b9d01SCy Schubert 					  i_proto, i_proto_len);
2364*a90b9d01SCy Schubert 		if (!pe) {
2365*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
2366*a90b9d01SCy Schubert 				      "Invalid Initiator Protocol Key (Pe)");
2367*a90b9d01SCy Schubert 			goto fail;
2368*a90b9d01SCy Schubert 		}
2369*a90b9d01SCy Schubert 		dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2370*a90b9d01SCy Schubert 		crypto_ec_key_deinit(auth->peer_protocol_key);
2371*a90b9d01SCy Schubert 		auth->peer_protocol_key = pe;
2372*a90b9d01SCy Schubert 		auth->new_key_received = true;
2373*a90b9d01SCy Schubert 		auth->waiting_new_key = false;
2374*a90b9d01SCy Schubert 
2375*a90b9d01SCy Schubert 		if (dpp_derive_auth_i(auth, auth_i) < 0)
2376*a90b9d01SCy Schubert 			goto fail;
2377*a90b9d01SCy Schubert 
2378*a90b9d01SCy Schubert 		rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2379*a90b9d01SCy Schubert 					 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2380*a90b9d01SCy Schubert 		if (!rx_auth_i) {
2381*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
2382*a90b9d01SCy Schubert 				      "Missing Initiator Authentication Tag");
2383*a90b9d01SCy Schubert 			goto fail;
2384*a90b9d01SCy Schubert 		}
2385*a90b9d01SCy Schubert 		if (rx_auth_i_len != auth->curve->hash_len ||
2386*a90b9d01SCy Schubert 		    os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2387*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
2388*a90b9d01SCy Schubert 				      "Mismatch in Initiator Authenticating Tag");
2389*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2390*a90b9d01SCy Schubert 				    rx_auth_i, rx_auth_i_len);
2391*a90b9d01SCy Schubert 			wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2392*a90b9d01SCy Schubert 				    auth_i, auth->curve->hash_len);
2393*a90b9d01SCy Schubert 			goto fail;
2394*a90b9d01SCy Schubert 		}
2395*a90b9d01SCy Schubert 	}
2396*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
2397*a90b9d01SCy Schubert 
239885732ac8SCy Schubert 	config_attr = dpp_get_attr(unwrapped, unwrapped_len,
239985732ac8SCy Schubert 				   DPP_ATTR_CONFIG_ATTR_OBJ,
240085732ac8SCy Schubert 				   &config_attr_len);
240185732ac8SCy Schubert 	if (!config_attr) {
240285732ac8SCy Schubert 		dpp_auth_fail(auth,
240385732ac8SCy Schubert 			      "Missing or invalid Config Attributes attribute");
240485732ac8SCy Schubert 		goto fail;
240585732ac8SCy Schubert 	}
240685732ac8SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
240785732ac8SCy Schubert 			  config_attr, config_attr_len);
240885732ac8SCy Schubert 
240985732ac8SCy Schubert 	root = json_parse((const char *) config_attr, config_attr_len);
241085732ac8SCy Schubert 	if (!root) {
241185732ac8SCy Schubert 		dpp_auth_fail(auth, "Could not parse Config Attributes");
241285732ac8SCy Schubert 		goto fail;
241385732ac8SCy Schubert 	}
241485732ac8SCy Schubert 
241585732ac8SCy Schubert 	token = json_get_member(root, "name");
241685732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
241785732ac8SCy Schubert 		dpp_auth_fail(auth, "No Config Attributes - name");
241885732ac8SCy Schubert 		goto fail;
241985732ac8SCy Schubert 	}
242085732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
2421*a90b9d01SCy Schubert 	os_free(auth->e_name);
2422*a90b9d01SCy Schubert 	auth->e_name = os_strdup(token->string);
242385732ac8SCy Schubert 
242485732ac8SCy Schubert 	token = json_get_member(root, "wi-fi_tech");
242585732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
242685732ac8SCy Schubert 		dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
242785732ac8SCy Schubert 		goto fail;
242885732ac8SCy Schubert 	}
242985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
243085732ac8SCy Schubert 	if (os_strcmp(token->string, "infra") != 0) {
243185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
243285732ac8SCy Schubert 			   token->string);
243385732ac8SCy Schubert 		dpp_auth_fail(auth, "Unsupported wi-fi_tech");
243485732ac8SCy Schubert 		goto fail;
243585732ac8SCy Schubert 	}
243685732ac8SCy Schubert 
243785732ac8SCy Schubert 	token = json_get_member(root, "netRole");
243885732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
243985732ac8SCy Schubert 		dpp_auth_fail(auth, "No Config Attributes - netRole");
244085732ac8SCy Schubert 		goto fail;
244185732ac8SCy Schubert 	}
244285732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
244385732ac8SCy Schubert 	if (os_strcmp(token->string, "sta") == 0) {
2444c1d255d3SCy Schubert 		netrole = DPP_NETROLE_STA;
244585732ac8SCy Schubert 	} else if (os_strcmp(token->string, "ap") == 0) {
2446c1d255d3SCy Schubert 		netrole = DPP_NETROLE_AP;
2447c1d255d3SCy Schubert 	} else if (os_strcmp(token->string, "configurator") == 0) {
2448c1d255d3SCy Schubert 		netrole = DPP_NETROLE_CONFIGURATOR;
244985732ac8SCy Schubert 	} else {
245085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
245185732ac8SCy Schubert 			   token->string);
245285732ac8SCy Schubert 		dpp_auth_fail(auth, "Unsupported netRole");
245385732ac8SCy Schubert 		goto fail;
245485732ac8SCy Schubert 	}
2455c1d255d3SCy Schubert 	auth->e_netrole = netrole;
245685732ac8SCy Schubert 
2457c1d255d3SCy Schubert 	token = json_get_member(root, "mudurl");
2458c1d255d3SCy Schubert 	if (token && token->type == JSON_STRING) {
2459c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
2460c1d255d3SCy Schubert 		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2461c1d255d3SCy Schubert 			token->string);
2462*a90b9d01SCy Schubert 		os_free(auth->e_mud_url);
2463*a90b9d01SCy Schubert 		auth->e_mud_url = os_strdup(token->string);
2464c1d255d3SCy Schubert 	}
2465c1d255d3SCy Schubert 
2466c1d255d3SCy Schubert 	token = json_get_member(root, "bandSupport");
2467c1d255d3SCy Schubert 	if (token && token->type == JSON_ARRAY) {
2468c1d255d3SCy Schubert 		int *opclass = NULL;
2469c1d255d3SCy Schubert 		char txt[200], *pos, *end;
2470c1d255d3SCy Schubert 		int i, res;
2471c1d255d3SCy Schubert 
2472c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2473c1d255d3SCy Schubert 		token = token->child;
2474c1d255d3SCy Schubert 		while (token) {
2475c1d255d3SCy Schubert 			if (token->type != JSON_NUMBER) {
2476c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
2477c1d255d3SCy Schubert 					   "DPP: Invalid bandSupport array member type");
2478c1d255d3SCy Schubert 			} else {
2479c1d255d3SCy Schubert 				wpa_printf(MSG_DEBUG,
2480c1d255d3SCy Schubert 					   "DPP: Supported global operating class: %d",
2481c1d255d3SCy Schubert 					   token->number);
2482c1d255d3SCy Schubert 				int_array_add_unique(&opclass, token->number);
2483c1d255d3SCy Schubert 			}
2484c1d255d3SCy Schubert 			token = token->sibling;
2485c1d255d3SCy Schubert 		}
2486c1d255d3SCy Schubert 
2487c1d255d3SCy Schubert 		txt[0] = '\0';
2488c1d255d3SCy Schubert 		pos = txt;
2489c1d255d3SCy Schubert 		end = txt + sizeof(txt);
2490c1d255d3SCy Schubert 		for (i = 0; opclass && opclass[i]; i++) {
2491c1d255d3SCy Schubert 			res = os_snprintf(pos, end - pos, "%s%d",
2492c1d255d3SCy Schubert 					  pos == txt ? "" : ",", opclass[i]);
2493c1d255d3SCy Schubert 			if (os_snprintf_error(end - pos, res)) {
2494c1d255d3SCy Schubert 				*pos = '\0';
2495c1d255d3SCy Schubert 				break;
2496c1d255d3SCy Schubert 			}
2497c1d255d3SCy Schubert 			pos += res;
2498c1d255d3SCy Schubert 		}
2499*a90b9d01SCy Schubert 		os_free(auth->e_band_support);
2500*a90b9d01SCy Schubert 		auth->e_band_support = opclass;
2501c1d255d3SCy Schubert 		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2502c1d255d3SCy Schubert 			txt);
2503c1d255d3SCy Schubert 	}
2504c1d255d3SCy Schubert 
2505c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2506c1d255d3SCy Schubert 	cert_req = json_get_member_base64(root, "pkcs10");
2507c1d255d3SCy Schubert 	if (cert_req) {
2508c1d255d3SCy Schubert 		char *txt;
2509c1d255d3SCy Schubert 		int id;
2510c1d255d3SCy Schubert 
2511c1d255d3SCy Schubert 		wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2512c1d255d3SCy Schubert 		if (dpp_validate_csr(auth, cert_req) < 0) {
2513c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2514c1d255d3SCy Schubert 			auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2515c1d255d3SCy Schubert 			goto cont;
2516c1d255d3SCy Schubert 		}
2517c1d255d3SCy Schubert 
2518*a90b9d01SCy Schubert 		id = dpp_get_peer_bi_id(auth);
2519*a90b9d01SCy Schubert 		if (id < 0)
2520c1d255d3SCy Schubert 			goto fail;
2521c1d255d3SCy Schubert 
2522c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2523c1d255d3SCy Schubert 		txt = base64_encode_no_lf(wpabuf_head(cert_req),
2524c1d255d3SCy Schubert 					  wpabuf_len(cert_req), NULL);
2525c1d255d3SCy Schubert 		if (!txt)
2526c1d255d3SCy Schubert 			goto fail;
2527c1d255d3SCy Schubert 
2528c1d255d3SCy Schubert 		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2529c1d255d3SCy Schubert 			id, txt);
2530c1d255d3SCy Schubert 		os_free(txt);
2531c1d255d3SCy Schubert 		auth->waiting_csr = false;
2532c1d255d3SCy Schubert 		auth->waiting_cert = true;
2533c1d255d3SCy Schubert 		goto fail;
2534c1d255d3SCy Schubert 	}
2535c1d255d3SCy Schubert cont:
2536c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
2537c1d255d3SCy Schubert 
2538c1d255d3SCy Schubert 	resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2539c1d255d3SCy Schubert 				   cert_req);
254085732ac8SCy Schubert 
254185732ac8SCy Schubert fail:
2542c1d255d3SCy Schubert 	wpabuf_free(cert_req);
254385732ac8SCy Schubert 	json_free(root);
254485732ac8SCy Schubert 	os_free(unwrapped);
254585732ac8SCy Schubert 	return resp;
254685732ac8SCy Schubert }
254785732ac8SCy Schubert 
254885732ac8SCy Schubert 
2549c1d255d3SCy Schubert static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
255085732ac8SCy Schubert 				 struct json_token *cred)
255185732ac8SCy Schubert {
255285732ac8SCy Schubert 	struct json_token *pass, *psk_hex;
255385732ac8SCy Schubert 
255485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
255585732ac8SCy Schubert 
255685732ac8SCy Schubert 	pass = json_get_member(cred, "pass");
255785732ac8SCy Schubert 	psk_hex = json_get_member(cred, "psk_hex");
255885732ac8SCy Schubert 
255985732ac8SCy Schubert 	if (pass && pass->type == JSON_STRING) {
256085732ac8SCy Schubert 		size_t len = os_strlen(pass->string);
256185732ac8SCy Schubert 
256285732ac8SCy Schubert 		wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
256385732ac8SCy Schubert 				      pass->string, len);
256485732ac8SCy Schubert 		if (len < 8 || len > 63)
256585732ac8SCy Schubert 			return -1;
2566c1d255d3SCy Schubert 		os_strlcpy(conf->passphrase, pass->string,
2567c1d255d3SCy Schubert 			   sizeof(conf->passphrase));
256885732ac8SCy Schubert 	} else if (psk_hex && psk_hex->type == JSON_STRING) {
2569c1d255d3SCy Schubert 		if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
257085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
257185732ac8SCy Schubert 				   "DPP: Unexpected psk_hex with akm=sae");
257285732ac8SCy Schubert 			return -1;
257385732ac8SCy Schubert 		}
257485732ac8SCy Schubert 		if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
2575c1d255d3SCy Schubert 		    hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
257685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
257785732ac8SCy Schubert 			return -1;
257885732ac8SCy Schubert 		}
257985732ac8SCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
2580c1d255d3SCy Schubert 				conf->psk, PMK_LEN);
2581c1d255d3SCy Schubert 		conf->psk_set = 1;
258285732ac8SCy Schubert 	} else {
258385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
258485732ac8SCy Schubert 		return -1;
258585732ac8SCy Schubert 	}
258685732ac8SCy Schubert 
2587c1d255d3SCy Schubert 	if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
258885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
258985732ac8SCy Schubert 		return -1;
259085732ac8SCy Schubert 	}
259185732ac8SCy Schubert 
259285732ac8SCy Schubert 	return 0;
259385732ac8SCy Schubert }
259485732ac8SCy Schubert 
259585732ac8SCy Schubert 
25964b72b91aSCy Schubert struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
259785732ac8SCy Schubert 				     const struct dpp_curve_params **key_curve)
259885732ac8SCy Schubert {
259985732ac8SCy Schubert 	struct json_token *token;
260085732ac8SCy Schubert 	const struct dpp_curve_params *curve;
260185732ac8SCy Schubert 	struct wpabuf *x = NULL, *y = NULL;
26024b72b91aSCy Schubert 	struct crypto_ec_key *key = NULL;
260385732ac8SCy Schubert 
260485732ac8SCy Schubert 	token = json_get_member(jwk, "kty");
260585732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
260685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
260785732ac8SCy Schubert 		goto fail;
260885732ac8SCy Schubert 	}
260985732ac8SCy Schubert 	if (os_strcmp(token->string, "EC") != 0) {
261085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
261185732ac8SCy Schubert 			   token->string);
261285732ac8SCy Schubert 		goto fail;
261385732ac8SCy Schubert 	}
261485732ac8SCy Schubert 
261585732ac8SCy Schubert 	token = json_get_member(jwk, "crv");
261685732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
261785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
261885732ac8SCy Schubert 		goto fail;
261985732ac8SCy Schubert 	}
262085732ac8SCy Schubert 	curve = dpp_get_curve_jwk_crv(token->string);
262185732ac8SCy Schubert 	if (!curve) {
262285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
262385732ac8SCy Schubert 			   token->string);
262485732ac8SCy Schubert 		goto fail;
262585732ac8SCy Schubert 	}
262685732ac8SCy Schubert 
262785732ac8SCy Schubert 	x = json_get_member_base64url(jwk, "x");
262885732ac8SCy Schubert 	if (!x) {
262985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
263085732ac8SCy Schubert 		goto fail;
263185732ac8SCy Schubert 	}
263285732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
263385732ac8SCy Schubert 	if (wpabuf_len(x) != curve->prime_len) {
263485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
263585732ac8SCy Schubert 			   "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
263685732ac8SCy Schubert 			   (unsigned int) wpabuf_len(x),
263785732ac8SCy Schubert 			   (unsigned int) curve->prime_len, curve->name);
263885732ac8SCy Schubert 		goto fail;
263985732ac8SCy Schubert 	}
264085732ac8SCy Schubert 
264185732ac8SCy Schubert 	y = json_get_member_base64url(jwk, "y");
264285732ac8SCy Schubert 	if (!y) {
264385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
264485732ac8SCy Schubert 		goto fail;
264585732ac8SCy Schubert 	}
264685732ac8SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
264785732ac8SCy Schubert 	if (wpabuf_len(y) != curve->prime_len) {
264885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
264985732ac8SCy Schubert 			   "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
265085732ac8SCy Schubert 			   (unsigned int) wpabuf_len(y),
265185732ac8SCy Schubert 			   (unsigned int) curve->prime_len, curve->name);
265285732ac8SCy Schubert 		goto fail;
265385732ac8SCy Schubert 	}
265485732ac8SCy Schubert 
26554b72b91aSCy Schubert 	key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
26564b72b91aSCy Schubert 				    wpabuf_head(y), wpabuf_len(x));
26574b72b91aSCy Schubert 	if (!key)
265885732ac8SCy Schubert 		goto fail;
265985732ac8SCy Schubert 
266085732ac8SCy Schubert 	*key_curve = curve;
266185732ac8SCy Schubert 
266285732ac8SCy Schubert fail:
266385732ac8SCy Schubert 	wpabuf_free(x);
266485732ac8SCy Schubert 	wpabuf_free(y);
266585732ac8SCy Schubert 
26664b72b91aSCy Schubert 	return key;
266785732ac8SCy Schubert }
266885732ac8SCy Schubert 
266985732ac8SCy Schubert 
267085732ac8SCy Schubert int dpp_key_expired(const char *timestamp, os_time_t *expiry)
267185732ac8SCy Schubert {
267285732ac8SCy Schubert 	struct os_time now;
267385732ac8SCy Schubert 	unsigned int year, month, day, hour, min, sec;
267485732ac8SCy Schubert 	os_time_t utime;
267585732ac8SCy Schubert 	const char *pos;
267685732ac8SCy Schubert 
267785732ac8SCy Schubert 	/* ISO 8601 date and time:
267885732ac8SCy Schubert 	 * <date>T<time>
267985732ac8SCy Schubert 	 * YYYY-MM-DDTHH:MM:SSZ
268085732ac8SCy Schubert 	 * YYYY-MM-DDTHH:MM:SS+03:00
268185732ac8SCy Schubert 	 */
268285732ac8SCy Schubert 	if (os_strlen(timestamp) < 19) {
268385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
268485732ac8SCy Schubert 			   "DPP: Too short timestamp - assume expired key");
268585732ac8SCy Schubert 		return 1;
268685732ac8SCy Schubert 	}
268785732ac8SCy Schubert 	if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
268885732ac8SCy Schubert 		   &year, &month, &day, &hour, &min, &sec) != 6) {
268985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
269085732ac8SCy Schubert 			   "DPP: Failed to parse expiration day - assume expired key");
269185732ac8SCy Schubert 		return 1;
269285732ac8SCy Schubert 	}
269385732ac8SCy Schubert 
269485732ac8SCy Schubert 	if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
269585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
269685732ac8SCy Schubert 			   "DPP: Invalid date/time information - assume expired key");
269785732ac8SCy Schubert 		return 1;
269885732ac8SCy Schubert 	}
269985732ac8SCy Schubert 
270085732ac8SCy Schubert 	pos = timestamp + 19;
270185732ac8SCy Schubert 	if (*pos == 'Z' || *pos == '\0') {
270285732ac8SCy Schubert 		/* In UTC - no need to adjust */
270385732ac8SCy Schubert 	} else if (*pos == '-' || *pos == '+') {
270485732ac8SCy Schubert 		int items;
270585732ac8SCy Schubert 
270685732ac8SCy Schubert 		/* Adjust local time to UTC */
270785732ac8SCy Schubert 		items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
270885732ac8SCy Schubert 		if (items < 1) {
270985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
271085732ac8SCy Schubert 				   "DPP: Invalid time zone designator (%s) - assume expired key",
271185732ac8SCy Schubert 				   pos);
271285732ac8SCy Schubert 			return 1;
271385732ac8SCy Schubert 		}
271485732ac8SCy Schubert 		if (*pos == '-')
271585732ac8SCy Schubert 			utime += 3600 * hour;
271685732ac8SCy Schubert 		if (*pos == '+')
271785732ac8SCy Schubert 			utime -= 3600 * hour;
271885732ac8SCy Schubert 		if (items > 1) {
271985732ac8SCy Schubert 			if (*pos == '-')
272085732ac8SCy Schubert 				utime += 60 * min;
272185732ac8SCy Schubert 			if (*pos == '+')
272285732ac8SCy Schubert 				utime -= 60 * min;
272385732ac8SCy Schubert 		}
272485732ac8SCy Schubert 	} else {
272585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
272685732ac8SCy Schubert 			   "DPP: Invalid time zone designator (%s) - assume expired key",
272785732ac8SCy Schubert 			   pos);
272885732ac8SCy Schubert 		return 1;
272985732ac8SCy Schubert 	}
273085732ac8SCy Schubert 	if (expiry)
273185732ac8SCy Schubert 		*expiry = utime;
273285732ac8SCy Schubert 
273385732ac8SCy Schubert 	if (os_get_time(&now) < 0) {
273485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
273585732ac8SCy Schubert 			   "DPP: Cannot get current time - assume expired key");
273685732ac8SCy Schubert 		return 1;
273785732ac8SCy Schubert 	}
273885732ac8SCy Schubert 
273985732ac8SCy Schubert 	if (now.sec > utime) {
274085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
274185732ac8SCy Schubert 			   utime, now.sec);
274285732ac8SCy Schubert 		return 1;
274385732ac8SCy Schubert 	}
274485732ac8SCy Schubert 
274585732ac8SCy Schubert 	return 0;
274685732ac8SCy Schubert }
274785732ac8SCy Schubert 
274885732ac8SCy Schubert 
274985732ac8SCy Schubert static int dpp_parse_connector(struct dpp_authentication *auth,
2750c1d255d3SCy Schubert 			       struct dpp_config_obj *conf,
275185732ac8SCy Schubert 			       const unsigned char *payload,
275285732ac8SCy Schubert 			       u16 payload_len)
275385732ac8SCy Schubert {
275485732ac8SCy Schubert 	struct json_token *root, *groups, *netkey, *token;
275585732ac8SCy Schubert 	int ret = -1;
27564b72b91aSCy Schubert 	struct crypto_ec_key *key = NULL;
275785732ac8SCy Schubert 	const struct dpp_curve_params *curve;
275885732ac8SCy Schubert 	unsigned int rules = 0;
275985732ac8SCy Schubert 
276085732ac8SCy Schubert 	root = json_parse((const char *) payload, payload_len);
276185732ac8SCy Schubert 	if (!root) {
276285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
276385732ac8SCy Schubert 		goto fail;
276485732ac8SCy Schubert 	}
276585732ac8SCy Schubert 
276685732ac8SCy Schubert 	groups = json_get_member(root, "groups");
276785732ac8SCy Schubert 	if (!groups || groups->type != JSON_ARRAY) {
276885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No groups array found");
276985732ac8SCy Schubert 		goto skip_groups;
277085732ac8SCy Schubert 	}
277185732ac8SCy Schubert 	for (token = groups->child; token; token = token->sibling) {
277285732ac8SCy Schubert 		struct json_token *id, *role;
277385732ac8SCy Schubert 
277485732ac8SCy Schubert 		id = json_get_member(token, "groupId");
277585732ac8SCy Schubert 		if (!id || id->type != JSON_STRING) {
277685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
277785732ac8SCy Schubert 			goto fail;
277885732ac8SCy Schubert 		}
277985732ac8SCy Schubert 
278085732ac8SCy Schubert 		role = json_get_member(token, "netRole");
278185732ac8SCy Schubert 		if (!role || role->type != JSON_STRING) {
278285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
278385732ac8SCy Schubert 			goto fail;
278485732ac8SCy Schubert 		}
278585732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
278685732ac8SCy Schubert 			   "DPP: connector group: groupId='%s' netRole='%s'",
278785732ac8SCy Schubert 			   id->string, role->string);
278885732ac8SCy Schubert 		rules++;
278985732ac8SCy Schubert 	}
279085732ac8SCy Schubert skip_groups:
279185732ac8SCy Schubert 
279285732ac8SCy Schubert 	if (!rules) {
279385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
279485732ac8SCy Schubert 			   "DPP: Connector includes no groups");
279585732ac8SCy Schubert 		goto fail;
279685732ac8SCy Schubert 	}
279785732ac8SCy Schubert 
279885732ac8SCy Schubert 	token = json_get_member(root, "expiry");
279985732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
280085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
280185732ac8SCy Schubert 			   "DPP: No expiry string found - connector does not expire");
280285732ac8SCy Schubert 	} else {
280385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
280485732ac8SCy Schubert 		if (dpp_key_expired(token->string,
280585732ac8SCy Schubert 				    &auth->net_access_key_expiry)) {
280685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
280785732ac8SCy Schubert 				   "DPP: Connector (netAccessKey) has expired");
280885732ac8SCy Schubert 			goto fail;
280985732ac8SCy Schubert 		}
281085732ac8SCy Schubert 	}
281185732ac8SCy Schubert 
281285732ac8SCy Schubert 	netkey = json_get_member(root, "netAccessKey");
281385732ac8SCy Schubert 	if (!netkey || netkey->type != JSON_OBJECT) {
281485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
281585732ac8SCy Schubert 		goto fail;
281685732ac8SCy Schubert 	}
281785732ac8SCy Schubert 
281885732ac8SCy Schubert 	key = dpp_parse_jwk(netkey, &curve);
281985732ac8SCy Schubert 	if (!key)
282085732ac8SCy Schubert 		goto fail;
282185732ac8SCy Schubert 	dpp_debug_print_key("DPP: Received netAccessKey", key);
282285732ac8SCy Schubert 
28234b72b91aSCy Schubert 	if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
282485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
282585732ac8SCy Schubert 			   "DPP: netAccessKey in connector does not match own protocol key");
282685732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
282785732ac8SCy Schubert 		if (auth->ignore_netaccesskey_mismatch) {
282885732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
282985732ac8SCy Schubert 				   "DPP: TESTING - skip netAccessKey mismatch");
283085732ac8SCy Schubert 		} else {
283185732ac8SCy Schubert 			goto fail;
283285732ac8SCy Schubert 		}
283385732ac8SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
283485732ac8SCy Schubert 		goto fail;
283585732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
283685732ac8SCy Schubert 	}
283785732ac8SCy Schubert 
283885732ac8SCy Schubert 	ret = 0;
283985732ac8SCy Schubert fail:
28404b72b91aSCy Schubert 	crypto_ec_key_deinit(key);
284185732ac8SCy Schubert 	json_free(root);
284285732ac8SCy Schubert 	return ret;
284385732ac8SCy Schubert }
284485732ac8SCy Schubert 
284585732ac8SCy Schubert 
28464b72b91aSCy Schubert static void dpp_copy_csign(struct dpp_config_obj *conf,
28474b72b91aSCy Schubert 			   struct crypto_ec_key *csign)
284885732ac8SCy Schubert {
28494b72b91aSCy Schubert 	struct wpabuf *c_sign_key;
285085732ac8SCy Schubert 
28514b72b91aSCy Schubert 	c_sign_key = crypto_ec_key_get_subject_public_key(csign);
28524b72b91aSCy Schubert 	if (!c_sign_key)
285385732ac8SCy Schubert 		return;
28544b72b91aSCy Schubert 
2855c1d255d3SCy Schubert 	wpabuf_free(conf->c_sign_key);
28564b72b91aSCy Schubert 	conf->c_sign_key = c_sign_key;
285785732ac8SCy Schubert }
285885732ac8SCy Schubert 
285985732ac8SCy Schubert 
28604b72b91aSCy Schubert static void dpp_copy_ppkey(struct dpp_config_obj *conf,
28614b72b91aSCy Schubert 			   struct crypto_ec_key *ppkey)
2862c1d255d3SCy Schubert {
28634b72b91aSCy Schubert 	struct wpabuf *pp_key;
2864c1d255d3SCy Schubert 
28654b72b91aSCy Schubert 	pp_key = crypto_ec_key_get_subject_public_key(ppkey);
28664b72b91aSCy Schubert 	if (!pp_key)
2867c1d255d3SCy Schubert 		return;
28684b72b91aSCy Schubert 
2869c1d255d3SCy Schubert 	wpabuf_free(conf->pp_key);
28704b72b91aSCy Schubert 	conf->pp_key = pp_key;
2871c1d255d3SCy Schubert }
2872c1d255d3SCy Schubert 
2873c1d255d3SCy Schubert 
2874c1d255d3SCy Schubert static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2875c1d255d3SCy Schubert 				  struct dpp_config_obj *conf)
287685732ac8SCy Schubert {
28774b72b91aSCy Schubert 	struct wpabuf *net_access_key;
28784b72b91aSCy Schubert 	struct crypto_ec_key *own_key;
287985732ac8SCy Schubert 
2880c1d255d3SCy Schubert 	own_key = auth->own_protocol_key;
2881c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2882c1d255d3SCy Schubert 	if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2883c1d255d3SCy Schubert 	    auth->reconfig_old_protocol_key)
2884c1d255d3SCy Schubert 		own_key = auth->reconfig_old_protocol_key;
2885c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
28864b72b91aSCy Schubert 
28874b72b91aSCy Schubert 	net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
28884b72b91aSCy Schubert 	if (!net_access_key)
288985732ac8SCy Schubert 		return;
289085732ac8SCy Schubert 
289185732ac8SCy Schubert 	wpabuf_free(auth->net_access_key);
28924b72b91aSCy Schubert 	auth->net_access_key = net_access_key;
289385732ac8SCy Schubert }
289485732ac8SCy Schubert 
289585732ac8SCy Schubert 
289685732ac8SCy Schubert static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
2897c1d255d3SCy Schubert 			      struct dpp_config_obj *conf,
289885732ac8SCy Schubert 			      struct json_token *cred)
289985732ac8SCy Schubert {
290085732ac8SCy Schubert 	struct dpp_signed_connector_info info;
2901c1d255d3SCy Schubert 	struct json_token *token, *csign, *ppkey;
290285732ac8SCy Schubert 	int ret = -1;
29034b72b91aSCy Schubert 	struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
2904c1d255d3SCy Schubert 	const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
290585732ac8SCy Schubert 	const char *signed_connector;
290685732ac8SCy Schubert 
290785732ac8SCy Schubert 	os_memset(&info, 0, sizeof(info));
290885732ac8SCy Schubert 
2909c1d255d3SCy Schubert 	if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
29104bc52338SCy Schubert 		wpa_printf(MSG_DEBUG,
29114bc52338SCy Schubert 			   "DPP: Legacy credential included in Connector credential");
2912c1d255d3SCy Schubert 		if (dpp_parse_cred_legacy(conf, cred) < 0)
29134bc52338SCy Schubert 			return -1;
29144bc52338SCy Schubert 	}
29154bc52338SCy Schubert 
291685732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Connector credential");
291785732ac8SCy Schubert 
291885732ac8SCy Schubert 	csign = json_get_member(cred, "csign");
291985732ac8SCy Schubert 	if (!csign || csign->type != JSON_OBJECT) {
292085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
292185732ac8SCy Schubert 		goto fail;
292285732ac8SCy Schubert 	}
292385732ac8SCy Schubert 
292485732ac8SCy Schubert 	csign_pub = dpp_parse_jwk(csign, &key_curve);
292585732ac8SCy Schubert 	if (!csign_pub) {
292685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
292785732ac8SCy Schubert 		goto fail;
292885732ac8SCy Schubert 	}
292985732ac8SCy Schubert 	dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
293085732ac8SCy Schubert 
2931c1d255d3SCy Schubert 	ppkey = json_get_member(cred, "ppKey");
2932c1d255d3SCy Schubert 	if (ppkey && ppkey->type == JSON_OBJECT) {
2933c1d255d3SCy Schubert 		pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2934c1d255d3SCy Schubert 		if (!pp_pub) {
2935c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2936c1d255d3SCy Schubert 			goto fail;
2937c1d255d3SCy Schubert 		}
2938c1d255d3SCy Schubert 		dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2939c1d255d3SCy Schubert 		if (key_curve != pp_curve) {
2940c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
2941c1d255d3SCy Schubert 				   "DPP: C-sign-key and ppKey do not use the same curve");
2942c1d255d3SCy Schubert 			goto fail;
2943c1d255d3SCy Schubert 		}
2944c1d255d3SCy Schubert 	}
2945c1d255d3SCy Schubert 
294685732ac8SCy Schubert 	token = json_get_member(cred, "signedConnector");
294785732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
294885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
294985732ac8SCy Schubert 		goto fail;
295085732ac8SCy Schubert 	}
295185732ac8SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
295285732ac8SCy Schubert 			  token->string, os_strlen(token->string));
295385732ac8SCy Schubert 	signed_connector = token->string;
295485732ac8SCy Schubert 
295585732ac8SCy Schubert 	if (os_strchr(signed_connector, '"') ||
295685732ac8SCy Schubert 	    os_strchr(signed_connector, '\n')) {
295785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
295885732ac8SCy Schubert 			   "DPP: Unexpected character in signedConnector");
295985732ac8SCy Schubert 		goto fail;
296085732ac8SCy Schubert 	}
296185732ac8SCy Schubert 
296285732ac8SCy Schubert 	if (dpp_process_signed_connector(&info, csign_pub,
296385732ac8SCy Schubert 					 signed_connector) != DPP_STATUS_OK)
296485732ac8SCy Schubert 		goto fail;
296585732ac8SCy Schubert 
2966c1d255d3SCy Schubert 	if (dpp_parse_connector(auth, conf,
2967c1d255d3SCy Schubert 				info.payload, info.payload_len) < 0) {
296885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
296985732ac8SCy Schubert 		goto fail;
297085732ac8SCy Schubert 	}
297185732ac8SCy Schubert 
2972c1d255d3SCy Schubert 	os_free(conf->connector);
2973c1d255d3SCy Schubert 	conf->connector = os_strdup(signed_connector);
297485732ac8SCy Schubert 
2975c1d255d3SCy Schubert 	dpp_copy_csign(conf, csign_pub);
2976c1d255d3SCy Schubert 	if (pp_pub)
2977c1d255d3SCy Schubert 		dpp_copy_ppkey(conf, pp_pub);
2978c1d255d3SCy Schubert 	if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
2979c1d255d3SCy Schubert 		dpp_copy_netaccesskey(auth, conf);
298085732ac8SCy Schubert 
298185732ac8SCy Schubert 	ret = 0;
298285732ac8SCy Schubert fail:
29834b72b91aSCy Schubert 	crypto_ec_key_deinit(csign_pub);
29844b72b91aSCy Schubert 	crypto_ec_key_deinit(pp_pub);
298585732ac8SCy Schubert 	os_free(info.payload);
298685732ac8SCy Schubert 	return ret;
298785732ac8SCy Schubert }
298885732ac8SCy Schubert 
298985732ac8SCy Schubert 
2990c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2991c1d255d3SCy Schubert static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2992c1d255d3SCy Schubert 				struct dpp_config_obj *conf,
2993c1d255d3SCy Schubert 				struct json_token *cred)
2994c1d255d3SCy Schubert {
2995c1d255d3SCy Schubert 	struct json_token *ent, *name;
2996c1d255d3SCy Schubert 
2997c1d255d3SCy Schubert 	ent = json_get_member(cred, "entCreds");
2998c1d255d3SCy Schubert 	if (!ent || ent->type != JSON_OBJECT) {
2999c1d255d3SCy Schubert 		dpp_auth_fail(auth, "No entCreds in JSON");
3000c1d255d3SCy Schubert 		return -1;
3001c1d255d3SCy Schubert 	}
3002c1d255d3SCy Schubert 
3003c1d255d3SCy Schubert 	conf->certbag = json_get_member_base64(ent, "certBag");
3004c1d255d3SCy Schubert 	if (!conf->certbag) {
3005c1d255d3SCy Schubert 		dpp_auth_fail(auth, "No certBag in JSON");
3006c1d255d3SCy Schubert 		return -1;
3007c1d255d3SCy Schubert 	}
3008c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
30094b72b91aSCy Schubert 	conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
3010c1d255d3SCy Schubert 	if (!conf->certs) {
3011c1d255d3SCy Schubert 		dpp_auth_fail(auth, "No certificates in certBag");
3012c1d255d3SCy Schubert 		return -1;
3013c1d255d3SCy Schubert 	}
3014c1d255d3SCy Schubert 
3015c1d255d3SCy Schubert 	conf->cacert = json_get_member_base64(ent, "caCert");
3016c1d255d3SCy Schubert 	if (conf->cacert)
3017c1d255d3SCy Schubert 		wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3018c1d255d3SCy Schubert 				conf->cacert);
3019c1d255d3SCy Schubert 
3020c1d255d3SCy Schubert 	name = json_get_member(ent, "trustedEapServerName");
3021c1d255d3SCy Schubert 	if (name &&
3022c1d255d3SCy Schubert 	    (name->type != JSON_STRING ||
3023c1d255d3SCy Schubert 	     has_ctrl_char((const u8 *) name->string,
3024c1d255d3SCy Schubert 			   os_strlen(name->string)))) {
3025c1d255d3SCy Schubert 		dpp_auth_fail(auth,
3026c1d255d3SCy Schubert 			      "Invalid trustedEapServerName type in JSON");
3027c1d255d3SCy Schubert 		return -1;
3028c1d255d3SCy Schubert 	}
3029c1d255d3SCy Schubert 	if (name && name->string) {
3030c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3031c1d255d3SCy Schubert 			   name->string);
3032c1d255d3SCy Schubert 		conf->server_name = os_strdup(name->string);
3033c1d255d3SCy Schubert 		if (!conf->server_name)
3034c1d255d3SCy Schubert 			return -1;
3035c1d255d3SCy Schubert 	}
3036c1d255d3SCy Schubert 
3037c1d255d3SCy Schubert 	return 0;
3038c1d255d3SCy Schubert }
3039c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3040c1d255d3SCy Schubert 
3041c1d255d3SCy Schubert 
304285732ac8SCy Schubert const char * dpp_akm_str(enum dpp_akm akm)
304385732ac8SCy Schubert {
304485732ac8SCy Schubert 	switch (akm) {
304585732ac8SCy Schubert 	case DPP_AKM_DPP:
304685732ac8SCy Schubert 		return "dpp";
304785732ac8SCy Schubert 	case DPP_AKM_PSK:
304885732ac8SCy Schubert 		return "psk";
304985732ac8SCy Schubert 	case DPP_AKM_SAE:
305085732ac8SCy Schubert 		return "sae";
305185732ac8SCy Schubert 	case DPP_AKM_PSK_SAE:
305285732ac8SCy Schubert 		return "psk+sae";
30534bc52338SCy Schubert 	case DPP_AKM_SAE_DPP:
30544bc52338SCy Schubert 		return "dpp+sae";
30554bc52338SCy Schubert 	case DPP_AKM_PSK_SAE_DPP:
30564bc52338SCy Schubert 		return "dpp+psk+sae";
3057c1d255d3SCy Schubert 	case DPP_AKM_DOT1X:
3058c1d255d3SCy Schubert 		return "dot1x";
3059c1d255d3SCy Schubert 	default:
3060c1d255d3SCy Schubert 		return "??";
3061c1d255d3SCy Schubert 	}
3062c1d255d3SCy Schubert }
3063c1d255d3SCy Schubert 
3064c1d255d3SCy Schubert 
3065c1d255d3SCy Schubert const char * dpp_akm_selector_str(enum dpp_akm akm)
3066c1d255d3SCy Schubert {
3067c1d255d3SCy Schubert 	switch (akm) {
3068c1d255d3SCy Schubert 	case DPP_AKM_DPP:
3069c1d255d3SCy Schubert 		return "506F9A02";
3070c1d255d3SCy Schubert 	case DPP_AKM_PSK:
3071c1d255d3SCy Schubert 		return "000FAC02+000FAC06";
3072c1d255d3SCy Schubert 	case DPP_AKM_SAE:
3073c1d255d3SCy Schubert 		return "000FAC08";
3074c1d255d3SCy Schubert 	case DPP_AKM_PSK_SAE:
3075c1d255d3SCy Schubert 		return "000FAC02+000FAC06+000FAC08";
3076c1d255d3SCy Schubert 	case DPP_AKM_SAE_DPP:
3077c1d255d3SCy Schubert 		return "506F9A02+000FAC08";
3078c1d255d3SCy Schubert 	case DPP_AKM_PSK_SAE_DPP:
3079c1d255d3SCy Schubert 		return "506F9A02+000FAC08+000FAC02+000FAC06";
3080c1d255d3SCy Schubert 	case DPP_AKM_DOT1X:
3081c1d255d3SCy Schubert 		return "000FAC01+000FAC05";
308285732ac8SCy Schubert 	default:
308385732ac8SCy Schubert 		return "??";
308485732ac8SCy Schubert 	}
308585732ac8SCy Schubert }
308685732ac8SCy Schubert 
308785732ac8SCy Schubert 
308885732ac8SCy Schubert static enum dpp_akm dpp_akm_from_str(const char *akm)
308985732ac8SCy Schubert {
3090c1d255d3SCy Schubert 	const char *pos;
3091c1d255d3SCy Schubert 	int dpp = 0, psk = 0, sae = 0, dot1x = 0;
3092c1d255d3SCy Schubert 
309385732ac8SCy Schubert 	if (os_strcmp(akm, "psk") == 0)
309485732ac8SCy Schubert 		return DPP_AKM_PSK;
309585732ac8SCy Schubert 	if (os_strcmp(akm, "sae") == 0)
309685732ac8SCy Schubert 		return DPP_AKM_SAE;
309785732ac8SCy Schubert 	if (os_strcmp(akm, "psk+sae") == 0)
309885732ac8SCy Schubert 		return DPP_AKM_PSK_SAE;
309985732ac8SCy Schubert 	if (os_strcmp(akm, "dpp") == 0)
310085732ac8SCy Schubert 		return DPP_AKM_DPP;
31014bc52338SCy Schubert 	if (os_strcmp(akm, "dpp+sae") == 0)
31024bc52338SCy Schubert 		return DPP_AKM_SAE_DPP;
31034bc52338SCy Schubert 	if (os_strcmp(akm, "dpp+psk+sae") == 0)
31044bc52338SCy Schubert 		return DPP_AKM_PSK_SAE_DPP;
3105c1d255d3SCy Schubert 	if (os_strcmp(akm, "dot1x") == 0)
3106c1d255d3SCy Schubert 		return DPP_AKM_DOT1X;
3107c1d255d3SCy Schubert 
3108c1d255d3SCy Schubert 	pos = akm;
3109c1d255d3SCy Schubert 	while (*pos) {
3110c1d255d3SCy Schubert 		if (os_strlen(pos) < 8)
3111c1d255d3SCy Schubert 			break;
3112c1d255d3SCy Schubert 		if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3113c1d255d3SCy Schubert 			dpp = 1;
3114c1d255d3SCy Schubert 		else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3115c1d255d3SCy Schubert 			psk = 1;
3116c1d255d3SCy Schubert 		else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3117c1d255d3SCy Schubert 			psk = 1;
3118c1d255d3SCy Schubert 		else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3119c1d255d3SCy Schubert 			sae = 1;
3120c1d255d3SCy Schubert 		else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3121c1d255d3SCy Schubert 			dot1x = 1;
3122c1d255d3SCy Schubert 		else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3123c1d255d3SCy Schubert 			dot1x = 1;
3124c1d255d3SCy Schubert 		pos += 8;
3125c1d255d3SCy Schubert 		if (*pos != '+')
3126c1d255d3SCy Schubert 			break;
3127c1d255d3SCy Schubert 		pos++;
3128c1d255d3SCy Schubert 	}
3129c1d255d3SCy Schubert 
3130c1d255d3SCy Schubert 	if (dpp && psk && sae)
3131c1d255d3SCy Schubert 		return DPP_AKM_PSK_SAE_DPP;
3132c1d255d3SCy Schubert 	if (dpp && sae)
3133c1d255d3SCy Schubert 		return DPP_AKM_SAE_DPP;
3134c1d255d3SCy Schubert 	if (dpp)
3135c1d255d3SCy Schubert 		return DPP_AKM_DPP;
3136c1d255d3SCy Schubert 	if (psk && sae)
3137c1d255d3SCy Schubert 		return DPP_AKM_PSK_SAE;
3138c1d255d3SCy Schubert 	if (sae)
3139c1d255d3SCy Schubert 		return DPP_AKM_SAE;
3140c1d255d3SCy Schubert 	if (psk)
3141c1d255d3SCy Schubert 		return DPP_AKM_PSK;
3142c1d255d3SCy Schubert 	if (dot1x)
3143c1d255d3SCy Schubert 		return DPP_AKM_DOT1X;
3144c1d255d3SCy Schubert 
314585732ac8SCy Schubert 	return DPP_AKM_UNKNOWN;
314685732ac8SCy Schubert }
314785732ac8SCy Schubert 
314885732ac8SCy Schubert 
314985732ac8SCy Schubert static int dpp_parse_conf_obj(struct dpp_authentication *auth,
315085732ac8SCy Schubert 			      const u8 *conf_obj, u16 conf_obj_len)
315185732ac8SCy Schubert {
315285732ac8SCy Schubert 	int ret = -1;
315385732ac8SCy Schubert 	struct json_token *root, *token, *discovery, *cred;
3154c1d255d3SCy Schubert 	struct dpp_config_obj *conf;
3155c1d255d3SCy Schubert 	struct wpabuf *ssid64 = NULL;
3156c1d255d3SCy Schubert 	int legacy;
315785732ac8SCy Schubert 
315885732ac8SCy Schubert 	root = json_parse((const char *) conf_obj, conf_obj_len);
315985732ac8SCy Schubert 	if (!root)
316085732ac8SCy Schubert 		return -1;
316185732ac8SCy Schubert 	if (root->type != JSON_OBJECT) {
316285732ac8SCy Schubert 		dpp_auth_fail(auth, "JSON root is not an object");
316385732ac8SCy Schubert 		goto fail;
316485732ac8SCy Schubert 	}
316585732ac8SCy Schubert 
316685732ac8SCy Schubert 	token = json_get_member(root, "wi-fi_tech");
316785732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
316885732ac8SCy Schubert 		dpp_auth_fail(auth, "No wi-fi_tech string value found");
316985732ac8SCy Schubert 		goto fail;
317085732ac8SCy Schubert 	}
317185732ac8SCy Schubert 	if (os_strcmp(token->string, "infra") != 0) {
317285732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
317385732ac8SCy Schubert 			   token->string);
317485732ac8SCy Schubert 		dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
317585732ac8SCy Schubert 		goto fail;
317685732ac8SCy Schubert 	}
317785732ac8SCy Schubert 
317885732ac8SCy Schubert 	discovery = json_get_member(root, "discovery");
317985732ac8SCy Schubert 	if (!discovery || discovery->type != JSON_OBJECT) {
318085732ac8SCy Schubert 		dpp_auth_fail(auth, "No discovery object in JSON");
318185732ac8SCy Schubert 		goto fail;
318285732ac8SCy Schubert 	}
318385732ac8SCy Schubert 
3184c1d255d3SCy Schubert 	ssid64 = json_get_member_base64url(discovery, "ssid64");
3185c1d255d3SCy Schubert 	if (ssid64) {
3186c1d255d3SCy Schubert 		wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3187c1d255d3SCy Schubert 				  wpabuf_head(ssid64), wpabuf_len(ssid64));
3188c1d255d3SCy Schubert 		if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3189c1d255d3SCy Schubert 			dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3190c1d255d3SCy Schubert 			goto fail;
3191c1d255d3SCy Schubert 		}
3192c1d255d3SCy Schubert 	} else {
319385732ac8SCy Schubert 		token = json_get_member(discovery, "ssid");
319485732ac8SCy Schubert 		if (!token || token->type != JSON_STRING) {
3195c1d255d3SCy Schubert 			dpp_auth_fail(auth,
3196c1d255d3SCy Schubert 				      "No discovery::ssid string value found");
319785732ac8SCy Schubert 			goto fail;
319885732ac8SCy Schubert 		}
319985732ac8SCy Schubert 		wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
320085732ac8SCy Schubert 				  token->string, os_strlen(token->string));
320185732ac8SCy Schubert 		if (os_strlen(token->string) > SSID_MAX_LEN) {
3202c1d255d3SCy Schubert 			dpp_auth_fail(auth,
3203c1d255d3SCy Schubert 				      "Too long discovery::ssid string value");
320485732ac8SCy Schubert 			goto fail;
320585732ac8SCy Schubert 		}
3206c1d255d3SCy Schubert 	}
3207c1d255d3SCy Schubert 
3208c1d255d3SCy Schubert 	if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3209c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3210c1d255d3SCy Schubert 			   "DPP: No room for this many Config Objects - ignore this one");
3211c1d255d3SCy Schubert 		ret = 0;
3212c1d255d3SCy Schubert 		goto fail;
3213c1d255d3SCy Schubert 	}
3214c1d255d3SCy Schubert 	conf = &auth->conf_obj[auth->num_conf_obj++];
3215c1d255d3SCy Schubert 
3216c1d255d3SCy Schubert 	if (ssid64) {
3217c1d255d3SCy Schubert 		conf->ssid_len = wpabuf_len(ssid64);
3218c1d255d3SCy Schubert 		os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3219c1d255d3SCy Schubert 	} else {
3220c1d255d3SCy Schubert 		conf->ssid_len = os_strlen(token->string);
3221c1d255d3SCy Schubert 		os_memcpy(conf->ssid, token->string, conf->ssid_len);
3222c1d255d3SCy Schubert 	}
3223c1d255d3SCy Schubert 
3224c1d255d3SCy Schubert 	token = json_get_member(discovery, "ssid_charset");
3225c1d255d3SCy Schubert 	if (token && token->type == JSON_NUMBER) {
3226c1d255d3SCy Schubert 		conf->ssid_charset = token->number;
3227c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3228c1d255d3SCy Schubert 			   conf->ssid_charset);
3229c1d255d3SCy Schubert 	}
323085732ac8SCy Schubert 
323185732ac8SCy Schubert 	cred = json_get_member(root, "cred");
323285732ac8SCy Schubert 	if (!cred || cred->type != JSON_OBJECT) {
323385732ac8SCy Schubert 		dpp_auth_fail(auth, "No cred object in JSON");
323485732ac8SCy Schubert 		goto fail;
323585732ac8SCy Schubert 	}
323685732ac8SCy Schubert 
323785732ac8SCy Schubert 	token = json_get_member(cred, "akm");
323885732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
323985732ac8SCy Schubert 		dpp_auth_fail(auth, "No cred::akm string value found");
324085732ac8SCy Schubert 		goto fail;
324185732ac8SCy Schubert 	}
3242c1d255d3SCy Schubert 	conf->akm = dpp_akm_from_str(token->string);
324385732ac8SCy Schubert 
3244c1d255d3SCy Schubert 	legacy = dpp_akm_legacy(conf->akm);
3245c1d255d3SCy Schubert 	if (legacy && auth->peer_version >= 2) {
3246c1d255d3SCy Schubert 		struct json_token *csign, *s_conn;
3247c1d255d3SCy Schubert 
3248c1d255d3SCy Schubert 		csign = json_get_member(cred, "csign");
3249c1d255d3SCy Schubert 		s_conn = json_get_member(cred, "signedConnector");
3250c1d255d3SCy Schubert 		if (csign && csign->type == JSON_OBJECT &&
3251c1d255d3SCy Schubert 		    s_conn && s_conn->type == JSON_STRING)
3252c1d255d3SCy Schubert 			legacy = 0;
3253c1d255d3SCy Schubert 	}
3254c1d255d3SCy Schubert 	if (legacy) {
3255c1d255d3SCy Schubert 		if (dpp_parse_cred_legacy(conf, cred) < 0)
325685732ac8SCy Schubert 			goto fail;
3257c1d255d3SCy Schubert 	} else if (dpp_akm_dpp(conf->akm) ||
3258c1d255d3SCy Schubert 		   (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
3259c1d255d3SCy Schubert 		if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
326085732ac8SCy Schubert 			goto fail;
3261c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3262c1d255d3SCy Schubert 	} else if (conf->akm == DPP_AKM_DOT1X) {
3263c1d255d3SCy Schubert 		if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3264c1d255d3SCy Schubert 		    dpp_parse_cred_dpp(auth, conf, cred) < 0)
3265c1d255d3SCy Schubert 			goto fail;
3266c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
326785732ac8SCy Schubert 	} else {
326885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
326985732ac8SCy Schubert 			   token->string);
327085732ac8SCy Schubert 		dpp_auth_fail(auth, "Unsupported akm");
327185732ac8SCy Schubert 		goto fail;
327285732ac8SCy Schubert 	}
327385732ac8SCy Schubert 
327485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
327585732ac8SCy Schubert 	ret = 0;
327685732ac8SCy Schubert fail:
3277c1d255d3SCy Schubert 	wpabuf_free(ssid64);
327885732ac8SCy Schubert 	json_free(root);
327985732ac8SCy Schubert 	return ret;
328085732ac8SCy Schubert }
328185732ac8SCy Schubert 
328285732ac8SCy Schubert 
3283c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3284c1d255d3SCy Schubert static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3285c1d255d3SCy Schubert {
3286c1d255d3SCy Schubert 	const u8 *b64;
3287c1d255d3SCy Schubert 	u16 b64_len;
3288c1d255d3SCy Schubert 
3289c1d255d3SCy Schubert 	b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3290c1d255d3SCy Schubert 	if (!b64)
3291c1d255d3SCy Schubert 		return NULL;
3292c1d255d3SCy Schubert 	return base64_decode((const char *) b64, b64_len, len);
3293c1d255d3SCy Schubert }
3294c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3295c1d255d3SCy Schubert 
3296c1d255d3SCy Schubert 
329785732ac8SCy Schubert int dpp_conf_resp_rx(struct dpp_authentication *auth,
329885732ac8SCy Schubert 		     const struct wpabuf *resp)
329985732ac8SCy Schubert {
330085732ac8SCy Schubert 	const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
330185732ac8SCy Schubert 	u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
3302c1d255d3SCy Schubert 	const u8 *env_data;
3303c1d255d3SCy Schubert 	u16 env_data_len;
330485732ac8SCy Schubert 	const u8 *addr[1];
330585732ac8SCy Schubert 	size_t len[1];
330685732ac8SCy Schubert 	u8 *unwrapped = NULL;
330785732ac8SCy Schubert 	size_t unwrapped_len = 0;
330885732ac8SCy Schubert 	int ret = -1;
330985732ac8SCy Schubert 
33104bc52338SCy Schubert 	auth->conf_resp_status = 255;
33114bc52338SCy Schubert 
331285732ac8SCy Schubert 	if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
331385732ac8SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in config response");
331485732ac8SCy Schubert 		return -1;
331585732ac8SCy Schubert 	}
331685732ac8SCy Schubert 
331785732ac8SCy Schubert 	wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
331885732ac8SCy Schubert 				    DPP_ATTR_WRAPPED_DATA,
331985732ac8SCy Schubert 				    &wrapped_data_len);
332085732ac8SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
332185732ac8SCy Schubert 		dpp_auth_fail(auth,
332285732ac8SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
332385732ac8SCy Schubert 		return -1;
332485732ac8SCy Schubert 	}
332585732ac8SCy Schubert 
332685732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
332785732ac8SCy Schubert 		    wrapped_data, wrapped_data_len);
332885732ac8SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
332985732ac8SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
333085732ac8SCy Schubert 	if (!unwrapped)
333185732ac8SCy Schubert 		return -1;
333285732ac8SCy Schubert 
333385732ac8SCy Schubert 	addr[0] = wpabuf_head(resp);
333485732ac8SCy Schubert 	len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
333585732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
333685732ac8SCy Schubert 
333785732ac8SCy Schubert 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
333885732ac8SCy Schubert 			    wrapped_data, wrapped_data_len,
333985732ac8SCy Schubert 			    1, addr, len, unwrapped) < 0) {
334085732ac8SCy Schubert 		dpp_auth_fail(auth, "AES-SIV decryption failed");
334185732ac8SCy Schubert 		goto fail;
334285732ac8SCy Schubert 	}
334385732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
334485732ac8SCy Schubert 		    unwrapped, unwrapped_len);
334585732ac8SCy Schubert 
334685732ac8SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
334785732ac8SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
334885732ac8SCy Schubert 		goto fail;
334985732ac8SCy Schubert 	}
335085732ac8SCy Schubert 
335185732ac8SCy Schubert 	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
335285732ac8SCy Schubert 			       DPP_ATTR_ENROLLEE_NONCE,
335385732ac8SCy Schubert 			       &e_nonce_len);
335485732ac8SCy Schubert 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
335585732ac8SCy Schubert 		dpp_auth_fail(auth,
335685732ac8SCy Schubert 			      "Missing or invalid Enrollee Nonce attribute");
335785732ac8SCy Schubert 		goto fail;
335885732ac8SCy Schubert 	}
335985732ac8SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
336085732ac8SCy Schubert 	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
336185732ac8SCy Schubert 		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
336285732ac8SCy Schubert 		goto fail;
336385732ac8SCy Schubert 	}
336485732ac8SCy Schubert 
336585732ac8SCy Schubert 	status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
336685732ac8SCy Schubert 			      DPP_ATTR_STATUS, &status_len);
336785732ac8SCy Schubert 	if (!status || status_len < 1) {
336885732ac8SCy Schubert 		dpp_auth_fail(auth,
336985732ac8SCy Schubert 			      "Missing or invalid required DPP Status attribute");
337085732ac8SCy Schubert 		goto fail;
337185732ac8SCy Schubert 	}
33724bc52338SCy Schubert 	auth->conf_resp_status = status[0];
337385732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3374c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3375c1d255d3SCy Schubert 	if (status[0] == DPP_STATUS_CSR_NEEDED) {
3376c1d255d3SCy Schubert 		u8 *csrattrs;
3377c1d255d3SCy Schubert 		size_t csrattrs_len;
3378c1d255d3SCy Schubert 
3379c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3380c1d255d3SCy Schubert 
3381c1d255d3SCy Schubert 		csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3382c1d255d3SCy Schubert 					     &csrattrs_len);
3383c1d255d3SCy Schubert 		if (!csrattrs) {
3384c1d255d3SCy Schubert 			dpp_auth_fail(auth,
3385c1d255d3SCy Schubert 				      "Missing or invalid CSR Attributes Request attribute");
3386c1d255d3SCy Schubert 			goto fail;
3387c1d255d3SCy Schubert 		}
3388c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3389c1d255d3SCy Schubert 		os_free(auth->csrattrs);
3390c1d255d3SCy Schubert 		auth->csrattrs = csrattrs;
3391c1d255d3SCy Schubert 		auth->csrattrs_len = csrattrs_len;
3392c1d255d3SCy Schubert 		ret = -2;
3393c1d255d3SCy Schubert 		goto fail;
3394c1d255d3SCy Schubert 	}
3395c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3396*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
3397*a90b9d01SCy Schubert 	if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3398*a90b9d01SCy Schubert 		const u8 *fcgroup, *r_proto;
3399*a90b9d01SCy Schubert 		u16 fcgroup_len, r_proto_len;
3400*a90b9d01SCy Schubert 		u16 group;
3401*a90b9d01SCy Schubert 		const struct dpp_curve_params *curve;
3402*a90b9d01SCy Schubert 		struct crypto_ec_key *new_pe;
3403*a90b9d01SCy Schubert 		struct crypto_ec_key *pc;
3404*a90b9d01SCy Schubert 
3405*a90b9d01SCy Schubert 		fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3406*a90b9d01SCy Schubert 				       DPP_ATTR_FINITE_CYCLIC_GROUP,
3407*a90b9d01SCy Schubert 				       &fcgroup_len);
3408*a90b9d01SCy Schubert 		if (!fcgroup || fcgroup_len != 2) {
3409*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
3410*a90b9d01SCy Schubert 				      "Missing or invalid required Finite Cyclic Group attribute");
3411*a90b9d01SCy Schubert 			goto fail;
3412*a90b9d01SCy Schubert 		}
3413*a90b9d01SCy Schubert 		group = WPA_GET_LE16(fcgroup);
3414*a90b9d01SCy Schubert 
3415*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
3416*a90b9d01SCy Schubert 			   "DPP: Configurator requested a new protocol key from group %u",
3417*a90b9d01SCy Schubert 			   group);
3418*a90b9d01SCy Schubert 		curve = dpp_get_curve_ike_group(group);
3419*a90b9d01SCy Schubert 		if (!curve) {
3420*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
3421*a90b9d01SCy Schubert 				      "Unsupported group for new protocol key");
3422*a90b9d01SCy Schubert 			goto fail;
3423*a90b9d01SCy Schubert 		}
3424*a90b9d01SCy Schubert 
3425*a90b9d01SCy Schubert 		new_pe = dpp_gen_keypair(curve);
3426*a90b9d01SCy Schubert 		if (!new_pe) {
3427*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
3428*a90b9d01SCy Schubert 				      "Failed to generate a new protocol key");
3429*a90b9d01SCy Schubert 			goto fail;
3430*a90b9d01SCy Schubert 		}
3431*a90b9d01SCy Schubert 
3432*a90b9d01SCy Schubert 		crypto_ec_key_deinit(auth->own_protocol_key);
3433*a90b9d01SCy Schubert 		auth->own_protocol_key = new_pe;
3434*a90b9d01SCy Schubert 		auth->new_curve = curve;
3435*a90b9d01SCy Schubert 
3436*a90b9d01SCy Schubert 		r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3437*a90b9d01SCy Schubert 				       DPP_ATTR_R_PROTOCOL_KEY,
3438*a90b9d01SCy Schubert 				       &r_proto_len);
3439*a90b9d01SCy Schubert 		if (!r_proto) {
3440*a90b9d01SCy Schubert 			dpp_auth_fail(auth,
3441*a90b9d01SCy Schubert 				      "Missing required Responder Protocol Key attribute (Pc)");
3442*a90b9d01SCy Schubert 			goto fail;
3443*a90b9d01SCy Schubert 		}
3444*a90b9d01SCy Schubert 		wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3445*a90b9d01SCy Schubert 			    r_proto, r_proto_len);
3446*a90b9d01SCy Schubert 
3447*a90b9d01SCy Schubert 		pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3448*a90b9d01SCy Schubert 		if (!pc) {
3449*a90b9d01SCy Schubert 			dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3450*a90b9d01SCy Schubert 			goto fail;
3451*a90b9d01SCy Schubert 		}
3452*a90b9d01SCy Schubert 		dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3453*a90b9d01SCy Schubert 
3454*a90b9d01SCy Schubert 		crypto_ec_key_deinit(auth->peer_protocol_key);
3455*a90b9d01SCy Schubert 		auth->peer_protocol_key = pc;
3456*a90b9d01SCy Schubert 
3457*a90b9d01SCy Schubert 		auth->waiting_new_key = true;
3458*a90b9d01SCy Schubert 		ret = -3;
3459*a90b9d01SCy Schubert 		goto fail;
3460*a90b9d01SCy Schubert 	}
3461*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
346285732ac8SCy Schubert 	if (status[0] != DPP_STATUS_OK) {
346385732ac8SCy Schubert 		dpp_auth_fail(auth, "Configurator rejected configuration");
346485732ac8SCy Schubert 		goto fail;
346585732ac8SCy Schubert 	}
346685732ac8SCy Schubert 
3467c1d255d3SCy Schubert 	env_data = dpp_get_attr(unwrapped, unwrapped_len,
3468c1d255d3SCy Schubert 				DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3469c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3470c1d255d3SCy Schubert 	if (env_data &&
3471c1d255d3SCy Schubert 	    dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3472c1d255d3SCy Schubert 		goto fail;
3473c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3474c1d255d3SCy Schubert 
3475c1d255d3SCy Schubert 	conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3476c1d255d3SCy Schubert 				&conf_obj_len);
3477c1d255d3SCy Schubert 	if (!conf_obj && !env_data) {
347885732ac8SCy Schubert 		dpp_auth_fail(auth,
347985732ac8SCy Schubert 			      "Missing required Configuration Object attribute");
348085732ac8SCy Schubert 		goto fail;
348185732ac8SCy Schubert 	}
3482c1d255d3SCy Schubert 	while (conf_obj) {
348385732ac8SCy Schubert 		wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
348485732ac8SCy Schubert 				  conf_obj, conf_obj_len);
348585732ac8SCy Schubert 		if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
348685732ac8SCy Schubert 			goto fail;
3487c1d255d3SCy Schubert 		conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3488c1d255d3SCy Schubert 					     DPP_ATTR_CONFIG_OBJ,
3489c1d255d3SCy Schubert 					     &conf_obj_len);
3490c1d255d3SCy Schubert 	}
3491c1d255d3SCy Schubert 
3492c1d255d3SCy Schubert #ifdef CONFIG_DPP2
3493c1d255d3SCy Schubert 	status = dpp_get_attr(unwrapped, unwrapped_len,
3494c1d255d3SCy Schubert 			      DPP_ATTR_SEND_CONN_STATUS, &status_len);
3495c1d255d3SCy Schubert 	if (status) {
3496c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
3497c1d255d3SCy Schubert 			   "DPP: Configurator requested connection status result");
3498c1d255d3SCy Schubert 		auth->conn_status_requested = 1;
3499c1d255d3SCy Schubert 	}
3500c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
350185732ac8SCy Schubert 
350285732ac8SCy Schubert 	ret = 0;
350385732ac8SCy Schubert 
350485732ac8SCy Schubert fail:
350585732ac8SCy Schubert 	os_free(unwrapped);
350685732ac8SCy Schubert 	return ret;
350785732ac8SCy Schubert }
350885732ac8SCy Schubert 
350985732ac8SCy Schubert 
35104bc52338SCy Schubert #ifdef CONFIG_DPP2
3511c1d255d3SCy Schubert 
35124bc52338SCy Schubert enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
35134bc52338SCy Schubert 					 const u8 *hdr,
35144bc52338SCy Schubert 					 const u8 *attr_start, size_t attr_len)
35154bc52338SCy Schubert {
35164bc52338SCy Schubert 	const u8 *wrapped_data, *status, *e_nonce;
35174bc52338SCy Schubert 	u16 wrapped_data_len, status_len, e_nonce_len;
35184bc52338SCy Schubert 	const u8 *addr[2];
35194bc52338SCy Schubert 	size_t len[2];
35204bc52338SCy Schubert 	u8 *unwrapped = NULL;
35214bc52338SCy Schubert 	size_t unwrapped_len = 0;
35224bc52338SCy Schubert 	enum dpp_status_error ret = 256;
35234bc52338SCy Schubert 
35244bc52338SCy Schubert 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
35254bc52338SCy Schubert 				    &wrapped_data_len);
35264bc52338SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
35274bc52338SCy Schubert 		dpp_auth_fail(auth,
35284bc52338SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
35294bc52338SCy Schubert 		goto fail;
35304bc52338SCy Schubert 	}
35314bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
35324bc52338SCy Schubert 		    wrapped_data, wrapped_data_len);
35334bc52338SCy Schubert 
35344bc52338SCy Schubert 	attr_len = wrapped_data - 4 - attr_start;
35354bc52338SCy Schubert 
35364bc52338SCy Schubert 	addr[0] = hdr;
35374bc52338SCy Schubert 	len[0] = DPP_HDR_LEN;
35384bc52338SCy Schubert 	addr[1] = attr_start;
35394bc52338SCy Schubert 	len[1] = attr_len;
35404bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
35414bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
35424bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
35434bc52338SCy Schubert 		    wrapped_data, wrapped_data_len);
35444bc52338SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
35454bc52338SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
35464bc52338SCy Schubert 	if (!unwrapped)
35474bc52338SCy Schubert 		goto fail;
35484bc52338SCy Schubert 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
35494bc52338SCy Schubert 			    wrapped_data, wrapped_data_len,
35504bc52338SCy Schubert 			    2, addr, len, unwrapped) < 0) {
35514bc52338SCy Schubert 		dpp_auth_fail(auth, "AES-SIV decryption failed");
35524bc52338SCy Schubert 		goto fail;
35534bc52338SCy Schubert 	}
35544bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
35554bc52338SCy Schubert 		    unwrapped, unwrapped_len);
35564bc52338SCy Schubert 
35574bc52338SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
35584bc52338SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
35594bc52338SCy Schubert 		goto fail;
35604bc52338SCy Schubert 	}
35614bc52338SCy Schubert 
35624bc52338SCy Schubert 	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
35634bc52338SCy Schubert 			       DPP_ATTR_ENROLLEE_NONCE,
35644bc52338SCy Schubert 			       &e_nonce_len);
35654bc52338SCy Schubert 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
35664bc52338SCy Schubert 		dpp_auth_fail(auth,
35674bc52338SCy Schubert 			      "Missing or invalid Enrollee Nonce attribute");
35684bc52338SCy Schubert 		goto fail;
35694bc52338SCy Schubert 	}
35704bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
35714bc52338SCy Schubert 	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
35724bc52338SCy Schubert 		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
35734bc52338SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
35744bc52338SCy Schubert 			    auth->e_nonce, e_nonce_len);
35754bc52338SCy Schubert 		goto fail;
35764bc52338SCy Schubert 	}
35774bc52338SCy Schubert 
35784bc52338SCy Schubert 	status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
35794bc52338SCy Schubert 			      &status_len);
35804bc52338SCy Schubert 	if (!status || status_len < 1) {
35814bc52338SCy Schubert 		dpp_auth_fail(auth,
35824bc52338SCy Schubert 			      "Missing or invalid required DPP Status attribute");
35834bc52338SCy Schubert 		goto fail;
35844bc52338SCy Schubert 	}
35854bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
35864bc52338SCy Schubert 	ret = status[0];
35874bc52338SCy Schubert 
35884bc52338SCy Schubert fail:
35894bc52338SCy Schubert 	bin_clear_free(unwrapped, unwrapped_len);
35904bc52338SCy Schubert 	return ret;
35914bc52338SCy Schubert }
35924bc52338SCy Schubert 
35934bc52338SCy Schubert 
35944bc52338SCy Schubert struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
35954bc52338SCy Schubert 				      enum dpp_status_error status)
35964bc52338SCy Schubert {
35974bc52338SCy Schubert 	struct wpabuf *msg, *clear;
35984bc52338SCy Schubert 	size_t nonce_len, clear_len, attr_len;
35994bc52338SCy Schubert 	const u8 *addr[2];
36004bc52338SCy Schubert 	size_t len[2];
36014bc52338SCy Schubert 	u8 *wrapped;
36024bc52338SCy Schubert 
36034bc52338SCy Schubert 	nonce_len = auth->curve->nonce_len;
36044bc52338SCy Schubert 	clear_len = 5 + 4 + nonce_len;
36054bc52338SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
36064bc52338SCy Schubert 	clear = wpabuf_alloc(clear_len);
36074bc52338SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
36084bc52338SCy Schubert 	if (!clear || !msg)
3609c1d255d3SCy Schubert 		goto fail;
36104bc52338SCy Schubert 
36114bc52338SCy Schubert 	/* DPP Status */
36124bc52338SCy Schubert 	dpp_build_attr_status(clear, status);
36134bc52338SCy Schubert 
36144bc52338SCy Schubert 	/* E-nonce */
36154bc52338SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
36164bc52338SCy Schubert 	wpabuf_put_le16(clear, nonce_len);
36174bc52338SCy Schubert 	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
36184bc52338SCy Schubert 
36194bc52338SCy Schubert 	/* OUI, OUI type, Crypto Suite, DPP frame type */
36204bc52338SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
36214bc52338SCy Schubert 	len[0] = 3 + 1 + 1 + 1;
36224bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
36234bc52338SCy Schubert 
36244bc52338SCy Schubert 	/* Attributes before Wrapped Data (none) */
36254bc52338SCy Schubert 	addr[1] = wpabuf_put(msg, 0);
36264bc52338SCy Schubert 	len[1] = 0;
36274bc52338SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
36284bc52338SCy Schubert 
36294bc52338SCy Schubert 	/* Wrapped Data */
36304bc52338SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
36314bc52338SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
36324bc52338SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
36334bc52338SCy Schubert 
36344bc52338SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
36354bc52338SCy Schubert 	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
36364bc52338SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
36374bc52338SCy Schubert 			    2, addr, len, wrapped) < 0)
36384bc52338SCy Schubert 		goto fail;
36394bc52338SCy Schubert 
36404bc52338SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
36414bc52338SCy Schubert 	wpabuf_free(clear);
36424bc52338SCy Schubert 	return msg;
36434bc52338SCy Schubert fail:
36444bc52338SCy Schubert 	wpabuf_free(clear);
36454bc52338SCy Schubert 	wpabuf_free(msg);
36464bc52338SCy Schubert 	return NULL;
36474bc52338SCy Schubert }
36484bc52338SCy Schubert 
36494bc52338SCy Schubert 
3650c1d255d3SCy Schubert static int valid_channel_list(const char *val)
3651c1d255d3SCy Schubert {
3652c1d255d3SCy Schubert 	while (*val) {
3653c1d255d3SCy Schubert 		if (!((*val >= '0' && *val <= '9') ||
3654c1d255d3SCy Schubert 		      *val == '/' || *val == ','))
3655c1d255d3SCy Schubert 			return 0;
3656c1d255d3SCy Schubert 		val++;
3657c1d255d3SCy Schubert 	}
3658c1d255d3SCy Schubert 
3659c1d255d3SCy Schubert 	return 1;
3660c1d255d3SCy Schubert }
3661c1d255d3SCy Schubert 
3662c1d255d3SCy Schubert 
3663c1d255d3SCy Schubert enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3664c1d255d3SCy Schubert 						const u8 *hdr,
3665c1d255d3SCy Schubert 						const u8 *attr_start,
3666c1d255d3SCy Schubert 						size_t attr_len,
3667c1d255d3SCy Schubert 						u8 *ssid, size_t *ssid_len,
3668c1d255d3SCy Schubert 						char **channel_list)
3669c1d255d3SCy Schubert {
3670c1d255d3SCy Schubert 	const u8 *wrapped_data, *status, *e_nonce;
3671c1d255d3SCy Schubert 	u16 wrapped_data_len, status_len, e_nonce_len;
3672c1d255d3SCy Schubert 	const u8 *addr[2];
3673c1d255d3SCy Schubert 	size_t len[2];
3674c1d255d3SCy Schubert 	u8 *unwrapped = NULL;
3675c1d255d3SCy Schubert 	size_t unwrapped_len = 0;
3676c1d255d3SCy Schubert 	enum dpp_status_error ret = 256;
3677c1d255d3SCy Schubert 	struct json_token *root = NULL, *token;
3678c1d255d3SCy Schubert 	struct wpabuf *ssid64;
3679c1d255d3SCy Schubert 
3680c1d255d3SCy Schubert 	*ssid_len = 0;
3681c1d255d3SCy Schubert 	*channel_list = NULL;
3682c1d255d3SCy Schubert 
3683c1d255d3SCy Schubert 	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3684c1d255d3SCy Schubert 				    &wrapped_data_len);
3685c1d255d3SCy Schubert 	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3686c1d255d3SCy Schubert 		dpp_auth_fail(auth,
3687c1d255d3SCy Schubert 			      "Missing or invalid required Wrapped Data attribute");
3688c1d255d3SCy Schubert 		goto fail;
3689c1d255d3SCy Schubert 	}
3690c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3691c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
3692c1d255d3SCy Schubert 
3693c1d255d3SCy Schubert 	attr_len = wrapped_data - 4 - attr_start;
3694c1d255d3SCy Schubert 
3695c1d255d3SCy Schubert 	addr[0] = hdr;
3696c1d255d3SCy Schubert 	len[0] = DPP_HDR_LEN;
3697c1d255d3SCy Schubert 	addr[1] = attr_start;
3698c1d255d3SCy Schubert 	len[1] = attr_len;
3699c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3700c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3701c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3702c1d255d3SCy Schubert 		    wrapped_data, wrapped_data_len);
3703c1d255d3SCy Schubert 	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3704c1d255d3SCy Schubert 	unwrapped = os_malloc(unwrapped_len);
3705c1d255d3SCy Schubert 	if (!unwrapped)
3706c1d255d3SCy Schubert 		goto fail;
3707c1d255d3SCy Schubert 	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3708c1d255d3SCy Schubert 			    wrapped_data, wrapped_data_len,
3709c1d255d3SCy Schubert 			    2, addr, len, unwrapped) < 0) {
3710c1d255d3SCy Schubert 		dpp_auth_fail(auth, "AES-SIV decryption failed");
3711c1d255d3SCy Schubert 		goto fail;
3712c1d255d3SCy Schubert 	}
3713c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3714c1d255d3SCy Schubert 		    unwrapped, unwrapped_len);
3715c1d255d3SCy Schubert 
3716c1d255d3SCy Schubert 	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3717c1d255d3SCy Schubert 		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3718c1d255d3SCy Schubert 		goto fail;
3719c1d255d3SCy Schubert 	}
3720c1d255d3SCy Schubert 
3721c1d255d3SCy Schubert 	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3722c1d255d3SCy Schubert 			       DPP_ATTR_ENROLLEE_NONCE,
3723c1d255d3SCy Schubert 			       &e_nonce_len);
3724c1d255d3SCy Schubert 	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3725c1d255d3SCy Schubert 		dpp_auth_fail(auth,
3726c1d255d3SCy Schubert 			      "Missing or invalid Enrollee Nonce attribute");
3727c1d255d3SCy Schubert 		goto fail;
3728c1d255d3SCy Schubert 	}
3729c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3730c1d255d3SCy Schubert 	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3731c1d255d3SCy Schubert 		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3732c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3733c1d255d3SCy Schubert 			    auth->e_nonce, e_nonce_len);
3734c1d255d3SCy Schubert 		goto fail;
3735c1d255d3SCy Schubert 	}
3736c1d255d3SCy Schubert 
3737c1d255d3SCy Schubert 	status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3738c1d255d3SCy Schubert 			      &status_len);
3739c1d255d3SCy Schubert 	if (!status) {
3740c1d255d3SCy Schubert 		dpp_auth_fail(auth,
3741c1d255d3SCy Schubert 			      "Missing required DPP Connection Status attribute");
3742c1d255d3SCy Schubert 		goto fail;
3743c1d255d3SCy Schubert 	}
3744c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3745c1d255d3SCy Schubert 			  status, status_len);
3746c1d255d3SCy Schubert 
3747c1d255d3SCy Schubert 	root = json_parse((const char *) status, status_len);
3748c1d255d3SCy Schubert 	if (!root) {
3749c1d255d3SCy Schubert 		dpp_auth_fail(auth, "Could not parse connStatus");
3750c1d255d3SCy Schubert 		goto fail;
3751c1d255d3SCy Schubert 	}
3752c1d255d3SCy Schubert 
3753c1d255d3SCy Schubert 	ssid64 = json_get_member_base64url(root, "ssid64");
3754c1d255d3SCy Schubert 	if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3755c1d255d3SCy Schubert 		*ssid_len = wpabuf_len(ssid64);
3756c1d255d3SCy Schubert 		os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
3757c1d255d3SCy Schubert 	}
3758c1d255d3SCy Schubert 	wpabuf_free(ssid64);
3759c1d255d3SCy Schubert 
3760c1d255d3SCy Schubert 	token = json_get_member(root, "channelList");
3761c1d255d3SCy Schubert 	if (token && token->type == JSON_STRING &&
3762c1d255d3SCy Schubert 	    valid_channel_list(token->string))
3763c1d255d3SCy Schubert 		*channel_list = os_strdup(token->string);
3764c1d255d3SCy Schubert 
3765c1d255d3SCy Schubert 	token = json_get_member(root, "result");
3766c1d255d3SCy Schubert 	if (!token || token->type != JSON_NUMBER) {
3767c1d255d3SCy Schubert 		dpp_auth_fail(auth, "No connStatus - result");
3768c1d255d3SCy Schubert 		goto fail;
3769c1d255d3SCy Schubert 	}
3770c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3771c1d255d3SCy Schubert 	ret = token->number;
3772c1d255d3SCy Schubert 
3773c1d255d3SCy Schubert fail:
3774c1d255d3SCy Schubert 	json_free(root);
3775c1d255d3SCy Schubert 	bin_clear_free(unwrapped, unwrapped_len);
3776c1d255d3SCy Schubert 	return ret;
3777c1d255d3SCy Schubert }
3778c1d255d3SCy Schubert 
3779c1d255d3SCy Schubert 
3780c1d255d3SCy Schubert struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3781c1d255d3SCy Schubert 				      const u8 *ssid, size_t ssid_len,
3782c1d255d3SCy Schubert 				      const char *channel_list)
3783c1d255d3SCy Schubert {
3784c1d255d3SCy Schubert 	struct wpabuf *json;
3785c1d255d3SCy Schubert 
3786c1d255d3SCy Schubert 	json = wpabuf_alloc(1000);
3787c1d255d3SCy Schubert 	if (!json)
3788c1d255d3SCy Schubert 		return NULL;
3789c1d255d3SCy Schubert 	json_start_object(json, NULL);
3790c1d255d3SCy Schubert 	json_add_int(json, "result", result);
3791c1d255d3SCy Schubert 	if (ssid) {
3792c1d255d3SCy Schubert 		json_value_sep(json);
3793c1d255d3SCy Schubert 		if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3794c1d255d3SCy Schubert 			wpabuf_free(json);
3795c1d255d3SCy Schubert 			return NULL;
3796c1d255d3SCy Schubert 		}
3797c1d255d3SCy Schubert 	}
3798c1d255d3SCy Schubert 	if (channel_list) {
3799c1d255d3SCy Schubert 		json_value_sep(json);
3800c1d255d3SCy Schubert 		json_add_string(json, "channelList", channel_list);
3801c1d255d3SCy Schubert 	}
3802c1d255d3SCy Schubert 	json_end_object(json);
3803c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3804c1d255d3SCy Schubert 			  wpabuf_head(json), wpabuf_len(json));
3805c1d255d3SCy Schubert 
3806c1d255d3SCy Schubert 	return json;
3807c1d255d3SCy Schubert }
3808c1d255d3SCy Schubert 
3809c1d255d3SCy Schubert 
3810c1d255d3SCy Schubert struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3811c1d255d3SCy Schubert 					     enum dpp_status_error result,
3812c1d255d3SCy Schubert 					     const u8 *ssid, size_t ssid_len,
3813c1d255d3SCy Schubert 					     const char *channel_list)
3814c1d255d3SCy Schubert {
3815c1d255d3SCy Schubert 	struct wpabuf *msg = NULL, *clear = NULL, *json;
3816c1d255d3SCy Schubert 	size_t nonce_len, clear_len, attr_len;
3817c1d255d3SCy Schubert 	const u8 *addr[2];
3818c1d255d3SCy Schubert 	size_t len[2];
3819c1d255d3SCy Schubert 	u8 *wrapped;
3820c1d255d3SCy Schubert 
3821c1d255d3SCy Schubert 	json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
3822c1d255d3SCy Schubert 	if (!json)
3823c1d255d3SCy Schubert 		return NULL;
3824c1d255d3SCy Schubert 
3825c1d255d3SCy Schubert 	nonce_len = auth->curve->nonce_len;
3826c1d255d3SCy Schubert 	clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3827c1d255d3SCy Schubert 	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3828c1d255d3SCy Schubert 	clear = wpabuf_alloc(clear_len);
3829c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3830c1d255d3SCy Schubert 	if (!clear || !msg)
3831c1d255d3SCy Schubert 		goto fail;
3832c1d255d3SCy Schubert 
3833c1d255d3SCy Schubert 	/* E-nonce */
3834c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3835c1d255d3SCy Schubert 	wpabuf_put_le16(clear, nonce_len);
3836c1d255d3SCy Schubert 	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3837c1d255d3SCy Schubert 
3838c1d255d3SCy Schubert 	/* DPP Connection Status */
3839c1d255d3SCy Schubert 	wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3840c1d255d3SCy Schubert 	wpabuf_put_le16(clear, wpabuf_len(json));
3841c1d255d3SCy Schubert 	wpabuf_put_buf(clear, json);
3842c1d255d3SCy Schubert 
3843c1d255d3SCy Schubert 	/* OUI, OUI type, Crypto Suite, DPP frame type */
3844c1d255d3SCy Schubert 	addr[0] = wpabuf_head_u8(msg) + 2;
3845c1d255d3SCy Schubert 	len[0] = 3 + 1 + 1 + 1;
3846c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3847c1d255d3SCy Schubert 
3848c1d255d3SCy Schubert 	/* Attributes before Wrapped Data (none) */
3849c1d255d3SCy Schubert 	addr[1] = wpabuf_put(msg, 0);
3850c1d255d3SCy Schubert 	len[1] = 0;
3851c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3852c1d255d3SCy Schubert 
3853c1d255d3SCy Schubert 	/* Wrapped Data */
3854c1d255d3SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3855c1d255d3SCy Schubert 	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3856c1d255d3SCy Schubert 	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3857c1d255d3SCy Schubert 
3858c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3859c1d255d3SCy Schubert 	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3860c1d255d3SCy Schubert 			    wpabuf_head(clear), wpabuf_len(clear),
3861c1d255d3SCy Schubert 			    2, addr, len, wrapped) < 0)
3862c1d255d3SCy Schubert 		goto fail;
3863c1d255d3SCy Schubert 
3864c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3865c1d255d3SCy Schubert 			msg);
3866c1d255d3SCy Schubert 	wpabuf_free(json);
3867c1d255d3SCy Schubert 	wpabuf_free(clear);
3868c1d255d3SCy Schubert 	return msg;
3869c1d255d3SCy Schubert fail:
3870c1d255d3SCy Schubert 	wpabuf_free(json);
3871c1d255d3SCy Schubert 	wpabuf_free(clear);
3872c1d255d3SCy Schubert 	wpabuf_free(msg);
3873c1d255d3SCy Schubert 	return NULL;
3874c1d255d3SCy Schubert }
3875c1d255d3SCy Schubert 
3876c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3877c1d255d3SCy Schubert 
3878c1d255d3SCy Schubert 
387985732ac8SCy Schubert void dpp_configurator_free(struct dpp_configurator *conf)
388085732ac8SCy Schubert {
388185732ac8SCy Schubert 	if (!conf)
388285732ac8SCy Schubert 		return;
38834b72b91aSCy Schubert 	crypto_ec_key_deinit(conf->csign);
388485732ac8SCy Schubert 	os_free(conf->kid);
3885c1d255d3SCy Schubert 	os_free(conf->connector);
38864b72b91aSCy Schubert 	crypto_ec_key_deinit(conf->connector_key);
38874b72b91aSCy Schubert 	crypto_ec_key_deinit(conf->pp_key);
388885732ac8SCy Schubert 	os_free(conf);
388985732ac8SCy Schubert }
389085732ac8SCy Schubert 
389185732ac8SCy Schubert 
389285732ac8SCy Schubert int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
389385732ac8SCy Schubert 			     size_t buflen)
389485732ac8SCy Schubert {
38954b72b91aSCy Schubert 	struct wpabuf *key;
38964b72b91aSCy Schubert 	int ret = -1;
389785732ac8SCy Schubert 
389885732ac8SCy Schubert 	if (!conf->csign)
389985732ac8SCy Schubert 		return -1;
390085732ac8SCy Schubert 
39014b72b91aSCy Schubert 	key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
39024b72b91aSCy Schubert 	if (!key)
390385732ac8SCy Schubert 		return -1;
390485732ac8SCy Schubert 
39054b72b91aSCy Schubert 	ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
390685732ac8SCy Schubert 
39074b72b91aSCy Schubert 	wpabuf_clear_free(key);
390885732ac8SCy Schubert 	return ret;
390985732ac8SCy Schubert }
391085732ac8SCy Schubert 
391185732ac8SCy Schubert 
3912c1d255d3SCy Schubert static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
391385732ac8SCy Schubert {
391485732ac8SCy Schubert 	struct wpabuf *csign_pub = NULL;
391585732ac8SCy Schubert 	const u8 *addr[1];
391685732ac8SCy Schubert 	size_t len[1];
3917c1d255d3SCy Schubert 	int res;
391885732ac8SCy Schubert 
39194b72b91aSCy Schubert 	csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
392085732ac8SCy Schubert 	if (!csign_pub) {
392185732ac8SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3922c1d255d3SCy Schubert 		return -1;
392385732ac8SCy Schubert 	}
392485732ac8SCy Schubert 
392585732ac8SCy Schubert 	/* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
392685732ac8SCy Schubert 	addr[0] = wpabuf_head(csign_pub);
392785732ac8SCy Schubert 	len[0] = wpabuf_len(csign_pub);
3928c1d255d3SCy Schubert 	res = sha256_vector(1, addr, len, conf->kid_hash);
3929c1d255d3SCy Schubert 	wpabuf_free(csign_pub);
3930c1d255d3SCy Schubert 	if (res < 0) {
393185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
393285732ac8SCy Schubert 			   "DPP: Failed to derive kid for C-sign-key");
3933c1d255d3SCy Schubert 		return -1;
393485732ac8SCy Schubert 	}
393585732ac8SCy Schubert 
3936c1d255d3SCy Schubert 	conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3937c1d255d3SCy Schubert 				      NULL);
3938c1d255d3SCy Schubert 	return conf->kid ? 0 : -1;
3939c1d255d3SCy Schubert }
3940c1d255d3SCy Schubert 
3941c1d255d3SCy Schubert 
3942c1d255d3SCy Schubert static struct dpp_configurator *
3943c1d255d3SCy Schubert dpp_keygen_configurator(const char *curve, const u8 *privkey,
3944c1d255d3SCy Schubert 			size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
3945c1d255d3SCy Schubert {
3946c1d255d3SCy Schubert 	struct dpp_configurator *conf;
3947c1d255d3SCy Schubert 
3948c1d255d3SCy Schubert 	conf = os_zalloc(sizeof(*conf));
3949c1d255d3SCy Schubert 	if (!conf)
3950c1d255d3SCy Schubert 		return NULL;
3951c1d255d3SCy Schubert 
3952c1d255d3SCy Schubert 	conf->curve = dpp_get_curve_name(curve);
3953c1d255d3SCy Schubert 	if (!conf->curve) {
3954c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3955c1d255d3SCy Schubert 		os_free(conf);
3956c1d255d3SCy Schubert 		return NULL;
3957c1d255d3SCy Schubert 	}
3958c1d255d3SCy Schubert 
3959c1d255d3SCy Schubert 	if (privkey)
3960c1d255d3SCy Schubert 		conf->csign = dpp_set_keypair(&conf->curve, privkey,
3961c1d255d3SCy Schubert 					      privkey_len);
3962c1d255d3SCy Schubert 	else
3963c1d255d3SCy Schubert 		conf->csign = dpp_gen_keypair(conf->curve);
3964c1d255d3SCy Schubert 	if (pp_key)
3965c1d255d3SCy Schubert 		conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3966c1d255d3SCy Schubert 					       pp_key_len);
3967c1d255d3SCy Schubert 	else
3968c1d255d3SCy Schubert 		conf->pp_key = dpp_gen_keypair(conf->curve);
3969c1d255d3SCy Schubert 	if (!conf->csign || !conf->pp_key)
397085732ac8SCy Schubert 		goto fail;
3971c1d255d3SCy Schubert 	conf->own = 1;
3972c1d255d3SCy Schubert 
3973c1d255d3SCy Schubert 	if (dpp_configurator_gen_kid(conf) < 0)
3974c1d255d3SCy Schubert 		goto fail;
397585732ac8SCy Schubert 	return conf;
397685732ac8SCy Schubert fail:
397785732ac8SCy Schubert 	dpp_configurator_free(conf);
3978c1d255d3SCy Schubert 	return NULL;
397985732ac8SCy Schubert }
398085732ac8SCy Schubert 
398185732ac8SCy Schubert 
398285732ac8SCy Schubert int dpp_configurator_own_config(struct dpp_authentication *auth,
398385732ac8SCy Schubert 				const char *curve, int ap)
398485732ac8SCy Schubert {
398585732ac8SCy Schubert 	struct wpabuf *conf_obj;
398685732ac8SCy Schubert 	int ret = -1;
398785732ac8SCy Schubert 
398885732ac8SCy Schubert 	if (!auth->conf) {
398985732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
399085732ac8SCy Schubert 		return -1;
399185732ac8SCy Schubert 	}
399285732ac8SCy Schubert 
399385732ac8SCy Schubert 	auth->curve = dpp_get_curve_name(curve);
399485732ac8SCy Schubert 	if (!auth->curve) {
3995c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
399685732ac8SCy Schubert 		return -1;
399785732ac8SCy Schubert 	}
3998c1d255d3SCy Schubert 
399985732ac8SCy Schubert 	wpa_printf(MSG_DEBUG,
400085732ac8SCy Schubert 		   "DPP: Building own configuration/connector with curve %s",
400185732ac8SCy Schubert 		   auth->curve->name);
400285732ac8SCy Schubert 
400385732ac8SCy Schubert 	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
400485732ac8SCy Schubert 	if (!auth->own_protocol_key)
400585732ac8SCy Schubert 		return -1;
4006c1d255d3SCy Schubert 	dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
400785732ac8SCy Schubert 	auth->peer_protocol_key = auth->own_protocol_key;
4008c1d255d3SCy Schubert 	dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
400985732ac8SCy Schubert 
4010c1d255d3SCy Schubert 	conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
4011c1d255d3SCy Schubert 	if (!conf_obj) {
4012c1d255d3SCy Schubert 		wpabuf_free(auth->conf_obj[0].c_sign_key);
4013c1d255d3SCy Schubert 		auth->conf_obj[0].c_sign_key = NULL;
401485732ac8SCy Schubert 		goto fail;
4015c1d255d3SCy Schubert 	}
401685732ac8SCy Schubert 	ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
401785732ac8SCy Schubert 				 wpabuf_len(conf_obj));
401885732ac8SCy Schubert fail:
401985732ac8SCy Schubert 	wpabuf_free(conf_obj);
402085732ac8SCy Schubert 	auth->peer_protocol_key = NULL;
402185732ac8SCy Schubert 	return ret;
402285732ac8SCy Schubert }
402385732ac8SCy Schubert 
402485732ac8SCy Schubert 
402585732ac8SCy Schubert static int dpp_compatible_netrole(const char *role1, const char *role2)
402685732ac8SCy Schubert {
402785732ac8SCy Schubert 	return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
402885732ac8SCy Schubert 		(os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
402985732ac8SCy Schubert }
403085732ac8SCy Schubert 
403185732ac8SCy Schubert 
403285732ac8SCy Schubert static int dpp_connector_compatible_group(struct json_token *root,
403385732ac8SCy Schubert 					  const char *group_id,
4034c1d255d3SCy Schubert 					  const char *net_role,
4035c1d255d3SCy Schubert 					  bool reconfig)
403685732ac8SCy Schubert {
403785732ac8SCy Schubert 	struct json_token *groups, *token;
403885732ac8SCy Schubert 
403985732ac8SCy Schubert 	groups = json_get_member(root, "groups");
404085732ac8SCy Schubert 	if (!groups || groups->type != JSON_ARRAY)
404185732ac8SCy Schubert 		return 0;
404285732ac8SCy Schubert 
404385732ac8SCy Schubert 	for (token = groups->child; token; token = token->sibling) {
404485732ac8SCy Schubert 		struct json_token *id, *role;
404585732ac8SCy Schubert 
404685732ac8SCy Schubert 		id = json_get_member(token, "groupId");
404785732ac8SCy Schubert 		if (!id || id->type != JSON_STRING)
404885732ac8SCy Schubert 			continue;
404985732ac8SCy Schubert 
405085732ac8SCy Schubert 		role = json_get_member(token, "netRole");
405185732ac8SCy Schubert 		if (!role || role->type != JSON_STRING)
405285732ac8SCy Schubert 			continue;
405385732ac8SCy Schubert 
405485732ac8SCy Schubert 		if (os_strcmp(id->string, "*") != 0 &&
405585732ac8SCy Schubert 		    os_strcmp(group_id, "*") != 0 &&
405685732ac8SCy Schubert 		    os_strcmp(id->string, group_id) != 0)
405785732ac8SCy Schubert 			continue;
405885732ac8SCy Schubert 
4059c1d255d3SCy Schubert 		if (reconfig && os_strcmp(net_role, "configurator") == 0)
4060c1d255d3SCy Schubert 			return 1;
4061c1d255d3SCy Schubert 		if (!reconfig && dpp_compatible_netrole(role->string, net_role))
406285732ac8SCy Schubert 			return 1;
406385732ac8SCy Schubert 	}
406485732ac8SCy Schubert 
406585732ac8SCy Schubert 	return 0;
406685732ac8SCy Schubert }
406785732ac8SCy Schubert 
406885732ac8SCy Schubert 
4069c1d255d3SCy Schubert int dpp_connector_match_groups(struct json_token *own_root,
4070c1d255d3SCy Schubert 			       struct json_token *peer_root, bool reconfig)
407185732ac8SCy Schubert {
407285732ac8SCy Schubert 	struct json_token *groups, *token;
407385732ac8SCy Schubert 
407485732ac8SCy Schubert 	groups = json_get_member(peer_root, "groups");
407585732ac8SCy Schubert 	if (!groups || groups->type != JSON_ARRAY) {
407685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
407785732ac8SCy Schubert 		return 0;
407885732ac8SCy Schubert 	}
407985732ac8SCy Schubert 
408085732ac8SCy Schubert 	for (token = groups->child; token; token = token->sibling) {
408185732ac8SCy Schubert 		struct json_token *id, *role;
408285732ac8SCy Schubert 
408385732ac8SCy Schubert 		id = json_get_member(token, "groupId");
408485732ac8SCy Schubert 		if (!id || id->type != JSON_STRING) {
408585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
408685732ac8SCy Schubert 				   "DPP: Missing peer groupId string");
408785732ac8SCy Schubert 			continue;
408885732ac8SCy Schubert 		}
408985732ac8SCy Schubert 
409085732ac8SCy Schubert 		role = json_get_member(token, "netRole");
409185732ac8SCy Schubert 		if (!role || role->type != JSON_STRING) {
409285732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
409385732ac8SCy Schubert 				   "DPP: Missing peer groups::netRole string");
409485732ac8SCy Schubert 			continue;
409585732ac8SCy Schubert 		}
409685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
409785732ac8SCy Schubert 			   "DPP: peer connector group: groupId='%s' netRole='%s'",
409885732ac8SCy Schubert 			   id->string, role->string);
409985732ac8SCy Schubert 		if (dpp_connector_compatible_group(own_root, id->string,
4100c1d255d3SCy Schubert 						   role->string, reconfig)) {
410185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
410285732ac8SCy Schubert 				   "DPP: Compatible group/netRole in own connector");
410385732ac8SCy Schubert 			return 1;
410485732ac8SCy Schubert 		}
410585732ac8SCy Schubert 	}
410685732ac8SCy Schubert 
410785732ac8SCy Schubert 	return 0;
410885732ac8SCy Schubert }
410985732ac8SCy Schubert 
411085732ac8SCy Schubert 
4111c1d255d3SCy Schubert struct json_token * dpp_parse_own_connector(const char *own_connector)
411285732ac8SCy Schubert {
4113c1d255d3SCy Schubert 	unsigned char *own_conn;
4114c1d255d3SCy Schubert 	size_t own_conn_len;
4115c1d255d3SCy Schubert 	const char *pos, *end;
4116c1d255d3SCy Schubert 	struct json_token *own_root;
411785732ac8SCy Schubert 
4118c1d255d3SCy Schubert 	pos = os_strchr(own_connector, '.');
4119c1d255d3SCy Schubert 	if (!pos) {
4120c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4121c1d255d3SCy Schubert 		return NULL;
4122c1d255d3SCy Schubert 	}
4123c1d255d3SCy Schubert 	pos++;
4124c1d255d3SCy Schubert 	end = os_strchr(pos, '.');
4125c1d255d3SCy Schubert 	if (!end) {
4126c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4127c1d255d3SCy Schubert 		return NULL;
4128c1d255d3SCy Schubert 	}
4129c1d255d3SCy Schubert 	own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4130c1d255d3SCy Schubert 	if (!own_conn) {
4131c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
4132c1d255d3SCy Schubert 			   "DPP: Failed to base64url decode own signedConnector JWS Payload");
4133c1d255d3SCy Schubert 		return NULL;
413485732ac8SCy Schubert 	}
413585732ac8SCy Schubert 
4136c1d255d3SCy Schubert 	own_root = json_parse((const char *) own_conn, own_conn_len);
4137c1d255d3SCy Schubert 	os_free(own_conn);
4138c1d255d3SCy Schubert 	if (!own_root)
4139c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
414085732ac8SCy Schubert 
4141c1d255d3SCy Schubert 	return own_root;
414285732ac8SCy Schubert }
414385732ac8SCy Schubert 
414485732ac8SCy Schubert 
414585732ac8SCy Schubert enum dpp_status_error
414685732ac8SCy Schubert dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
414785732ac8SCy Schubert 	       const u8 *net_access_key, size_t net_access_key_len,
414885732ac8SCy Schubert 	       const u8 *csign_key, size_t csign_key_len,
414985732ac8SCy Schubert 	       const u8 *peer_connector, size_t peer_connector_len,
4150*a90b9d01SCy Schubert 	       os_time_t *expiry, u8 *peer_key_hash)
415185732ac8SCy Schubert {
415285732ac8SCy Schubert 	struct json_token *root = NULL, *netkey, *token;
415385732ac8SCy Schubert 	struct json_token *own_root = NULL;
415485732ac8SCy Schubert 	enum dpp_status_error ret = 255, res;
4155*a90b9d01SCy Schubert 	struct crypto_ec_key *own_key = NULL;
415685732ac8SCy Schubert 	struct wpabuf *own_key_pub = NULL;
415785732ac8SCy Schubert 	const struct dpp_curve_params *curve, *own_curve;
415885732ac8SCy Schubert 	struct dpp_signed_connector_info info;
415985732ac8SCy Schubert 	size_t Nx_len;
416085732ac8SCy Schubert 	u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
416185732ac8SCy Schubert 
416285732ac8SCy Schubert 	os_memset(intro, 0, sizeof(*intro));
416385732ac8SCy Schubert 	os_memset(&info, 0, sizeof(info));
416485732ac8SCy Schubert 	if (expiry)
416585732ac8SCy Schubert 		*expiry = 0;
416685732ac8SCy Schubert 
416785732ac8SCy Schubert 	own_key = dpp_set_keypair(&own_curve, net_access_key,
416885732ac8SCy Schubert 				  net_access_key_len);
416985732ac8SCy Schubert 	if (!own_key) {
417085732ac8SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
417185732ac8SCy Schubert 		goto fail;
417285732ac8SCy Schubert 	}
417385732ac8SCy Schubert 
4174c1d255d3SCy Schubert 	own_root = dpp_parse_own_connector(own_connector);
4175c1d255d3SCy Schubert 	if (!own_root)
417685732ac8SCy Schubert 		goto fail;
417785732ac8SCy Schubert 
4178c1d255d3SCy Schubert 	res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
417985732ac8SCy Schubert 					 peer_connector, peer_connector_len);
418085732ac8SCy Schubert 	if (res != DPP_STATUS_OK) {
418185732ac8SCy Schubert 		ret = res;
418285732ac8SCy Schubert 		goto fail;
418385732ac8SCy Schubert 	}
418485732ac8SCy Schubert 
418585732ac8SCy Schubert 	root = json_parse((const char *) info.payload, info.payload_len);
418685732ac8SCy Schubert 	if (!root) {
418785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
418885732ac8SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
418985732ac8SCy Schubert 		goto fail;
419085732ac8SCy Schubert 	}
419185732ac8SCy Schubert 
4192c1d255d3SCy Schubert 	if (!dpp_connector_match_groups(own_root, root, false)) {
419385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
419485732ac8SCy Schubert 			   "DPP: Peer connector does not include compatible group netrole with own connector");
419585732ac8SCy Schubert 		ret = DPP_STATUS_NO_MATCH;
419685732ac8SCy Schubert 		goto fail;
419785732ac8SCy Schubert 	}
419885732ac8SCy Schubert 
419985732ac8SCy Schubert 	token = json_get_member(root, "expiry");
420085732ac8SCy Schubert 	if (!token || token->type != JSON_STRING) {
420185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
420285732ac8SCy Schubert 			   "DPP: No expiry string found - connector does not expire");
420385732ac8SCy Schubert 	} else {
420485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
420585732ac8SCy Schubert 		if (dpp_key_expired(token->string, expiry)) {
420685732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
420785732ac8SCy Schubert 				   "DPP: Connector (netAccessKey) has expired");
420885732ac8SCy Schubert 			ret = DPP_STATUS_INVALID_CONNECTOR;
420985732ac8SCy Schubert 			goto fail;
421085732ac8SCy Schubert 		}
421185732ac8SCy Schubert 	}
421285732ac8SCy Schubert 
421332a95656SCy Schubert #ifdef CONFIG_DPP3
421432a95656SCy Schubert 	token = json_get_member(root, "version");
421532a95656SCy Schubert 	if (token && token->type == JSON_NUMBER) {
421632a95656SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
421732a95656SCy Schubert 		intro->peer_version = token->number;
421832a95656SCy Schubert 	}
421932a95656SCy Schubert #endif /* CONFIG_DPP3 */
422032a95656SCy Schubert 
422185732ac8SCy Schubert 	netkey = json_get_member(root, "netAccessKey");
422285732ac8SCy Schubert 	if (!netkey || netkey->type != JSON_OBJECT) {
422385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
422485732ac8SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
422585732ac8SCy Schubert 		goto fail;
422685732ac8SCy Schubert 	}
422785732ac8SCy Schubert 
4228*a90b9d01SCy Schubert 	intro->peer_key = dpp_parse_jwk(netkey, &curve);
4229*a90b9d01SCy Schubert 	if (!intro->peer_key) {
423085732ac8SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
423185732ac8SCy Schubert 		goto fail;
423285732ac8SCy Schubert 	}
4233*a90b9d01SCy Schubert 	dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
423485732ac8SCy Schubert 
423585732ac8SCy Schubert 	if (own_curve != curve) {
423685732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
423785732ac8SCy Schubert 			   "DPP: Mismatching netAccessKey curves (%s != %s)",
423885732ac8SCy Schubert 			   own_curve->name, curve->name);
423985732ac8SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
424085732ac8SCy Schubert 		goto fail;
424185732ac8SCy Schubert 	}
424285732ac8SCy Schubert 
424385732ac8SCy Schubert 	/* ECDH: N = nk * PK */
4244*a90b9d01SCy Schubert 	if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
424585732ac8SCy Schubert 		goto fail;
424685732ac8SCy Schubert 
424785732ac8SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
424885732ac8SCy Schubert 			Nx, Nx_len);
424985732ac8SCy Schubert 
425085732ac8SCy Schubert 	/* PMK = HKDF(<>, "DPP PMK", N.x) */
425185732ac8SCy Schubert 	if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
425285732ac8SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
425385732ac8SCy Schubert 		goto fail;
425485732ac8SCy Schubert 	}
425585732ac8SCy Schubert 	intro->pmk_len = curve->hash_len;
425685732ac8SCy Schubert 
425785732ac8SCy Schubert 	/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4258*a90b9d01SCy Schubert 	if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4259*a90b9d01SCy Schubert 	    0) {
426085732ac8SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
426185732ac8SCy Schubert 		goto fail;
426285732ac8SCy Schubert 	}
426385732ac8SCy Schubert 
4264*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
4265*a90b9d01SCy Schubert 	if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4266*a90b9d01SCy Schubert 			   &intro->aead_id) < 0) {
4267*a90b9d01SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4268*a90b9d01SCy Schubert 			   curve->ike_group);
4269*a90b9d01SCy Schubert 		goto fail;
4270*a90b9d01SCy Schubert 	}
4271*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
4272*a90b9d01SCy Schubert 
4273*a90b9d01SCy Schubert 	if (peer_key_hash)
4274*a90b9d01SCy Schubert 		dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
4275*a90b9d01SCy Schubert 
427685732ac8SCy Schubert 	ret = DPP_STATUS_OK;
427785732ac8SCy Schubert fail:
427885732ac8SCy Schubert 	if (ret != DPP_STATUS_OK)
4279*a90b9d01SCy Schubert 		dpp_peer_intro_deinit(intro);
428085732ac8SCy Schubert 	os_memset(Nx, 0, sizeof(Nx));
428185732ac8SCy Schubert 	os_free(info.payload);
42824b72b91aSCy Schubert 	crypto_ec_key_deinit(own_key);
428385732ac8SCy Schubert 	wpabuf_free(own_key_pub);
428485732ac8SCy Schubert 	json_free(root);
428585732ac8SCy Schubert 	json_free(own_root);
428685732ac8SCy Schubert 	return ret;
428785732ac8SCy Schubert }
428885732ac8SCy Schubert 
428985732ac8SCy Schubert 
4290*a90b9d01SCy Schubert void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4291*a90b9d01SCy Schubert {
4292*a90b9d01SCy Schubert 	if (!intro)
4293*a90b9d01SCy Schubert 		return;
4294*a90b9d01SCy Schubert 
4295*a90b9d01SCy Schubert 	crypto_ec_key_deinit(intro->peer_key);
4296*a90b9d01SCy Schubert 	os_memset(intro, 0, sizeof(*intro));
4297*a90b9d01SCy Schubert }
4298*a90b9d01SCy Schubert 
4299*a90b9d01SCy Schubert 
430032a95656SCy Schubert #ifdef CONFIG_DPP3
430132a95656SCy Schubert int dpp_get_connector_version(const char *connector)
430232a95656SCy Schubert {
430332a95656SCy Schubert 	struct json_token *root, *token;
430432a95656SCy Schubert 	int ver = -1;
430532a95656SCy Schubert 
430632a95656SCy Schubert 	root = dpp_parse_own_connector(connector);
430732a95656SCy Schubert 	if (!root)
430832a95656SCy Schubert 		return -1;
430932a95656SCy Schubert 
431032a95656SCy Schubert 	token = json_get_member(root, "version");
431132a95656SCy Schubert 	if (token && token->type == JSON_NUMBER)
431232a95656SCy Schubert 		ver = token->number;
431332a95656SCy Schubert 
431432a95656SCy Schubert 	json_free(root);
431532a95656SCy Schubert 	return ver;
431632a95656SCy Schubert }
431732a95656SCy Schubert #endif /* CONFIG_DPP3 */
431832a95656SCy Schubert 
431932a95656SCy Schubert 
4320c1d255d3SCy Schubert unsigned int dpp_next_id(struct dpp_global *dpp)
43214bc52338SCy Schubert {
43224bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
43234bc52338SCy Schubert 	unsigned int max_id = 0;
43244bc52338SCy Schubert 
43254bc52338SCy Schubert 	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
43264bc52338SCy Schubert 		if (bi->id > max_id)
43274bc52338SCy Schubert 			max_id = bi->id;
43284bc52338SCy Schubert 	}
43294bc52338SCy Schubert 	return max_id + 1;
43304bc52338SCy Schubert }
43314bc52338SCy Schubert 
43324bc52338SCy Schubert 
43334bc52338SCy Schubert static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
43344bc52338SCy Schubert {
43354bc52338SCy Schubert 	struct dpp_bootstrap_info *bi, *tmp;
43364bc52338SCy Schubert 	int found = 0;
43374bc52338SCy Schubert 
43384bc52338SCy Schubert 	if (!dpp)
43394bc52338SCy Schubert 		return -1;
43404bc52338SCy Schubert 
43414bc52338SCy Schubert 	dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
43424bc52338SCy Schubert 			      struct dpp_bootstrap_info, list) {
43434bc52338SCy Schubert 		if (id && bi->id != id)
43444bc52338SCy Schubert 			continue;
43454bc52338SCy Schubert 		found = 1;
4346c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4347c1d255d3SCy Schubert 		if (dpp->remove_bi)
4348c1d255d3SCy Schubert 			dpp->remove_bi(dpp->cb_ctx, bi);
4349c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
43504bc52338SCy Schubert 		dl_list_del(&bi->list);
43514bc52338SCy Schubert 		dpp_bootstrap_info_free(bi);
43524bc52338SCy Schubert 	}
43534bc52338SCy Schubert 
43544bc52338SCy Schubert 	if (id == 0)
43554bc52338SCy Schubert 		return 0; /* flush succeeds regardless of entries found */
43564bc52338SCy Schubert 	return found ? 0 : -1;
43574bc52338SCy Schubert }
43584bc52338SCy Schubert 
43594bc52338SCy Schubert 
43604bc52338SCy Schubert struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
43614bc52338SCy Schubert 					    const char *uri)
43624bc52338SCy Schubert {
43634bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
43644bc52338SCy Schubert 
43654bc52338SCy Schubert 	if (!dpp)
43664bc52338SCy Schubert 		return NULL;
43674bc52338SCy Schubert 
4368c1d255d3SCy Schubert 	bi = dpp_parse_uri(uri);
43694bc52338SCy Schubert 	if (!bi)
43704bc52338SCy Schubert 		return NULL;
43714bc52338SCy Schubert 
4372c1d255d3SCy Schubert 	bi->type = DPP_BOOTSTRAP_QR_CODE;
4373c1d255d3SCy Schubert 	bi->id = dpp_next_id(dpp);
4374c1d255d3SCy Schubert 	dl_list_add(&dpp->bootstrap, &bi->list);
4375c1d255d3SCy Schubert 	return bi;
4376c1d255d3SCy Schubert }
4377c1d255d3SCy Schubert 
4378c1d255d3SCy Schubert 
4379c1d255d3SCy Schubert struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4380c1d255d3SCy Schubert 					    const char *uri)
4381c1d255d3SCy Schubert {
4382c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
4383c1d255d3SCy Schubert 
4384c1d255d3SCy Schubert 	if (!dpp)
4385c1d255d3SCy Schubert 		return NULL;
4386c1d255d3SCy Schubert 
4387c1d255d3SCy Schubert 	bi = dpp_parse_uri(uri);
4388c1d255d3SCy Schubert 	if (!bi)
4389c1d255d3SCy Schubert 		return NULL;
4390c1d255d3SCy Schubert 
4391c1d255d3SCy Schubert 	bi->type = DPP_BOOTSTRAP_NFC_URI;
43924bc52338SCy Schubert 	bi->id = dpp_next_id(dpp);
43934bc52338SCy Schubert 	dl_list_add(&dpp->bootstrap, &bi->list);
43944bc52338SCy Schubert 	return bi;
43954bc52338SCy Schubert }
43964bc52338SCy Schubert 
43974bc52338SCy Schubert 
4398*a90b9d01SCy Schubert static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4399*a90b9d01SCy Schubert 					   char *txt)
4400*a90b9d01SCy Schubert {
4401*a90b9d01SCy Schubert 	char *token, *context = NULL;
4402*a90b9d01SCy Schubert 	u8 curves = 0;
4403*a90b9d01SCy Schubert 
4404*a90b9d01SCy Schubert 	if (!txt)
4405*a90b9d01SCy Schubert 		return 0;
4406*a90b9d01SCy Schubert 
4407*a90b9d01SCy Schubert 	while ((token = str_token(txt, ":", &context))) {
4408*a90b9d01SCy Schubert 		if (os_strcmp(token, "P-256") == 0) {
4409*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4410*a90b9d01SCy Schubert 		} else if (os_strcmp(token, "P-384") == 0) {
4411*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4412*a90b9d01SCy Schubert 		} else if (os_strcmp(token, "P-521") == 0) {
4413*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4414*a90b9d01SCy Schubert 		} else if (os_strcmp(token, "BP-256") == 0) {
4415*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4416*a90b9d01SCy Schubert 		} else if (os_strcmp(token, "BP-384") == 0) {
4417*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4418*a90b9d01SCy Schubert 		} else if (os_strcmp(token, "BP-512") == 0) {
4419*a90b9d01SCy Schubert 			curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4420*a90b9d01SCy Schubert 		} else {
4421*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4422*a90b9d01SCy Schubert 				   token);
4423*a90b9d01SCy Schubert 			return -1;
4424*a90b9d01SCy Schubert 		}
4425*a90b9d01SCy Schubert 	}
4426*a90b9d01SCy Schubert 	bi->supported_curves = curves;
4427*a90b9d01SCy Schubert 
4428*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4429*a90b9d01SCy Schubert 		   bi->supported_curves);
4430*a90b9d01SCy Schubert 
4431*a90b9d01SCy Schubert 	return 0;
4432*a90b9d01SCy Schubert }
4433*a90b9d01SCy Schubert 
4434*a90b9d01SCy Schubert 
44354bc52338SCy Schubert int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
44364bc52338SCy Schubert {
4437c1d255d3SCy Schubert 	char *mac = NULL, *info = NULL, *curve = NULL;
4438*a90b9d01SCy Schubert 	char *key = NULL, *supported_curves = NULL, *host = NULL;
44394bc52338SCy Schubert 	u8 *privkey = NULL;
44404bc52338SCy Schubert 	size_t privkey_len = 0;
44414bc52338SCy Schubert 	int ret = -1;
44424bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
44434bc52338SCy Schubert 
44444bc52338SCy Schubert 	if (!dpp)
44454bc52338SCy Schubert 		return -1;
44464bc52338SCy Schubert 
44474bc52338SCy Schubert 	bi = os_zalloc(sizeof(*bi));
44484bc52338SCy Schubert 	if (!bi)
44494bc52338SCy Schubert 		goto fail;
44504bc52338SCy Schubert 
44514bc52338SCy Schubert 	if (os_strstr(cmd, "type=qrcode"))
44524bc52338SCy Schubert 		bi->type = DPP_BOOTSTRAP_QR_CODE;
44534bc52338SCy Schubert 	else if (os_strstr(cmd, "type=pkex"))
44544bc52338SCy Schubert 		bi->type = DPP_BOOTSTRAP_PKEX;
4455c1d255d3SCy Schubert 	else if (os_strstr(cmd, "type=nfc-uri"))
4456c1d255d3SCy Schubert 		bi->type = DPP_BOOTSTRAP_NFC_URI;
44574bc52338SCy Schubert 	else
44584bc52338SCy Schubert 		goto fail;
44594bc52338SCy Schubert 
4460c1d255d3SCy Schubert 	bi->chan = get_param(cmd, " chan=");
44614bc52338SCy Schubert 	mac = get_param(cmd, " mac=");
44624bc52338SCy Schubert 	info = get_param(cmd, " info=");
44634bc52338SCy Schubert 	curve = get_param(cmd, " curve=");
44644bc52338SCy Schubert 	key = get_param(cmd, " key=");
4465*a90b9d01SCy Schubert 	supported_curves = get_param(cmd, " supported_curves=");
4466*a90b9d01SCy Schubert 	host = get_param(cmd, " host=");
44674bc52338SCy Schubert 
44684bc52338SCy Schubert 	if (key) {
44694bc52338SCy Schubert 		privkey_len = os_strlen(key) / 2;
44704bc52338SCy Schubert 		privkey = os_malloc(privkey_len);
44714bc52338SCy Schubert 		if (!privkey ||
44724bc52338SCy Schubert 		    hexstr2bin(key, privkey, privkey_len) < 0)
44734bc52338SCy Schubert 			goto fail;
44744bc52338SCy Schubert 	}
44754bc52338SCy Schubert 
4476c1d255d3SCy Schubert 	if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4477c1d255d3SCy Schubert 	    dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4478c1d255d3SCy Schubert 	    dpp_parse_uri_mac(bi, mac) < 0 ||
4479c1d255d3SCy Schubert 	    dpp_parse_uri_info(bi, info) < 0 ||
4480*a90b9d01SCy Schubert 	    dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
4481*a90b9d01SCy Schubert 	    dpp_parse_uri_host(bi, host) < 0 ||
4482c1d255d3SCy Schubert 	    dpp_gen_uri(bi) < 0)
44834bc52338SCy Schubert 		goto fail;
44844bc52338SCy Schubert 
44854bc52338SCy Schubert 	bi->id = dpp_next_id(dpp);
44864bc52338SCy Schubert 	dl_list_add(&dpp->bootstrap, &bi->list);
44874bc52338SCy Schubert 	ret = bi->id;
44884bc52338SCy Schubert 	bi = NULL;
44894bc52338SCy Schubert fail:
44904bc52338SCy Schubert 	os_free(curve);
44914bc52338SCy Schubert 	os_free(mac);
44924bc52338SCy Schubert 	os_free(info);
44934bc52338SCy Schubert 	str_clear_free(key);
4494*a90b9d01SCy Schubert 	os_free(supported_curves);
4495*a90b9d01SCy Schubert 	os_free(host);
44964bc52338SCy Schubert 	bin_clear_free(privkey, privkey_len);
44974bc52338SCy Schubert 	dpp_bootstrap_info_free(bi);
44984bc52338SCy Schubert 	return ret;
44994bc52338SCy Schubert }
45004bc52338SCy Schubert 
45014bc52338SCy Schubert 
45024bc52338SCy Schubert struct dpp_bootstrap_info *
45034bc52338SCy Schubert dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
45044bc52338SCy Schubert {
45054bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
45064bc52338SCy Schubert 
45074bc52338SCy Schubert 	if (!dpp)
45084bc52338SCy Schubert 		return NULL;
45094bc52338SCy Schubert 
45104bc52338SCy Schubert 	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
45114bc52338SCy Schubert 		if (bi->id == id)
45124bc52338SCy Schubert 			return bi;
45134bc52338SCy Schubert 	}
45144bc52338SCy Schubert 	return NULL;
45154bc52338SCy Schubert }
45164bc52338SCy Schubert 
45174bc52338SCy Schubert 
45184bc52338SCy Schubert int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
45194bc52338SCy Schubert {
45204bc52338SCy Schubert 	unsigned int id_val;
45214bc52338SCy Schubert 
45224bc52338SCy Schubert 	if (os_strcmp(id, "*") == 0) {
45234bc52338SCy Schubert 		id_val = 0;
45244bc52338SCy Schubert 	} else {
45254bc52338SCy Schubert 		id_val = atoi(id);
45264bc52338SCy Schubert 		if (id_val == 0)
45274bc52338SCy Schubert 			return -1;
45284bc52338SCy Schubert 	}
45294bc52338SCy Schubert 
45304bc52338SCy Schubert 	return dpp_bootstrap_del(dpp, id_val);
45314bc52338SCy Schubert }
45324bc52338SCy Schubert 
45334bc52338SCy Schubert 
45344bc52338SCy Schubert const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
45354bc52338SCy Schubert {
45364bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
45374bc52338SCy Schubert 
45384bc52338SCy Schubert 	bi = dpp_bootstrap_get_id(dpp, id);
45394bc52338SCy Schubert 	if (!bi)
45404bc52338SCy Schubert 		return NULL;
45414bc52338SCy Schubert 	return bi->uri;
45424bc52338SCy Schubert }
45434bc52338SCy Schubert 
45444bc52338SCy Schubert 
45454bc52338SCy Schubert int dpp_bootstrap_info(struct dpp_global *dpp, int id,
45464bc52338SCy Schubert 		       char *reply, int reply_size)
45474bc52338SCy Schubert {
45484bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
4549206b73d0SCy Schubert 	char pkhash[2 * SHA256_MAC_LEN + 1];
4550*a90b9d01SCy Schubert 	char supp_curves[100];
4551*a90b9d01SCy Schubert 	char host[100];
4552*a90b9d01SCy Schubert 	int ret;
45534bc52338SCy Schubert 
45544bc52338SCy Schubert 	bi = dpp_bootstrap_get_id(dpp, id);
45554bc52338SCy Schubert 	if (!bi)
45564bc52338SCy Schubert 		return -1;
4557206b73d0SCy Schubert 	wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4558206b73d0SCy Schubert 			 SHA256_MAC_LEN);
4559*a90b9d01SCy Schubert 
4560*a90b9d01SCy Schubert 	supp_curves[0] = '\0';
4561*a90b9d01SCy Schubert 	if (bi->supported_curves) {
4562*a90b9d01SCy Schubert 		size_t i;
4563*a90b9d01SCy Schubert 		char *pos = supp_curves;
4564*a90b9d01SCy Schubert 		char *end = &supp_curves[sizeof(supp_curves)];
4565*a90b9d01SCy Schubert 		const char *curve[6] = { "P-256", "P-384", "P-521",
4566*a90b9d01SCy Schubert 					 "BP-256", "BP-384", "BP-512" };
4567*a90b9d01SCy Schubert 
4568*a90b9d01SCy Schubert 		ret = os_snprintf(pos, end - pos, "supp_curves=");
4569*a90b9d01SCy Schubert 		if (os_snprintf_error(end - pos, ret))
4570*a90b9d01SCy Schubert 			return -1;
4571*a90b9d01SCy Schubert 		pos += ret;
4572*a90b9d01SCy Schubert 
4573*a90b9d01SCy Schubert 		for (i = 0; i < ARRAY_SIZE(curve); i++) {
4574*a90b9d01SCy Schubert 			if (!(bi->supported_curves & BIT(i)))
4575*a90b9d01SCy Schubert 				continue;
4576*a90b9d01SCy Schubert 			ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4577*a90b9d01SCy Schubert 			if (os_snprintf_error(end - pos, ret))
4578*a90b9d01SCy Schubert 				return -1;
4579*a90b9d01SCy Schubert 			pos += ret;
4580*a90b9d01SCy Schubert 		}
4581*a90b9d01SCy Schubert 
4582*a90b9d01SCy Schubert 		if (pos[-1] == ':')
4583*a90b9d01SCy Schubert 			pos[-1] = '\n';
4584*a90b9d01SCy Schubert 		else
4585*a90b9d01SCy Schubert 			supp_curves[0] = '\0';
4586*a90b9d01SCy Schubert 	}
4587*a90b9d01SCy Schubert 
4588*a90b9d01SCy Schubert 	host[0] = '\0';
4589*a90b9d01SCy Schubert 	if (bi->host) {
4590*a90b9d01SCy Schubert 		char buf[100];
4591*a90b9d01SCy Schubert 
4592*a90b9d01SCy Schubert 		ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4593*a90b9d01SCy Schubert 				  hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4594*a90b9d01SCy Schubert 				  bi->port);
4595*a90b9d01SCy Schubert 		if (os_snprintf_error(sizeof(host), ret))
4596*a90b9d01SCy Schubert 			return -1;
4597*a90b9d01SCy Schubert 	}
4598*a90b9d01SCy Schubert 
45994bc52338SCy Schubert 	return os_snprintf(reply, reply_size, "type=%s\n"
46004bc52338SCy Schubert 			   "mac_addr=" MACSTR "\n"
46014bc52338SCy Schubert 			   "info=%s\n"
46024bc52338SCy Schubert 			   "num_freq=%u\n"
4603c1d255d3SCy Schubert 			   "use_freq=%u\n"
4604206b73d0SCy Schubert 			   "curve=%s\n"
4605c1d255d3SCy Schubert 			   "pkhash=%s\n"
4606*a90b9d01SCy Schubert 			   "version=%d\n%s%s",
46074bc52338SCy Schubert 			   dpp_bootstrap_type_txt(bi->type),
46084bc52338SCy Schubert 			   MAC2STR(bi->mac_addr),
46094bc52338SCy Schubert 			   bi->info ? bi->info : "",
46104bc52338SCy Schubert 			   bi->num_freq,
4611c1d255d3SCy Schubert 			   bi->num_freq == 1 ? bi->freq[0] : 0,
4612206b73d0SCy Schubert 			   bi->curve->name,
4613c1d255d3SCy Schubert 			   pkhash,
4614*a90b9d01SCy Schubert 			   bi->version,
4615*a90b9d01SCy Schubert 			   supp_curves,
4616*a90b9d01SCy Schubert 			   host);
4617c1d255d3SCy Schubert }
4618c1d255d3SCy Schubert 
4619c1d255d3SCy Schubert 
4620c1d255d3SCy Schubert int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4621c1d255d3SCy Schubert {
4622c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
4623c1d255d3SCy Schubert 
4624c1d255d3SCy Schubert 	bi = dpp_bootstrap_get_id(dpp, id);
4625c1d255d3SCy Schubert 	if (!bi)
4626c1d255d3SCy Schubert 		return -1;
4627c1d255d3SCy Schubert 
4628c1d255d3SCy Schubert 	str_clear_free(bi->configurator_params);
4629c1d255d3SCy Schubert 
4630c1d255d3SCy Schubert 	if (params) {
4631c1d255d3SCy Schubert 		bi->configurator_params = os_strdup(params);
4632c1d255d3SCy Schubert 		return bi->configurator_params ? 0 : -1;
4633c1d255d3SCy Schubert 	}
4634c1d255d3SCy Schubert 
4635c1d255d3SCy Schubert 	bi->configurator_params = NULL;
4636c1d255d3SCy Schubert 	return 0;
46374bc52338SCy Schubert }
46384bc52338SCy Schubert 
46394bc52338SCy Schubert 
46404bc52338SCy Schubert void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
46414bc52338SCy Schubert 			     const u8 *r_bootstrap,
46424bc52338SCy Schubert 			     struct dpp_bootstrap_info **own_bi,
46434bc52338SCy Schubert 			     struct dpp_bootstrap_info **peer_bi)
46444bc52338SCy Schubert {
46454bc52338SCy Schubert 	struct dpp_bootstrap_info *bi;
46464bc52338SCy Schubert 
46474bc52338SCy Schubert 	*own_bi = NULL;
46484bc52338SCy Schubert 	*peer_bi = NULL;
46494bc52338SCy Schubert 	if (!dpp)
46504bc52338SCy Schubert 		return;
46514bc52338SCy Schubert 
46524bc52338SCy Schubert 	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
46534bc52338SCy Schubert 		if (!*own_bi && bi->own &&
46544bc52338SCy Schubert 		    os_memcmp(bi->pubkey_hash, r_bootstrap,
46554bc52338SCy Schubert 			      SHA256_MAC_LEN) == 0) {
46564bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
46574bc52338SCy Schubert 				   "DPP: Found matching own bootstrapping information");
46584bc52338SCy Schubert 			*own_bi = bi;
46594bc52338SCy Schubert 		}
46604bc52338SCy Schubert 
46614bc52338SCy Schubert 		if (!*peer_bi && !bi->own &&
46624bc52338SCy Schubert 		    os_memcmp(bi->pubkey_hash, i_bootstrap,
46634bc52338SCy Schubert 			      SHA256_MAC_LEN) == 0) {
46644bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
46654bc52338SCy Schubert 				   "DPP: Found matching peer bootstrapping information");
46664bc52338SCy Schubert 			*peer_bi = bi;
46674bc52338SCy Schubert 		}
46684bc52338SCy Schubert 
46694bc52338SCy Schubert 		if (*own_bi && *peer_bi)
46704bc52338SCy Schubert 			break;
46714bc52338SCy Schubert 	}
4672c1d255d3SCy Schubert }
46734bc52338SCy Schubert 
4674c1d255d3SCy Schubert 
4675c1d255d3SCy Schubert #ifdef CONFIG_DPP2
4676c1d255d3SCy Schubert struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4677c1d255d3SCy Schubert 						     const u8 *hash)
4678c1d255d3SCy Schubert {
4679c1d255d3SCy Schubert 	struct dpp_bootstrap_info *bi;
4680c1d255d3SCy Schubert 
4681c1d255d3SCy Schubert 	if (!dpp)
4682c1d255d3SCy Schubert 		return NULL;
4683c1d255d3SCy Schubert 
4684c1d255d3SCy Schubert 	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4685c1d255d3SCy Schubert 		if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4686c1d255d3SCy Schubert 					  SHA256_MAC_LEN) == 0)
4687c1d255d3SCy Schubert 			return bi;
4688c1d255d3SCy Schubert 	}
4689c1d255d3SCy Schubert 
4690c1d255d3SCy Schubert 	return NULL;
4691c1d255d3SCy Schubert }
4692c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
4693c1d255d3SCy Schubert 
4694c1d255d3SCy Schubert 
4695c1d255d3SCy Schubert static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4696c1d255d3SCy Schubert 				     struct dpp_bootstrap_info *peer_bi)
4697c1d255d3SCy Schubert {
4698c1d255d3SCy Schubert 	unsigned int i, freq = 0;
4699c1d255d3SCy Schubert 	enum hostapd_hw_mode mode;
4700c1d255d3SCy Schubert 	u8 op_class, channel;
4701c1d255d3SCy Schubert 	char chan[20];
4702c1d255d3SCy Schubert 
4703c1d255d3SCy Schubert 	if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
4704c1d255d3SCy Schubert 		return 0; /* no channel preference/constraint */
4705c1d255d3SCy Schubert 
4706c1d255d3SCy Schubert 	for (i = 0; i < peer_bi->num_freq; i++) {
4707c1d255d3SCy Schubert 		if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
4708c1d255d3SCy Schubert 		    freq_included(own_bi->freq, own_bi->num_freq,
4709c1d255d3SCy Schubert 				  peer_bi->freq[i])) {
4710c1d255d3SCy Schubert 			freq = peer_bi->freq[i];
4711c1d255d3SCy Schubert 			break;
4712c1d255d3SCy Schubert 		}
4713c1d255d3SCy Schubert 	}
4714c1d255d3SCy Schubert 	if (!freq) {
4715c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4716c1d255d3SCy Schubert 		return -1;
4717c1d255d3SCy Schubert 	}
4718c1d255d3SCy Schubert 
4719c1d255d3SCy Schubert 	mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4720c1d255d3SCy Schubert 	if (mode == NUM_HOSTAPD_MODES) {
4721c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
4722c1d255d3SCy Schubert 			   "DPP: Could not determine operating class or channel number for %u MHz",
4723c1d255d3SCy Schubert 			   freq);
4724c1d255d3SCy Schubert 	}
4725c1d255d3SCy Schubert 
4726c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
4727c1d255d3SCy Schubert 		   "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4728c1d255d3SCy Schubert 		   freq, op_class, channel);
4729c1d255d3SCy Schubert 	os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4730c1d255d3SCy Schubert 	os_free(own_bi->chan);
4731c1d255d3SCy Schubert 	own_bi->chan = os_strdup(chan);
4732c1d255d3SCy Schubert 	own_bi->freq[0] = freq;
4733c1d255d3SCy Schubert 	own_bi->num_freq = 1;
4734c1d255d3SCy Schubert 	os_free(peer_bi->chan);
4735c1d255d3SCy Schubert 	peer_bi->chan = os_strdup(chan);
4736c1d255d3SCy Schubert 	peer_bi->freq[0] = freq;
4737c1d255d3SCy Schubert 	peer_bi->num_freq = 1;
4738c1d255d3SCy Schubert 
4739c1d255d3SCy Schubert 	return dpp_gen_uri(own_bi);
4740c1d255d3SCy Schubert }
4741c1d255d3SCy Schubert 
4742c1d255d3SCy Schubert 
4743c1d255d3SCy Schubert static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4744c1d255d3SCy Schubert 				 struct dpp_bootstrap_info *peer_bi)
4745c1d255d3SCy Schubert {
4746c1d255d3SCy Schubert 	if (peer_bi->curve == own_bi->curve)
4747c1d255d3SCy Schubert 		return 0;
4748c1d255d3SCy Schubert 
4749c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG,
4750c1d255d3SCy Schubert 		   "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4751c1d255d3SCy Schubert 
47524b72b91aSCy Schubert 	crypto_ec_key_deinit(own_bi->pubkey);
4753c1d255d3SCy Schubert 	own_bi->pubkey = NULL;
4754c1d255d3SCy Schubert 
4755c1d255d3SCy Schubert 	if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4756c1d255d3SCy Schubert 	    dpp_gen_uri(own_bi) < 0)
4757c1d255d3SCy Schubert 		goto fail;
4758c1d255d3SCy Schubert 
4759c1d255d3SCy Schubert 	return 0;
4760c1d255d3SCy Schubert fail:
4761c1d255d3SCy Schubert 	dl_list_del(&own_bi->list);
4762c1d255d3SCy Schubert 	dpp_bootstrap_info_free(own_bi);
4763c1d255d3SCy Schubert 	return -1;
4764c1d255d3SCy Schubert }
4765c1d255d3SCy Schubert 
4766c1d255d3SCy Schubert 
4767c1d255d3SCy Schubert int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4768c1d255d3SCy Schubert 		      struct dpp_bootstrap_info *peer_bi)
4769c1d255d3SCy Schubert {
4770c1d255d3SCy Schubert 	if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4771c1d255d3SCy Schubert 	    dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4772c1d255d3SCy Schubert 		return -1;
4773c1d255d3SCy Schubert 	return 0;
47744bc52338SCy Schubert }
47754bc52338SCy Schubert 
47764bc52338SCy Schubert 
47774bc52338SCy Schubert static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
47784bc52338SCy Schubert {
47794bc52338SCy Schubert 	struct dpp_configurator *conf;
47804bc52338SCy Schubert 	unsigned int max_id = 0;
47814bc52338SCy Schubert 
47824bc52338SCy Schubert 	dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
47834bc52338SCy Schubert 			 list) {
47844bc52338SCy Schubert 		if (conf->id > max_id)
47854bc52338SCy Schubert 			max_id = conf->id;
47864bc52338SCy Schubert 	}
47874bc52338SCy Schubert 	return max_id + 1;
47884bc52338SCy Schubert }
47894bc52338SCy Schubert 
47904bc52338SCy Schubert 
47914bc52338SCy Schubert int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
47924bc52338SCy Schubert {
4793*a90b9d01SCy Schubert 	char *curve;
4794c1d255d3SCy Schubert 	char *key = NULL, *ppkey = NULL;
4795c1d255d3SCy Schubert 	u8 *privkey = NULL, *pp_key = NULL;
4796c1d255d3SCy Schubert 	size_t privkey_len = 0, pp_key_len = 0;
47974bc52338SCy Schubert 	int ret = -1;
47984bc52338SCy Schubert 	struct dpp_configurator *conf = NULL;
4799*a90b9d01SCy Schubert 	const struct dpp_curve_params *net_access_key_curve = NULL;
4800*a90b9d01SCy Schubert 
4801*a90b9d01SCy Schubert 	curve = get_param(cmd, " net_access_key_curve=");
4802*a90b9d01SCy Schubert 	if (curve) {
4803*a90b9d01SCy Schubert 		net_access_key_curve = dpp_get_curve_name(curve);
4804*a90b9d01SCy Schubert 		if (!net_access_key_curve) {
4805*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
4806*a90b9d01SCy Schubert 				   "DPP: Unsupported net_access_key_curve: %s",
4807*a90b9d01SCy Schubert 				   curve);
4808*a90b9d01SCy Schubert 			goto fail;
4809*a90b9d01SCy Schubert 		}
4810*a90b9d01SCy Schubert 		os_free(curve);
4811*a90b9d01SCy Schubert 	}
48124bc52338SCy Schubert 
48134bc52338SCy Schubert 	curve = get_param(cmd, " curve=");
48144bc52338SCy Schubert 	key = get_param(cmd, " key=");
4815c1d255d3SCy Schubert 	ppkey = get_param(cmd, " ppkey=");
48164bc52338SCy Schubert 
48174bc52338SCy Schubert 	if (key) {
48184bc52338SCy Schubert 		privkey_len = os_strlen(key) / 2;
48194bc52338SCy Schubert 		privkey = os_malloc(privkey_len);
48204bc52338SCy Schubert 		if (!privkey ||
48214bc52338SCy Schubert 		    hexstr2bin(key, privkey, privkey_len) < 0)
48224bc52338SCy Schubert 			goto fail;
48234bc52338SCy Schubert 	}
48244bc52338SCy Schubert 
4825c1d255d3SCy Schubert 	if (ppkey) {
4826c1d255d3SCy Schubert 		pp_key_len = os_strlen(ppkey) / 2;
4827c1d255d3SCy Schubert 		pp_key = os_malloc(pp_key_len);
4828c1d255d3SCy Schubert 		if (!pp_key ||
4829c1d255d3SCy Schubert 		    hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4830c1d255d3SCy Schubert 			goto fail;
4831c1d255d3SCy Schubert 	}
4832c1d255d3SCy Schubert 
4833c1d255d3SCy Schubert 	conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4834c1d255d3SCy Schubert 				       pp_key, pp_key_len);
48354bc52338SCy Schubert 	if (!conf)
48364bc52338SCy Schubert 		goto fail;
48374bc52338SCy Schubert 
4838*a90b9d01SCy Schubert 	conf->net_access_key_curve = net_access_key_curve;
48394bc52338SCy Schubert 	conf->id = dpp_next_configurator_id(dpp);
48404bc52338SCy Schubert 	dl_list_add(&dpp->configurator, &conf->list);
48414bc52338SCy Schubert 	ret = conf->id;
48424bc52338SCy Schubert 	conf = NULL;
48434bc52338SCy Schubert fail:
48444bc52338SCy Schubert 	os_free(curve);
48454bc52338SCy Schubert 	str_clear_free(key);
4846c1d255d3SCy Schubert 	str_clear_free(ppkey);
48474bc52338SCy Schubert 	bin_clear_free(privkey, privkey_len);
4848c1d255d3SCy Schubert 	bin_clear_free(pp_key, pp_key_len);
48494bc52338SCy Schubert 	dpp_configurator_free(conf);
48504bc52338SCy Schubert 	return ret;
48514bc52338SCy Schubert }
48524bc52338SCy Schubert 
48534bc52338SCy Schubert 
4854*a90b9d01SCy Schubert int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4855*a90b9d01SCy Schubert {
4856*a90b9d01SCy Schubert 	unsigned int id;
4857*a90b9d01SCy Schubert 	struct dpp_configurator *conf;
4858*a90b9d01SCy Schubert 	char *curve;
4859*a90b9d01SCy Schubert 
4860*a90b9d01SCy Schubert 	id = atoi(cmd);
4861*a90b9d01SCy Schubert 	conf = dpp_configurator_get_id(dpp, id);
4862*a90b9d01SCy Schubert 	if (!conf)
4863*a90b9d01SCy Schubert 		return -1;
4864*a90b9d01SCy Schubert 
4865*a90b9d01SCy Schubert 	curve = get_param(cmd, " net_access_key_curve=");
4866*a90b9d01SCy Schubert 	if (curve) {
4867*a90b9d01SCy Schubert 		const struct dpp_curve_params *net_access_key_curve;
4868*a90b9d01SCy Schubert 
4869*a90b9d01SCy Schubert 		net_access_key_curve = dpp_get_curve_name(curve);
4870*a90b9d01SCy Schubert 		os_free(curve);
4871*a90b9d01SCy Schubert 		if (!net_access_key_curve)
4872*a90b9d01SCy Schubert 			return -1;
4873*a90b9d01SCy Schubert 		conf->net_access_key_curve = net_access_key_curve;
4874*a90b9d01SCy Schubert 	}
4875*a90b9d01SCy Schubert 
4876*a90b9d01SCy Schubert 	return 0;
4877*a90b9d01SCy Schubert }
4878*a90b9d01SCy Schubert 
4879*a90b9d01SCy Schubert 
48804bc52338SCy Schubert static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
48814bc52338SCy Schubert {
48824bc52338SCy Schubert 	struct dpp_configurator *conf, *tmp;
48834bc52338SCy Schubert 	int found = 0;
48844bc52338SCy Schubert 
48854bc52338SCy Schubert 	if (!dpp)
48864bc52338SCy Schubert 		return -1;
48874bc52338SCy Schubert 
48884bc52338SCy Schubert 	dl_list_for_each_safe(conf, tmp, &dpp->configurator,
48894bc52338SCy Schubert 			      struct dpp_configurator, list) {
48904bc52338SCy Schubert 		if (id && conf->id != id)
48914bc52338SCy Schubert 			continue;
48924bc52338SCy Schubert 		found = 1;
48934bc52338SCy Schubert 		dl_list_del(&conf->list);
48944bc52338SCy Schubert 		dpp_configurator_free(conf);
48954bc52338SCy Schubert 	}
48964bc52338SCy Schubert 
48974bc52338SCy Schubert 	if (id == 0)
48984bc52338SCy Schubert 		return 0; /* flush succeeds regardless of entries found */
48994bc52338SCy Schubert 	return found ? 0 : -1;
49004bc52338SCy Schubert }
49014bc52338SCy Schubert 
49024bc52338SCy Schubert 
49034bc52338SCy Schubert int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
49044bc52338SCy Schubert {
49054bc52338SCy Schubert 	unsigned int id_val;
49064bc52338SCy Schubert 
49074bc52338SCy Schubert 	if (os_strcmp(id, "*") == 0) {
49084bc52338SCy Schubert 		id_val = 0;
49094bc52338SCy Schubert 	} else {
49104bc52338SCy Schubert 		id_val = atoi(id);
49114bc52338SCy Schubert 		if (id_val == 0)
49124bc52338SCy Schubert 			return -1;
49134bc52338SCy Schubert 	}
49144bc52338SCy Schubert 
49154bc52338SCy Schubert 	return dpp_configurator_del(dpp, id_val);
49164bc52338SCy Schubert }
49174bc52338SCy Schubert 
49184bc52338SCy Schubert 
49194bc52338SCy Schubert int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
49204bc52338SCy Schubert 				char *buf, size_t buflen)
49214bc52338SCy Schubert {
49224bc52338SCy Schubert 	struct dpp_configurator *conf;
49234bc52338SCy Schubert 
49244bc52338SCy Schubert 	conf = dpp_configurator_get_id(dpp, id);
49254bc52338SCy Schubert 	if (!conf)
49264bc52338SCy Schubert 		return -1;
49274bc52338SCy Schubert 
49284bc52338SCy Schubert 	return dpp_configurator_get_key(conf, buf, buflen);
49294bc52338SCy Schubert }
49304bc52338SCy Schubert 
49314bc52338SCy Schubert 
4932206b73d0SCy Schubert #ifdef CONFIG_DPP2
4933206b73d0SCy Schubert 
4934c1d255d3SCy Schubert int dpp_configurator_from_backup(struct dpp_global *dpp,
4935c1d255d3SCy Schubert 				 struct dpp_asymmetric_key *key)
4936206b73d0SCy Schubert {
4937c1d255d3SCy Schubert 	struct dpp_configurator *conf;
49384b72b91aSCy Schubert 	const struct dpp_curve_params *curve, *curve_pp;
4939c1d255d3SCy Schubert 
4940c1d255d3SCy Schubert 	if (!key->csign || !key->pp_key)
4941c1d255d3SCy Schubert 		return -1;
49424b72b91aSCy Schubert 
49434b72b91aSCy Schubert 	curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
4944c1d255d3SCy Schubert 	if (!curve) {
4945c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4946c1d255d3SCy Schubert 		return -1;
4947206b73d0SCy Schubert 	}
49484b72b91aSCy Schubert 
49494b72b91aSCy Schubert 	curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
49504b72b91aSCy Schubert 	if (!curve_pp) {
49514b72b91aSCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
4952c1d255d3SCy Schubert 		return -1;
49534b72b91aSCy Schubert 	}
49544b72b91aSCy Schubert 
49554b72b91aSCy Schubert 	if (curve != curve_pp) {
4956c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
4957c1d255d3SCy Schubert 			   "DPP: Mismatch in c-sign-key and ppKey groups");
4958c1d255d3SCy Schubert 		return -1;
4959c1d255d3SCy Schubert 	}
4960c1d255d3SCy Schubert 
4961c1d255d3SCy Schubert 	conf = os_zalloc(sizeof(*conf));
4962c1d255d3SCy Schubert 	if (!conf)
4963c1d255d3SCy Schubert 		return -1;
4964c1d255d3SCy Schubert 	conf->curve = curve;
4965c1d255d3SCy Schubert 	conf->csign = key->csign;
4966c1d255d3SCy Schubert 	key->csign = NULL;
4967c1d255d3SCy Schubert 	conf->pp_key = key->pp_key;
4968c1d255d3SCy Schubert 	key->pp_key = NULL;
4969c1d255d3SCy Schubert 	conf->own = 1;
4970c1d255d3SCy Schubert 	if (dpp_configurator_gen_kid(conf) < 0) {
4971c1d255d3SCy Schubert 		dpp_configurator_free(conf);
4972c1d255d3SCy Schubert 		return -1;
4973c1d255d3SCy Schubert 	}
4974c1d255d3SCy Schubert 
4975c1d255d3SCy Schubert 	conf->id = dpp_next_configurator_id(dpp);
4976c1d255d3SCy Schubert 	dl_list_add(&dpp->configurator, &conf->list);
4977c1d255d3SCy Schubert 	return conf->id;
4978206b73d0SCy Schubert }
4979206b73d0SCy Schubert 
4980206b73d0SCy Schubert 
4981c1d255d3SCy Schubert struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4982c1d255d3SCy Schubert 						    const u8 *kid)
4983206b73d0SCy Schubert {
4984c1d255d3SCy Schubert 	struct dpp_configurator *conf;
4985206b73d0SCy Schubert 
4986206b73d0SCy Schubert 	if (!dpp)
4987c1d255d3SCy Schubert 		return NULL;
4988206b73d0SCy Schubert 
4989c1d255d3SCy Schubert 	dl_list_for_each(conf, &dpp->configurator,
4990c1d255d3SCy Schubert 			 struct dpp_configurator, list) {
4991c1d255d3SCy Schubert 		if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4992c1d255d3SCy Schubert 			return conf;
4993206b73d0SCy Schubert 	}
4994c1d255d3SCy Schubert 	return NULL;
4995206b73d0SCy Schubert }
4996206b73d0SCy Schubert 
4997206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
4998206b73d0SCy Schubert 
4999206b73d0SCy Schubert 
5000206b73d0SCy Schubert struct dpp_global * dpp_global_init(struct dpp_global_config *config)
50014bc52338SCy Schubert {
50024bc52338SCy Schubert 	struct dpp_global *dpp;
50034bc52338SCy Schubert 
50044bc52338SCy Schubert 	dpp = os_zalloc(sizeof(*dpp));
50054bc52338SCy Schubert 	if (!dpp)
50064bc52338SCy Schubert 		return NULL;
5007206b73d0SCy Schubert #ifdef CONFIG_DPP2
5008206b73d0SCy Schubert 	dpp->cb_ctx = config->cb_ctx;
5009c1d255d3SCy Schubert 	dpp->remove_bi = config->remove_bi;
5010206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
50114bc52338SCy Schubert 
50124bc52338SCy Schubert 	dl_list_init(&dpp->bootstrap);
50134bc52338SCy Schubert 	dl_list_init(&dpp->configurator);
5014206b73d0SCy Schubert #ifdef CONFIG_DPP2
5015206b73d0SCy Schubert 	dl_list_init(&dpp->controllers);
5016206b73d0SCy Schubert 	dl_list_init(&dpp->tcp_init);
5017*a90b9d01SCy Schubert 	dpp->relay_sock = -1;
5018206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
50194bc52338SCy Schubert 
50204bc52338SCy Schubert 	return dpp;
50214bc52338SCy Schubert }
50224bc52338SCy Schubert 
50234bc52338SCy Schubert 
50244bc52338SCy Schubert void dpp_global_clear(struct dpp_global *dpp)
50254bc52338SCy Schubert {
50264bc52338SCy Schubert 	if (!dpp)
50274bc52338SCy Schubert 		return;
50284bc52338SCy Schubert 
50294bc52338SCy Schubert 	dpp_bootstrap_del(dpp, 0);
50304bc52338SCy Schubert 	dpp_configurator_del(dpp, 0);
5031206b73d0SCy Schubert #ifdef CONFIG_DPP2
5032206b73d0SCy Schubert 	dpp_tcp_init_flush(dpp);
5033206b73d0SCy Schubert 	dpp_relay_flush_controllers(dpp);
5034206b73d0SCy Schubert 	dpp_controller_stop(dpp);
5035206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
50364bc52338SCy Schubert }
50374bc52338SCy Schubert 
50384bc52338SCy Schubert 
50394bc52338SCy Schubert void dpp_global_deinit(struct dpp_global *dpp)
50404bc52338SCy Schubert {
50414bc52338SCy Schubert 	dpp_global_clear(dpp);
50424bc52338SCy Schubert 	os_free(dpp);
50434bc52338SCy Schubert }
5044206b73d0SCy Schubert 
5045206b73d0SCy Schubert 
5046*a90b9d01SCy Schubert void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
5047*a90b9d01SCy Schubert {
5048*a90b9d01SCy Schubert 	u8 hash[SHA256_MAC_LEN];
5049*a90b9d01SCy Schubert 	char hex[SHA256_MAC_LEN * 2 + 1];
5050*a90b9d01SCy Schubert 
5051*a90b9d01SCy Schubert 	if (auth->peer_protocol_key) {
5052*a90b9d01SCy Schubert 		dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
5053*a90b9d01SCy Schubert 		wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
5054*a90b9d01SCy Schubert 	} else {
5055*a90b9d01SCy Schubert 		hex[0] = '\0';
5056*a90b9d01SCy Schubert 	}
5057*a90b9d01SCy Schubert 	wpa_msg(auth->msg_ctx, MSG_INFO,
5058*a90b9d01SCy Schubert 		DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d",
5059*a90b9d01SCy Schubert 		initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1,
5060*a90b9d01SCy Schubert 		auth->peer_bi ? (int) auth->peer_bi->id : -1);
5061*a90b9d01SCy Schubert }
5062*a90b9d01SCy Schubert 
5063*a90b9d01SCy Schubert 
5064206b73d0SCy Schubert #ifdef CONFIG_DPP2
5065206b73d0SCy Schubert 
5066c1d255d3SCy Schubert struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5067206b73d0SCy Schubert {
5068206b73d0SCy Schubert 	struct wpabuf *msg;
5069206b73d0SCy Schubert 
5070c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5071c1d255d3SCy Schubert 
5072c1d255d3SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5073206b73d0SCy Schubert 	if (!msg)
5074206b73d0SCy Schubert 		return NULL;
5075c1d255d3SCy Schubert 
5076c1d255d3SCy Schubert 	/* Responder Bootstrapping Key Hash */
5077c1d255d3SCy Schubert 	dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5078c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG,
5079c1d255d3SCy Schubert 			"DPP: Presence Announcement frame attributes", msg);
5080206b73d0SCy Schubert 	return msg;
5081206b73d0SCy Schubert }
5082206b73d0SCy Schubert 
5083206b73d0SCy Schubert 
5084c1d255d3SCy Schubert void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5085c1d255d3SCy Schubert 				unsigned int freq, const u8 *hash)
5086206b73d0SCy Schubert {
5087c1d255d3SCy Schubert 	char hex[SHA256_MAC_LEN * 2 + 1];
5088206b73d0SCy Schubert 
5089c1d255d3SCy Schubert 	wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5090c1d255d3SCy Schubert 	wpa_msg(msg_ctx, MSG_INFO,
5091c1d255d3SCy Schubert 		DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5092c1d255d3SCy Schubert 		id, MAC2STR(src), freq, hex);
5093206b73d0SCy Schubert }
5094206b73d0SCy Schubert 
5095206b73d0SCy Schubert #endif /* CONFIG_DPP2 */
5096*a90b9d01SCy Schubert 
5097*a90b9d01SCy Schubert 
5098*a90b9d01SCy Schubert #ifdef CONFIG_DPP3
5099*a90b9d01SCy Schubert 
5100*a90b9d01SCy Schubert struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5101*a90b9d01SCy Schubert {
5102*a90b9d01SCy Schubert 	struct wpabuf *msg;
5103*a90b9d01SCy Schubert 	const u8 *r_hash = bi->pubkey_hash_chirp;
5104*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
5105*a90b9d01SCy Schubert 	u8 test_hash[SHA256_MAC_LEN];
5106*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
5107*a90b9d01SCy Schubert 
5108*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG,
5109*a90b9d01SCy Schubert 		   "DPP: Build Push Button Presence Announcement frame");
5110*a90b9d01SCy Schubert 
5111*a90b9d01SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5112*a90b9d01SCy Schubert 			    4 + SHA256_MAC_LEN);
5113*a90b9d01SCy Schubert 	if (!msg)
5114*a90b9d01SCy Schubert 		return NULL;
5115*a90b9d01SCy Schubert 
5116*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
5117*a90b9d01SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5118*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
5119*a90b9d01SCy Schubert 			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
5120*a90b9d01SCy Schubert 		os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5121*a90b9d01SCy Schubert 		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5122*a90b9d01SCy Schubert 		r_hash = test_hash;
5123*a90b9d01SCy Schubert 	}
5124*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
5125*a90b9d01SCy Schubert 
5126*a90b9d01SCy Schubert 	/* Responder Bootstrapping Key Hash */
5127*a90b9d01SCy Schubert 	dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5128*a90b9d01SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG,
5129*a90b9d01SCy Schubert 			"DPP: Push Button Presence Announcement frame attributes",
5130*a90b9d01SCy Schubert 			msg);
5131*a90b9d01SCy Schubert 	return msg;
5132*a90b9d01SCy Schubert }
5133*a90b9d01SCy Schubert 
5134*a90b9d01SCy Schubert 
5135*a90b9d01SCy Schubert struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5136*a90b9d01SCy Schubert 					       const u8 *e_hash,
5137*a90b9d01SCy Schubert 					       const u8 *c_nonce,
5138*a90b9d01SCy Schubert 					       size_t c_nonce_len)
5139*a90b9d01SCy Schubert {
5140*a90b9d01SCy Schubert 	struct wpabuf *msg;
5141*a90b9d01SCy Schubert 	const u8 *i_hash = bi->pubkey_hash_chirp;
5142*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
5143*a90b9d01SCy Schubert 	u8 test_hash[SHA256_MAC_LEN];
5144*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
5145*a90b9d01SCy Schubert 
5146*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG,
5147*a90b9d01SCy Schubert 		   "DPP: Build Push Button Presence Announcement Response frame");
5148*a90b9d01SCy Schubert 
5149*a90b9d01SCy Schubert 	msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5150*a90b9d01SCy Schubert 			    2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5151*a90b9d01SCy Schubert 	if (!msg)
5152*a90b9d01SCy Schubert 		return NULL;
5153*a90b9d01SCy Schubert 
5154*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
5155*a90b9d01SCy Schubert 	if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5156*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
5157*a90b9d01SCy Schubert 			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
5158*a90b9d01SCy Schubert 		os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5159*a90b9d01SCy Schubert 		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5160*a90b9d01SCy Schubert 		i_hash = test_hash;
5161*a90b9d01SCy Schubert 	} else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5162*a90b9d01SCy Schubert 		wpa_printf(MSG_INFO,
5163*a90b9d01SCy Schubert 			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
5164*a90b9d01SCy Schubert 		os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5165*a90b9d01SCy Schubert 		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5166*a90b9d01SCy Schubert 		e_hash = test_hash;
5167*a90b9d01SCy Schubert 	}
5168*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
5169*a90b9d01SCy Schubert 
5170*a90b9d01SCy Schubert 	/* Initiator Bootstrapping Key Hash */
5171*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5172*a90b9d01SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5173*a90b9d01SCy Schubert 	wpabuf_put_le16(msg, SHA256_MAC_LEN);
5174*a90b9d01SCy Schubert 	wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5175*a90b9d01SCy Schubert 
5176*a90b9d01SCy Schubert 	/* Responder Bootstrapping Key Hash */
5177*a90b9d01SCy Schubert 	dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5178*a90b9d01SCy Schubert 
5179*a90b9d01SCy Schubert 	/* Configurator Nonce */
5180*a90b9d01SCy Schubert 	wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5181*a90b9d01SCy Schubert 	wpabuf_put_le16(msg, c_nonce_len);
5182*a90b9d01SCy Schubert 	wpabuf_put_data(msg, c_nonce, c_nonce_len);
5183*a90b9d01SCy Schubert 
5184*a90b9d01SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG,
5185*a90b9d01SCy Schubert 			"DPP: Push Button Presence Announcement Response frame attributes",
5186*a90b9d01SCy Schubert 			msg);
5187*a90b9d01SCy Schubert 	return msg;
5188*a90b9d01SCy Schubert }
5189*a90b9d01SCy Schubert 
5190*a90b9d01SCy Schubert #endif /* CONFIG_DPP3 */
5191