1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * DPP functionality shared between hostapd and wpa_supplicant
3e5b75505Sopenharmony_ci * Copyright (c) 2017, Qualcomm Atheros, Inc.
4e5b75505Sopenharmony_ci * Copyright (c) 2018-2019, The Linux Foundation
5e5b75505Sopenharmony_ci *
6e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
7e5b75505Sopenharmony_ci * See README for more details.
8e5b75505Sopenharmony_ci */
9e5b75505Sopenharmony_ci
10e5b75505Sopenharmony_ci#include "utils/includes.h"
11e5b75505Sopenharmony_ci#include <fcntl.h>
12e5b75505Sopenharmony_ci#include <openssl/opensslv.h>
13e5b75505Sopenharmony_ci#include <openssl/err.h>
14e5b75505Sopenharmony_ci#include <openssl/asn1.h>
15e5b75505Sopenharmony_ci#include <openssl/asn1t.h>
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci#include "utils/common.h"
18e5b75505Sopenharmony_ci#include "utils/base64.h"
19e5b75505Sopenharmony_ci#include "utils/json.h"
20e5b75505Sopenharmony_ci#include "utils/ip_addr.h"
21e5b75505Sopenharmony_ci#include "utils/eloop.h"
22e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h"
23e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
24e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h"
25e5b75505Sopenharmony_ci#include "common/gas.h"
26e5b75505Sopenharmony_ci#include "crypto/crypto.h"
27e5b75505Sopenharmony_ci#include "crypto/random.h"
28e5b75505Sopenharmony_ci#include "crypto/aes.h"
29e5b75505Sopenharmony_ci#include "crypto/aes_siv.h"
30e5b75505Sopenharmony_ci#include "crypto/sha384.h"
31e5b75505Sopenharmony_ci#include "crypto/sha512.h"
32e5b75505Sopenharmony_ci#include "drivers/driver.h"
33e5b75505Sopenharmony_ci#include "dpp.h"
34e5b75505Sopenharmony_ci
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
37e5b75505Sopenharmony_cienum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
38e5b75505Sopenharmony_ciu8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
39e5b75505Sopenharmony_ciu8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
40e5b75505Sopenharmony_ciu8 dpp_pkex_ephemeral_key_override[600];
41e5b75505Sopenharmony_cisize_t dpp_pkex_ephemeral_key_override_len = 0;
42e5b75505Sopenharmony_ciu8 dpp_protocol_key_override[600];
43e5b75505Sopenharmony_cisize_t dpp_protocol_key_override_len = 0;
44e5b75505Sopenharmony_ciu8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
45e5b75505Sopenharmony_cisize_t dpp_nonce_override_len = 0;
46e5b75505Sopenharmony_ci
47e5b75505Sopenharmony_cistatic int dpp_test_gen_invalid_key(struct wpabuf *msg,
48e5b75505Sopenharmony_ci				    const struct dpp_curve_params *curve);
49e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
50e5b75505Sopenharmony_ci
51e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
52e5b75505Sopenharmony_ci	(defined(LIBRESSL_VERSION_NUMBER) && \
53e5b75505Sopenharmony_ci	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
54e5b75505Sopenharmony_ci/* Compatibility wrappers for older versions. */
55e5b75505Sopenharmony_ci
56e5b75505Sopenharmony_cistatic int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
57e5b75505Sopenharmony_ci{
58e5b75505Sopenharmony_ci	sig->r = r;
59e5b75505Sopenharmony_ci	sig->s = s;
60e5b75505Sopenharmony_ci	return 1;
61e5b75505Sopenharmony_ci}
62e5b75505Sopenharmony_ci
63e5b75505Sopenharmony_ci
64e5b75505Sopenharmony_cistatic void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
65e5b75505Sopenharmony_ci			   const BIGNUM **ps)
66e5b75505Sopenharmony_ci{
67e5b75505Sopenharmony_ci	if (pr)
68e5b75505Sopenharmony_ci		*pr = sig->r;
69e5b75505Sopenharmony_ci	if (ps)
70e5b75505Sopenharmony_ci		*ps = sig->s;
71e5b75505Sopenharmony_ci}
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ci#endif
74e5b75505Sopenharmony_ci
75e5b75505Sopenharmony_ci
76e5b75505Sopenharmony_cistruct dpp_connection {
77e5b75505Sopenharmony_ci	struct dl_list list;
78e5b75505Sopenharmony_ci	struct dpp_controller *ctrl;
79e5b75505Sopenharmony_ci	struct dpp_relay_controller *relay;
80e5b75505Sopenharmony_ci	struct dpp_global *global;
81e5b75505Sopenharmony_ci	struct dpp_authentication *auth;
82e5b75505Sopenharmony_ci	int sock;
83e5b75505Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
84e5b75505Sopenharmony_ci	unsigned int freq;
85e5b75505Sopenharmony_ci	u8 msg_len[4];
86e5b75505Sopenharmony_ci	size_t msg_len_octets;
87e5b75505Sopenharmony_ci	struct wpabuf *msg;
88e5b75505Sopenharmony_ci	struct wpabuf *msg_out;
89e5b75505Sopenharmony_ci	size_t msg_out_pos;
90e5b75505Sopenharmony_ci	unsigned int read_eloop:1;
91e5b75505Sopenharmony_ci	unsigned int write_eloop:1;
92e5b75505Sopenharmony_ci	unsigned int on_tcp_tx_complete_gas_done:1;
93e5b75505Sopenharmony_ci	unsigned int on_tcp_tx_complete_remove:1;
94e5b75505Sopenharmony_ci	unsigned int on_tcp_tx_complete_auth_ok:1;
95e5b75505Sopenharmony_ci};
96e5b75505Sopenharmony_ci
97e5b75505Sopenharmony_ci/* Remote Controller */
98e5b75505Sopenharmony_cistruct dpp_relay_controller {
99e5b75505Sopenharmony_ci	struct dl_list list;
100e5b75505Sopenharmony_ci	struct dpp_global *global;
101e5b75505Sopenharmony_ci	u8 pkhash[SHA256_MAC_LEN];
102e5b75505Sopenharmony_ci	struct hostapd_ip_addr ipaddr;
103e5b75505Sopenharmony_ci	void *cb_ctx;
104e5b75505Sopenharmony_ci	void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
105e5b75505Sopenharmony_ci		   size_t len);
106e5b75505Sopenharmony_ci	void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
107e5b75505Sopenharmony_ci			    int prot, struct wpabuf *buf);
108e5b75505Sopenharmony_ci	struct dl_list conn; /* struct dpp_connection */
109e5b75505Sopenharmony_ci};
110e5b75505Sopenharmony_ci
111e5b75505Sopenharmony_ci/* Local Controller */
112e5b75505Sopenharmony_cistruct dpp_controller {
113e5b75505Sopenharmony_ci	struct dpp_global *global;
114e5b75505Sopenharmony_ci	u8 allowed_roles;
115e5b75505Sopenharmony_ci	int qr_mutual;
116e5b75505Sopenharmony_ci	int sock;
117e5b75505Sopenharmony_ci	struct dl_list conn; /* struct dpp_connection */
118e5b75505Sopenharmony_ci	char *configurator_params;
119e5b75505Sopenharmony_ci};
120e5b75505Sopenharmony_ci
121e5b75505Sopenharmony_cistruct dpp_global {
122e5b75505Sopenharmony_ci	void *msg_ctx;
123e5b75505Sopenharmony_ci	struct dl_list bootstrap; /* struct dpp_bootstrap_info */
124e5b75505Sopenharmony_ci	struct dl_list configurator; /* struct dpp_configurator */
125e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
126e5b75505Sopenharmony_ci	struct dl_list controllers; /* struct dpp_relay_controller */
127e5b75505Sopenharmony_ci	struct dpp_controller *controller;
128e5b75505Sopenharmony_ci	struct dl_list tcp_init; /* struct dpp_connection */
129e5b75505Sopenharmony_ci	void *cb_ctx;
130e5b75505Sopenharmony_ci	int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
131e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
132e5b75505Sopenharmony_ci};
133e5b75505Sopenharmony_ci
134e5b75505Sopenharmony_cistatic const struct dpp_curve_params dpp_curves[] = {
135e5b75505Sopenharmony_ci	/* The mandatory to support and the default NIST P-256 curve needs to
136e5b75505Sopenharmony_ci	 * be the first entry on this list. */
137e5b75505Sopenharmony_ci	{ "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
138e5b75505Sopenharmony_ci	{ "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
139e5b75505Sopenharmony_ci	{ "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
140e5b75505Sopenharmony_ci	{ "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
141e5b75505Sopenharmony_ci	{ "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
142e5b75505Sopenharmony_ci	{ "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
143e5b75505Sopenharmony_ci	{ NULL, 0, 0, 0, 0, NULL, 0, NULL }
144e5b75505Sopenharmony_ci};
145e5b75505Sopenharmony_ci
146e5b75505Sopenharmony_ci
147e5b75505Sopenharmony_ci/* Role-specific elements for PKEX */
148e5b75505Sopenharmony_ci
149e5b75505Sopenharmony_ci/* NIST P-256 */
150e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p256[32] = {
151e5b75505Sopenharmony_ci	0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
152e5b75505Sopenharmony_ci	0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
153e5b75505Sopenharmony_ci	0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
154e5b75505Sopenharmony_ci	0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
155e5b75505Sopenharmony_ci };
156e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p256[32] = {
157e5b75505Sopenharmony_ci	0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
158e5b75505Sopenharmony_ci	0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
159e5b75505Sopenharmony_ci	0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
160e5b75505Sopenharmony_ci	0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
161e5b75505Sopenharmony_ci };
162e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p256[32] = {
163e5b75505Sopenharmony_ci	0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
164e5b75505Sopenharmony_ci	0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
165e5b75505Sopenharmony_ci	0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
166e5b75505Sopenharmony_ci	0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
167e5b75505Sopenharmony_ci};
168e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p256[32] = {
169e5b75505Sopenharmony_ci	0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
170e5b75505Sopenharmony_ci	0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
171e5b75505Sopenharmony_ci	0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
172e5b75505Sopenharmony_ci	0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
173e5b75505Sopenharmony_ci};
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_ci/* NIST P-384 */
176e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p384[48] = {
177e5b75505Sopenharmony_ci	0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
178e5b75505Sopenharmony_ci	0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
179e5b75505Sopenharmony_ci	0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
180e5b75505Sopenharmony_ci	0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
181e5b75505Sopenharmony_ci	0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
182e5b75505Sopenharmony_ci	0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
183e5b75505Sopenharmony_ci};
184e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p384[48] = {
185e5b75505Sopenharmony_ci	0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
186e5b75505Sopenharmony_ci	0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
187e5b75505Sopenharmony_ci	0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
188e5b75505Sopenharmony_ci	0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
189e5b75505Sopenharmony_ci	0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
190e5b75505Sopenharmony_ci	0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
191e5b75505Sopenharmony_ci};
192e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p384[48] = {
193e5b75505Sopenharmony_ci	0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
194e5b75505Sopenharmony_ci	0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
195e5b75505Sopenharmony_ci	0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
196e5b75505Sopenharmony_ci	0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
197e5b75505Sopenharmony_ci	0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
198e5b75505Sopenharmony_ci	0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
199e5b75505Sopenharmony_ci};
200e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p384[48] = {
201e5b75505Sopenharmony_ci	0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
202e5b75505Sopenharmony_ci	0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
203e5b75505Sopenharmony_ci	0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
204e5b75505Sopenharmony_ci	0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
205e5b75505Sopenharmony_ci	0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
206e5b75505Sopenharmony_ci	0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
207e5b75505Sopenharmony_ci};
208e5b75505Sopenharmony_ci
209e5b75505Sopenharmony_ci/* NIST P-521 */
210e5b75505Sopenharmony_cistatic const u8 pkex_init_x_p521[66] = {
211e5b75505Sopenharmony_ci	0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
212e5b75505Sopenharmony_ci	0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
213e5b75505Sopenharmony_ci	0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
214e5b75505Sopenharmony_ci	0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
215e5b75505Sopenharmony_ci	0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
216e5b75505Sopenharmony_ci	0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
217e5b75505Sopenharmony_ci	0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
218e5b75505Sopenharmony_ci	0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
219e5b75505Sopenharmony_ci	0x97, 0x76
220e5b75505Sopenharmony_ci};
221e5b75505Sopenharmony_cistatic const u8 pkex_init_y_p521[66] = {
222e5b75505Sopenharmony_ci	0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
223e5b75505Sopenharmony_ci	0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
224e5b75505Sopenharmony_ci	0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
225e5b75505Sopenharmony_ci	0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
226e5b75505Sopenharmony_ci	0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
227e5b75505Sopenharmony_ci	0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
228e5b75505Sopenharmony_ci	0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
229e5b75505Sopenharmony_ci	0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
230e5b75505Sopenharmony_ci	0x03, 0xa8
231e5b75505Sopenharmony_ci};
232e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_p521[66] = {
233e5b75505Sopenharmony_ci	0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
234e5b75505Sopenharmony_ci	0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
235e5b75505Sopenharmony_ci	0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
236e5b75505Sopenharmony_ci	0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
237e5b75505Sopenharmony_ci	0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
238e5b75505Sopenharmony_ci	0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
239e5b75505Sopenharmony_ci	0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
240e5b75505Sopenharmony_ci	0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
241e5b75505Sopenharmony_ci	0x84, 0xb4
242e5b75505Sopenharmony_ci};
243e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_p521[66] = {
244e5b75505Sopenharmony_ci	0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
245e5b75505Sopenharmony_ci	0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
246e5b75505Sopenharmony_ci	0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
247e5b75505Sopenharmony_ci	0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
248e5b75505Sopenharmony_ci	0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
249e5b75505Sopenharmony_ci	0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
250e5b75505Sopenharmony_ci	0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
251e5b75505Sopenharmony_ci	0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
252e5b75505Sopenharmony_ci	0xce, 0xe1
253e5b75505Sopenharmony_ci};
254e5b75505Sopenharmony_ci
255e5b75505Sopenharmony_ci/* Brainpool P-256r1 */
256e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p256r1[32] = {
257e5b75505Sopenharmony_ci	0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
258e5b75505Sopenharmony_ci	0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
259e5b75505Sopenharmony_ci	0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
260e5b75505Sopenharmony_ci	0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
261e5b75505Sopenharmony_ci};
262e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p256r1[32] = {
263e5b75505Sopenharmony_ci	0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
264e5b75505Sopenharmony_ci	0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
265e5b75505Sopenharmony_ci	0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
266e5b75505Sopenharmony_ci	0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
267e5b75505Sopenharmony_ci};
268e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p256r1[32] = {
269e5b75505Sopenharmony_ci	0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
270e5b75505Sopenharmony_ci	0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
271e5b75505Sopenharmony_ci	0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
272e5b75505Sopenharmony_ci	0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
273e5b75505Sopenharmony_ci};
274e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p256r1[32] = {
275e5b75505Sopenharmony_ci	0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
276e5b75505Sopenharmony_ci	0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
277e5b75505Sopenharmony_ci	0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
278e5b75505Sopenharmony_ci	0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
279e5b75505Sopenharmony_ci};
280e5b75505Sopenharmony_ci
281e5b75505Sopenharmony_ci/* Brainpool P-384r1 */
282e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p384r1[48] = {
283e5b75505Sopenharmony_ci	0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
284e5b75505Sopenharmony_ci	0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
285e5b75505Sopenharmony_ci	0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
286e5b75505Sopenharmony_ci	0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
287e5b75505Sopenharmony_ci	0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
288e5b75505Sopenharmony_ci	0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
289e5b75505Sopenharmony_ci};
290e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p384r1[48] = {
291e5b75505Sopenharmony_ci	0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
292e5b75505Sopenharmony_ci	0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
293e5b75505Sopenharmony_ci	0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
294e5b75505Sopenharmony_ci	0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
295e5b75505Sopenharmony_ci	0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
296e5b75505Sopenharmony_ci	0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
297e5b75505Sopenharmony_ci};
298e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p384r1[48] = {
299e5b75505Sopenharmony_ci	0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
300e5b75505Sopenharmony_ci	0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
301e5b75505Sopenharmony_ci	0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
302e5b75505Sopenharmony_ci	0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
303e5b75505Sopenharmony_ci	0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
304e5b75505Sopenharmony_ci	0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
305e5b75505Sopenharmony_ci};
306e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p384r1[48] = {
307e5b75505Sopenharmony_ci	0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
308e5b75505Sopenharmony_ci	0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
309e5b75505Sopenharmony_ci	0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
310e5b75505Sopenharmony_ci	0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
311e5b75505Sopenharmony_ci	0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
312e5b75505Sopenharmony_ci	0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
313e5b75505Sopenharmony_ci};
314e5b75505Sopenharmony_ci
315e5b75505Sopenharmony_ci/* Brainpool P-512r1 */
316e5b75505Sopenharmony_cistatic const u8 pkex_init_x_bp_p512r1[64] = {
317e5b75505Sopenharmony_ci	0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
318e5b75505Sopenharmony_ci	0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
319e5b75505Sopenharmony_ci	0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
320e5b75505Sopenharmony_ci	0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
321e5b75505Sopenharmony_ci	0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
322e5b75505Sopenharmony_ci	0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
323e5b75505Sopenharmony_ci	0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
324e5b75505Sopenharmony_ci	0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
325e5b75505Sopenharmony_ci};
326e5b75505Sopenharmony_cistatic const u8 pkex_init_y_bp_p512r1[64] = {
327e5b75505Sopenharmony_ci	0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
328e5b75505Sopenharmony_ci	0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
329e5b75505Sopenharmony_ci	0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
330e5b75505Sopenharmony_ci	0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
331e5b75505Sopenharmony_ci	0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
332e5b75505Sopenharmony_ci	0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
333e5b75505Sopenharmony_ci	0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
334e5b75505Sopenharmony_ci	0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
335e5b75505Sopenharmony_ci};
336e5b75505Sopenharmony_cistatic const u8 pkex_resp_x_bp_p512r1[64] = {
337e5b75505Sopenharmony_ci	0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
338e5b75505Sopenharmony_ci	0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
339e5b75505Sopenharmony_ci	0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
340e5b75505Sopenharmony_ci	0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
341e5b75505Sopenharmony_ci	0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
342e5b75505Sopenharmony_ci	0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
343e5b75505Sopenharmony_ci	0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
344e5b75505Sopenharmony_ci	0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
345e5b75505Sopenharmony_ci};
346e5b75505Sopenharmony_cistatic const u8 pkex_resp_y_bp_p512r1[64] = {
347e5b75505Sopenharmony_ci	0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
348e5b75505Sopenharmony_ci	0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
349e5b75505Sopenharmony_ci	0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
350e5b75505Sopenharmony_ci	0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
351e5b75505Sopenharmony_ci	0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
352e5b75505Sopenharmony_ci	0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
353e5b75505Sopenharmony_ci	0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
354e5b75505Sopenharmony_ci	0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
355e5b75505Sopenharmony_ci};
356e5b75505Sopenharmony_ci
357e5b75505Sopenharmony_ci
358e5b75505Sopenharmony_cistatic void dpp_debug_print_point(const char *title, const EC_GROUP *group,
359e5b75505Sopenharmony_ci				  const EC_POINT *point)
360e5b75505Sopenharmony_ci{
361e5b75505Sopenharmony_ci	BIGNUM *x, *y;
362e5b75505Sopenharmony_ci	BN_CTX *ctx;
363e5b75505Sopenharmony_ci	char *x_str = NULL, *y_str = NULL;
364e5b75505Sopenharmony_ci
365e5b75505Sopenharmony_ci	if (!wpa_debug_show_keys)
366e5b75505Sopenharmony_ci		return;
367e5b75505Sopenharmony_ci
368e5b75505Sopenharmony_ci	ctx = BN_CTX_new();
369e5b75505Sopenharmony_ci	x = BN_new();
370e5b75505Sopenharmony_ci	y = BN_new();
371e5b75505Sopenharmony_ci	if (!ctx || !x || !y ||
372e5b75505Sopenharmony_ci	    EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
373e5b75505Sopenharmony_ci		goto fail;
374e5b75505Sopenharmony_ci
375e5b75505Sopenharmony_ci	x_str = BN_bn2hex(x);
376e5b75505Sopenharmony_ci	y_str = BN_bn2hex(y);
377e5b75505Sopenharmony_ci	if (!x_str || !y_str)
378e5b75505Sopenharmony_ci		goto fail;
379e5b75505Sopenharmony_ci
380e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
381e5b75505Sopenharmony_ci
382e5b75505Sopenharmony_cifail:
383e5b75505Sopenharmony_ci	OPENSSL_free(x_str);
384e5b75505Sopenharmony_ci	OPENSSL_free(y_str);
385e5b75505Sopenharmony_ci	BN_free(x);
386e5b75505Sopenharmony_ci	BN_free(y);
387e5b75505Sopenharmony_ci	BN_CTX_free(ctx);
388e5b75505Sopenharmony_ci}
389e5b75505Sopenharmony_ci
390e5b75505Sopenharmony_ci
391e5b75505Sopenharmony_cistatic int dpp_hash_vector(const struct dpp_curve_params *curve,
392e5b75505Sopenharmony_ci			   size_t num_elem, const u8 *addr[], const size_t *len,
393e5b75505Sopenharmony_ci			   u8 *mac)
394e5b75505Sopenharmony_ci{
395e5b75505Sopenharmony_ci	if (curve->hash_len == 32)
396e5b75505Sopenharmony_ci		return sha256_vector(num_elem, addr, len, mac);
397e5b75505Sopenharmony_ci	if (curve->hash_len == 48)
398e5b75505Sopenharmony_ci		return sha384_vector(num_elem, addr, len, mac);
399e5b75505Sopenharmony_ci	if (curve->hash_len == 64)
400e5b75505Sopenharmony_ci		return sha512_vector(num_elem, addr, len, mac);
401e5b75505Sopenharmony_ci	return -1;
402e5b75505Sopenharmony_ci}
403e5b75505Sopenharmony_ci
404e5b75505Sopenharmony_ci
405e5b75505Sopenharmony_cistatic int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
406e5b75505Sopenharmony_ci			   const char *label, u8 *out, size_t outlen)
407e5b75505Sopenharmony_ci{
408e5b75505Sopenharmony_ci	if (hash_len == 32)
409e5b75505Sopenharmony_ci		return hmac_sha256_kdf(secret, secret_len, NULL,
410e5b75505Sopenharmony_ci				       (const u8 *) label, os_strlen(label),
411e5b75505Sopenharmony_ci				       out, outlen);
412e5b75505Sopenharmony_ci	if (hash_len == 48)
413e5b75505Sopenharmony_ci		return hmac_sha384_kdf(secret, secret_len, NULL,
414e5b75505Sopenharmony_ci				       (const u8 *) label, os_strlen(label),
415e5b75505Sopenharmony_ci				       out, outlen);
416e5b75505Sopenharmony_ci	if (hash_len == 64)
417e5b75505Sopenharmony_ci		return hmac_sha512_kdf(secret, secret_len, NULL,
418e5b75505Sopenharmony_ci				       (const u8 *) label, os_strlen(label),
419e5b75505Sopenharmony_ci				       out, outlen);
420e5b75505Sopenharmony_ci	return -1;
421e5b75505Sopenharmony_ci}
422e5b75505Sopenharmony_ci
423e5b75505Sopenharmony_ci
424e5b75505Sopenharmony_cistatic int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
425e5b75505Sopenharmony_ci			   size_t num_elem, const u8 *addr[],
426e5b75505Sopenharmony_ci			   const size_t *len, u8 *mac)
427e5b75505Sopenharmony_ci{
428e5b75505Sopenharmony_ci	if (hash_len == 32)
429e5b75505Sopenharmony_ci		return hmac_sha256_vector(key, key_len, num_elem, addr, len,
430e5b75505Sopenharmony_ci					  mac);
431e5b75505Sopenharmony_ci	if (hash_len == 48)
432e5b75505Sopenharmony_ci		return hmac_sha384_vector(key, key_len, num_elem, addr, len,
433e5b75505Sopenharmony_ci					  mac);
434e5b75505Sopenharmony_ci	if (hash_len == 64)
435e5b75505Sopenharmony_ci		return hmac_sha512_vector(key, key_len, num_elem, addr, len,
436e5b75505Sopenharmony_ci					  mac);
437e5b75505Sopenharmony_ci	return -1;
438e5b75505Sopenharmony_ci}
439e5b75505Sopenharmony_ci
440e5b75505Sopenharmony_ci
441e5b75505Sopenharmony_cistatic int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
442e5b75505Sopenharmony_ci		    const u8 *data, size_t data_len, u8 *mac)
443e5b75505Sopenharmony_ci{
444e5b75505Sopenharmony_ci	if (hash_len == 32)
445e5b75505Sopenharmony_ci		return hmac_sha256(key, key_len, data, data_len, mac);
446e5b75505Sopenharmony_ci	if (hash_len == 48)
447e5b75505Sopenharmony_ci		return hmac_sha384(key, key_len, data, data_len, mac);
448e5b75505Sopenharmony_ci	if (hash_len == 64)
449e5b75505Sopenharmony_ci		return hmac_sha512(key, key_len, data, data_len, mac);
450e5b75505Sopenharmony_ci	return -1;
451e5b75505Sopenharmony_ci}
452e5b75505Sopenharmony_ci
453e5b75505Sopenharmony_ci
454e5b75505Sopenharmony_cistatic int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
455e5b75505Sopenharmony_ci{
456e5b75505Sopenharmony_ci	int num_bytes, offset;
457e5b75505Sopenharmony_ci
458e5b75505Sopenharmony_ci	num_bytes = BN_num_bytes(bn);
459e5b75505Sopenharmony_ci	if ((size_t) num_bytes > len)
460e5b75505Sopenharmony_ci		return -1;
461e5b75505Sopenharmony_ci	offset = len - num_bytes;
462e5b75505Sopenharmony_ci	os_memset(pos, 0, offset);
463e5b75505Sopenharmony_ci	BN_bn2bin(bn, pos + offset);
464e5b75505Sopenharmony_ci	return 0;
465e5b75505Sopenharmony_ci}
466e5b75505Sopenharmony_ci
467e5b75505Sopenharmony_ci
468e5b75505Sopenharmony_cistatic struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
469e5b75505Sopenharmony_ci{
470e5b75505Sopenharmony_ci	int len, res;
471e5b75505Sopenharmony_ci	EC_KEY *eckey;
472e5b75505Sopenharmony_ci	struct wpabuf *buf;
473e5b75505Sopenharmony_ci	unsigned char *pos;
474e5b75505Sopenharmony_ci
475e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(pkey);
476e5b75505Sopenharmony_ci	if (!eckey)
477e5b75505Sopenharmony_ci		return NULL;
478e5b75505Sopenharmony_ci	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
479e5b75505Sopenharmony_ci	len = i2o_ECPublicKey(eckey, NULL);
480e5b75505Sopenharmony_ci	if (len <= 0) {
481e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
482e5b75505Sopenharmony_ci			   "DDP: Failed to determine public key encoding length");
483e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
484e5b75505Sopenharmony_ci		return NULL;
485e5b75505Sopenharmony_ci	}
486e5b75505Sopenharmony_ci
487e5b75505Sopenharmony_ci	buf = wpabuf_alloc(len);
488e5b75505Sopenharmony_ci	if (!buf) {
489e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
490e5b75505Sopenharmony_ci		return NULL;
491e5b75505Sopenharmony_ci	}
492e5b75505Sopenharmony_ci
493e5b75505Sopenharmony_ci	pos = wpabuf_put(buf, len);
494e5b75505Sopenharmony_ci	res = i2o_ECPublicKey(eckey, &pos);
495e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
496e5b75505Sopenharmony_ci	if (res != len) {
497e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
498e5b75505Sopenharmony_ci			   "DDP: Failed to encode public key (res=%d/%d)",
499e5b75505Sopenharmony_ci			   res, len);
500e5b75505Sopenharmony_ci		wpabuf_free(buf);
501e5b75505Sopenharmony_ci		return NULL;
502e5b75505Sopenharmony_ci	}
503e5b75505Sopenharmony_ci
504e5b75505Sopenharmony_ci	if (!prefix) {
505e5b75505Sopenharmony_ci		/* Remove 0x04 prefix to match DPP definition */
506e5b75505Sopenharmony_ci		pos = wpabuf_mhead(buf);
507e5b75505Sopenharmony_ci		os_memmove(pos, pos + 1, len - 1);
508e5b75505Sopenharmony_ci		buf->used--;
509e5b75505Sopenharmony_ci	}
510e5b75505Sopenharmony_ci
511e5b75505Sopenharmony_ci	return buf;
512e5b75505Sopenharmony_ci}
513e5b75505Sopenharmony_ci
514e5b75505Sopenharmony_ci
515e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
516e5b75505Sopenharmony_ci					     const u8 *buf_x, const u8 *buf_y,
517e5b75505Sopenharmony_ci					     size_t len)
518e5b75505Sopenharmony_ci{
519e5b75505Sopenharmony_ci	EC_KEY *eckey = NULL;
520e5b75505Sopenharmony_ci	BN_CTX *ctx;
521e5b75505Sopenharmony_ci	EC_POINT *point = NULL;
522e5b75505Sopenharmony_ci	BIGNUM *x = NULL, *y = NULL;
523e5b75505Sopenharmony_ci	EVP_PKEY *pkey = NULL;
524e5b75505Sopenharmony_ci
525e5b75505Sopenharmony_ci	ctx = BN_CTX_new();
526e5b75505Sopenharmony_ci	if (!ctx) {
527e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Out of memory");
528e5b75505Sopenharmony_ci		return NULL;
529e5b75505Sopenharmony_ci	}
530e5b75505Sopenharmony_ci
531e5b75505Sopenharmony_ci	point = EC_POINT_new(group);
532e5b75505Sopenharmony_ci	x = BN_bin2bn(buf_x, len, NULL);
533e5b75505Sopenharmony_ci	y = BN_bin2bn(buf_y, len, NULL);
534e5b75505Sopenharmony_ci	if (!point || !x || !y) {
535e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Out of memory");
536e5b75505Sopenharmony_ci		goto fail;
537e5b75505Sopenharmony_ci	}
538e5b75505Sopenharmony_ci
539e5b75505Sopenharmony_ci	if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
540e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
541e5b75505Sopenharmony_ci			   "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
542e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
543e5b75505Sopenharmony_ci		goto fail;
544e5b75505Sopenharmony_ci	}
545e5b75505Sopenharmony_ci
546e5b75505Sopenharmony_ci	if (!EC_POINT_is_on_curve(group, point, ctx) ||
547e5b75505Sopenharmony_ci	    EC_POINT_is_at_infinity(group, point)) {
548e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Invalid point");
549e5b75505Sopenharmony_ci		goto fail;
550e5b75505Sopenharmony_ci	}
551e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
552e5b75505Sopenharmony_ci
553e5b75505Sopenharmony_ci	eckey = EC_KEY_new();
554e5b75505Sopenharmony_ci	if (!eckey ||
555e5b75505Sopenharmony_ci	    EC_KEY_set_group(eckey, group) != 1 ||
556e5b75505Sopenharmony_ci	    EC_KEY_set_public_key(eckey, point) != 1) {
557e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
558e5b75505Sopenharmony_ci			   "DPP: Failed to set EC_KEY: %s",
559e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
560e5b75505Sopenharmony_ci		goto fail;
561e5b75505Sopenharmony_ci	}
562e5b75505Sopenharmony_ci	EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
563e5b75505Sopenharmony_ci
564e5b75505Sopenharmony_ci	pkey = EVP_PKEY_new();
565e5b75505Sopenharmony_ci	if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
566e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
567e5b75505Sopenharmony_ci		goto fail;
568e5b75505Sopenharmony_ci	}
569e5b75505Sopenharmony_ci
570e5b75505Sopenharmony_ciout:
571e5b75505Sopenharmony_ci	BN_free(x);
572e5b75505Sopenharmony_ci	BN_free(y);
573e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
574e5b75505Sopenharmony_ci	EC_POINT_free(point);
575e5b75505Sopenharmony_ci	BN_CTX_free(ctx);
576e5b75505Sopenharmony_ci	return pkey;
577e5b75505Sopenharmony_cifail:
578e5b75505Sopenharmony_ci	EVP_PKEY_free(pkey);
579e5b75505Sopenharmony_ci	pkey = NULL;
580e5b75505Sopenharmony_ci	goto out;
581e5b75505Sopenharmony_ci}
582e5b75505Sopenharmony_ci
583e5b75505Sopenharmony_ci
584e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
585e5b75505Sopenharmony_ci				       const u8 *buf, size_t len)
586e5b75505Sopenharmony_ci{
587e5b75505Sopenharmony_ci	EC_KEY *eckey;
588e5b75505Sopenharmony_ci	const EC_GROUP *group;
589e5b75505Sopenharmony_ci	EVP_PKEY *pkey = NULL;
590e5b75505Sopenharmony_ci
591e5b75505Sopenharmony_ci	if (len & 1)
592e5b75505Sopenharmony_ci		return NULL;
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(group_key);
595e5b75505Sopenharmony_ci	if (!eckey) {
596e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
597e5b75505Sopenharmony_ci			   "DPP: Could not get EC_KEY from group_key");
598e5b75505Sopenharmony_ci		return NULL;
599e5b75505Sopenharmony_ci	}
600e5b75505Sopenharmony_ci
601e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(eckey);
602e5b75505Sopenharmony_ci	if (group)
603e5b75505Sopenharmony_ci		pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
604e5b75505Sopenharmony_ci						  len / 2);
605e5b75505Sopenharmony_ci	else
606e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
607e5b75505Sopenharmony_ci
608e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
609e5b75505Sopenharmony_ci	return pkey;
610e5b75505Sopenharmony_ci}
611e5b75505Sopenharmony_ci
612e5b75505Sopenharmony_ci
613e5b75505Sopenharmony_cistatic int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
614e5b75505Sopenharmony_ci		    u8 *secret, size_t *secret_len)
615e5b75505Sopenharmony_ci{
616e5b75505Sopenharmony_ci	EVP_PKEY_CTX *ctx;
617e5b75505Sopenharmony_ci	int ret = -1;
618e5b75505Sopenharmony_ci
619e5b75505Sopenharmony_ci	ERR_clear_error();
620e5b75505Sopenharmony_ci	*secret_len = 0;
621e5b75505Sopenharmony_ci
622e5b75505Sopenharmony_ci	ctx = EVP_PKEY_CTX_new(own, NULL);
623e5b75505Sopenharmony_ci	if (!ctx) {
624e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
625e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
626e5b75505Sopenharmony_ci		return -1;
627e5b75505Sopenharmony_ci	}
628e5b75505Sopenharmony_ci
629e5b75505Sopenharmony_ci	if (EVP_PKEY_derive_init(ctx) != 1) {
630e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
631e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
632e5b75505Sopenharmony_ci		goto fail;
633e5b75505Sopenharmony_ci	}
634e5b75505Sopenharmony_ci
635e5b75505Sopenharmony_ci	if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
636e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
637e5b75505Sopenharmony_ci			   "DPP: EVP_PKEY_derive_set_peet failed: %s",
638e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
639e5b75505Sopenharmony_ci		goto fail;
640e5b75505Sopenharmony_ci	}
641e5b75505Sopenharmony_ci
642e5b75505Sopenharmony_ci	if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
643e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
644e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
645e5b75505Sopenharmony_ci		goto fail;
646e5b75505Sopenharmony_ci	}
647e5b75505Sopenharmony_ci
648e5b75505Sopenharmony_ci	if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
649e5b75505Sopenharmony_ci		u8 buf[200];
650e5b75505Sopenharmony_ci		int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
651e5b75505Sopenharmony_ci
652e5b75505Sopenharmony_ci		/* It looks like OpenSSL can return unexpectedly large buffer
653e5b75505Sopenharmony_ci		 * need for shared secret from EVP_PKEY_derive(NULL) in some
654e5b75505Sopenharmony_ci		 * cases. For example, group 19 has shown cases where secret_len
655e5b75505Sopenharmony_ci		 * is set to 72 even though the actual length ends up being
656e5b75505Sopenharmony_ci		 * updated to 32 when EVP_PKEY_derive() is called with a buffer
657e5b75505Sopenharmony_ci		 * for the value. Work around this by trying to fetch the value
658e5b75505Sopenharmony_ci		 * and continue if it is within supported range even when the
659e5b75505Sopenharmony_ci		 * initial buffer need is claimed to be larger. */
660e5b75505Sopenharmony_ci		wpa_printf(level,
661e5b75505Sopenharmony_ci			   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
662e5b75505Sopenharmony_ci			   (int) *secret_len);
663e5b75505Sopenharmony_ci		if (*secret_len > 200)
664e5b75505Sopenharmony_ci			goto fail;
665e5b75505Sopenharmony_ci		if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
666e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
667e5b75505Sopenharmony_ci				   ERR_error_string(ERR_get_error(), NULL));
668e5b75505Sopenharmony_ci			goto fail;
669e5b75505Sopenharmony_ci		}
670e5b75505Sopenharmony_ci		if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
671e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
672e5b75505Sopenharmony_ci				   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
673e5b75505Sopenharmony_ci				   (int) *secret_len);
674e5b75505Sopenharmony_ci			goto fail;
675e5b75505Sopenharmony_ci		}
676e5b75505Sopenharmony_ci		wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
677e5b75505Sopenharmony_ci				buf, *secret_len);
678e5b75505Sopenharmony_ci		os_memcpy(secret, buf, *secret_len);
679e5b75505Sopenharmony_ci		forced_memzero(buf, sizeof(buf));
680e5b75505Sopenharmony_ci		goto done;
681e5b75505Sopenharmony_ci	}
682e5b75505Sopenharmony_ci
683e5b75505Sopenharmony_ci	if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
684e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
685e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
686e5b75505Sopenharmony_ci		goto fail;
687e5b75505Sopenharmony_ci	}
688e5b75505Sopenharmony_ci
689e5b75505Sopenharmony_cidone:
690e5b75505Sopenharmony_ci	ret = 0;
691e5b75505Sopenharmony_ci
692e5b75505Sopenharmony_cifail:
693e5b75505Sopenharmony_ci	EVP_PKEY_CTX_free(ctx);
694e5b75505Sopenharmony_ci	return ret;
695e5b75505Sopenharmony_ci}
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci
698e5b75505Sopenharmony_cistatic void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
699e5b75505Sopenharmony_ci{
700e5b75505Sopenharmony_ci	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
701e5b75505Sopenharmony_ci}
702e5b75505Sopenharmony_ci
703e5b75505Sopenharmony_ci
704e5b75505Sopenharmony_cistruct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
705e5b75505Sopenharmony_ci			      size_t len)
706e5b75505Sopenharmony_ci{
707e5b75505Sopenharmony_ci	struct wpabuf *msg;
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci	msg = wpabuf_alloc(8 + len);
710e5b75505Sopenharmony_ci	if (!msg)
711e5b75505Sopenharmony_ci		return NULL;
712e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
713e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
714e5b75505Sopenharmony_ci	wpabuf_put_be24(msg, OUI_WFA);
715e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, DPP_OUI_TYPE);
716e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, 1); /* Crypto Suite */
717e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, type);
718e5b75505Sopenharmony_ci	return msg;
719e5b75505Sopenharmony_ci}
720e5b75505Sopenharmony_ci
721e5b75505Sopenharmony_ci
722e5b75505Sopenharmony_ciconst u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
723e5b75505Sopenharmony_ci{
724e5b75505Sopenharmony_ci	u16 id, alen;
725e5b75505Sopenharmony_ci	const u8 *pos = buf, *end = buf + len;
726e5b75505Sopenharmony_ci
727e5b75505Sopenharmony_ci	while (end - pos >= 4) {
728e5b75505Sopenharmony_ci		id = WPA_GET_LE16(pos);
729e5b75505Sopenharmony_ci		pos += 2;
730e5b75505Sopenharmony_ci		alen = WPA_GET_LE16(pos);
731e5b75505Sopenharmony_ci		pos += 2;
732e5b75505Sopenharmony_ci		if (alen > end - pos)
733e5b75505Sopenharmony_ci			return NULL;
734e5b75505Sopenharmony_ci		if (id == req_id) {
735e5b75505Sopenharmony_ci			*ret_len = alen;
736e5b75505Sopenharmony_ci			return pos;
737e5b75505Sopenharmony_ci		}
738e5b75505Sopenharmony_ci		pos += alen;
739e5b75505Sopenharmony_ci	}
740e5b75505Sopenharmony_ci
741e5b75505Sopenharmony_ci	return NULL;
742e5b75505Sopenharmony_ci}
743e5b75505Sopenharmony_ci
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ciint dpp_check_attrs(const u8 *buf, size_t len)
746e5b75505Sopenharmony_ci{
747e5b75505Sopenharmony_ci	const u8 *pos, *end;
748e5b75505Sopenharmony_ci	int wrapped_data = 0;
749e5b75505Sopenharmony_ci
750e5b75505Sopenharmony_ci	pos = buf;
751e5b75505Sopenharmony_ci	end = buf + len;
752e5b75505Sopenharmony_ci	while (end - pos >= 4) {
753e5b75505Sopenharmony_ci		u16 id, alen;
754e5b75505Sopenharmony_ci
755e5b75505Sopenharmony_ci		id = WPA_GET_LE16(pos);
756e5b75505Sopenharmony_ci		pos += 2;
757e5b75505Sopenharmony_ci		alen = WPA_GET_LE16(pos);
758e5b75505Sopenharmony_ci		pos += 2;
759e5b75505Sopenharmony_ci		wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
760e5b75505Sopenharmony_ci			   id, alen);
761e5b75505Sopenharmony_ci		if (alen > end - pos) {
762e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
763e5b75505Sopenharmony_ci				   "DPP: Truncated message - not enough room for the attribute - dropped");
764e5b75505Sopenharmony_ci			return -1;
765e5b75505Sopenharmony_ci		}
766e5b75505Sopenharmony_ci		if (wrapped_data) {
767e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
768e5b75505Sopenharmony_ci				   "DPP: An unexpected attribute included after the Wrapped Data attribute");
769e5b75505Sopenharmony_ci			return -1;
770e5b75505Sopenharmony_ci		}
771e5b75505Sopenharmony_ci		if (id == DPP_ATTR_WRAPPED_DATA)
772e5b75505Sopenharmony_ci			wrapped_data = 1;
773e5b75505Sopenharmony_ci		pos += alen;
774e5b75505Sopenharmony_ci	}
775e5b75505Sopenharmony_ci
776e5b75505Sopenharmony_ci	if (end != pos) {
777e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
778e5b75505Sopenharmony_ci			   "DPP: Unexpected octets (%d) after the last attribute",
779e5b75505Sopenharmony_ci			   (int) (end - pos));
780e5b75505Sopenharmony_ci		return -1;
781e5b75505Sopenharmony_ci	}
782e5b75505Sopenharmony_ci
783e5b75505Sopenharmony_ci	return 0;
784e5b75505Sopenharmony_ci}
785e5b75505Sopenharmony_ci
786e5b75505Sopenharmony_ci
787e5b75505Sopenharmony_civoid dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
788e5b75505Sopenharmony_ci{
789e5b75505Sopenharmony_ci	if (!info)
790e5b75505Sopenharmony_ci		return;
791e5b75505Sopenharmony_ci	os_free(info->uri);
792e5b75505Sopenharmony_ci	os_free(info->info);
793e5b75505Sopenharmony_ci	EVP_PKEY_free(info->pubkey);
794e5b75505Sopenharmony_ci	os_free(info);
795e5b75505Sopenharmony_ci}
796e5b75505Sopenharmony_ci
797e5b75505Sopenharmony_ci
798e5b75505Sopenharmony_ciconst char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
799e5b75505Sopenharmony_ci{
800e5b75505Sopenharmony_ci	switch (type) {
801e5b75505Sopenharmony_ci	case DPP_BOOTSTRAP_QR_CODE:
802e5b75505Sopenharmony_ci		return "QRCODE";
803e5b75505Sopenharmony_ci	case DPP_BOOTSTRAP_PKEX:
804e5b75505Sopenharmony_ci		return "PKEX";
805e5b75505Sopenharmony_ci	}
806e5b75505Sopenharmony_ci	return "??";
807e5b75505Sopenharmony_ci}
808e5b75505Sopenharmony_ci
809e5b75505Sopenharmony_ci
810e5b75505Sopenharmony_cistatic int dpp_uri_valid_info(const char *info)
811e5b75505Sopenharmony_ci{
812e5b75505Sopenharmony_ci	while (*info) {
813e5b75505Sopenharmony_ci		unsigned char val = *info++;
814e5b75505Sopenharmony_ci
815e5b75505Sopenharmony_ci		if (val < 0x20 || val > 0x7e || val == 0x3b)
816e5b75505Sopenharmony_ci			return 0;
817e5b75505Sopenharmony_ci	}
818e5b75505Sopenharmony_ci
819e5b75505Sopenharmony_ci	return 1;
820e5b75505Sopenharmony_ci}
821e5b75505Sopenharmony_ci
822e5b75505Sopenharmony_ci
823e5b75505Sopenharmony_cistatic int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
824e5b75505Sopenharmony_ci{
825e5b75505Sopenharmony_ci	bi->uri = os_strdup(uri);
826e5b75505Sopenharmony_ci	return bi->uri ? 0 : -1;
827e5b75505Sopenharmony_ci}
828e5b75505Sopenharmony_ci
829e5b75505Sopenharmony_ci
830e5b75505Sopenharmony_ciint dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
831e5b75505Sopenharmony_ci			    const char *chan_list)
832e5b75505Sopenharmony_ci{
833e5b75505Sopenharmony_ci	const char *pos = chan_list, *pos2;
834e5b75505Sopenharmony_ci	int opclass = -1, channel, freq;
835e5b75505Sopenharmony_ci
836e5b75505Sopenharmony_ci	while (pos && *pos && *pos != ';') {
837e5b75505Sopenharmony_ci		pos2 = pos;
838e5b75505Sopenharmony_ci		while (*pos2 >= '0' && *pos2 <= '9')
839e5b75505Sopenharmony_ci			pos2++;
840e5b75505Sopenharmony_ci		if (*pos2 == '/') {
841e5b75505Sopenharmony_ci			opclass = atoi(pos);
842e5b75505Sopenharmony_ci			pos = pos2 + 1;
843e5b75505Sopenharmony_ci		}
844e5b75505Sopenharmony_ci		if (opclass <= 0)
845e5b75505Sopenharmony_ci			goto fail;
846e5b75505Sopenharmony_ci		channel = atoi(pos);
847e5b75505Sopenharmony_ci		if (channel <= 0)
848e5b75505Sopenharmony_ci			goto fail;
849e5b75505Sopenharmony_ci		while (*pos >= '0' && *pos <= '9')
850e5b75505Sopenharmony_ci			pos++;
851e5b75505Sopenharmony_ci		freq = ieee80211_chan_to_freq(NULL, opclass, channel);
852e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
853e5b75505Sopenharmony_ci			   "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
854e5b75505Sopenharmony_ci			   opclass, channel, freq);
855e5b75505Sopenharmony_ci		if (freq < 0) {
856e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
857e5b75505Sopenharmony_ci				   "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
858e5b75505Sopenharmony_ci				   opclass, channel);
859e5b75505Sopenharmony_ci		} else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
860e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
861e5b75505Sopenharmony_ci				   "DPP: Too many channels in URI channel-list - ignore list");
862e5b75505Sopenharmony_ci			bi->num_freq = 0;
863e5b75505Sopenharmony_ci			break;
864e5b75505Sopenharmony_ci		} else {
865e5b75505Sopenharmony_ci			bi->freq[bi->num_freq++] = freq;
866e5b75505Sopenharmony_ci		}
867e5b75505Sopenharmony_ci
868e5b75505Sopenharmony_ci		if (*pos == ';' || *pos == '\0')
869e5b75505Sopenharmony_ci			break;
870e5b75505Sopenharmony_ci		if (*pos != ',')
871e5b75505Sopenharmony_ci			goto fail;
872e5b75505Sopenharmony_ci		pos++;
873e5b75505Sopenharmony_ci	}
874e5b75505Sopenharmony_ci
875e5b75505Sopenharmony_ci	return 0;
876e5b75505Sopenharmony_cifail:
877e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
878e5b75505Sopenharmony_ci	return -1;
879e5b75505Sopenharmony_ci}
880e5b75505Sopenharmony_ci
881e5b75505Sopenharmony_ci
882e5b75505Sopenharmony_ciint dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
883e5b75505Sopenharmony_ci{
884e5b75505Sopenharmony_ci	if (!mac)
885e5b75505Sopenharmony_ci		return 0;
886e5b75505Sopenharmony_ci
887e5b75505Sopenharmony_ci	if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
888e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
889e5b75505Sopenharmony_ci		return -1;
890e5b75505Sopenharmony_ci	}
891e5b75505Sopenharmony_ci
892e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
893e5b75505Sopenharmony_ci
894e5b75505Sopenharmony_ci	return 0;
895e5b75505Sopenharmony_ci}
896e5b75505Sopenharmony_ci
897e5b75505Sopenharmony_ci
898e5b75505Sopenharmony_ciint dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
899e5b75505Sopenharmony_ci{
900e5b75505Sopenharmony_ci	const char *end;
901e5b75505Sopenharmony_ci
902e5b75505Sopenharmony_ci	if (!info)
903e5b75505Sopenharmony_ci		return 0;
904e5b75505Sopenharmony_ci
905e5b75505Sopenharmony_ci	end = os_strchr(info, ';');
906e5b75505Sopenharmony_ci	if (!end)
907e5b75505Sopenharmony_ci		end = info + os_strlen(info);
908e5b75505Sopenharmony_ci	bi->info = os_malloc(end - info + 1);
909e5b75505Sopenharmony_ci	if (!bi->info)
910e5b75505Sopenharmony_ci		return -1;
911e5b75505Sopenharmony_ci	os_memcpy(bi->info, info, end - info);
912e5b75505Sopenharmony_ci	bi->info[end - info] = '\0';
913e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
914e5b75505Sopenharmony_ci	if (!dpp_uri_valid_info(bi->info)) {
915e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
916e5b75505Sopenharmony_ci		return -1;
917e5b75505Sopenharmony_ci	}
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_ci	return 0;
920e5b75505Sopenharmony_ci}
921e5b75505Sopenharmony_ci
922e5b75505Sopenharmony_ci
923e5b75505Sopenharmony_cistatic const struct dpp_curve_params *
924e5b75505Sopenharmony_cidpp_get_curve_oid(const ASN1_OBJECT *poid)
925e5b75505Sopenharmony_ci{
926e5b75505Sopenharmony_ci	ASN1_OBJECT *oid;
927e5b75505Sopenharmony_ci	int i;
928e5b75505Sopenharmony_ci
929e5b75505Sopenharmony_ci	for (i = 0; dpp_curves[i].name; i++) {
930e5b75505Sopenharmony_ci		oid = OBJ_txt2obj(dpp_curves[i].name, 0);
931e5b75505Sopenharmony_ci		if (oid && OBJ_cmp(poid, oid) == 0)
932e5b75505Sopenharmony_ci			return &dpp_curves[i];
933e5b75505Sopenharmony_ci	}
934e5b75505Sopenharmony_ci	return NULL;
935e5b75505Sopenharmony_ci}
936e5b75505Sopenharmony_ci
937e5b75505Sopenharmony_ci
938e5b75505Sopenharmony_cistatic const struct dpp_curve_params * dpp_get_curve_nid(int nid)
939e5b75505Sopenharmony_ci{
940e5b75505Sopenharmony_ci	int i, tmp;
941e5b75505Sopenharmony_ci
942e5b75505Sopenharmony_ci	if (!nid)
943e5b75505Sopenharmony_ci		return NULL;
944e5b75505Sopenharmony_ci	for (i = 0; dpp_curves[i].name; i++) {
945e5b75505Sopenharmony_ci		tmp = OBJ_txt2nid(dpp_curves[i].name);
946e5b75505Sopenharmony_ci		if (tmp == nid)
947e5b75505Sopenharmony_ci			return &dpp_curves[i];
948e5b75505Sopenharmony_ci	}
949e5b75505Sopenharmony_ci	return NULL;
950e5b75505Sopenharmony_ci}
951e5b75505Sopenharmony_ci
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_cistatic int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
954e5b75505Sopenharmony_ci{
955e5b75505Sopenharmony_ci	const char *end;
956e5b75505Sopenharmony_ci	u8 *data;
957e5b75505Sopenharmony_ci	size_t data_len;
958e5b75505Sopenharmony_ci	EVP_PKEY *pkey;
959e5b75505Sopenharmony_ci	const unsigned char *p;
960e5b75505Sopenharmony_ci	int res;
961e5b75505Sopenharmony_ci	X509_PUBKEY *pub = NULL;
962e5b75505Sopenharmony_ci	ASN1_OBJECT *ppkalg;
963e5b75505Sopenharmony_ci	const unsigned char *pk;
964e5b75505Sopenharmony_ci	int ppklen;
965e5b75505Sopenharmony_ci	X509_ALGOR *pa;
966e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
967e5b75505Sopenharmony_ci	(defined(LIBRESSL_VERSION_NUMBER) && \
968e5b75505Sopenharmony_ci	 LIBRESSL_VERSION_NUMBER < 0x20800000L)
969e5b75505Sopenharmony_ci	ASN1_OBJECT *pa_oid;
970e5b75505Sopenharmony_ci#else
971e5b75505Sopenharmony_ci	const ASN1_OBJECT *pa_oid;
972e5b75505Sopenharmony_ci#endif
973e5b75505Sopenharmony_ci	const void *pval;
974e5b75505Sopenharmony_ci	int ptype;
975e5b75505Sopenharmony_ci	const ASN1_OBJECT *poid;
976e5b75505Sopenharmony_ci	char buf[100];
977e5b75505Sopenharmony_ci
978e5b75505Sopenharmony_ci	end = os_strchr(info, ';');
979e5b75505Sopenharmony_ci	if (!end)
980e5b75505Sopenharmony_ci		return -1;
981e5b75505Sopenharmony_ci
982e5b75505Sopenharmony_ci	data = base64_decode((const unsigned char *) info, end - info,
983e5b75505Sopenharmony_ci			     &data_len);
984e5b75505Sopenharmony_ci	if (!data) {
985e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
986e5b75505Sopenharmony_ci			   "DPP: Invalid base64 encoding on URI public-key");
987e5b75505Sopenharmony_ci		return -1;
988e5b75505Sopenharmony_ci	}
989e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
990e5b75505Sopenharmony_ci		    data, data_len);
991e5b75505Sopenharmony_ci
992e5b75505Sopenharmony_ci	if (sha256_vector(1, (const u8 **) &data, &data_len,
993e5b75505Sopenharmony_ci			  bi->pubkey_hash) < 0) {
994e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
995e5b75505Sopenharmony_ci		os_free(data);
996e5b75505Sopenharmony_ci		return -1;
997e5b75505Sopenharmony_ci	}
998e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
999e5b75505Sopenharmony_ci		    bi->pubkey_hash, SHA256_MAC_LEN);
1000e5b75505Sopenharmony_ci
1001e5b75505Sopenharmony_ci	/* DER encoded ASN.1 SubjectPublicKeyInfo
1002e5b75505Sopenharmony_ci	 *
1003e5b75505Sopenharmony_ci	 * SubjectPublicKeyInfo  ::=  SEQUENCE  {
1004e5b75505Sopenharmony_ci	 *      algorithm            AlgorithmIdentifier,
1005e5b75505Sopenharmony_ci	 *      subjectPublicKey     BIT STRING  }
1006e5b75505Sopenharmony_ci	 *
1007e5b75505Sopenharmony_ci	 * AlgorithmIdentifier  ::=  SEQUENCE  {
1008e5b75505Sopenharmony_ci	 *      algorithm               OBJECT IDENTIFIER,
1009e5b75505Sopenharmony_ci	 *      parameters              ANY DEFINED BY algorithm OPTIONAL  }
1010e5b75505Sopenharmony_ci	 *
1011e5b75505Sopenharmony_ci	 * subjectPublicKey = compressed format public key per ANSI X9.63
1012e5b75505Sopenharmony_ci	 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1013e5b75505Sopenharmony_ci	 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1014e5b75505Sopenharmony_ci	 *       prime256v1 (1.2.840.10045.3.1.7)
1015e5b75505Sopenharmony_ci	 */
1016e5b75505Sopenharmony_ci
1017e5b75505Sopenharmony_ci	p = data;
1018e5b75505Sopenharmony_ci	pkey = d2i_PUBKEY(NULL, &p, data_len);
1019e5b75505Sopenharmony_ci	os_free(data);
1020e5b75505Sopenharmony_ci
1021e5b75505Sopenharmony_ci	if (!pkey) {
1022e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1023e5b75505Sopenharmony_ci			   "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1024e5b75505Sopenharmony_ci		return -1;
1025e5b75505Sopenharmony_ci	}
1026e5b75505Sopenharmony_ci
1027e5b75505Sopenharmony_ci	if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
1028e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1029e5b75505Sopenharmony_ci			   "DPP: SubjectPublicKeyInfo does not describe an EC key");
1030e5b75505Sopenharmony_ci		EVP_PKEY_free(pkey);
1031e5b75505Sopenharmony_ci		return -1;
1032e5b75505Sopenharmony_ci	}
1033e5b75505Sopenharmony_ci
1034e5b75505Sopenharmony_ci	res = X509_PUBKEY_set(&pub, pkey);
1035e5b75505Sopenharmony_ci	if (res != 1) {
1036e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
1037e5b75505Sopenharmony_ci		goto fail;
1038e5b75505Sopenharmony_ci	}
1039e5b75505Sopenharmony_ci
1040e5b75505Sopenharmony_ci	res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
1041e5b75505Sopenharmony_ci	if (res != 1) {
1042e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1043e5b75505Sopenharmony_ci			   "DPP: Could not extract SubjectPublicKeyInfo parameters");
1044e5b75505Sopenharmony_ci		goto fail;
1045e5b75505Sopenharmony_ci	}
1046e5b75505Sopenharmony_ci	res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
1047e5b75505Sopenharmony_ci	if (res < 0 || (size_t) res >= sizeof(buf)) {
1048e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1049e5b75505Sopenharmony_ci			   "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1050e5b75505Sopenharmony_ci		goto fail;
1051e5b75505Sopenharmony_ci	}
1052e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
1053e5b75505Sopenharmony_ci	if (os_strcmp(buf, "id-ecPublicKey") != 0) {
1054e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1055e5b75505Sopenharmony_ci			   "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1056e5b75505Sopenharmony_ci		goto fail;
1057e5b75505Sopenharmony_ci	}
1058e5b75505Sopenharmony_ci
1059e5b75505Sopenharmony_ci	X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
1060e5b75505Sopenharmony_ci	if (ptype != V_ASN1_OBJECT) {
1061e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1062e5b75505Sopenharmony_ci			   "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1063e5b75505Sopenharmony_ci		goto fail;
1064e5b75505Sopenharmony_ci	}
1065e5b75505Sopenharmony_ci	poid = pval;
1066e5b75505Sopenharmony_ci	res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
1067e5b75505Sopenharmony_ci	if (res < 0 || (size_t) res >= sizeof(buf)) {
1068e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1069e5b75505Sopenharmony_ci			   "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1070e5b75505Sopenharmony_ci		goto fail;
1071e5b75505Sopenharmony_ci	}
1072e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
1073e5b75505Sopenharmony_ci	bi->curve = dpp_get_curve_oid(poid);
1074e5b75505Sopenharmony_ci	if (!bi->curve) {
1075e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1076e5b75505Sopenharmony_ci			   "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1077e5b75505Sopenharmony_ci			   buf);
1078e5b75505Sopenharmony_ci		goto fail;
1079e5b75505Sopenharmony_ci	}
1080e5b75505Sopenharmony_ci
1081e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
1082e5b75505Sopenharmony_ci
1083e5b75505Sopenharmony_ci	X509_PUBKEY_free(pub);
1084e5b75505Sopenharmony_ci	bi->pubkey = pkey;
1085e5b75505Sopenharmony_ci	return 0;
1086e5b75505Sopenharmony_cifail:
1087e5b75505Sopenharmony_ci	X509_PUBKEY_free(pub);
1088e5b75505Sopenharmony_ci	EVP_PKEY_free(pkey);
1089e5b75505Sopenharmony_ci	return -1;
1090e5b75505Sopenharmony_ci}
1091e5b75505Sopenharmony_ci
1092e5b75505Sopenharmony_ci
1093e5b75505Sopenharmony_cistatic struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
1094e5b75505Sopenharmony_ci{
1095e5b75505Sopenharmony_ci	const char *pos = uri;
1096e5b75505Sopenharmony_ci	const char *end;
1097e5b75505Sopenharmony_ci	const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
1098e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
1099e5b75505Sopenharmony_ci
1100e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
1101e5b75505Sopenharmony_ci
1102e5b75505Sopenharmony_ci	if (os_strncmp(pos, "DPP:", 4) != 0) {
1103e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
1104e5b75505Sopenharmony_ci		return NULL;
1105e5b75505Sopenharmony_ci	}
1106e5b75505Sopenharmony_ci	pos += 4;
1107e5b75505Sopenharmony_ci
1108e5b75505Sopenharmony_ci	for (;;) {
1109e5b75505Sopenharmony_ci		end = os_strchr(pos, ';');
1110e5b75505Sopenharmony_ci		if (!end)
1111e5b75505Sopenharmony_ci			break;
1112e5b75505Sopenharmony_ci
1113e5b75505Sopenharmony_ci		if (end == pos) {
1114e5b75505Sopenharmony_ci			/* Handle terminating ";;" and ignore unexpected ";"
1115e5b75505Sopenharmony_ci			 * for parsing robustness. */
1116e5b75505Sopenharmony_ci			pos++;
1117e5b75505Sopenharmony_ci			continue;
1118e5b75505Sopenharmony_ci		}
1119e5b75505Sopenharmony_ci
1120e5b75505Sopenharmony_ci		if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
1121e5b75505Sopenharmony_ci			chan_list = pos + 2;
1122e5b75505Sopenharmony_ci		else if (pos[0] == 'M' && pos[1] == ':' && !mac)
1123e5b75505Sopenharmony_ci			mac = pos + 2;
1124e5b75505Sopenharmony_ci		else if (pos[0] == 'I' && pos[1] == ':' && !info)
1125e5b75505Sopenharmony_ci			info = pos + 2;
1126e5b75505Sopenharmony_ci		else if (pos[0] == 'K' && pos[1] == ':' && !pk)
1127e5b75505Sopenharmony_ci			pk = pos + 2;
1128e5b75505Sopenharmony_ci		else
1129e5b75505Sopenharmony_ci			wpa_hexdump_ascii(MSG_DEBUG,
1130e5b75505Sopenharmony_ci					  "DPP: Ignore unrecognized URI parameter",
1131e5b75505Sopenharmony_ci					  pos, end - pos);
1132e5b75505Sopenharmony_ci		pos = end + 1;
1133e5b75505Sopenharmony_ci	}
1134e5b75505Sopenharmony_ci
1135e5b75505Sopenharmony_ci	if (!pk) {
1136e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: URI missing public-key");
1137e5b75505Sopenharmony_ci		return NULL;
1138e5b75505Sopenharmony_ci	}
1139e5b75505Sopenharmony_ci
1140e5b75505Sopenharmony_ci	bi = os_zalloc(sizeof(*bi));
1141e5b75505Sopenharmony_ci	if (!bi)
1142e5b75505Sopenharmony_ci		return NULL;
1143e5b75505Sopenharmony_ci
1144e5b75505Sopenharmony_ci	if (dpp_clone_uri(bi, uri) < 0 ||
1145e5b75505Sopenharmony_ci	    dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
1146e5b75505Sopenharmony_ci	    dpp_parse_uri_mac(bi, mac) < 0 ||
1147e5b75505Sopenharmony_ci	    dpp_parse_uri_info(bi, info) < 0 ||
1148e5b75505Sopenharmony_ci	    dpp_parse_uri_pk(bi, pk) < 0) {
1149e5b75505Sopenharmony_ci		dpp_bootstrap_info_free(bi);
1150e5b75505Sopenharmony_ci		bi = NULL;
1151e5b75505Sopenharmony_ci	}
1152e5b75505Sopenharmony_ci
1153e5b75505Sopenharmony_ci	return bi;
1154e5b75505Sopenharmony_ci}
1155e5b75505Sopenharmony_ci
1156e5b75505Sopenharmony_ci
1157e5b75505Sopenharmony_cistruct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
1158e5b75505Sopenharmony_ci{
1159e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
1160e5b75505Sopenharmony_ci
1161e5b75505Sopenharmony_ci	bi = dpp_parse_uri(uri);
1162e5b75505Sopenharmony_ci	if (bi)
1163e5b75505Sopenharmony_ci		bi->type = DPP_BOOTSTRAP_QR_CODE;
1164e5b75505Sopenharmony_ci	return bi;
1165e5b75505Sopenharmony_ci}
1166e5b75505Sopenharmony_ci
1167e5b75505Sopenharmony_ci
1168e5b75505Sopenharmony_cistatic void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1169e5b75505Sopenharmony_ci{
1170e5b75505Sopenharmony_ci	EC_KEY *eckey;
1171e5b75505Sopenharmony_ci	BIO *out;
1172e5b75505Sopenharmony_ci	size_t rlen;
1173e5b75505Sopenharmony_ci	char *txt;
1174e5b75505Sopenharmony_ci	int res;
1175e5b75505Sopenharmony_ci	unsigned char *der = NULL;
1176e5b75505Sopenharmony_ci	int der_len;
1177e5b75505Sopenharmony_ci	const EC_GROUP *group;
1178e5b75505Sopenharmony_ci	const EC_POINT *point;
1179e5b75505Sopenharmony_ci
1180e5b75505Sopenharmony_ci	out = BIO_new(BIO_s_mem());
1181e5b75505Sopenharmony_ci	if (!out)
1182e5b75505Sopenharmony_ci		return;
1183e5b75505Sopenharmony_ci
1184e5b75505Sopenharmony_ci	EVP_PKEY_print_private(out, key, 0, NULL);
1185e5b75505Sopenharmony_ci	rlen = BIO_ctrl_pending(out);
1186e5b75505Sopenharmony_ci	txt = os_malloc(rlen + 1);
1187e5b75505Sopenharmony_ci	if (txt) {
1188e5b75505Sopenharmony_ci		res = BIO_read(out, txt, rlen);
1189e5b75505Sopenharmony_ci		if (res > 0) {
1190e5b75505Sopenharmony_ci			txt[res] = '\0';
1191e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1192e5b75505Sopenharmony_ci		}
1193e5b75505Sopenharmony_ci		os_free(txt);
1194e5b75505Sopenharmony_ci	}
1195e5b75505Sopenharmony_ci	BIO_free(out);
1196e5b75505Sopenharmony_ci
1197e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(key);
1198e5b75505Sopenharmony_ci	if (!eckey)
1199e5b75505Sopenharmony_ci		return;
1200e5b75505Sopenharmony_ci
1201e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(eckey);
1202e5b75505Sopenharmony_ci	point = EC_KEY_get0_public_key(eckey);
1203e5b75505Sopenharmony_ci	if (group && point)
1204e5b75505Sopenharmony_ci		dpp_debug_print_point(title, group, point);
1205e5b75505Sopenharmony_ci
1206e5b75505Sopenharmony_ci	der_len = i2d_ECPrivateKey(eckey, &der);
1207e5b75505Sopenharmony_ci	if (der_len > 0)
1208e5b75505Sopenharmony_ci		wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1209e5b75505Sopenharmony_ci	OPENSSL_free(der);
1210e5b75505Sopenharmony_ci	if (der_len <= 0) {
1211e5b75505Sopenharmony_ci		der = NULL;
1212e5b75505Sopenharmony_ci		der_len = i2d_EC_PUBKEY(eckey, &der);
1213e5b75505Sopenharmony_ci		if (der_len > 0)
1214e5b75505Sopenharmony_ci			wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1215e5b75505Sopenharmony_ci		OPENSSL_free(der);
1216e5b75505Sopenharmony_ci	}
1217e5b75505Sopenharmony_ci
1218e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
1219e5b75505Sopenharmony_ci}
1220e5b75505Sopenharmony_ci
1221e5b75505Sopenharmony_ci
1222e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1223e5b75505Sopenharmony_ci{
1224e5b75505Sopenharmony_ci	EVP_PKEY_CTX *kctx = NULL;
1225e5b75505Sopenharmony_ci	EC_KEY *ec_params = NULL;
1226e5b75505Sopenharmony_ci	EVP_PKEY *params = NULL, *key = NULL;
1227e5b75505Sopenharmony_ci	int nid;
1228e5b75505Sopenharmony_ci
1229e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1230e5b75505Sopenharmony_ci
1231e5b75505Sopenharmony_ci	nid = OBJ_txt2nid(curve->name);
1232e5b75505Sopenharmony_ci	if (nid == NID_undef) {
1233e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1234e5b75505Sopenharmony_ci		return NULL;
1235e5b75505Sopenharmony_ci	}
1236e5b75505Sopenharmony_ci
1237e5b75505Sopenharmony_ci	ec_params = EC_KEY_new_by_curve_name(nid);
1238e5b75505Sopenharmony_ci	if (!ec_params) {
1239e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
1240e5b75505Sopenharmony_ci			   "DPP: Failed to generate EC_KEY parameters");
1241e5b75505Sopenharmony_ci		goto fail;
1242e5b75505Sopenharmony_ci	}
1243e5b75505Sopenharmony_ci	EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1244e5b75505Sopenharmony_ci	params = EVP_PKEY_new();
1245e5b75505Sopenharmony_ci	if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1246e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
1247e5b75505Sopenharmony_ci			   "DPP: Failed to generate EVP_PKEY parameters");
1248e5b75505Sopenharmony_ci		goto fail;
1249e5b75505Sopenharmony_ci	}
1250e5b75505Sopenharmony_ci
1251e5b75505Sopenharmony_ci	kctx = EVP_PKEY_CTX_new(params, NULL);
1252e5b75505Sopenharmony_ci	if (!kctx ||
1253e5b75505Sopenharmony_ci	    EVP_PKEY_keygen_init(kctx) != 1 ||
1254e5b75505Sopenharmony_ci	    EVP_PKEY_keygen(kctx, &key) != 1) {
1255e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
1256e5b75505Sopenharmony_ci		key = NULL;
1257e5b75505Sopenharmony_ci		goto fail;
1258e5b75505Sopenharmony_ci	}
1259e5b75505Sopenharmony_ci
1260e5b75505Sopenharmony_ci	if (wpa_debug_show_keys)
1261e5b75505Sopenharmony_ci		dpp_debug_print_key("Own generated key", key);
1262e5b75505Sopenharmony_ci
1263e5b75505Sopenharmony_cifail:
1264e5b75505Sopenharmony_ci	EC_KEY_free(ec_params);
1265e5b75505Sopenharmony_ci	EVP_PKEY_free(params);
1266e5b75505Sopenharmony_ci	EVP_PKEY_CTX_free(kctx);
1267e5b75505Sopenharmony_ci	return key;
1268e5b75505Sopenharmony_ci}
1269e5b75505Sopenharmony_ci
1270e5b75505Sopenharmony_ci
1271e5b75505Sopenharmony_cistatic const struct dpp_curve_params *
1272e5b75505Sopenharmony_cidpp_get_curve_name(const char *name)
1273e5b75505Sopenharmony_ci{
1274e5b75505Sopenharmony_ci	int i;
1275e5b75505Sopenharmony_ci
1276e5b75505Sopenharmony_ci	for (i = 0; dpp_curves[i].name; i++) {
1277e5b75505Sopenharmony_ci		if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1278e5b75505Sopenharmony_ci		    (dpp_curves[i].jwk_crv &&
1279e5b75505Sopenharmony_ci		     os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1280e5b75505Sopenharmony_ci			return &dpp_curves[i];
1281e5b75505Sopenharmony_ci	}
1282e5b75505Sopenharmony_ci	return NULL;
1283e5b75505Sopenharmony_ci}
1284e5b75505Sopenharmony_ci
1285e5b75505Sopenharmony_ci
1286e5b75505Sopenharmony_cistatic const struct dpp_curve_params *
1287e5b75505Sopenharmony_cidpp_get_curve_jwk_crv(const char *name)
1288e5b75505Sopenharmony_ci{
1289e5b75505Sopenharmony_ci	int i;
1290e5b75505Sopenharmony_ci
1291e5b75505Sopenharmony_ci	for (i = 0; dpp_curves[i].name; i++) {
1292e5b75505Sopenharmony_ci		if (dpp_curves[i].jwk_crv &&
1293e5b75505Sopenharmony_ci		    os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1294e5b75505Sopenharmony_ci			return &dpp_curves[i];
1295e5b75505Sopenharmony_ci	}
1296e5b75505Sopenharmony_ci	return NULL;
1297e5b75505Sopenharmony_ci}
1298e5b75505Sopenharmony_ci
1299e5b75505Sopenharmony_ci
1300e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1301e5b75505Sopenharmony_ci				  const u8 *privkey, size_t privkey_len)
1302e5b75505Sopenharmony_ci{
1303e5b75505Sopenharmony_ci	EVP_PKEY *pkey;
1304e5b75505Sopenharmony_ci	EC_KEY *eckey;
1305e5b75505Sopenharmony_ci	const EC_GROUP *group;
1306e5b75505Sopenharmony_ci	int nid;
1307e5b75505Sopenharmony_ci
1308e5b75505Sopenharmony_ci	pkey = EVP_PKEY_new();
1309e5b75505Sopenharmony_ci	if (!pkey)
1310e5b75505Sopenharmony_ci		return NULL;
1311e5b75505Sopenharmony_ci	eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1312e5b75505Sopenharmony_ci	if (!eckey) {
1313e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1314e5b75505Sopenharmony_ci			   "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1315e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
1316e5b75505Sopenharmony_ci		EVP_PKEY_free(pkey);
1317e5b75505Sopenharmony_ci		return NULL;
1318e5b75505Sopenharmony_ci	}
1319e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(eckey);
1320e5b75505Sopenharmony_ci	if (!group) {
1321e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
1322e5b75505Sopenharmony_ci		EVP_PKEY_free(pkey);
1323e5b75505Sopenharmony_ci		return NULL;
1324e5b75505Sopenharmony_ci	}
1325e5b75505Sopenharmony_ci	nid = EC_GROUP_get_curve_name(group);
1326e5b75505Sopenharmony_ci	*curve = dpp_get_curve_nid(nid);
1327e5b75505Sopenharmony_ci	if (!*curve) {
1328e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1329e5b75505Sopenharmony_ci			   "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1330e5b75505Sopenharmony_ci			   nid);
1331e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
1332e5b75505Sopenharmony_ci		EVP_PKEY_free(pkey);
1333e5b75505Sopenharmony_ci		return NULL;
1334e5b75505Sopenharmony_ci	}
1335e5b75505Sopenharmony_ci
1336e5b75505Sopenharmony_ci	if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1337e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
1338e5b75505Sopenharmony_ci		EVP_PKEY_free(pkey);
1339e5b75505Sopenharmony_ci		return NULL;
1340e5b75505Sopenharmony_ci	}
1341e5b75505Sopenharmony_ci	return pkey;
1342e5b75505Sopenharmony_ci}
1343e5b75505Sopenharmony_ci
1344e5b75505Sopenharmony_ci
1345e5b75505Sopenharmony_citypedef struct {
1346e5b75505Sopenharmony_ci	/* AlgorithmIdentifier ecPublicKey with optional parameters present
1347e5b75505Sopenharmony_ci	 * as an OID identifying the curve */
1348e5b75505Sopenharmony_ci	X509_ALGOR *alg;
1349e5b75505Sopenharmony_ci	/* Compressed format public key per ANSI X9.63 */
1350e5b75505Sopenharmony_ci	ASN1_BIT_STRING *pub_key;
1351e5b75505Sopenharmony_ci} DPP_BOOTSTRAPPING_KEY;
1352e5b75505Sopenharmony_ci
1353e5b75505Sopenharmony_ciASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1354e5b75505Sopenharmony_ci	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1355e5b75505Sopenharmony_ci	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1356e5b75505Sopenharmony_ci} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1357e5b75505Sopenharmony_ci
1358e5b75505Sopenharmony_ciIMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1359e5b75505Sopenharmony_ci
1360e5b75505Sopenharmony_ci
1361e5b75505Sopenharmony_cistatic struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
1362e5b75505Sopenharmony_ci{
1363e5b75505Sopenharmony_ci	unsigned char *der = NULL;
1364e5b75505Sopenharmony_ci	int der_len;
1365e5b75505Sopenharmony_ci	EC_KEY *eckey;
1366e5b75505Sopenharmony_ci	struct wpabuf *ret = NULL;
1367e5b75505Sopenharmony_ci	size_t len;
1368e5b75505Sopenharmony_ci	const EC_GROUP *group;
1369e5b75505Sopenharmony_ci	const EC_POINT *point;
1370e5b75505Sopenharmony_ci	BN_CTX *ctx;
1371e5b75505Sopenharmony_ci	DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1372e5b75505Sopenharmony_ci	int nid;
1373e5b75505Sopenharmony_ci
1374e5b75505Sopenharmony_ci	ctx = BN_CTX_new();
1375e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(key);
1376e5b75505Sopenharmony_ci	if (!ctx || !eckey)
1377e5b75505Sopenharmony_ci		goto fail;
1378e5b75505Sopenharmony_ci
1379e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(eckey);
1380e5b75505Sopenharmony_ci	point = EC_KEY_get0_public_key(eckey);
1381e5b75505Sopenharmony_ci	if (!group || !point)
1382e5b75505Sopenharmony_ci		goto fail;
1383e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: bootstrap public key", group, point);
1384e5b75505Sopenharmony_ci	nid = EC_GROUP_get_curve_name(group);
1385e5b75505Sopenharmony_ci
1386e5b75505Sopenharmony_ci	bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1387e5b75505Sopenharmony_ci	if (!bootstrap ||
1388e5b75505Sopenharmony_ci	    X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1389e5b75505Sopenharmony_ci			    V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1390e5b75505Sopenharmony_ci		goto fail;
1391e5b75505Sopenharmony_ci
1392e5b75505Sopenharmony_ci	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1393e5b75505Sopenharmony_ci				 NULL, 0, ctx);
1394e5b75505Sopenharmony_ci	if (len == 0)
1395e5b75505Sopenharmony_ci		goto fail;
1396e5b75505Sopenharmony_ci
1397e5b75505Sopenharmony_ci	der = OPENSSL_malloc(len);
1398e5b75505Sopenharmony_ci	if (!der)
1399e5b75505Sopenharmony_ci		goto fail;
1400e5b75505Sopenharmony_ci	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1401e5b75505Sopenharmony_ci				 der, len, ctx);
1402e5b75505Sopenharmony_ci
1403e5b75505Sopenharmony_ci	OPENSSL_free(bootstrap->pub_key->data);
1404e5b75505Sopenharmony_ci	bootstrap->pub_key->data = der;
1405e5b75505Sopenharmony_ci	der = NULL;
1406e5b75505Sopenharmony_ci	bootstrap->pub_key->length = len;
1407e5b75505Sopenharmony_ci	/* No unused bits */
1408e5b75505Sopenharmony_ci	bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1409e5b75505Sopenharmony_ci	bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1410e5b75505Sopenharmony_ci
1411e5b75505Sopenharmony_ci	der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
1412e5b75505Sopenharmony_ci	if (der_len <= 0) {
1413e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
1414e5b75505Sopenharmony_ci			   "DDP: Failed to build DER encoded public key");
1415e5b75505Sopenharmony_ci		goto fail;
1416e5b75505Sopenharmony_ci	}
1417e5b75505Sopenharmony_ci
1418e5b75505Sopenharmony_ci	ret = wpabuf_alloc_copy(der, der_len);
1419e5b75505Sopenharmony_cifail:
1420e5b75505Sopenharmony_ci	DPP_BOOTSTRAPPING_KEY_free(bootstrap);
1421e5b75505Sopenharmony_ci	OPENSSL_free(der);
1422e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
1423e5b75505Sopenharmony_ci	BN_CTX_free(ctx);
1424e5b75505Sopenharmony_ci	return ret;
1425e5b75505Sopenharmony_ci}
1426e5b75505Sopenharmony_ci
1427e5b75505Sopenharmony_ci
1428e5b75505Sopenharmony_ciint dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1429e5b75505Sopenharmony_ci{
1430e5b75505Sopenharmony_ci	struct wpabuf *der;
1431e5b75505Sopenharmony_ci	int res;
1432e5b75505Sopenharmony_ci	const u8 *addr[1];
1433e5b75505Sopenharmony_ci	size_t len[1];
1434e5b75505Sopenharmony_ci
1435e5b75505Sopenharmony_ci	der = dpp_bootstrap_key_der(bi->pubkey);
1436e5b75505Sopenharmony_ci	if (!der)
1437e5b75505Sopenharmony_ci		return -1;
1438e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1439e5b75505Sopenharmony_ci			der);
1440e5b75505Sopenharmony_ci
1441e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(der);
1442e5b75505Sopenharmony_ci	len[0] = wpabuf_len(der);
1443e5b75505Sopenharmony_ci	res = sha256_vector(1, addr, len, bi->pubkey_hash);
1444e5b75505Sopenharmony_ci	if (res < 0)
1445e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1446e5b75505Sopenharmony_ci	else
1447e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1448e5b75505Sopenharmony_ci			    SHA256_MAC_LEN);
1449e5b75505Sopenharmony_ci	wpabuf_free(der);
1450e5b75505Sopenharmony_ci	return res;
1451e5b75505Sopenharmony_ci}
1452e5b75505Sopenharmony_ci
1453e5b75505Sopenharmony_ci
1454e5b75505Sopenharmony_cichar * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1455e5b75505Sopenharmony_ci		  const u8 *privkey, size_t privkey_len)
1456e5b75505Sopenharmony_ci{
1457e5b75505Sopenharmony_ci	unsigned char *base64 = NULL;
1458e5b75505Sopenharmony_ci	char *pos, *end;
1459e5b75505Sopenharmony_ci	size_t len;
1460e5b75505Sopenharmony_ci	struct wpabuf *der = NULL;
1461e5b75505Sopenharmony_ci	const u8 *addr[1];
1462e5b75505Sopenharmony_ci	int res;
1463e5b75505Sopenharmony_ci
1464e5b75505Sopenharmony_ci	if (!curve) {
1465e5b75505Sopenharmony_ci		bi->curve = &dpp_curves[0];
1466e5b75505Sopenharmony_ci	} else {
1467e5b75505Sopenharmony_ci		bi->curve = dpp_get_curve_name(curve);
1468e5b75505Sopenharmony_ci		if (!bi->curve) {
1469e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1470e5b75505Sopenharmony_ci				   curve);
1471e5b75505Sopenharmony_ci			return NULL;
1472e5b75505Sopenharmony_ci		}
1473e5b75505Sopenharmony_ci	}
1474e5b75505Sopenharmony_ci	if (privkey)
1475e5b75505Sopenharmony_ci		bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1476e5b75505Sopenharmony_ci	else
1477e5b75505Sopenharmony_ci		bi->pubkey = dpp_gen_keypair(bi->curve);
1478e5b75505Sopenharmony_ci	if (!bi->pubkey)
1479e5b75505Sopenharmony_ci		goto fail;
1480e5b75505Sopenharmony_ci	bi->own = 1;
1481e5b75505Sopenharmony_ci
1482e5b75505Sopenharmony_ci	der = dpp_bootstrap_key_der(bi->pubkey);
1483e5b75505Sopenharmony_ci	if (!der)
1484e5b75505Sopenharmony_ci		goto fail;
1485e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1486e5b75505Sopenharmony_ci			der);
1487e5b75505Sopenharmony_ci
1488e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(der);
1489e5b75505Sopenharmony_ci	len = wpabuf_len(der);
1490e5b75505Sopenharmony_ci	res = sha256_vector(1, addr, &len, bi->pubkey_hash);
1491e5b75505Sopenharmony_ci	if (res < 0) {
1492e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1493e5b75505Sopenharmony_ci		goto fail;
1494e5b75505Sopenharmony_ci	}
1495e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1496e5b75505Sopenharmony_ci		    SHA256_MAC_LEN);
1497e5b75505Sopenharmony_ci
1498e5b75505Sopenharmony_ci	base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1499e5b75505Sopenharmony_ci	wpabuf_free(der);
1500e5b75505Sopenharmony_ci	der = NULL;
1501e5b75505Sopenharmony_ci	if (!base64)
1502e5b75505Sopenharmony_ci		goto fail;
1503e5b75505Sopenharmony_ci	pos = (char *) base64;
1504e5b75505Sopenharmony_ci	end = pos + len;
1505e5b75505Sopenharmony_ci	for (;;) {
1506e5b75505Sopenharmony_ci		pos = os_strchr(pos, '\n');
1507e5b75505Sopenharmony_ci		if (!pos)
1508e5b75505Sopenharmony_ci			break;
1509e5b75505Sopenharmony_ci		os_memmove(pos, pos + 1, end - pos);
1510e5b75505Sopenharmony_ci	}
1511e5b75505Sopenharmony_ci	return (char *) base64;
1512e5b75505Sopenharmony_cifail:
1513e5b75505Sopenharmony_ci	os_free(base64);
1514e5b75505Sopenharmony_ci	wpabuf_free(der);
1515e5b75505Sopenharmony_ci	return NULL;
1516e5b75505Sopenharmony_ci}
1517e5b75505Sopenharmony_ci
1518e5b75505Sopenharmony_ci
1519e5b75505Sopenharmony_cistatic int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1520e5b75505Sopenharmony_ci			 unsigned int hash_len)
1521e5b75505Sopenharmony_ci{
1522e5b75505Sopenharmony_ci	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1523e5b75505Sopenharmony_ci	const char *info = "first intermediate key";
1524e5b75505Sopenharmony_ci	int res;
1525e5b75505Sopenharmony_ci
1526e5b75505Sopenharmony_ci	/* k1 = HKDF(<>, "first intermediate key", M.x) */
1527e5b75505Sopenharmony_ci
1528e5b75505Sopenharmony_ci	/* HKDF-Extract(<>, M.x) */
1529e5b75505Sopenharmony_ci	os_memset(salt, 0, hash_len);
1530e5b75505Sopenharmony_ci	if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
1531e5b75505Sopenharmony_ci		return -1;
1532e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1533e5b75505Sopenharmony_ci			prk, hash_len);
1534e5b75505Sopenharmony_ci
1535e5b75505Sopenharmony_ci	/* HKDF-Expand(PRK, info, L) */
1536e5b75505Sopenharmony_ci	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
1537e5b75505Sopenharmony_ci	os_memset(prk, 0, hash_len);
1538e5b75505Sopenharmony_ci	if (res < 0)
1539e5b75505Sopenharmony_ci		return -1;
1540e5b75505Sopenharmony_ci
1541e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1542e5b75505Sopenharmony_ci			k1, hash_len);
1543e5b75505Sopenharmony_ci	return 0;
1544e5b75505Sopenharmony_ci}
1545e5b75505Sopenharmony_ci
1546e5b75505Sopenharmony_ci
1547e5b75505Sopenharmony_cistatic int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1548e5b75505Sopenharmony_ci			 unsigned int hash_len)
1549e5b75505Sopenharmony_ci{
1550e5b75505Sopenharmony_ci	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1551e5b75505Sopenharmony_ci	const char *info = "second intermediate key";
1552e5b75505Sopenharmony_ci	int res;
1553e5b75505Sopenharmony_ci
1554e5b75505Sopenharmony_ci	/* k2 = HKDF(<>, "second intermediate key", N.x) */
1555e5b75505Sopenharmony_ci
1556e5b75505Sopenharmony_ci	/* HKDF-Extract(<>, N.x) */
1557e5b75505Sopenharmony_ci	os_memset(salt, 0, hash_len);
1558e5b75505Sopenharmony_ci	res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
1559e5b75505Sopenharmony_ci	if (res < 0)
1560e5b75505Sopenharmony_ci		return -1;
1561e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1562e5b75505Sopenharmony_ci			prk, hash_len);
1563e5b75505Sopenharmony_ci
1564e5b75505Sopenharmony_ci	/* HKDF-Expand(PRK, info, L) */
1565e5b75505Sopenharmony_ci	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
1566e5b75505Sopenharmony_ci	os_memset(prk, 0, hash_len);
1567e5b75505Sopenharmony_ci	if (res < 0)
1568e5b75505Sopenharmony_ci		return -1;
1569e5b75505Sopenharmony_ci
1570e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1571e5b75505Sopenharmony_ci			k2, hash_len);
1572e5b75505Sopenharmony_ci	return 0;
1573e5b75505Sopenharmony_ci}
1574e5b75505Sopenharmony_ci
1575e5b75505Sopenharmony_ci
1576e5b75505Sopenharmony_cistatic int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1577e5b75505Sopenharmony_ci			 unsigned int hash_len)
1578e5b75505Sopenharmony_ci{
1579e5b75505Sopenharmony_ci	size_t nonce_len;
1580e5b75505Sopenharmony_ci	u8 nonces[2 * DPP_MAX_NONCE_LEN];
1581e5b75505Sopenharmony_ci	const char *info_ke = "DPP Key";
1582e5b75505Sopenharmony_ci	u8 prk[DPP_MAX_HASH_LEN];
1583e5b75505Sopenharmony_ci	int res;
1584e5b75505Sopenharmony_ci	const u8 *addr[3];
1585e5b75505Sopenharmony_ci	size_t len[3];
1586e5b75505Sopenharmony_ci	size_t num_elem = 0;
1587e5b75505Sopenharmony_ci
1588e5b75505Sopenharmony_ci	if (!auth->Mx_len || !auth->Nx_len) {
1589e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1590e5b75505Sopenharmony_ci			   "DPP: Mx/Nx not available - cannot derive ke");
1591e5b75505Sopenharmony_ci		return -1;
1592e5b75505Sopenharmony_ci	}
1593e5b75505Sopenharmony_ci
1594e5b75505Sopenharmony_ci	/* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1595e5b75505Sopenharmony_ci
1596e5b75505Sopenharmony_ci	/* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1597e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
1598e5b75505Sopenharmony_ci	os_memcpy(nonces, auth->i_nonce, nonce_len);
1599e5b75505Sopenharmony_ci	os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1600e5b75505Sopenharmony_ci	addr[num_elem] = auth->Mx;
1601e5b75505Sopenharmony_ci	len[num_elem] = auth->Mx_len;
1602e5b75505Sopenharmony_ci	num_elem++;
1603e5b75505Sopenharmony_ci	addr[num_elem] = auth->Nx;
1604e5b75505Sopenharmony_ci	len[num_elem] = auth->Nx_len;
1605e5b75505Sopenharmony_ci	num_elem++;
1606e5b75505Sopenharmony_ci	if (auth->peer_bi && auth->own_bi) {
1607e5b75505Sopenharmony_ci		if (!auth->Lx_len) {
1608e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1609e5b75505Sopenharmony_ci				   "DPP: Lx not available - cannot derive ke");
1610e5b75505Sopenharmony_ci			return -1;
1611e5b75505Sopenharmony_ci		}
1612e5b75505Sopenharmony_ci		addr[num_elem] = auth->Lx;
1613e5b75505Sopenharmony_ci		len[num_elem] = auth->secret_len;
1614e5b75505Sopenharmony_ci		num_elem++;
1615e5b75505Sopenharmony_ci	}
1616e5b75505Sopenharmony_ci	res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1617e5b75505Sopenharmony_ci			      num_elem, addr, len, prk);
1618e5b75505Sopenharmony_ci	if (res < 0)
1619e5b75505Sopenharmony_ci		return -1;
1620e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1621e5b75505Sopenharmony_ci			prk, hash_len);
1622e5b75505Sopenharmony_ci
1623e5b75505Sopenharmony_ci	/* HKDF-Expand(PRK, info, L) */
1624e5b75505Sopenharmony_ci	res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
1625e5b75505Sopenharmony_ci	os_memset(prk, 0, hash_len);
1626e5b75505Sopenharmony_ci	if (res < 0)
1627e5b75505Sopenharmony_ci		return -1;
1628e5b75505Sopenharmony_ci
1629e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1630e5b75505Sopenharmony_ci			ke, hash_len);
1631e5b75505Sopenharmony_ci	return 0;
1632e5b75505Sopenharmony_ci}
1633e5b75505Sopenharmony_ci
1634e5b75505Sopenharmony_ci
1635e5b75505Sopenharmony_cistatic void dpp_build_attr_status(struct wpabuf *msg,
1636e5b75505Sopenharmony_ci				  enum dpp_status_error status)
1637e5b75505Sopenharmony_ci{
1638e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1639e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1640e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 1);
1641e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, status);
1642e5b75505Sopenharmony_ci}
1643e5b75505Sopenharmony_ci
1644e5b75505Sopenharmony_ci
1645e5b75505Sopenharmony_cistatic void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1646e5b75505Sopenharmony_ci						const u8 *hash)
1647e5b75505Sopenharmony_ci{
1648e5b75505Sopenharmony_ci	if (hash) {
1649e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1650e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1651e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, SHA256_MAC_LEN);
1652e5b75505Sopenharmony_ci		wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1653e5b75505Sopenharmony_ci	}
1654e5b75505Sopenharmony_ci}
1655e5b75505Sopenharmony_ci
1656e5b75505Sopenharmony_ci
1657e5b75505Sopenharmony_cistatic void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1658e5b75505Sopenharmony_ci						const u8 *hash)
1659e5b75505Sopenharmony_ci{
1660e5b75505Sopenharmony_ci	if (hash) {
1661e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1662e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1663e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, SHA256_MAC_LEN);
1664e5b75505Sopenharmony_ci		wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1665e5b75505Sopenharmony_ci	}
1666e5b75505Sopenharmony_ci}
1667e5b75505Sopenharmony_ci
1668e5b75505Sopenharmony_ci
1669e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1670e5b75505Sopenharmony_ci					  const struct wpabuf *pi,
1671e5b75505Sopenharmony_ci					  size_t nonce_len,
1672e5b75505Sopenharmony_ci					  const u8 *r_pubkey_hash,
1673e5b75505Sopenharmony_ci					  const u8 *i_pubkey_hash,
1674e5b75505Sopenharmony_ci					  unsigned int neg_freq)
1675e5b75505Sopenharmony_ci{
1676e5b75505Sopenharmony_ci	struct wpabuf *msg;
1677e5b75505Sopenharmony_ci	u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1678e5b75505Sopenharmony_ci	u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1679e5b75505Sopenharmony_ci	u8 *pos;
1680e5b75505Sopenharmony_ci	const u8 *addr[2];
1681e5b75505Sopenharmony_ci	size_t len[2], siv_len, attr_len;
1682e5b75505Sopenharmony_ci	u8 *attr_start, *attr_end;
1683e5b75505Sopenharmony_ci
1684e5b75505Sopenharmony_ci	/* Build DPP Authentication Request frame attributes */
1685e5b75505Sopenharmony_ci	attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1686e5b75505Sopenharmony_ci		4 + sizeof(wrapped_data);
1687e5b75505Sopenharmony_ci	if (neg_freq > 0)
1688e5b75505Sopenharmony_ci		attr_len += 4 + 2;
1689e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1690e5b75505Sopenharmony_ci	attr_len += 5;
1691e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1692e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1693e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1694e5b75505Sopenharmony_ci		attr_len += 5;
1695e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1696e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1697e5b75505Sopenharmony_ci	if (!msg)
1698e5b75505Sopenharmony_ci		return NULL;
1699e5b75505Sopenharmony_ci
1700e5b75505Sopenharmony_ci	attr_start = wpabuf_put(msg, 0);
1701e5b75505Sopenharmony_ci
1702e5b75505Sopenharmony_ci	/* Responder Bootstrapping Key Hash */
1703e5b75505Sopenharmony_ci	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1704e5b75505Sopenharmony_ci
1705e5b75505Sopenharmony_ci	/* Initiator Bootstrapping Key Hash */
1706e5b75505Sopenharmony_ci	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1707e5b75505Sopenharmony_ci
1708e5b75505Sopenharmony_ci	/* Initiator Protocol Key */
1709e5b75505Sopenharmony_ci	if (pi) {
1710e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1711e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, wpabuf_len(pi));
1712e5b75505Sopenharmony_ci		wpabuf_put_buf(msg, pi);
1713e5b75505Sopenharmony_ci	}
1714e5b75505Sopenharmony_ci
1715e5b75505Sopenharmony_ci	/* Channel */
1716e5b75505Sopenharmony_ci	if (neg_freq > 0) {
1717e5b75505Sopenharmony_ci		u8 op_class, channel;
1718e5b75505Sopenharmony_ci
1719e5b75505Sopenharmony_ci		if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1720e5b75505Sopenharmony_ci						  &channel) ==
1721e5b75505Sopenharmony_ci		    NUM_HOSTAPD_MODES) {
1722e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
1723e5b75505Sopenharmony_ci				   "DPP: Unsupported negotiation frequency request: %d",
1724e5b75505Sopenharmony_ci				   neg_freq);
1725e5b75505Sopenharmony_ci			wpabuf_free(msg);
1726e5b75505Sopenharmony_ci			return NULL;
1727e5b75505Sopenharmony_ci		}
1728e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1729e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, 2);
1730e5b75505Sopenharmony_ci		wpabuf_put_u8(msg, op_class);
1731e5b75505Sopenharmony_ci		wpabuf_put_u8(msg, channel);
1732e5b75505Sopenharmony_ci	}
1733e5b75505Sopenharmony_ci
1734e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1735e5b75505Sopenharmony_ci	/* Protocol Version */
1736e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1737e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 1);
1738e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, 2);
1739e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1740e5b75505Sopenharmony_ci
1741e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1742e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1743e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1744e5b75505Sopenharmony_ci		goto skip_wrapped_data;
1745e5b75505Sopenharmony_ci	}
1746e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1747e5b75505Sopenharmony_ci
1748e5b75505Sopenharmony_ci	/* Wrapped data ({I-nonce, I-capabilities}k1) */
1749e5b75505Sopenharmony_ci	pos = clear;
1750e5b75505Sopenharmony_ci
1751e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1752e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1753e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1754e5b75505Sopenharmony_ci		goto skip_i_nonce;
1755e5b75505Sopenharmony_ci	}
1756e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1757e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1758e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1759e5b75505Sopenharmony_ci		pos += 2;
1760e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, nonce_len - 1);
1761e5b75505Sopenharmony_ci		pos += 2;
1762e5b75505Sopenharmony_ci		os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1763e5b75505Sopenharmony_ci		pos += nonce_len - 1;
1764e5b75505Sopenharmony_ci		goto skip_i_nonce;
1765e5b75505Sopenharmony_ci	}
1766e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1767e5b75505Sopenharmony_ci
1768e5b75505Sopenharmony_ci	/* I-nonce */
1769e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1770e5b75505Sopenharmony_ci	pos += 2;
1771e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, nonce_len);
1772e5b75505Sopenharmony_ci	pos += 2;
1773e5b75505Sopenharmony_ci	os_memcpy(pos, auth->i_nonce, nonce_len);
1774e5b75505Sopenharmony_ci	pos += nonce_len;
1775e5b75505Sopenharmony_ci
1776e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1777e5b75505Sopenharmony_ciskip_i_nonce:
1778e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1779e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1780e5b75505Sopenharmony_ci		goto skip_i_capab;
1781e5b75505Sopenharmony_ci	}
1782e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1783e5b75505Sopenharmony_ci
1784e5b75505Sopenharmony_ci	/* I-capabilities */
1785e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1786e5b75505Sopenharmony_ci	pos += 2;
1787e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, 1);
1788e5b75505Sopenharmony_ci	pos += 2;
1789e5b75505Sopenharmony_ci	auth->i_capab = auth->allowed_roles;
1790e5b75505Sopenharmony_ci	*pos++ = auth->i_capab;
1791e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1792e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1793e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1794e5b75505Sopenharmony_ci		pos[-1] = 0;
1795e5b75505Sopenharmony_ci	}
1796e5b75505Sopenharmony_ciskip_i_capab:
1797e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1798e5b75505Sopenharmony_ci
1799e5b75505Sopenharmony_ci	attr_end = wpabuf_put(msg, 0);
1800e5b75505Sopenharmony_ci
1801e5b75505Sopenharmony_ci	/* OUI, OUI type, Crypto Suite, DPP frame type */
1802e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
1803e5b75505Sopenharmony_ci	len[0] = 3 + 1 + 1 + 1;
1804e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1805e5b75505Sopenharmony_ci
1806e5b75505Sopenharmony_ci	/* Attributes before Wrapped Data */
1807e5b75505Sopenharmony_ci	addr[1] = attr_start;
1808e5b75505Sopenharmony_ci	len[1] = attr_end - attr_start;
1809e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1810e5b75505Sopenharmony_ci
1811e5b75505Sopenharmony_ci	siv_len = pos - clear;
1812e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1813e5b75505Sopenharmony_ci	if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1814e5b75505Sopenharmony_ci			    2, addr, len, wrapped_data) < 0) {
1815e5b75505Sopenharmony_ci		wpabuf_free(msg);
1816e5b75505Sopenharmony_ci		return NULL;
1817e5b75505Sopenharmony_ci	}
1818e5b75505Sopenharmony_ci	siv_len += AES_BLOCK_SIZE;
1819e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1820e5b75505Sopenharmony_ci		    wrapped_data, siv_len);
1821e5b75505Sopenharmony_ci
1822e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1823e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, siv_len);
1824e5b75505Sopenharmony_ci	wpabuf_put_data(msg, wrapped_data, siv_len);
1825e5b75505Sopenharmony_ci
1826e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1827e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1828e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1829e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
1830e5b75505Sopenharmony_ci	}
1831e5b75505Sopenharmony_ciskip_wrapped_data:
1832e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1833e5b75505Sopenharmony_ci
1834e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG,
1835e5b75505Sopenharmony_ci			"DPP: Authentication Request frame attributes", msg);
1836e5b75505Sopenharmony_ci
1837e5b75505Sopenharmony_ci	return msg;
1838e5b75505Sopenharmony_ci}
1839e5b75505Sopenharmony_ci
1840e5b75505Sopenharmony_ci
1841e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1842e5b75505Sopenharmony_ci					   enum dpp_status_error status,
1843e5b75505Sopenharmony_ci					   const struct wpabuf *pr,
1844e5b75505Sopenharmony_ci					   size_t nonce_len,
1845e5b75505Sopenharmony_ci					   const u8 *r_pubkey_hash,
1846e5b75505Sopenharmony_ci					   const u8 *i_pubkey_hash,
1847e5b75505Sopenharmony_ci					   const u8 *r_nonce, const u8 *i_nonce,
1848e5b75505Sopenharmony_ci					   const u8 *wrapped_r_auth,
1849e5b75505Sopenharmony_ci					   size_t wrapped_r_auth_len,
1850e5b75505Sopenharmony_ci					   const u8 *siv_key)
1851e5b75505Sopenharmony_ci{
1852e5b75505Sopenharmony_ci	struct wpabuf *msg;
1853e5b75505Sopenharmony_ci#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1854e5b75505Sopenharmony_ci		4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1855e5b75505Sopenharmony_ci	u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1856e5b75505Sopenharmony_ci	u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1857e5b75505Sopenharmony_ci	const u8 *addr[2];
1858e5b75505Sopenharmony_ci	size_t len[2], siv_len, attr_len;
1859e5b75505Sopenharmony_ci	u8 *attr_start, *attr_end, *pos;
1860e5b75505Sopenharmony_ci
1861e5b75505Sopenharmony_ci	auth->waiting_auth_conf = 1;
1862e5b75505Sopenharmony_ci	auth->auth_resp_tries = 0;
1863e5b75505Sopenharmony_ci
1864e5b75505Sopenharmony_ci	/* Build DPP Authentication Response frame attributes */
1865e5b75505Sopenharmony_ci	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1866e5b75505Sopenharmony_ci		4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
1867e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1868e5b75505Sopenharmony_ci	attr_len += 5;
1869e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1870e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1871e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1872e5b75505Sopenharmony_ci		attr_len += 5;
1873e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1874e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1875e5b75505Sopenharmony_ci	if (!msg)
1876e5b75505Sopenharmony_ci		return NULL;
1877e5b75505Sopenharmony_ci
1878e5b75505Sopenharmony_ci	attr_start = wpabuf_put(msg, 0);
1879e5b75505Sopenharmony_ci
1880e5b75505Sopenharmony_ci	/* DPP Status */
1881e5b75505Sopenharmony_ci	if (status != 255)
1882e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, status);
1883e5b75505Sopenharmony_ci
1884e5b75505Sopenharmony_ci	/* Responder Bootstrapping Key Hash */
1885e5b75505Sopenharmony_ci	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1886e5b75505Sopenharmony_ci
1887e5b75505Sopenharmony_ci	/* Initiator Bootstrapping Key Hash (mutual authentication) */
1888e5b75505Sopenharmony_ci	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1889e5b75505Sopenharmony_ci
1890e5b75505Sopenharmony_ci	/* Responder Protocol Key */
1891e5b75505Sopenharmony_ci	if (pr) {
1892e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1893e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, wpabuf_len(pr));
1894e5b75505Sopenharmony_ci		wpabuf_put_buf(msg, pr);
1895e5b75505Sopenharmony_ci	}
1896e5b75505Sopenharmony_ci
1897e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
1898e5b75505Sopenharmony_ci	/* Protocol Version */
1899e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1900e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 1);
1901e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, 2);
1902e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
1903e5b75505Sopenharmony_ci
1904e5b75505Sopenharmony_ci	attr_end = wpabuf_put(msg, 0);
1905e5b75505Sopenharmony_ci
1906e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1907e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1908e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1909e5b75505Sopenharmony_ci		goto skip_wrapped_data;
1910e5b75505Sopenharmony_ci	}
1911e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1912e5b75505Sopenharmony_ci
1913e5b75505Sopenharmony_ci	/* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1914e5b75505Sopenharmony_ci	pos = clear;
1915e5b75505Sopenharmony_ci
1916e5b75505Sopenharmony_ci	if (r_nonce) {
1917e5b75505Sopenharmony_ci		/* R-nonce */
1918e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1919e5b75505Sopenharmony_ci		pos += 2;
1920e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, nonce_len);
1921e5b75505Sopenharmony_ci		pos += 2;
1922e5b75505Sopenharmony_ci		os_memcpy(pos, r_nonce, nonce_len);
1923e5b75505Sopenharmony_ci		pos += nonce_len;
1924e5b75505Sopenharmony_ci	}
1925e5b75505Sopenharmony_ci
1926e5b75505Sopenharmony_ci	if (i_nonce) {
1927e5b75505Sopenharmony_ci		/* I-nonce */
1928e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1929e5b75505Sopenharmony_ci		pos += 2;
1930e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, nonce_len);
1931e5b75505Sopenharmony_ci		pos += 2;
1932e5b75505Sopenharmony_ci		os_memcpy(pos, i_nonce, nonce_len);
1933e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1934e5b75505Sopenharmony_ci		if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1935e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1936e5b75505Sopenharmony_ci			pos[nonce_len / 2] ^= 0x01;
1937e5b75505Sopenharmony_ci		}
1938e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1939e5b75505Sopenharmony_ci		pos += nonce_len;
1940e5b75505Sopenharmony_ci	}
1941e5b75505Sopenharmony_ci
1942e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1943e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1944e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1945e5b75505Sopenharmony_ci		goto skip_r_capab;
1946e5b75505Sopenharmony_ci	}
1947e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1948e5b75505Sopenharmony_ci
1949e5b75505Sopenharmony_ci	/* R-capabilities */
1950e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1951e5b75505Sopenharmony_ci	pos += 2;
1952e5b75505Sopenharmony_ci	WPA_PUT_LE16(pos, 1);
1953e5b75505Sopenharmony_ci	pos += 2;
1954e5b75505Sopenharmony_ci	auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1955e5b75505Sopenharmony_ci		DPP_CAPAB_ENROLLEE;
1956e5b75505Sopenharmony_ci	*pos++ = auth->r_capab;
1957e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
1958e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1959e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1960e5b75505Sopenharmony_ci		pos[-1] = 0;
1961e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1962e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1963e5b75505Sopenharmony_ci			   "DPP: TESTING - incompatible R-capabilities");
1964e5b75505Sopenharmony_ci		if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1965e5b75505Sopenharmony_ci		    (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1966e5b75505Sopenharmony_ci			pos[-1] = 0;
1967e5b75505Sopenharmony_ci		else
1968e5b75505Sopenharmony_ci			pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1969e5b75505Sopenharmony_ci				DPP_CAPAB_CONFIGURATOR;
1970e5b75505Sopenharmony_ci	}
1971e5b75505Sopenharmony_ciskip_r_capab:
1972e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
1973e5b75505Sopenharmony_ci
1974e5b75505Sopenharmony_ci	if (wrapped_r_auth) {
1975e5b75505Sopenharmony_ci		/* {R-auth}ke */
1976e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1977e5b75505Sopenharmony_ci		pos += 2;
1978e5b75505Sopenharmony_ci		WPA_PUT_LE16(pos, wrapped_r_auth_len);
1979e5b75505Sopenharmony_ci		pos += 2;
1980e5b75505Sopenharmony_ci		os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1981e5b75505Sopenharmony_ci		pos += wrapped_r_auth_len;
1982e5b75505Sopenharmony_ci	}
1983e5b75505Sopenharmony_ci
1984e5b75505Sopenharmony_ci	/* OUI, OUI type, Crypto Suite, DPP frame type */
1985e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
1986e5b75505Sopenharmony_ci	len[0] = 3 + 1 + 1 + 1;
1987e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1988e5b75505Sopenharmony_ci
1989e5b75505Sopenharmony_ci	/* Attributes before Wrapped Data */
1990e5b75505Sopenharmony_ci	addr[1] = attr_start;
1991e5b75505Sopenharmony_ci	len[1] = attr_end - attr_start;
1992e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1993e5b75505Sopenharmony_ci
1994e5b75505Sopenharmony_ci	siv_len = pos - clear;
1995e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1996e5b75505Sopenharmony_ci	if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1997e5b75505Sopenharmony_ci			    2, addr, len, wrapped_data) < 0) {
1998e5b75505Sopenharmony_ci		wpabuf_free(msg);
1999e5b75505Sopenharmony_ci		return NULL;
2000e5b75505Sopenharmony_ci	}
2001e5b75505Sopenharmony_ci	siv_len += AES_BLOCK_SIZE;
2002e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2003e5b75505Sopenharmony_ci		    wrapped_data, siv_len);
2004e5b75505Sopenharmony_ci
2005e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2006e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, siv_len);
2007e5b75505Sopenharmony_ci	wpabuf_put_data(msg, wrapped_data, siv_len);
2008e5b75505Sopenharmony_ci
2009e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2010e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
2011e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2012e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
2013e5b75505Sopenharmony_ci	}
2014e5b75505Sopenharmony_ciskip_wrapped_data:
2015e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2016e5b75505Sopenharmony_ci
2017e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG,
2018e5b75505Sopenharmony_ci			"DPP: Authentication Response frame attributes", msg);
2019e5b75505Sopenharmony_ci	return msg;
2020e5b75505Sopenharmony_ci}
2021e5b75505Sopenharmony_ci
2022e5b75505Sopenharmony_ci
2023e5b75505Sopenharmony_cistatic int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
2024e5b75505Sopenharmony_ci			       u16 num_modes, unsigned int freq)
2025e5b75505Sopenharmony_ci{
2026e5b75505Sopenharmony_ci	u16 m;
2027e5b75505Sopenharmony_ci	int c, flag;
2028e5b75505Sopenharmony_ci
2029e5b75505Sopenharmony_ci	if (!own_modes || !num_modes)
2030e5b75505Sopenharmony_ci		return 1;
2031e5b75505Sopenharmony_ci
2032e5b75505Sopenharmony_ci	for (m = 0; m < num_modes; m++) {
2033e5b75505Sopenharmony_ci		for (c = 0; c < own_modes[m].num_channels; c++) {
2034e5b75505Sopenharmony_ci			if ((unsigned int) own_modes[m].channels[c].freq !=
2035e5b75505Sopenharmony_ci			    freq)
2036e5b75505Sopenharmony_ci				continue;
2037e5b75505Sopenharmony_ci			flag = own_modes[m].channels[c].flag;
2038e5b75505Sopenharmony_ci			if (!(flag & (HOSTAPD_CHAN_DISABLED |
2039e5b75505Sopenharmony_ci				      HOSTAPD_CHAN_NO_IR |
2040e5b75505Sopenharmony_ci				      HOSTAPD_CHAN_RADAR)))
2041e5b75505Sopenharmony_ci				return 1;
2042e5b75505Sopenharmony_ci		}
2043e5b75505Sopenharmony_ci	}
2044e5b75505Sopenharmony_ci
2045e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
2046e5b75505Sopenharmony_ci	return 0;
2047e5b75505Sopenharmony_ci}
2048e5b75505Sopenharmony_ci
2049e5b75505Sopenharmony_ci
2050e5b75505Sopenharmony_cistatic int freq_included(const unsigned int freqs[], unsigned int num,
2051e5b75505Sopenharmony_ci			 unsigned int freq)
2052e5b75505Sopenharmony_ci{
2053e5b75505Sopenharmony_ci	while (num > 0) {
2054e5b75505Sopenharmony_ci		if (freqs[--num] == freq)
2055e5b75505Sopenharmony_ci			return 1;
2056e5b75505Sopenharmony_ci	}
2057e5b75505Sopenharmony_ci	return 0;
2058e5b75505Sopenharmony_ci}
2059e5b75505Sopenharmony_ci
2060e5b75505Sopenharmony_ci
2061e5b75505Sopenharmony_cistatic void freq_to_start(unsigned int freqs[], unsigned int num,
2062e5b75505Sopenharmony_ci			  unsigned int freq)
2063e5b75505Sopenharmony_ci{
2064e5b75505Sopenharmony_ci	unsigned int i;
2065e5b75505Sopenharmony_ci
2066e5b75505Sopenharmony_ci	for (i = 0; i < num; i++) {
2067e5b75505Sopenharmony_ci		if (freqs[i] == freq)
2068e5b75505Sopenharmony_ci			break;
2069e5b75505Sopenharmony_ci	}
2070e5b75505Sopenharmony_ci	if (i == 0 || i >= num)
2071e5b75505Sopenharmony_ci		return;
2072e5b75505Sopenharmony_ci	os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
2073e5b75505Sopenharmony_ci	freqs[0] = freq;
2074e5b75505Sopenharmony_ci}
2075e5b75505Sopenharmony_ci
2076e5b75505Sopenharmony_ci
2077e5b75505Sopenharmony_cistatic int dpp_channel_intersect(struct dpp_authentication *auth,
2078e5b75505Sopenharmony_ci				 struct hostapd_hw_modes *own_modes,
2079e5b75505Sopenharmony_ci				 u16 num_modes)
2080e5b75505Sopenharmony_ci{
2081e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
2082e5b75505Sopenharmony_ci	unsigned int i, freq;
2083e5b75505Sopenharmony_ci
2084e5b75505Sopenharmony_ci	for (i = 0; i < peer_bi->num_freq; i++) {
2085e5b75505Sopenharmony_ci		freq = peer_bi->freq[i];
2086e5b75505Sopenharmony_ci		if (freq_included(auth->freq, auth->num_freq, freq))
2087e5b75505Sopenharmony_ci			continue;
2088e5b75505Sopenharmony_ci		if (dpp_channel_ok_init(own_modes, num_modes, freq))
2089e5b75505Sopenharmony_ci			auth->freq[auth->num_freq++] = freq;
2090e5b75505Sopenharmony_ci	}
2091e5b75505Sopenharmony_ci	if (!auth->num_freq) {
2092e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2093e5b75505Sopenharmony_ci			   "DPP: No available channels for initiating DPP Authentication");
2094e5b75505Sopenharmony_ci		return -1;
2095e5b75505Sopenharmony_ci	}
2096e5b75505Sopenharmony_ci	auth->curr_freq = auth->freq[0];
2097e5b75505Sopenharmony_ci	return 0;
2098e5b75505Sopenharmony_ci}
2099e5b75505Sopenharmony_ci
2100e5b75505Sopenharmony_ci
2101e5b75505Sopenharmony_cistatic int dpp_channel_local_list(struct dpp_authentication *auth,
2102e5b75505Sopenharmony_ci				  struct hostapd_hw_modes *own_modes,
2103e5b75505Sopenharmony_ci				  u16 num_modes)
2104e5b75505Sopenharmony_ci{
2105e5b75505Sopenharmony_ci	u16 m;
2106e5b75505Sopenharmony_ci	int c, flag;
2107e5b75505Sopenharmony_ci	unsigned int freq;
2108e5b75505Sopenharmony_ci
2109e5b75505Sopenharmony_ci	auth->num_freq = 0;
2110e5b75505Sopenharmony_ci
2111e5b75505Sopenharmony_ci	if (!own_modes || !num_modes) {
2112e5b75505Sopenharmony_ci		auth->freq[0] = 2412;
2113e5b75505Sopenharmony_ci		auth->freq[1] = 2437;
2114e5b75505Sopenharmony_ci		auth->freq[2] = 2462;
2115e5b75505Sopenharmony_ci		auth->num_freq = 3;
2116e5b75505Sopenharmony_ci		return 0;
2117e5b75505Sopenharmony_ci	}
2118e5b75505Sopenharmony_ci
2119e5b75505Sopenharmony_ci	for (m = 0; m < num_modes; m++) {
2120e5b75505Sopenharmony_ci		for (c = 0; c < own_modes[m].num_channels; c++) {
2121e5b75505Sopenharmony_ci			freq = own_modes[m].channels[c].freq;
2122e5b75505Sopenharmony_ci			flag = own_modes[m].channels[c].flag;
2123e5b75505Sopenharmony_ci			if (flag & (HOSTAPD_CHAN_DISABLED |
2124e5b75505Sopenharmony_ci				    HOSTAPD_CHAN_NO_IR |
2125e5b75505Sopenharmony_ci				    HOSTAPD_CHAN_RADAR))
2126e5b75505Sopenharmony_ci				continue;
2127e5b75505Sopenharmony_ci			if (freq_included(auth->freq, auth->num_freq, freq))
2128e5b75505Sopenharmony_ci				continue;
2129e5b75505Sopenharmony_ci			auth->freq[auth->num_freq++] = freq;
2130e5b75505Sopenharmony_ci			if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
2131e5b75505Sopenharmony_ci				m = num_modes;
2132e5b75505Sopenharmony_ci				break;
2133e5b75505Sopenharmony_ci			}
2134e5b75505Sopenharmony_ci		}
2135e5b75505Sopenharmony_ci	}
2136e5b75505Sopenharmony_ci
2137e5b75505Sopenharmony_ci	return auth->num_freq == 0 ? -1 : 0;
2138e5b75505Sopenharmony_ci}
2139e5b75505Sopenharmony_ci
2140e5b75505Sopenharmony_ci
2141e5b75505Sopenharmony_cistatic int dpp_prepare_channel_list(struct dpp_authentication *auth,
2142e5b75505Sopenharmony_ci				    struct hostapd_hw_modes *own_modes,
2143e5b75505Sopenharmony_ci				    u16 num_modes)
2144e5b75505Sopenharmony_ci{
2145e5b75505Sopenharmony_ci	int res;
2146e5b75505Sopenharmony_ci	char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
2147e5b75505Sopenharmony_ci	unsigned int i;
2148e5b75505Sopenharmony_ci
2149e5b75505Sopenharmony_ci	if (auth->peer_bi->num_freq > 0)
2150e5b75505Sopenharmony_ci		res = dpp_channel_intersect(auth, own_modes, num_modes);
2151e5b75505Sopenharmony_ci	else
2152e5b75505Sopenharmony_ci		res = dpp_channel_local_list(auth, own_modes, num_modes);
2153e5b75505Sopenharmony_ci	if (res < 0)
2154e5b75505Sopenharmony_ci		return res;
2155e5b75505Sopenharmony_ci
2156e5b75505Sopenharmony_ci	/* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2157e5b75505Sopenharmony_ci	 * likely channels first. */
2158e5b75505Sopenharmony_ci	freq_to_start(auth->freq, auth->num_freq, 2462);
2159e5b75505Sopenharmony_ci	freq_to_start(auth->freq, auth->num_freq, 2412);
2160e5b75505Sopenharmony_ci	freq_to_start(auth->freq, auth->num_freq, 2437);
2161e5b75505Sopenharmony_ci
2162e5b75505Sopenharmony_ci	auth->freq_idx = 0;
2163e5b75505Sopenharmony_ci	auth->curr_freq = auth->freq[0];
2164e5b75505Sopenharmony_ci
2165e5b75505Sopenharmony_ci	pos = freqs;
2166e5b75505Sopenharmony_ci	end = pos + sizeof(freqs);
2167e5b75505Sopenharmony_ci	for (i = 0; i < auth->num_freq; i++) {
2168e5b75505Sopenharmony_ci		res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2169e5b75505Sopenharmony_ci		if (os_snprintf_error(end - pos, res))
2170e5b75505Sopenharmony_ci			break;
2171e5b75505Sopenharmony_ci		pos += res;
2172e5b75505Sopenharmony_ci	}
2173e5b75505Sopenharmony_ci	*pos = '\0';
2174e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2175e5b75505Sopenharmony_ci		   freqs);
2176e5b75505Sopenharmony_ci
2177e5b75505Sopenharmony_ci	return 0;
2178e5b75505Sopenharmony_ci}
2179e5b75505Sopenharmony_ci
2180e5b75505Sopenharmony_ci
2181e5b75505Sopenharmony_cistatic int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2182e5b75505Sopenharmony_ci{
2183e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
2184e5b75505Sopenharmony_ci	char *pk = NULL;
2185e5b75505Sopenharmony_ci	size_t len;
2186e5b75505Sopenharmony_ci
2187e5b75505Sopenharmony_ci	if (auth->own_bi)
2188e5b75505Sopenharmony_ci		return 0; /* already generated */
2189e5b75505Sopenharmony_ci
2190e5b75505Sopenharmony_ci	bi = os_zalloc(sizeof(*bi));
2191e5b75505Sopenharmony_ci	if (!bi)
2192e5b75505Sopenharmony_ci		return -1;
2193e5b75505Sopenharmony_ci	bi->type = DPP_BOOTSTRAP_QR_CODE;
2194e5b75505Sopenharmony_ci	pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
2195e5b75505Sopenharmony_ci	if (!pk)
2196e5b75505Sopenharmony_ci		goto fail;
2197e5b75505Sopenharmony_ci
2198e5b75505Sopenharmony_ci	len = 4; /* "DPP:" */
2199e5b75505Sopenharmony_ci	len += 4 + os_strlen(pk);
2200e5b75505Sopenharmony_ci	bi->uri = os_malloc(len + 1);
2201e5b75505Sopenharmony_ci	if (!bi->uri)
2202e5b75505Sopenharmony_ci		goto fail;
2203e5b75505Sopenharmony_ci	os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
2204e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
2205e5b75505Sopenharmony_ci		   "DPP: Auto-generated own bootstrapping key info: URI %s",
2206e5b75505Sopenharmony_ci		   bi->uri);
2207e5b75505Sopenharmony_ci
2208e5b75505Sopenharmony_ci	auth->tmp_own_bi = auth->own_bi = bi;
2209e5b75505Sopenharmony_ci
2210e5b75505Sopenharmony_ci	os_free(pk);
2211e5b75505Sopenharmony_ci
2212e5b75505Sopenharmony_ci	return 0;
2213e5b75505Sopenharmony_cifail:
2214e5b75505Sopenharmony_ci	os_free(pk);
2215e5b75505Sopenharmony_ci	dpp_bootstrap_info_free(bi);
2216e5b75505Sopenharmony_ci	return -1;
2217e5b75505Sopenharmony_ci}
2218e5b75505Sopenharmony_ci
2219e5b75505Sopenharmony_ci
2220e5b75505Sopenharmony_cistruct dpp_authentication * dpp_auth_init(void *msg_ctx,
2221e5b75505Sopenharmony_ci					  struct dpp_bootstrap_info *peer_bi,
2222e5b75505Sopenharmony_ci					  struct dpp_bootstrap_info *own_bi,
2223e5b75505Sopenharmony_ci					  u8 dpp_allowed_roles,
2224e5b75505Sopenharmony_ci					  unsigned int neg_freq,
2225e5b75505Sopenharmony_ci					  struct hostapd_hw_modes *own_modes,
2226e5b75505Sopenharmony_ci					  u16 num_modes)
2227e5b75505Sopenharmony_ci{
2228e5b75505Sopenharmony_ci	struct dpp_authentication *auth;
2229e5b75505Sopenharmony_ci	size_t nonce_len;
2230e5b75505Sopenharmony_ci	size_t secret_len;
2231e5b75505Sopenharmony_ci	struct wpabuf *pi = NULL;
2232e5b75505Sopenharmony_ci	const u8 *r_pubkey_hash, *i_pubkey_hash;
2233e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2234e5b75505Sopenharmony_ci	u8 test_hash[SHA256_MAC_LEN];
2235e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2236e5b75505Sopenharmony_ci
2237e5b75505Sopenharmony_ci	auth = os_zalloc(sizeof(*auth));
2238e5b75505Sopenharmony_ci	if (!auth)
2239e5b75505Sopenharmony_ci		return NULL;
2240e5b75505Sopenharmony_ci	auth->msg_ctx = msg_ctx;
2241e5b75505Sopenharmony_ci	auth->initiator = 1;
2242e5b75505Sopenharmony_ci	auth->waiting_auth_resp = 1;
2243e5b75505Sopenharmony_ci	auth->allowed_roles = dpp_allowed_roles;
2244e5b75505Sopenharmony_ci	auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
2245e5b75505Sopenharmony_ci	auth->peer_bi = peer_bi;
2246e5b75505Sopenharmony_ci	auth->own_bi = own_bi;
2247e5b75505Sopenharmony_ci	auth->curve = peer_bi->curve;
2248e5b75505Sopenharmony_ci
2249e5b75505Sopenharmony_ci	if (dpp_autogen_bootstrap_key(auth) < 0 ||
2250e5b75505Sopenharmony_ci	    dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
2251e5b75505Sopenharmony_ci		goto fail;
2252e5b75505Sopenharmony_ci
2253e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2254e5b75505Sopenharmony_ci	if (dpp_nonce_override_len > 0) {
2255e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2256e5b75505Sopenharmony_ci		nonce_len = dpp_nonce_override_len;
2257e5b75505Sopenharmony_ci		os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2258e5b75505Sopenharmony_ci	} else {
2259e5b75505Sopenharmony_ci		nonce_len = auth->curve->nonce_len;
2260e5b75505Sopenharmony_ci		if (random_get_bytes(auth->i_nonce, nonce_len)) {
2261e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
2262e5b75505Sopenharmony_ci				   "DPP: Failed to generate I-nonce");
2263e5b75505Sopenharmony_ci			goto fail;
2264e5b75505Sopenharmony_ci		}
2265e5b75505Sopenharmony_ci	}
2266e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
2267e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
2268e5b75505Sopenharmony_ci	if (random_get_bytes(auth->i_nonce, nonce_len)) {
2269e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2270e5b75505Sopenharmony_ci		goto fail;
2271e5b75505Sopenharmony_ci	}
2272e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2273e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2274e5b75505Sopenharmony_ci
2275e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2276e5b75505Sopenharmony_ci	if (dpp_protocol_key_override_len) {
2277e5b75505Sopenharmony_ci		const struct dpp_curve_params *tmp_curve;
2278e5b75505Sopenharmony_ci
2279e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2280e5b75505Sopenharmony_ci			   "DPP: TESTING - override protocol key");
2281e5b75505Sopenharmony_ci		auth->own_protocol_key = dpp_set_keypair(
2282e5b75505Sopenharmony_ci			&tmp_curve, dpp_protocol_key_override,
2283e5b75505Sopenharmony_ci			dpp_protocol_key_override_len);
2284e5b75505Sopenharmony_ci	} else {
2285e5b75505Sopenharmony_ci		auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2286e5b75505Sopenharmony_ci	}
2287e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
2288e5b75505Sopenharmony_ci	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2289e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2290e5b75505Sopenharmony_ci	if (!auth->own_protocol_key)
2291e5b75505Sopenharmony_ci		goto fail;
2292e5b75505Sopenharmony_ci
2293e5b75505Sopenharmony_ci	pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2294e5b75505Sopenharmony_ci	if (!pi)
2295e5b75505Sopenharmony_ci		goto fail;
2296e5b75505Sopenharmony_ci
2297e5b75505Sopenharmony_ci	/* ECDH: M = pI * BR */
2298e5b75505Sopenharmony_ci	if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
2299e5b75505Sopenharmony_ci		     auth->Mx, &secret_len) < 0)
2300e5b75505Sopenharmony_ci		goto fail;
2301e5b75505Sopenharmony_ci	auth->secret_len = secret_len;
2302e5b75505Sopenharmony_ci
2303e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2304e5b75505Sopenharmony_ci			auth->Mx, auth->secret_len);
2305e5b75505Sopenharmony_ci	auth->Mx_len = auth->secret_len;
2306e5b75505Sopenharmony_ci
2307e5b75505Sopenharmony_ci	if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2308e5b75505Sopenharmony_ci			  auth->curve->hash_len) < 0)
2309e5b75505Sopenharmony_ci		goto fail;
2310e5b75505Sopenharmony_ci
2311e5b75505Sopenharmony_ci	r_pubkey_hash = auth->peer_bi->pubkey_hash;
2312e5b75505Sopenharmony_ci	i_pubkey_hash = auth->own_bi->pubkey_hash;
2313e5b75505Sopenharmony_ci
2314e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2315e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2316e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2317e5b75505Sopenharmony_ci		r_pubkey_hash = NULL;
2318e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2319e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2320e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
2321e5b75505Sopenharmony_ci		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2322e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2323e5b75505Sopenharmony_ci		r_pubkey_hash = test_hash;
2324e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2325e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2326e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
2327e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2328e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2329e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
2330e5b75505Sopenharmony_ci		os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2331e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2332e5b75505Sopenharmony_ci		i_pubkey_hash = test_hash;
2333e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2334e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2335e5b75505Sopenharmony_ci		wpabuf_free(pi);
2336e5b75505Sopenharmony_ci		pi = NULL;
2337e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2338e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2339e5b75505Sopenharmony_ci		wpabuf_free(pi);
2340e5b75505Sopenharmony_ci		pi = wpabuf_alloc(2 * auth->curve->prime_len);
2341e5b75505Sopenharmony_ci		if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2342e5b75505Sopenharmony_ci			goto fail;
2343e5b75505Sopenharmony_ci	}
2344e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2345e5b75505Sopenharmony_ci
2346e5b75505Sopenharmony_ci	auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
2347e5b75505Sopenharmony_ci					   i_pubkey_hash, neg_freq);
2348e5b75505Sopenharmony_ci	if (!auth->req_msg)
2349e5b75505Sopenharmony_ci		goto fail;
2350e5b75505Sopenharmony_ci
2351e5b75505Sopenharmony_ciout:
2352e5b75505Sopenharmony_ci	wpabuf_free(pi);
2353e5b75505Sopenharmony_ci	return auth;
2354e5b75505Sopenharmony_cifail:
2355e5b75505Sopenharmony_ci	dpp_auth_deinit(auth);
2356e5b75505Sopenharmony_ci	auth = NULL;
2357e5b75505Sopenharmony_ci	goto out;
2358e5b75505Sopenharmony_ci}
2359e5b75505Sopenharmony_ci
2360e5b75505Sopenharmony_ci
2361e5b75505Sopenharmony_cistatic struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
2362e5b75505Sopenharmony_ci					       const char *json)
2363e5b75505Sopenharmony_ci{
2364e5b75505Sopenharmony_ci	size_t nonce_len;
2365e5b75505Sopenharmony_ci	size_t json_len, clear_len;
2366e5b75505Sopenharmony_ci	struct wpabuf *clear = NULL, *msg = NULL;
2367e5b75505Sopenharmony_ci	u8 *wrapped;
2368e5b75505Sopenharmony_ci	size_t attr_len;
2369e5b75505Sopenharmony_ci
2370e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2371e5b75505Sopenharmony_ci
2372e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
2373e5b75505Sopenharmony_ci	if (random_get_bytes(auth->e_nonce, nonce_len)) {
2374e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2375e5b75505Sopenharmony_ci		goto fail;
2376e5b75505Sopenharmony_ci	}
2377e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2378e5b75505Sopenharmony_ci	json_len = os_strlen(json);
2379e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
2380e5b75505Sopenharmony_ci
2381e5b75505Sopenharmony_ci	/* { E-nonce, configAttrib }ke */
2382e5b75505Sopenharmony_ci	clear_len = 4 + nonce_len + 4 + json_len;
2383e5b75505Sopenharmony_ci	clear = wpabuf_alloc(clear_len);
2384e5b75505Sopenharmony_ci	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2385e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2386e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
2387e5b75505Sopenharmony_ci		attr_len += 5;
2388e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2389e5b75505Sopenharmony_ci	msg = wpabuf_alloc(attr_len);
2390e5b75505Sopenharmony_ci	if (!clear || !msg)
2391e5b75505Sopenharmony_ci		goto fail;
2392e5b75505Sopenharmony_ci
2393e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2394e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2395e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2396e5b75505Sopenharmony_ci		goto skip_e_nonce;
2397e5b75505Sopenharmony_ci	}
2398e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2399e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2400e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2401e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, nonce_len - 1);
2402e5b75505Sopenharmony_ci		wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2403e5b75505Sopenharmony_ci		goto skip_e_nonce;
2404e5b75505Sopenharmony_ci	}
2405e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2406e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2407e5b75505Sopenharmony_ci		goto skip_wrapped_data;
2408e5b75505Sopenharmony_ci	}
2409e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2410e5b75505Sopenharmony_ci
2411e5b75505Sopenharmony_ci	/* E-nonce */
2412e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2413e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, nonce_len);
2414e5b75505Sopenharmony_ci	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2415e5b75505Sopenharmony_ci
2416e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2417e5b75505Sopenharmony_ciskip_e_nonce:
2418e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2419e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2420e5b75505Sopenharmony_ci		goto skip_conf_attr_obj;
2421e5b75505Sopenharmony_ci	}
2422e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2423e5b75505Sopenharmony_ci
2424e5b75505Sopenharmony_ci	/* configAttrib */
2425e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2426e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, json_len);
2427e5b75505Sopenharmony_ci	wpabuf_put_data(clear, json, json_len);
2428e5b75505Sopenharmony_ci
2429e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2430e5b75505Sopenharmony_ciskip_conf_attr_obj:
2431e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2432e5b75505Sopenharmony_ci
2433e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2434e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2435e5b75505Sopenharmony_ci	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2436e5b75505Sopenharmony_ci
2437e5b75505Sopenharmony_ci	/* No AES-SIV AD */
2438e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2439e5b75505Sopenharmony_ci	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2440e5b75505Sopenharmony_ci			    wpabuf_head(clear), wpabuf_len(clear),
2441e5b75505Sopenharmony_ci			    0, NULL, NULL, wrapped) < 0)
2442e5b75505Sopenharmony_ci		goto fail;
2443e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2444e5b75505Sopenharmony_ci		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2445e5b75505Sopenharmony_ci
2446e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2447e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2448e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2449e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
2450e5b75505Sopenharmony_ci	}
2451e5b75505Sopenharmony_ciskip_wrapped_data:
2452e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2453e5b75505Sopenharmony_ci
2454e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG,
2455e5b75505Sopenharmony_ci			"DPP: Configuration Request frame attributes", msg);
2456e5b75505Sopenharmony_ci	wpabuf_free(clear);
2457e5b75505Sopenharmony_ci	return msg;
2458e5b75505Sopenharmony_ci
2459e5b75505Sopenharmony_cifail:
2460e5b75505Sopenharmony_ci	wpabuf_free(clear);
2461e5b75505Sopenharmony_ci	wpabuf_free(msg);
2462e5b75505Sopenharmony_ci	return NULL;
2463e5b75505Sopenharmony_ci}
2464e5b75505Sopenharmony_ci
2465e5b75505Sopenharmony_ci
2466e5b75505Sopenharmony_cistatic void dpp_write_adv_proto(struct wpabuf *buf)
2467e5b75505Sopenharmony_ci{
2468e5b75505Sopenharmony_ci	/* Advertisement Protocol IE */
2469e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2470e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 8); /* Length */
2471e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0x7f);
2472e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2473e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 5);
2474e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_WFA);
2475e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, DPP_OUI_TYPE);
2476e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0x01);
2477e5b75505Sopenharmony_ci}
2478e5b75505Sopenharmony_ci
2479e5b75505Sopenharmony_ci
2480e5b75505Sopenharmony_cistatic void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
2481e5b75505Sopenharmony_ci{
2482e5b75505Sopenharmony_ci	/* GAS Query */
2483e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, wpabuf_len(query));
2484e5b75505Sopenharmony_ci	wpabuf_put_buf(buf, query);
2485e5b75505Sopenharmony_ci}
2486e5b75505Sopenharmony_ci
2487e5b75505Sopenharmony_ci
2488e5b75505Sopenharmony_cistruct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2489e5b75505Sopenharmony_ci				   const char *json)
2490e5b75505Sopenharmony_ci{
2491e5b75505Sopenharmony_ci	struct wpabuf *buf, *conf_req;
2492e5b75505Sopenharmony_ci
2493e5b75505Sopenharmony_ci	conf_req = dpp_build_conf_req_attr(auth, json);
2494e5b75505Sopenharmony_ci	if (!conf_req) {
2495e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
2496e5b75505Sopenharmony_ci			   "DPP: No configuration request data available");
2497e5b75505Sopenharmony_ci		return NULL;
2498e5b75505Sopenharmony_ci	}
2499e5b75505Sopenharmony_ci
2500e5b75505Sopenharmony_ci	buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
2501e5b75505Sopenharmony_ci	if (!buf) {
2502e5b75505Sopenharmony_ci		wpabuf_free(conf_req);
2503e5b75505Sopenharmony_ci		return NULL;
2504e5b75505Sopenharmony_ci	}
2505e5b75505Sopenharmony_ci
2506e5b75505Sopenharmony_ci	dpp_write_adv_proto(buf);
2507e5b75505Sopenharmony_ci	dpp_write_gas_query(buf, conf_req);
2508e5b75505Sopenharmony_ci	wpabuf_free(conf_req);
2509e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
2510e5b75505Sopenharmony_ci
2511e5b75505Sopenharmony_ci	return buf;
2512e5b75505Sopenharmony_ci}
2513e5b75505Sopenharmony_ci
2514e5b75505Sopenharmony_ci
2515e5b75505Sopenharmony_cistatic void dpp_auth_success(struct dpp_authentication *auth)
2516e5b75505Sopenharmony_ci{
2517e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
2518e5b75505Sopenharmony_ci		   "DPP: Authentication success - clear temporary keys");
2519e5b75505Sopenharmony_ci	os_memset(auth->Mx, 0, sizeof(auth->Mx));
2520e5b75505Sopenharmony_ci	auth->Mx_len = 0;
2521e5b75505Sopenharmony_ci	os_memset(auth->Nx, 0, sizeof(auth->Nx));
2522e5b75505Sopenharmony_ci	auth->Nx_len = 0;
2523e5b75505Sopenharmony_ci	os_memset(auth->Lx, 0, sizeof(auth->Lx));
2524e5b75505Sopenharmony_ci	auth->Lx_len = 0;
2525e5b75505Sopenharmony_ci	os_memset(auth->k1, 0, sizeof(auth->k1));
2526e5b75505Sopenharmony_ci	os_memset(auth->k2, 0, sizeof(auth->k2));
2527e5b75505Sopenharmony_ci
2528e5b75505Sopenharmony_ci	auth->auth_success = 1;
2529e5b75505Sopenharmony_ci}
2530e5b75505Sopenharmony_ci
2531e5b75505Sopenharmony_ci
2532e5b75505Sopenharmony_cistatic int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2533e5b75505Sopenharmony_ci{
2534e5b75505Sopenharmony_ci	struct wpabuf *pix, *prx, *bix, *brx;
2535e5b75505Sopenharmony_ci	const u8 *addr[7];
2536e5b75505Sopenharmony_ci	size_t len[7];
2537e5b75505Sopenharmony_ci	size_t i, num_elem = 0;
2538e5b75505Sopenharmony_ci	size_t nonce_len;
2539e5b75505Sopenharmony_ci	u8 zero = 0;
2540e5b75505Sopenharmony_ci	int res = -1;
2541e5b75505Sopenharmony_ci
2542e5b75505Sopenharmony_ci	/* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2543e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
2544e5b75505Sopenharmony_ci
2545e5b75505Sopenharmony_ci	if (auth->initiator) {
2546e5b75505Sopenharmony_ci		pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2547e5b75505Sopenharmony_ci		prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2548e5b75505Sopenharmony_ci		if (auth->own_bi)
2549e5b75505Sopenharmony_ci			bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2550e5b75505Sopenharmony_ci		else
2551e5b75505Sopenharmony_ci			bix = NULL;
2552e5b75505Sopenharmony_ci		brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2553e5b75505Sopenharmony_ci	} else {
2554e5b75505Sopenharmony_ci		pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2555e5b75505Sopenharmony_ci		prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2556e5b75505Sopenharmony_ci		if (auth->peer_bi)
2557e5b75505Sopenharmony_ci			bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2558e5b75505Sopenharmony_ci		else
2559e5b75505Sopenharmony_ci			bix = NULL;
2560e5b75505Sopenharmony_ci		brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2561e5b75505Sopenharmony_ci	}
2562e5b75505Sopenharmony_ci	if (!pix || !prx || !brx)
2563e5b75505Sopenharmony_ci		goto fail;
2564e5b75505Sopenharmony_ci
2565e5b75505Sopenharmony_ci	addr[num_elem] = auth->i_nonce;
2566e5b75505Sopenharmony_ci	len[num_elem] = nonce_len;
2567e5b75505Sopenharmony_ci	num_elem++;
2568e5b75505Sopenharmony_ci
2569e5b75505Sopenharmony_ci	addr[num_elem] = auth->r_nonce;
2570e5b75505Sopenharmony_ci	len[num_elem] = nonce_len;
2571e5b75505Sopenharmony_ci	num_elem++;
2572e5b75505Sopenharmony_ci
2573e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(pix);
2574e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(pix) / 2;
2575e5b75505Sopenharmony_ci	num_elem++;
2576e5b75505Sopenharmony_ci
2577e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(prx);
2578e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(prx) / 2;
2579e5b75505Sopenharmony_ci	num_elem++;
2580e5b75505Sopenharmony_ci
2581e5b75505Sopenharmony_ci	if (bix) {
2582e5b75505Sopenharmony_ci		addr[num_elem] = wpabuf_head(bix);
2583e5b75505Sopenharmony_ci		len[num_elem] = wpabuf_len(bix) / 2;
2584e5b75505Sopenharmony_ci		num_elem++;
2585e5b75505Sopenharmony_ci	}
2586e5b75505Sopenharmony_ci
2587e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(brx);
2588e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(brx) / 2;
2589e5b75505Sopenharmony_ci	num_elem++;
2590e5b75505Sopenharmony_ci
2591e5b75505Sopenharmony_ci	addr[num_elem] = &zero;
2592e5b75505Sopenharmony_ci	len[num_elem] = 1;
2593e5b75505Sopenharmony_ci	num_elem++;
2594e5b75505Sopenharmony_ci
2595e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2596e5b75505Sopenharmony_ci	for (i = 0; i < num_elem; i++)
2597e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2598e5b75505Sopenharmony_ci	res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
2599e5b75505Sopenharmony_ci	if (res == 0)
2600e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2601e5b75505Sopenharmony_ci			    auth->curve->hash_len);
2602e5b75505Sopenharmony_cifail:
2603e5b75505Sopenharmony_ci	wpabuf_free(pix);
2604e5b75505Sopenharmony_ci	wpabuf_free(prx);
2605e5b75505Sopenharmony_ci	wpabuf_free(bix);
2606e5b75505Sopenharmony_ci	wpabuf_free(brx);
2607e5b75505Sopenharmony_ci	return res;
2608e5b75505Sopenharmony_ci}
2609e5b75505Sopenharmony_ci
2610e5b75505Sopenharmony_ci
2611e5b75505Sopenharmony_cistatic int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2612e5b75505Sopenharmony_ci{
2613e5b75505Sopenharmony_ci	struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2614e5b75505Sopenharmony_ci	const u8 *addr[7];
2615e5b75505Sopenharmony_ci	size_t len[7];
2616e5b75505Sopenharmony_ci	size_t i, num_elem = 0;
2617e5b75505Sopenharmony_ci	size_t nonce_len;
2618e5b75505Sopenharmony_ci	u8 one = 1;
2619e5b75505Sopenharmony_ci	int res = -1;
2620e5b75505Sopenharmony_ci
2621e5b75505Sopenharmony_ci	/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2622e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
2623e5b75505Sopenharmony_ci
2624e5b75505Sopenharmony_ci	if (auth->initiator) {
2625e5b75505Sopenharmony_ci		pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2626e5b75505Sopenharmony_ci		prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2627e5b75505Sopenharmony_ci		if (auth->own_bi)
2628e5b75505Sopenharmony_ci			bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2629e5b75505Sopenharmony_ci		else
2630e5b75505Sopenharmony_ci			bix = NULL;
2631e5b75505Sopenharmony_ci		if (!auth->peer_bi)
2632e5b75505Sopenharmony_ci			goto fail;
2633e5b75505Sopenharmony_ci		brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2634e5b75505Sopenharmony_ci	} else {
2635e5b75505Sopenharmony_ci		pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2636e5b75505Sopenharmony_ci		prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2637e5b75505Sopenharmony_ci		if (auth->peer_bi)
2638e5b75505Sopenharmony_ci			bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2639e5b75505Sopenharmony_ci		else
2640e5b75505Sopenharmony_ci			bix = NULL;
2641e5b75505Sopenharmony_ci		if (!auth->own_bi)
2642e5b75505Sopenharmony_ci			goto fail;
2643e5b75505Sopenharmony_ci		brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2644e5b75505Sopenharmony_ci	}
2645e5b75505Sopenharmony_ci	if (!pix || !prx || !brx)
2646e5b75505Sopenharmony_ci		goto fail;
2647e5b75505Sopenharmony_ci
2648e5b75505Sopenharmony_ci	addr[num_elem] = auth->r_nonce;
2649e5b75505Sopenharmony_ci	len[num_elem] = nonce_len;
2650e5b75505Sopenharmony_ci	num_elem++;
2651e5b75505Sopenharmony_ci
2652e5b75505Sopenharmony_ci	addr[num_elem] = auth->i_nonce;
2653e5b75505Sopenharmony_ci	len[num_elem] = nonce_len;
2654e5b75505Sopenharmony_ci	num_elem++;
2655e5b75505Sopenharmony_ci
2656e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(prx);
2657e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(prx) / 2;
2658e5b75505Sopenharmony_ci	num_elem++;
2659e5b75505Sopenharmony_ci
2660e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(pix);
2661e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(pix) / 2;
2662e5b75505Sopenharmony_ci	num_elem++;
2663e5b75505Sopenharmony_ci
2664e5b75505Sopenharmony_ci	addr[num_elem] = wpabuf_head(brx);
2665e5b75505Sopenharmony_ci	len[num_elem] = wpabuf_len(brx) / 2;
2666e5b75505Sopenharmony_ci	num_elem++;
2667e5b75505Sopenharmony_ci
2668e5b75505Sopenharmony_ci	if (bix) {
2669e5b75505Sopenharmony_ci		addr[num_elem] = wpabuf_head(bix);
2670e5b75505Sopenharmony_ci		len[num_elem] = wpabuf_len(bix) / 2;
2671e5b75505Sopenharmony_ci		num_elem++;
2672e5b75505Sopenharmony_ci	}
2673e5b75505Sopenharmony_ci
2674e5b75505Sopenharmony_ci	addr[num_elem] = &one;
2675e5b75505Sopenharmony_ci	len[num_elem] = 1;
2676e5b75505Sopenharmony_ci	num_elem++;
2677e5b75505Sopenharmony_ci
2678e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2679e5b75505Sopenharmony_ci	for (i = 0; i < num_elem; i++)
2680e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2681e5b75505Sopenharmony_ci	res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2682e5b75505Sopenharmony_ci	if (res == 0)
2683e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2684e5b75505Sopenharmony_ci			    auth->curve->hash_len);
2685e5b75505Sopenharmony_cifail:
2686e5b75505Sopenharmony_ci	wpabuf_free(pix);
2687e5b75505Sopenharmony_ci	wpabuf_free(prx);
2688e5b75505Sopenharmony_ci	wpabuf_free(bix);
2689e5b75505Sopenharmony_ci	wpabuf_free(brx);
2690e5b75505Sopenharmony_ci	return res;
2691e5b75505Sopenharmony_ci}
2692e5b75505Sopenharmony_ci
2693e5b75505Sopenharmony_ci
2694e5b75505Sopenharmony_cistatic int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2695e5b75505Sopenharmony_ci{
2696e5b75505Sopenharmony_ci	const EC_GROUP *group;
2697e5b75505Sopenharmony_ci	EC_POINT *l = NULL;
2698e5b75505Sopenharmony_ci	EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2699e5b75505Sopenharmony_ci	const EC_POINT *BI_point;
2700e5b75505Sopenharmony_ci	BN_CTX *bnctx;
2701e5b75505Sopenharmony_ci	BIGNUM *lx, *sum, *q;
2702e5b75505Sopenharmony_ci	const BIGNUM *bR_bn, *pR_bn;
2703e5b75505Sopenharmony_ci	int ret = -1;
2704e5b75505Sopenharmony_ci
2705e5b75505Sopenharmony_ci	/* L = ((bR + pR) modulo q) * BI */
2706e5b75505Sopenharmony_ci
2707e5b75505Sopenharmony_ci	bnctx = BN_CTX_new();
2708e5b75505Sopenharmony_ci	sum = BN_new();
2709e5b75505Sopenharmony_ci	q = BN_new();
2710e5b75505Sopenharmony_ci	lx = BN_new();
2711e5b75505Sopenharmony_ci	if (!bnctx || !sum || !q || !lx)
2712e5b75505Sopenharmony_ci		goto fail;
2713e5b75505Sopenharmony_ci	BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2714e5b75505Sopenharmony_ci	if (!BI)
2715e5b75505Sopenharmony_ci		goto fail;
2716e5b75505Sopenharmony_ci	BI_point = EC_KEY_get0_public_key(BI);
2717e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(BI);
2718e5b75505Sopenharmony_ci	if (!group)
2719e5b75505Sopenharmony_ci		goto fail;
2720e5b75505Sopenharmony_ci
2721e5b75505Sopenharmony_ci	bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2722e5b75505Sopenharmony_ci	pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2723e5b75505Sopenharmony_ci	if (!bR || !pR)
2724e5b75505Sopenharmony_ci		goto fail;
2725e5b75505Sopenharmony_ci	bR_bn = EC_KEY_get0_private_key(bR);
2726e5b75505Sopenharmony_ci	pR_bn = EC_KEY_get0_private_key(pR);
2727e5b75505Sopenharmony_ci	if (!bR_bn || !pR_bn)
2728e5b75505Sopenharmony_ci		goto fail;
2729e5b75505Sopenharmony_ci	if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2730e5b75505Sopenharmony_ci	    BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2731e5b75505Sopenharmony_ci		goto fail;
2732e5b75505Sopenharmony_ci	l = EC_POINT_new(group);
2733e5b75505Sopenharmony_ci	if (!l ||
2734e5b75505Sopenharmony_ci	    EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2735e5b75505Sopenharmony_ci	    EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2736e5b75505Sopenharmony_ci						bnctx) != 1) {
2737e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
2738e5b75505Sopenharmony_ci			   "OpenSSL: failed: %s",
2739e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
2740e5b75505Sopenharmony_ci		goto fail;
2741e5b75505Sopenharmony_ci	}
2742e5b75505Sopenharmony_ci
2743e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2744e5b75505Sopenharmony_ci		goto fail;
2745e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2746e5b75505Sopenharmony_ci	auth->Lx_len = auth->secret_len;
2747e5b75505Sopenharmony_ci	ret = 0;
2748e5b75505Sopenharmony_cifail:
2749e5b75505Sopenharmony_ci	EC_POINT_clear_free(l);
2750e5b75505Sopenharmony_ci	EC_KEY_free(BI);
2751e5b75505Sopenharmony_ci	EC_KEY_free(bR);
2752e5b75505Sopenharmony_ci	EC_KEY_free(pR);
2753e5b75505Sopenharmony_ci	BN_clear_free(lx);
2754e5b75505Sopenharmony_ci	BN_clear_free(sum);
2755e5b75505Sopenharmony_ci	BN_free(q);
2756e5b75505Sopenharmony_ci	BN_CTX_free(bnctx);
2757e5b75505Sopenharmony_ci	return ret;
2758e5b75505Sopenharmony_ci}
2759e5b75505Sopenharmony_ci
2760e5b75505Sopenharmony_ci
2761e5b75505Sopenharmony_cistatic int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2762e5b75505Sopenharmony_ci{
2763e5b75505Sopenharmony_ci	const EC_GROUP *group;
2764e5b75505Sopenharmony_ci	EC_POINT *l = NULL, *sum = NULL;
2765e5b75505Sopenharmony_ci	EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2766e5b75505Sopenharmony_ci	const EC_POINT *BR_point, *PR_point;
2767e5b75505Sopenharmony_ci	BN_CTX *bnctx;
2768e5b75505Sopenharmony_ci	BIGNUM *lx;
2769e5b75505Sopenharmony_ci	const BIGNUM *bI_bn;
2770e5b75505Sopenharmony_ci	int ret = -1;
2771e5b75505Sopenharmony_ci
2772e5b75505Sopenharmony_ci	/* L = bI * (BR + PR) */
2773e5b75505Sopenharmony_ci
2774e5b75505Sopenharmony_ci	bnctx = BN_CTX_new();
2775e5b75505Sopenharmony_ci	lx = BN_new();
2776e5b75505Sopenharmony_ci	if (!bnctx || !lx)
2777e5b75505Sopenharmony_ci		goto fail;
2778e5b75505Sopenharmony_ci	BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2779e5b75505Sopenharmony_ci	PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2780e5b75505Sopenharmony_ci	if (!BR || !PR)
2781e5b75505Sopenharmony_ci		goto fail;
2782e5b75505Sopenharmony_ci	BR_point = EC_KEY_get0_public_key(BR);
2783e5b75505Sopenharmony_ci	PR_point = EC_KEY_get0_public_key(PR);
2784e5b75505Sopenharmony_ci
2785e5b75505Sopenharmony_ci	bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2786e5b75505Sopenharmony_ci	if (!bI)
2787e5b75505Sopenharmony_ci		goto fail;
2788e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(bI);
2789e5b75505Sopenharmony_ci	bI_bn = EC_KEY_get0_private_key(bI);
2790e5b75505Sopenharmony_ci	if (!group || !bI_bn)
2791e5b75505Sopenharmony_ci		goto fail;
2792e5b75505Sopenharmony_ci	sum = EC_POINT_new(group);
2793e5b75505Sopenharmony_ci	l = EC_POINT_new(group);
2794e5b75505Sopenharmony_ci	if (!sum || !l ||
2795e5b75505Sopenharmony_ci	    EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2796e5b75505Sopenharmony_ci	    EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2797e5b75505Sopenharmony_ci	    EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2798e5b75505Sopenharmony_ci						bnctx) != 1) {
2799e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
2800e5b75505Sopenharmony_ci			   "OpenSSL: failed: %s",
2801e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
2802e5b75505Sopenharmony_ci		goto fail;
2803e5b75505Sopenharmony_ci	}
2804e5b75505Sopenharmony_ci
2805e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2806e5b75505Sopenharmony_ci		goto fail;
2807e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2808e5b75505Sopenharmony_ci	auth->Lx_len = auth->secret_len;
2809e5b75505Sopenharmony_ci	ret = 0;
2810e5b75505Sopenharmony_cifail:
2811e5b75505Sopenharmony_ci	EC_POINT_clear_free(l);
2812e5b75505Sopenharmony_ci	EC_POINT_clear_free(sum);
2813e5b75505Sopenharmony_ci	EC_KEY_free(bI);
2814e5b75505Sopenharmony_ci	EC_KEY_free(BR);
2815e5b75505Sopenharmony_ci	EC_KEY_free(PR);
2816e5b75505Sopenharmony_ci	BN_clear_free(lx);
2817e5b75505Sopenharmony_ci	BN_CTX_free(bnctx);
2818e5b75505Sopenharmony_ci	return ret;
2819e5b75505Sopenharmony_ci}
2820e5b75505Sopenharmony_ci
2821e5b75505Sopenharmony_ci
2822e5b75505Sopenharmony_cistatic int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
2823e5b75505Sopenharmony_ci{
2824e5b75505Sopenharmony_ci	size_t nonce_len;
2825e5b75505Sopenharmony_ci	size_t secret_len;
2826e5b75505Sopenharmony_ci	struct wpabuf *msg, *pr = NULL;
2827e5b75505Sopenharmony_ci	u8 r_auth[4 + DPP_MAX_HASH_LEN];
2828e5b75505Sopenharmony_ci	u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
2829e5b75505Sopenharmony_ci	size_t wrapped_r_auth_len;
2830e5b75505Sopenharmony_ci	int ret = -1;
2831e5b75505Sopenharmony_ci	const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2832e5b75505Sopenharmony_ci	enum dpp_status_error status = DPP_STATUS_OK;
2833e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2834e5b75505Sopenharmony_ci	u8 test_hash[SHA256_MAC_LEN];
2835e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2836e5b75505Sopenharmony_ci
2837e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2838e5b75505Sopenharmony_ci	if (!auth->own_bi)
2839e5b75505Sopenharmony_ci		return -1;
2840e5b75505Sopenharmony_ci
2841e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2842e5b75505Sopenharmony_ci	if (dpp_nonce_override_len > 0) {
2843e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
2844e5b75505Sopenharmony_ci		nonce_len = dpp_nonce_override_len;
2845e5b75505Sopenharmony_ci		os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
2846e5b75505Sopenharmony_ci	} else {
2847e5b75505Sopenharmony_ci		nonce_len = auth->curve->nonce_len;
2848e5b75505Sopenharmony_ci		if (random_get_bytes(auth->r_nonce, nonce_len)) {
2849e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
2850e5b75505Sopenharmony_ci				   "DPP: Failed to generate R-nonce");
2851e5b75505Sopenharmony_ci			goto fail;
2852e5b75505Sopenharmony_ci		}
2853e5b75505Sopenharmony_ci	}
2854e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
2855e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
2856e5b75505Sopenharmony_ci	if (random_get_bytes(auth->r_nonce, nonce_len)) {
2857e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2858e5b75505Sopenharmony_ci		goto fail;
2859e5b75505Sopenharmony_ci	}
2860e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2861e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2862e5b75505Sopenharmony_ci
2863e5b75505Sopenharmony_ci	EVP_PKEY_free(auth->own_protocol_key);
2864e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2865e5b75505Sopenharmony_ci	if (dpp_protocol_key_override_len) {
2866e5b75505Sopenharmony_ci		const struct dpp_curve_params *tmp_curve;
2867e5b75505Sopenharmony_ci
2868e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2869e5b75505Sopenharmony_ci			   "DPP: TESTING - override protocol key");
2870e5b75505Sopenharmony_ci		auth->own_protocol_key = dpp_set_keypair(
2871e5b75505Sopenharmony_ci			&tmp_curve, dpp_protocol_key_override,
2872e5b75505Sopenharmony_ci			dpp_protocol_key_override_len);
2873e5b75505Sopenharmony_ci	} else {
2874e5b75505Sopenharmony_ci		auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2875e5b75505Sopenharmony_ci	}
2876e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
2877e5b75505Sopenharmony_ci	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2878e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2879e5b75505Sopenharmony_ci	if (!auth->own_protocol_key)
2880e5b75505Sopenharmony_ci		goto fail;
2881e5b75505Sopenharmony_ci
2882e5b75505Sopenharmony_ci	pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2883e5b75505Sopenharmony_ci	if (!pr)
2884e5b75505Sopenharmony_ci		goto fail;
2885e5b75505Sopenharmony_ci
2886e5b75505Sopenharmony_ci	/* ECDH: N = pR * PI */
2887e5b75505Sopenharmony_ci	if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
2888e5b75505Sopenharmony_ci		     auth->Nx, &secret_len) < 0)
2889e5b75505Sopenharmony_ci		goto fail;
2890e5b75505Sopenharmony_ci
2891e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2892e5b75505Sopenharmony_ci			auth->Nx, auth->secret_len);
2893e5b75505Sopenharmony_ci	auth->Nx_len = auth->secret_len;
2894e5b75505Sopenharmony_ci
2895e5b75505Sopenharmony_ci	if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2896e5b75505Sopenharmony_ci			  auth->curve->hash_len) < 0)
2897e5b75505Sopenharmony_ci		goto fail;
2898e5b75505Sopenharmony_ci
2899e5b75505Sopenharmony_ci	if (auth->own_bi && auth->peer_bi) {
2900e5b75505Sopenharmony_ci		/* Mutual authentication */
2901e5b75505Sopenharmony_ci		if (dpp_auth_derive_l_responder(auth) < 0)
2902e5b75505Sopenharmony_ci			goto fail;
2903e5b75505Sopenharmony_ci	}
2904e5b75505Sopenharmony_ci
2905e5b75505Sopenharmony_ci	if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2906e5b75505Sopenharmony_ci		goto fail;
2907e5b75505Sopenharmony_ci
2908e5b75505Sopenharmony_ci	/* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2909e5b75505Sopenharmony_ci	WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2910e5b75505Sopenharmony_ci	WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
2911e5b75505Sopenharmony_ci	if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2912e5b75505Sopenharmony_ci		goto fail;
2913e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2914e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2915e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2916e5b75505Sopenharmony_ci		r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2917e5b75505Sopenharmony_ci	}
2918e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2919e5b75505Sopenharmony_ci	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2920e5b75505Sopenharmony_ci			    r_auth, 4 + auth->curve->hash_len,
2921e5b75505Sopenharmony_ci			    0, NULL, NULL, wrapped_r_auth) < 0)
2922e5b75505Sopenharmony_ci		goto fail;
2923e5b75505Sopenharmony_ci	wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2924e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2925e5b75505Sopenharmony_ci		    wrapped_r_auth, wrapped_r_auth_len);
2926e5b75505Sopenharmony_ci	w_r_auth = wrapped_r_auth;
2927e5b75505Sopenharmony_ci
2928e5b75505Sopenharmony_ci	r_pubkey_hash = auth->own_bi->pubkey_hash;
2929e5b75505Sopenharmony_ci	if (auth->peer_bi)
2930e5b75505Sopenharmony_ci		i_pubkey_hash = auth->peer_bi->pubkey_hash;
2931e5b75505Sopenharmony_ci	else
2932e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
2933e5b75505Sopenharmony_ci
2934e5b75505Sopenharmony_ci	i_nonce = auth->i_nonce;
2935e5b75505Sopenharmony_ci	r_nonce = auth->r_nonce;
2936e5b75505Sopenharmony_ci
2937e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
2938e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2939e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2940e5b75505Sopenharmony_ci		r_pubkey_hash = NULL;
2941e5b75505Sopenharmony_ci	} else if (dpp_test ==
2942e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2943e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2944e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
2945e5b75505Sopenharmony_ci		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2946e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2947e5b75505Sopenharmony_ci		r_pubkey_hash = test_hash;
2948e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2949e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2950e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
2951e5b75505Sopenharmony_ci	} else if (dpp_test ==
2952e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2953e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
2954e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
2955e5b75505Sopenharmony_ci		if (i_pubkey_hash)
2956e5b75505Sopenharmony_ci			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2957e5b75505Sopenharmony_ci		else
2958e5b75505Sopenharmony_ci			os_memset(test_hash, 0, SHA256_MAC_LEN);
2959e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2960e5b75505Sopenharmony_ci		i_pubkey_hash = test_hash;
2961e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2962e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2963e5b75505Sopenharmony_ci		wpabuf_free(pr);
2964e5b75505Sopenharmony_ci		pr = NULL;
2965e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2966e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2967e5b75505Sopenharmony_ci		wpabuf_free(pr);
2968e5b75505Sopenharmony_ci		pr = wpabuf_alloc(2 * auth->curve->prime_len);
2969e5b75505Sopenharmony_ci		if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2970e5b75505Sopenharmony_ci			goto fail;
2971e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2972e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2973e5b75505Sopenharmony_ci		w_r_auth = NULL;
2974e5b75505Sopenharmony_ci		wrapped_r_auth_len = 0;
2975e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2976e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2977e5b75505Sopenharmony_ci		status = 255;
2978e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2979e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2980e5b75505Sopenharmony_ci		status = 254;
2981e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2982e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2983e5b75505Sopenharmony_ci		r_nonce = NULL;
2984e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2985e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2986e5b75505Sopenharmony_ci		i_nonce = NULL;
2987e5b75505Sopenharmony_ci	}
2988e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
2989e5b75505Sopenharmony_ci
2990e5b75505Sopenharmony_ci	msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2991e5b75505Sopenharmony_ci				  r_pubkey_hash, i_pubkey_hash,
2992e5b75505Sopenharmony_ci				  r_nonce, i_nonce,
2993e5b75505Sopenharmony_ci				  w_r_auth, wrapped_r_auth_len,
2994e5b75505Sopenharmony_ci				  auth->k2);
2995e5b75505Sopenharmony_ci	if (!msg)
2996e5b75505Sopenharmony_ci		goto fail;
2997e5b75505Sopenharmony_ci	wpabuf_free(auth->resp_msg);
2998e5b75505Sopenharmony_ci	auth->resp_msg = msg;
2999e5b75505Sopenharmony_ci	ret = 0;
3000e5b75505Sopenharmony_cifail:
3001e5b75505Sopenharmony_ci	wpabuf_free(pr);
3002e5b75505Sopenharmony_ci	return ret;
3003e5b75505Sopenharmony_ci}
3004e5b75505Sopenharmony_ci
3005e5b75505Sopenharmony_ci
3006e5b75505Sopenharmony_cistatic int dpp_auth_build_resp_status(struct dpp_authentication *auth,
3007e5b75505Sopenharmony_ci				      enum dpp_status_error status)
3008e5b75505Sopenharmony_ci{
3009e5b75505Sopenharmony_ci	struct wpabuf *msg;
3010e5b75505Sopenharmony_ci	const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
3011e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3012e5b75505Sopenharmony_ci	u8 test_hash[SHA256_MAC_LEN];
3013e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3014e5b75505Sopenharmony_ci
3015e5b75505Sopenharmony_ci	if (!auth->own_bi)
3016e5b75505Sopenharmony_ci		return -1;
3017e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
3018e5b75505Sopenharmony_ci
3019e5b75505Sopenharmony_ci	r_pubkey_hash = auth->own_bi->pubkey_hash;
3020e5b75505Sopenharmony_ci	if (auth->peer_bi)
3021e5b75505Sopenharmony_ci		i_pubkey_hash = auth->peer_bi->pubkey_hash;
3022e5b75505Sopenharmony_ci	else
3023e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
3024e5b75505Sopenharmony_ci
3025e5b75505Sopenharmony_ci	i_nonce = auth->i_nonce;
3026e5b75505Sopenharmony_ci
3027e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3028e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3029e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3030e5b75505Sopenharmony_ci		r_pubkey_hash = NULL;
3031e5b75505Sopenharmony_ci	} else if (dpp_test ==
3032e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3033e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3034e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
3035e5b75505Sopenharmony_ci		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3036e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3037e5b75505Sopenharmony_ci		r_pubkey_hash = test_hash;
3038e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3039e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3040e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
3041e5b75505Sopenharmony_ci	} else if (dpp_test ==
3042e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3043e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3044e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
3045e5b75505Sopenharmony_ci		if (i_pubkey_hash)
3046e5b75505Sopenharmony_ci			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3047e5b75505Sopenharmony_ci		else
3048e5b75505Sopenharmony_ci			os_memset(test_hash, 0, SHA256_MAC_LEN);
3049e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3050e5b75505Sopenharmony_ci		i_pubkey_hash = test_hash;
3051e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3052e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3053e5b75505Sopenharmony_ci		status = 255;
3054e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3055e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3056e5b75505Sopenharmony_ci		i_nonce = NULL;
3057e5b75505Sopenharmony_ci	}
3058e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3059e5b75505Sopenharmony_ci
3060e5b75505Sopenharmony_ci	msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
3061e5b75505Sopenharmony_ci				  r_pubkey_hash, i_pubkey_hash,
3062e5b75505Sopenharmony_ci				  NULL, i_nonce, NULL, 0, auth->k1);
3063e5b75505Sopenharmony_ci	if (!msg)
3064e5b75505Sopenharmony_ci		return -1;
3065e5b75505Sopenharmony_ci	wpabuf_free(auth->resp_msg);
3066e5b75505Sopenharmony_ci	auth->resp_msg = msg;
3067e5b75505Sopenharmony_ci	return 0;
3068e5b75505Sopenharmony_ci}
3069e5b75505Sopenharmony_ci
3070e5b75505Sopenharmony_ci
3071e5b75505Sopenharmony_cistruct dpp_authentication *
3072e5b75505Sopenharmony_cidpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
3073e5b75505Sopenharmony_ci		struct dpp_bootstrap_info *peer_bi,
3074e5b75505Sopenharmony_ci		struct dpp_bootstrap_info *own_bi,
3075e5b75505Sopenharmony_ci		unsigned int freq, const u8 *hdr, const u8 *attr_start,
3076e5b75505Sopenharmony_ci		size_t attr_len)
3077e5b75505Sopenharmony_ci{
3078e5b75505Sopenharmony_ci	EVP_PKEY *pi = NULL;
3079e5b75505Sopenharmony_ci	EVP_PKEY_CTX *ctx = NULL;
3080e5b75505Sopenharmony_ci	size_t secret_len;
3081e5b75505Sopenharmony_ci	const u8 *addr[2];
3082e5b75505Sopenharmony_ci	size_t len[2];
3083e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
3084e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
3085e5b75505Sopenharmony_ci	const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
3086e5b75505Sopenharmony_ci		*channel;
3087e5b75505Sopenharmony_ci	u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
3088e5b75505Sopenharmony_ci		i_bootstrap_len, channel_len;
3089e5b75505Sopenharmony_ci	struct dpp_authentication *auth = NULL;
3090e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
3091e5b75505Sopenharmony_ci	const u8 *version;
3092e5b75505Sopenharmony_ci	u16 version_len;
3093e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
3094e5b75505Sopenharmony_ci
3095e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3096e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
3097e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3098e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Authentication Request");
3099e5b75505Sopenharmony_ci		return NULL;
3100e5b75505Sopenharmony_ci	}
3101e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3102e5b75505Sopenharmony_ci
3103e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3104e5b75505Sopenharmony_ci				    &wrapped_data_len);
3105e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3106e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3107e5b75505Sopenharmony_ci			"Missing or invalid required Wrapped Data attribute");
3108e5b75505Sopenharmony_ci		return NULL;
3109e5b75505Sopenharmony_ci	}
3110e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
3111e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3112e5b75505Sopenharmony_ci	attr_len = wrapped_data - 4 - attr_start;
3113e5b75505Sopenharmony_ci
3114e5b75505Sopenharmony_ci	auth = os_zalloc(sizeof(*auth));
3115e5b75505Sopenharmony_ci	if (!auth)
3116e5b75505Sopenharmony_ci		goto fail;
3117e5b75505Sopenharmony_ci	auth->msg_ctx = msg_ctx;
3118e5b75505Sopenharmony_ci	auth->peer_bi = peer_bi;
3119e5b75505Sopenharmony_ci	auth->own_bi = own_bi;
3120e5b75505Sopenharmony_ci	auth->curve = own_bi->curve;
3121e5b75505Sopenharmony_ci	auth->curr_freq = freq;
3122e5b75505Sopenharmony_ci
3123e5b75505Sopenharmony_ci	auth->peer_version = 1; /* default to the first version */
3124e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
3125e5b75505Sopenharmony_ci	version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3126e5b75505Sopenharmony_ci			       &version_len);
3127e5b75505Sopenharmony_ci	if (version) {
3128e5b75505Sopenharmony_ci		if (version_len < 1 || version[0] == 0) {
3129e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
3130e5b75505Sopenharmony_ci				      "Invalid Protocol Version attribute");
3131e5b75505Sopenharmony_ci			goto fail;
3132e5b75505Sopenharmony_ci		}
3133e5b75505Sopenharmony_ci		auth->peer_version = version[0];
3134e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3135e5b75505Sopenharmony_ci			   auth->peer_version);
3136e5b75505Sopenharmony_ci	}
3137e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
3138e5b75505Sopenharmony_ci
3139e5b75505Sopenharmony_ci	channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
3140e5b75505Sopenharmony_ci			       &channel_len);
3141e5b75505Sopenharmony_ci	if (channel) {
3142e5b75505Sopenharmony_ci		int neg_freq;
3143e5b75505Sopenharmony_ci
3144e5b75505Sopenharmony_ci		if (channel_len < 2) {
3145e5b75505Sopenharmony_ci			dpp_auth_fail(auth, "Too short Channel attribute");
3146e5b75505Sopenharmony_ci			goto fail;
3147e5b75505Sopenharmony_ci		}
3148e5b75505Sopenharmony_ci
3149e5b75505Sopenharmony_ci		neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
3150e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3151e5b75505Sopenharmony_ci			   "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3152e5b75505Sopenharmony_ci			   channel[0], channel[1], neg_freq);
3153e5b75505Sopenharmony_ci		if (neg_freq < 0) {
3154e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
3155e5b75505Sopenharmony_ci				      "Unsupported Channel attribute value");
3156e5b75505Sopenharmony_ci			goto fail;
3157e5b75505Sopenharmony_ci		}
3158e5b75505Sopenharmony_ci
3159e5b75505Sopenharmony_ci		if (auth->curr_freq != (unsigned int) neg_freq) {
3160e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
3161e5b75505Sopenharmony_ci				   "DPP: Changing negotiation channel from %u MHz to %u MHz",
3162e5b75505Sopenharmony_ci				   freq, neg_freq);
3163e5b75505Sopenharmony_ci			auth->curr_freq = neg_freq;
3164e5b75505Sopenharmony_ci		}
3165e5b75505Sopenharmony_ci	}
3166e5b75505Sopenharmony_ci
3167e5b75505Sopenharmony_ci	i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
3168e5b75505Sopenharmony_ci			       &i_proto_len);
3169e5b75505Sopenharmony_ci	if (!i_proto) {
3170e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3171e5b75505Sopenharmony_ci			      "Missing required Initiator Protocol Key attribute");
3172e5b75505Sopenharmony_ci		goto fail;
3173e5b75505Sopenharmony_ci	}
3174e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
3175e5b75505Sopenharmony_ci		    i_proto, i_proto_len);
3176e5b75505Sopenharmony_ci
3177e5b75505Sopenharmony_ci	/* M = bR * PI */
3178e5b75505Sopenharmony_ci	pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
3179e5b75505Sopenharmony_ci	if (!pi) {
3180e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
3181e5b75505Sopenharmony_ci		goto fail;
3182e5b75505Sopenharmony_ci	}
3183e5b75505Sopenharmony_ci	dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
3184e5b75505Sopenharmony_ci
3185e5b75505Sopenharmony_ci	if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
3186e5b75505Sopenharmony_ci		goto fail;
3187e5b75505Sopenharmony_ci	auth->secret_len = secret_len;
3188e5b75505Sopenharmony_ci
3189e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
3190e5b75505Sopenharmony_ci			auth->Mx, auth->secret_len);
3191e5b75505Sopenharmony_ci	auth->Mx_len = auth->secret_len;
3192e5b75505Sopenharmony_ci
3193e5b75505Sopenharmony_ci	if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
3194e5b75505Sopenharmony_ci			  auth->curve->hash_len) < 0)
3195e5b75505Sopenharmony_ci		goto fail;
3196e5b75505Sopenharmony_ci
3197e5b75505Sopenharmony_ci	addr[0] = hdr;
3198e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
3199e5b75505Sopenharmony_ci	addr[1] = attr_start;
3200e5b75505Sopenharmony_ci	len[1] = attr_len;
3201e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3202e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3203e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3204e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3205e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3206e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
3207e5b75505Sopenharmony_ci	if (!unwrapped)
3208e5b75505Sopenharmony_ci		goto fail;
3209e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3210e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
3211e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
3212e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
3213e5b75505Sopenharmony_ci		goto fail;
3214e5b75505Sopenharmony_ci	}
3215e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3216e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
3217e5b75505Sopenharmony_ci
3218e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3219e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3220e5b75505Sopenharmony_ci		goto fail;
3221e5b75505Sopenharmony_ci	}
3222e5b75505Sopenharmony_ci
3223e5b75505Sopenharmony_ci	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3224e5b75505Sopenharmony_ci			       &i_nonce_len);
3225e5b75505Sopenharmony_ci	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3226e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid I-nonce");
3227e5b75505Sopenharmony_ci		goto fail;
3228e5b75505Sopenharmony_ci	}
3229e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3230e5b75505Sopenharmony_ci	os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3231e5b75505Sopenharmony_ci
3232e5b75505Sopenharmony_ci	i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3233e5b75505Sopenharmony_ci			       DPP_ATTR_I_CAPABILITIES,
3234e5b75505Sopenharmony_ci			       &i_capab_len);
3235e5b75505Sopenharmony_ci	if (!i_capab || i_capab_len < 1) {
3236e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid I-capabilities");
3237e5b75505Sopenharmony_ci		goto fail;
3238e5b75505Sopenharmony_ci	}
3239e5b75505Sopenharmony_ci	auth->i_capab = i_capab[0];
3240e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3241e5b75505Sopenharmony_ci
3242e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
3243e5b75505Sopenharmony_ci	unwrapped = NULL;
3244e5b75505Sopenharmony_ci
3245e5b75505Sopenharmony_ci	switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3246e5b75505Sopenharmony_ci	case DPP_CAPAB_ENROLLEE:
3247e5b75505Sopenharmony_ci		if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3248e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
3249e5b75505Sopenharmony_ci				   "DPP: Local policy does not allow Configurator role");
3250e5b75505Sopenharmony_ci			goto not_compatible;
3251e5b75505Sopenharmony_ci		}
3252e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3253e5b75505Sopenharmony_ci		auth->configurator = 1;
3254e5b75505Sopenharmony_ci		break;
3255e5b75505Sopenharmony_ci	case DPP_CAPAB_CONFIGURATOR:
3256e5b75505Sopenharmony_ci		if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3257e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
3258e5b75505Sopenharmony_ci				   "DPP: Local policy does not allow Enrollee role");
3259e5b75505Sopenharmony_ci			goto not_compatible;
3260e5b75505Sopenharmony_ci		}
3261e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3262e5b75505Sopenharmony_ci		auth->configurator = 0;
3263e5b75505Sopenharmony_ci		break;
3264e5b75505Sopenharmony_ci	case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3265e5b75505Sopenharmony_ci		if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3266e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3267e5b75505Sopenharmony_ci			auth->configurator = 0;
3268e5b75505Sopenharmony_ci		} else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3269e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3270e5b75505Sopenharmony_ci			auth->configurator = 1;
3271e5b75505Sopenharmony_ci		} else {
3272e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
3273e5b75505Sopenharmony_ci				   "DPP: Local policy does not allow Configurator/Enrollee role");
3274e5b75505Sopenharmony_ci			goto not_compatible;
3275e5b75505Sopenharmony_ci		}
3276e5b75505Sopenharmony_ci		break;
3277e5b75505Sopenharmony_ci	default:
3278e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
3279e5b75505Sopenharmony_ci		wpa_msg(auth->msg_ctx, MSG_INFO,
3280e5b75505Sopenharmony_ci			DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3281e5b75505Sopenharmony_ci			auth->i_capab & DPP_CAPAB_ROLE_MASK);
3282e5b75505Sopenharmony_ci		goto fail;
3283e5b75505Sopenharmony_ci	}
3284e5b75505Sopenharmony_ci
3285e5b75505Sopenharmony_ci	auth->peer_protocol_key = pi;
3286e5b75505Sopenharmony_ci	pi = NULL;
3287e5b75505Sopenharmony_ci	if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3288e5b75505Sopenharmony_ci		char hex[SHA256_MAC_LEN * 2 + 1];
3289e5b75505Sopenharmony_ci
3290e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3291e5b75505Sopenharmony_ci			   "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3292e5b75505Sopenharmony_ci		if (dpp_auth_build_resp_status(auth,
3293e5b75505Sopenharmony_ci					       DPP_STATUS_RESPONSE_PENDING) < 0)
3294e5b75505Sopenharmony_ci			goto fail;
3295e5b75505Sopenharmony_ci		i_bootstrap = dpp_get_attr(attr_start, attr_len,
3296e5b75505Sopenharmony_ci					   DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3297e5b75505Sopenharmony_ci					   &i_bootstrap_len);
3298e5b75505Sopenharmony_ci		if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3299e5b75505Sopenharmony_ci			auth->response_pending = 1;
3300e5b75505Sopenharmony_ci			os_memcpy(auth->waiting_pubkey_hash,
3301e5b75505Sopenharmony_ci				  i_bootstrap, i_bootstrap_len);
3302e5b75505Sopenharmony_ci			wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3303e5b75505Sopenharmony_ci					 i_bootstrap_len);
3304e5b75505Sopenharmony_ci		} else {
3305e5b75505Sopenharmony_ci			hex[0] = '\0';
3306e5b75505Sopenharmony_ci		}
3307e5b75505Sopenharmony_ci
3308e5b75505Sopenharmony_ci		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3309e5b75505Sopenharmony_ci			"%s", hex);
3310e5b75505Sopenharmony_ci		return auth;
3311e5b75505Sopenharmony_ci	}
3312e5b75505Sopenharmony_ci	if (dpp_auth_build_resp_ok(auth) < 0)
3313e5b75505Sopenharmony_ci		goto fail;
3314e5b75505Sopenharmony_ci
3315e5b75505Sopenharmony_ci	return auth;
3316e5b75505Sopenharmony_ci
3317e5b75505Sopenharmony_cinot_compatible:
3318e5b75505Sopenharmony_ci	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3319e5b75505Sopenharmony_ci		"i-capab=0x%02x", auth->i_capab);
3320e5b75505Sopenharmony_ci	if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3321e5b75505Sopenharmony_ci		auth->configurator = 1;
3322e5b75505Sopenharmony_ci	else
3323e5b75505Sopenharmony_ci		auth->configurator = 0;
3324e5b75505Sopenharmony_ci	auth->peer_protocol_key = pi;
3325e5b75505Sopenharmony_ci	pi = NULL;
3326e5b75505Sopenharmony_ci	if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3327e5b75505Sopenharmony_ci		goto fail;
3328e5b75505Sopenharmony_ci
3329e5b75505Sopenharmony_ci	auth->remove_on_tx_status = 1;
3330e5b75505Sopenharmony_ci	return auth;
3331e5b75505Sopenharmony_cifail:
3332e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
3333e5b75505Sopenharmony_ci	EVP_PKEY_free(pi);
3334e5b75505Sopenharmony_ci	EVP_PKEY_CTX_free(ctx);
3335e5b75505Sopenharmony_ci	dpp_auth_deinit(auth);
3336e5b75505Sopenharmony_ci	return NULL;
3337e5b75505Sopenharmony_ci}
3338e5b75505Sopenharmony_ci
3339e5b75505Sopenharmony_ci
3340e5b75505Sopenharmony_ciint dpp_notify_new_qr_code(struct dpp_authentication *auth,
3341e5b75505Sopenharmony_ci			   struct dpp_bootstrap_info *peer_bi)
3342e5b75505Sopenharmony_ci{
3343e5b75505Sopenharmony_ci	if (!auth || !auth->response_pending ||
3344e5b75505Sopenharmony_ci	    os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3345e5b75505Sopenharmony_ci		      SHA256_MAC_LEN) != 0)
3346e5b75505Sopenharmony_ci		return 0;
3347e5b75505Sopenharmony_ci
3348e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
3349e5b75505Sopenharmony_ci		   "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3350e5b75505Sopenharmony_ci		   MACSTR, MAC2STR(auth->peer_mac_addr));
3351e5b75505Sopenharmony_ci	auth->peer_bi = peer_bi;
3352e5b75505Sopenharmony_ci
3353e5b75505Sopenharmony_ci	if (dpp_auth_build_resp_ok(auth) < 0)
3354e5b75505Sopenharmony_ci		return -1;
3355e5b75505Sopenharmony_ci
3356e5b75505Sopenharmony_ci	return 1;
3357e5b75505Sopenharmony_ci}
3358e5b75505Sopenharmony_ci
3359e5b75505Sopenharmony_ci
3360e5b75505Sopenharmony_cistatic struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3361e5b75505Sopenharmony_ci					   enum dpp_status_error status)
3362e5b75505Sopenharmony_ci{
3363e5b75505Sopenharmony_ci	struct wpabuf *msg;
3364e5b75505Sopenharmony_ci	u8 i_auth[4 + DPP_MAX_HASH_LEN];
3365e5b75505Sopenharmony_ci	size_t i_auth_len;
3366e5b75505Sopenharmony_ci	u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3367e5b75505Sopenharmony_ci	size_t r_nonce_len;
3368e5b75505Sopenharmony_ci	const u8 *addr[2];
3369e5b75505Sopenharmony_ci	size_t len[2], attr_len;
3370e5b75505Sopenharmony_ci	u8 *wrapped_i_auth;
3371e5b75505Sopenharmony_ci	u8 *wrapped_r_nonce;
3372e5b75505Sopenharmony_ci	u8 *attr_start, *attr_end;
3373e5b75505Sopenharmony_ci	const u8 *r_pubkey_hash, *i_pubkey_hash;
3374e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3375e5b75505Sopenharmony_ci	u8 test_hash[SHA256_MAC_LEN];
3376e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3377e5b75505Sopenharmony_ci
3378e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3379e5b75505Sopenharmony_ci
3380e5b75505Sopenharmony_ci	i_auth_len = 4 + auth->curve->hash_len;
3381e5b75505Sopenharmony_ci	r_nonce_len = 4 + auth->curve->nonce_len;
3382e5b75505Sopenharmony_ci	/* Build DPP Authentication Confirmation frame attributes */
3383e5b75505Sopenharmony_ci	attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
3384e5b75505Sopenharmony_ci		4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
3385e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3386e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
3387e5b75505Sopenharmony_ci		attr_len += 5;
3388e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3389e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
3390e5b75505Sopenharmony_ci	if (!msg)
3391e5b75505Sopenharmony_ci		goto fail;
3392e5b75505Sopenharmony_ci
3393e5b75505Sopenharmony_ci	attr_start = wpabuf_put(msg, 0);
3394e5b75505Sopenharmony_ci
3395e5b75505Sopenharmony_ci	r_pubkey_hash = auth->peer_bi->pubkey_hash;
3396e5b75505Sopenharmony_ci	if (auth->own_bi)
3397e5b75505Sopenharmony_ci		i_pubkey_hash = auth->own_bi->pubkey_hash;
3398e5b75505Sopenharmony_ci	else
3399e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
3400e5b75505Sopenharmony_ci
3401e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3402e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3403e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3404e5b75505Sopenharmony_ci		goto skip_status;
3405e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3406e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3407e5b75505Sopenharmony_ci		status = 254;
3408e5b75505Sopenharmony_ci	}
3409e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3410e5b75505Sopenharmony_ci
3411e5b75505Sopenharmony_ci	/* DPP Status */
3412e5b75505Sopenharmony_ci	dpp_build_attr_status(msg, status);
3413e5b75505Sopenharmony_ci
3414e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3415e5b75505Sopenharmony_ciskip_status:
3416e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3417e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3418e5b75505Sopenharmony_ci		r_pubkey_hash = NULL;
3419e5b75505Sopenharmony_ci	} else if (dpp_test ==
3420e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3421e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3422e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid R-Bootstrap Key Hash");
3423e5b75505Sopenharmony_ci		os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3424e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3425e5b75505Sopenharmony_ci		r_pubkey_hash = test_hash;
3426e5b75505Sopenharmony_ci	} else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3427e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3428e5b75505Sopenharmony_ci		i_pubkey_hash = NULL;
3429e5b75505Sopenharmony_ci	} else if (dpp_test ==
3430e5b75505Sopenharmony_ci		   DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3431e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3432e5b75505Sopenharmony_ci			   "DPP: TESTING - invalid I-Bootstrap Key Hash");
3433e5b75505Sopenharmony_ci		if (i_pubkey_hash)
3434e5b75505Sopenharmony_ci			os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3435e5b75505Sopenharmony_ci		else
3436e5b75505Sopenharmony_ci			os_memset(test_hash, 0, SHA256_MAC_LEN);
3437e5b75505Sopenharmony_ci		test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3438e5b75505Sopenharmony_ci		i_pubkey_hash = test_hash;
3439e5b75505Sopenharmony_ci	}
3440e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3441e5b75505Sopenharmony_ci
3442e5b75505Sopenharmony_ci	/* Responder Bootstrapping Key Hash */
3443e5b75505Sopenharmony_ci	dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
3444e5b75505Sopenharmony_ci
3445e5b75505Sopenharmony_ci	/* Initiator Bootstrapping Key Hash (mutual authentication) */
3446e5b75505Sopenharmony_ci	dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
3447e5b75505Sopenharmony_ci
3448e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3449e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3450e5b75505Sopenharmony_ci		goto skip_wrapped_data;
3451e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3452e5b75505Sopenharmony_ci		i_auth_len = 0;
3453e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3454e5b75505Sopenharmony_ci
3455e5b75505Sopenharmony_ci	attr_end = wpabuf_put(msg, 0);
3456e5b75505Sopenharmony_ci
3457e5b75505Sopenharmony_ci	/* OUI, OUI type, Crypto Suite, DPP frame type */
3458e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
3459e5b75505Sopenharmony_ci	len[0] = 3 + 1 + 1 + 1;
3460e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3461e5b75505Sopenharmony_ci
3462e5b75505Sopenharmony_ci	/* Attributes before Wrapped Data */
3463e5b75505Sopenharmony_ci	addr[1] = attr_start;
3464e5b75505Sopenharmony_ci	len[1] = attr_end - attr_start;
3465e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3466e5b75505Sopenharmony_ci
3467e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK) {
3468e5b75505Sopenharmony_ci		/* I-auth wrapped with ke */
3469e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3470e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3471e5b75505Sopenharmony_ci		wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
3472e5b75505Sopenharmony_ci
3473e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3474e5b75505Sopenharmony_ci		if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3475e5b75505Sopenharmony_ci			goto skip_i_auth;
3476e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3477e5b75505Sopenharmony_ci
3478e5b75505Sopenharmony_ci		/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3479e5b75505Sopenharmony_ci		 *	      1) */
3480e5b75505Sopenharmony_ci		WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3481e5b75505Sopenharmony_ci		WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3482e5b75505Sopenharmony_ci		if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3483e5b75505Sopenharmony_ci			goto fail;
3484e5b75505Sopenharmony_ci
3485e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3486e5b75505Sopenharmony_ci		if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3487e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3488e5b75505Sopenharmony_ci			i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3489e5b75505Sopenharmony_ci		}
3490e5b75505Sopenharmony_ciskip_i_auth:
3491e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3492e5b75505Sopenharmony_ci		if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3493e5b75505Sopenharmony_ci				    i_auth, i_auth_len,
3494e5b75505Sopenharmony_ci				    2, addr, len, wrapped_i_auth) < 0)
3495e5b75505Sopenharmony_ci			goto fail;
3496e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3497e5b75505Sopenharmony_ci			    wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3498e5b75505Sopenharmony_ci	} else {
3499e5b75505Sopenharmony_ci		/* R-nonce wrapped with k2 */
3500e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3501e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3502e5b75505Sopenharmony_ci		wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3503e5b75505Sopenharmony_ci
3504e5b75505Sopenharmony_ci		WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3505e5b75505Sopenharmony_ci		WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3506e5b75505Sopenharmony_ci		os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3507e5b75505Sopenharmony_ci
3508e5b75505Sopenharmony_ci		if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3509e5b75505Sopenharmony_ci				    r_nonce, r_nonce_len,
3510e5b75505Sopenharmony_ci				    2, addr, len, wrapped_r_nonce) < 0)
3511e5b75505Sopenharmony_ci			goto fail;
3512e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3513e5b75505Sopenharmony_ci			    wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3514e5b75505Sopenharmony_ci	}
3515e5b75505Sopenharmony_ci
3516e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3517e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3518e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
3519e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
3520e5b75505Sopenharmony_ci	}
3521e5b75505Sopenharmony_ciskip_wrapped_data:
3522e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3523e5b75505Sopenharmony_ci
3524e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG,
3525e5b75505Sopenharmony_ci			"DPP: Authentication Confirmation frame attributes",
3526e5b75505Sopenharmony_ci			msg);
3527e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK)
3528e5b75505Sopenharmony_ci		dpp_auth_success(auth);
3529e5b75505Sopenharmony_ci
3530e5b75505Sopenharmony_ci	return msg;
3531e5b75505Sopenharmony_ci
3532e5b75505Sopenharmony_cifail:
3533e5b75505Sopenharmony_ci	wpabuf_free(msg);
3534e5b75505Sopenharmony_ci	return NULL;
3535e5b75505Sopenharmony_ci}
3536e5b75505Sopenharmony_ci
3537e5b75505Sopenharmony_ci
3538e5b75505Sopenharmony_cistatic void
3539e5b75505Sopenharmony_cidpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
3540e5b75505Sopenharmony_ci			const u8 *attr_start, size_t attr_len,
3541e5b75505Sopenharmony_ci			const u8 *wrapped_data, u16 wrapped_data_len,
3542e5b75505Sopenharmony_ci			enum dpp_status_error status)
3543e5b75505Sopenharmony_ci{
3544e5b75505Sopenharmony_ci	const u8 *addr[2];
3545e5b75505Sopenharmony_ci	size_t len[2];
3546e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
3547e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
3548e5b75505Sopenharmony_ci	const u8 *i_nonce, *r_capab;
3549e5b75505Sopenharmony_ci	u16 i_nonce_len, r_capab_len;
3550e5b75505Sopenharmony_ci
3551e5b75505Sopenharmony_ci	if (status == DPP_STATUS_NOT_COMPATIBLE) {
3552e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3553e5b75505Sopenharmony_ci			   "DPP: Responder reported incompatible roles");
3554e5b75505Sopenharmony_ci	} else if (status == DPP_STATUS_RESPONSE_PENDING) {
3555e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3556e5b75505Sopenharmony_ci			   "DPP: Responder reported more time needed");
3557e5b75505Sopenharmony_ci	} else {
3558e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3559e5b75505Sopenharmony_ci			   "DPP: Responder reported failure (status %d)",
3560e5b75505Sopenharmony_ci			   status);
3561e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Responder reported failure");
3562e5b75505Sopenharmony_ci		return;
3563e5b75505Sopenharmony_ci	}
3564e5b75505Sopenharmony_ci
3565e5b75505Sopenharmony_ci	addr[0] = hdr;
3566e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
3567e5b75505Sopenharmony_ci	addr[1] = attr_start;
3568e5b75505Sopenharmony_ci	len[1] = attr_len;
3569e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3570e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3571e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3572e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3573e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3574e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
3575e5b75505Sopenharmony_ci	if (!unwrapped)
3576e5b75505Sopenharmony_ci		goto fail;
3577e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3578e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
3579e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
3580e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
3581e5b75505Sopenharmony_ci		goto fail;
3582e5b75505Sopenharmony_ci	}
3583e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3584e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
3585e5b75505Sopenharmony_ci
3586e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3587e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3588e5b75505Sopenharmony_ci		goto fail;
3589e5b75505Sopenharmony_ci	}
3590e5b75505Sopenharmony_ci
3591e5b75505Sopenharmony_ci	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3592e5b75505Sopenharmony_ci			       &i_nonce_len);
3593e5b75505Sopenharmony_ci	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3594e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid I-nonce");
3595e5b75505Sopenharmony_ci		goto fail;
3596e5b75505Sopenharmony_ci	}
3597e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3598e5b75505Sopenharmony_ci	if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
3599e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "I-nonce mismatch");
3600e5b75505Sopenharmony_ci		goto fail;
3601e5b75505Sopenharmony_ci	}
3602e5b75505Sopenharmony_ci
3603e5b75505Sopenharmony_ci	r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3604e5b75505Sopenharmony_ci			       DPP_ATTR_R_CAPABILITIES,
3605e5b75505Sopenharmony_ci			       &r_capab_len);
3606e5b75505Sopenharmony_ci	if (!r_capab || r_capab_len < 1) {
3607e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3608e5b75505Sopenharmony_ci		goto fail;
3609e5b75505Sopenharmony_ci	}
3610e5b75505Sopenharmony_ci	auth->r_capab = r_capab[0];
3611e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3612e5b75505Sopenharmony_ci	if (status == DPP_STATUS_NOT_COMPATIBLE) {
3613e5b75505Sopenharmony_ci		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3614e5b75505Sopenharmony_ci			"r-capab=0x%02x", auth->r_capab);
3615e5b75505Sopenharmony_ci	} else if (status == DPP_STATUS_RESPONSE_PENDING) {
3616e5b75505Sopenharmony_ci		u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3617e5b75505Sopenharmony_ci
3618e5b75505Sopenharmony_ci		if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3619e5b75505Sopenharmony_ci		    (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3620e5b75505Sopenharmony_ci			wpa_msg(auth->msg_ctx, MSG_INFO,
3621e5b75505Sopenharmony_ci				DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3622e5b75505Sopenharmony_ci				role);
3623e5b75505Sopenharmony_ci		} else {
3624e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
3625e5b75505Sopenharmony_ci				   "DPP: Continue waiting for full DPP Authentication Response");
3626e5b75505Sopenharmony_ci			wpa_msg(auth->msg_ctx, MSG_INFO,
3627e5b75505Sopenharmony_ci				DPP_EVENT_RESPONSE_PENDING "%s",
3628e5b75505Sopenharmony_ci				auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3629e5b75505Sopenharmony_ci		}
3630e5b75505Sopenharmony_ci	}
3631e5b75505Sopenharmony_cifail:
3632e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
3633e5b75505Sopenharmony_ci}
3634e5b75505Sopenharmony_ci
3635e5b75505Sopenharmony_ci
3636e5b75505Sopenharmony_cistruct wpabuf *
3637e5b75505Sopenharmony_cidpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3638e5b75505Sopenharmony_ci		 const u8 *attr_start, size_t attr_len)
3639e5b75505Sopenharmony_ci{
3640e5b75505Sopenharmony_ci	EVP_PKEY *pr;
3641e5b75505Sopenharmony_ci	size_t secret_len;
3642e5b75505Sopenharmony_ci	const u8 *addr[2];
3643e5b75505Sopenharmony_ci	size_t len[2];
3644e5b75505Sopenharmony_ci	u8 *unwrapped = NULL, *unwrapped2 = NULL;
3645e5b75505Sopenharmony_ci	size_t unwrapped_len = 0, unwrapped2_len = 0;
3646e5b75505Sopenharmony_ci	const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3647e5b75505Sopenharmony_ci		*r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3648e5b75505Sopenharmony_ci	u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3649e5b75505Sopenharmony_ci		r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3650e5b75505Sopenharmony_ci		wrapped2_len, r_auth_len;
3651e5b75505Sopenharmony_ci	u8 r_auth2[DPP_MAX_HASH_LEN];
3652e5b75505Sopenharmony_ci	u8 role;
3653e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
3654e5b75505Sopenharmony_ci	const u8 *version;
3655e5b75505Sopenharmony_ci	u16 version_len;
3656e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
3657e5b75505Sopenharmony_ci
3658e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3659e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3660e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3661e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Authentication Response");
3662e5b75505Sopenharmony_ci		return NULL;
3663e5b75505Sopenharmony_ci	}
3664e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3665e5b75505Sopenharmony_ci
3666e5b75505Sopenharmony_ci	if (!auth->initiator || !auth->peer_bi) {
3667e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unexpected Authentication Response");
3668e5b75505Sopenharmony_ci		return NULL;
3669e5b75505Sopenharmony_ci	}
3670e5b75505Sopenharmony_ci
3671e5b75505Sopenharmony_ci	auth->waiting_auth_resp = 0;
3672e5b75505Sopenharmony_ci
3673e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3674e5b75505Sopenharmony_ci				    &wrapped_data_len);
3675e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3676e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3677e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
3678e5b75505Sopenharmony_ci		return NULL;
3679e5b75505Sopenharmony_ci	}
3680e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3681e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3682e5b75505Sopenharmony_ci
3683e5b75505Sopenharmony_ci	attr_len = wrapped_data - 4 - attr_start;
3684e5b75505Sopenharmony_ci
3685e5b75505Sopenharmony_ci	r_bootstrap = dpp_get_attr(attr_start, attr_len,
3686e5b75505Sopenharmony_ci				   DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3687e5b75505Sopenharmony_ci				   &r_bootstrap_len);
3688e5b75505Sopenharmony_ci	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3689e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3690e5b75505Sopenharmony_ci			      "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3691e5b75505Sopenharmony_ci		return NULL;
3692e5b75505Sopenharmony_ci	}
3693e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3694e5b75505Sopenharmony_ci		    r_bootstrap, r_bootstrap_len);
3695e5b75505Sopenharmony_ci	if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3696e5b75505Sopenharmony_ci		      SHA256_MAC_LEN) != 0) {
3697e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3698e5b75505Sopenharmony_ci			      "Unexpected Responder Bootstrapping Key Hash value");
3699e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG,
3700e5b75505Sopenharmony_ci			    "DPP: Expected Responder Bootstrapping Key Hash",
3701e5b75505Sopenharmony_ci			    auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3702e5b75505Sopenharmony_ci		return NULL;
3703e5b75505Sopenharmony_ci	}
3704e5b75505Sopenharmony_ci
3705e5b75505Sopenharmony_ci	i_bootstrap = dpp_get_attr(attr_start, attr_len,
3706e5b75505Sopenharmony_ci				   DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3707e5b75505Sopenharmony_ci				   &i_bootstrap_len);
3708e5b75505Sopenharmony_ci	if (i_bootstrap) {
3709e5b75505Sopenharmony_ci		if (i_bootstrap_len != SHA256_MAC_LEN) {
3710e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
3711e5b75505Sopenharmony_ci				      "Invalid Initiator Bootstrapping Key Hash attribute");
3712e5b75505Sopenharmony_ci			return NULL;
3713e5b75505Sopenharmony_ci		}
3714e5b75505Sopenharmony_ci		wpa_hexdump(MSG_MSGDUMP,
3715e5b75505Sopenharmony_ci			    "DPP: Initiator Bootstrapping Key Hash",
3716e5b75505Sopenharmony_ci			    i_bootstrap, i_bootstrap_len);
3717e5b75505Sopenharmony_ci		if (!auth->own_bi ||
3718e5b75505Sopenharmony_ci		    os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3719e5b75505Sopenharmony_ci			      SHA256_MAC_LEN) != 0) {
3720e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
3721e5b75505Sopenharmony_ci				      "Initiator Bootstrapping Key Hash attribute did not match");
3722e5b75505Sopenharmony_ci			return NULL;
3723e5b75505Sopenharmony_ci		}
3724e5b75505Sopenharmony_ci	} else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3725e5b75505Sopenharmony_ci		/* PKEX bootstrapping mandates use of mutual authentication */
3726e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3727e5b75505Sopenharmony_ci			      "Missing Initiator Bootstrapping Key Hash attribute");
3728e5b75505Sopenharmony_ci		return NULL;
3729e5b75505Sopenharmony_ci	}
3730e5b75505Sopenharmony_ci
3731e5b75505Sopenharmony_ci	auth->peer_version = 1; /* default to the first version */
3732e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
3733e5b75505Sopenharmony_ci	version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3734e5b75505Sopenharmony_ci			       &version_len);
3735e5b75505Sopenharmony_ci	if (version) {
3736e5b75505Sopenharmony_ci		if (version_len < 1 || version[0] == 0) {
3737e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
3738e5b75505Sopenharmony_ci				      "Invalid Protocol Version attribute");
3739e5b75505Sopenharmony_ci			return NULL;
3740e5b75505Sopenharmony_ci		}
3741e5b75505Sopenharmony_ci		auth->peer_version = version[0];
3742e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3743e5b75505Sopenharmony_ci			   auth->peer_version);
3744e5b75505Sopenharmony_ci	}
3745e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
3746e5b75505Sopenharmony_ci
3747e5b75505Sopenharmony_ci	status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3748e5b75505Sopenharmony_ci			      &status_len);
3749e5b75505Sopenharmony_ci	if (!status || status_len < 1) {
3750e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3751e5b75505Sopenharmony_ci			      "Missing or invalid required DPP Status attribute");
3752e5b75505Sopenharmony_ci		return NULL;
3753e5b75505Sopenharmony_ci	}
3754e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3755e5b75505Sopenharmony_ci	auth->auth_resp_status = status[0];
3756e5b75505Sopenharmony_ci	if (status[0] != DPP_STATUS_OK) {
3757e5b75505Sopenharmony_ci		dpp_auth_resp_rx_status(auth, hdr, attr_start,
3758e5b75505Sopenharmony_ci					attr_len, wrapped_data,
3759e5b75505Sopenharmony_ci					wrapped_data_len, status[0]);
3760e5b75505Sopenharmony_ci		return NULL;
3761e5b75505Sopenharmony_ci	}
3762e5b75505Sopenharmony_ci
3763e5b75505Sopenharmony_ci	if (!i_bootstrap && auth->own_bi) {
3764e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
3765e5b75505Sopenharmony_ci			   "DPP: Responder decided not to use mutual authentication");
3766e5b75505Sopenharmony_ci		auth->own_bi = NULL;
3767e5b75505Sopenharmony_ci	}
3768e5b75505Sopenharmony_ci
3769e5b75505Sopenharmony_ci	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3770e5b75505Sopenharmony_ci		auth->own_bi != NULL);
3771e5b75505Sopenharmony_ci
3772e5b75505Sopenharmony_ci	r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3773e5b75505Sopenharmony_ci			       &r_proto_len);
3774e5b75505Sopenharmony_ci	if (!r_proto) {
3775e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3776e5b75505Sopenharmony_ci			      "Missing required Responder Protocol Key attribute");
3777e5b75505Sopenharmony_ci		return NULL;
3778e5b75505Sopenharmony_ci	}
3779e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3780e5b75505Sopenharmony_ci		    r_proto, r_proto_len);
3781e5b75505Sopenharmony_ci
3782e5b75505Sopenharmony_ci	/* N = pI * PR */
3783e5b75505Sopenharmony_ci	pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3784e5b75505Sopenharmony_ci	if (!pr) {
3785e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid Responder Protocol Key");
3786e5b75505Sopenharmony_ci		return NULL;
3787e5b75505Sopenharmony_ci	}
3788e5b75505Sopenharmony_ci	dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3789e5b75505Sopenharmony_ci
3790e5b75505Sopenharmony_ci	if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
3791e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
3792e5b75505Sopenharmony_ci		goto fail;
3793e5b75505Sopenharmony_ci	}
3794e5b75505Sopenharmony_ci	EVP_PKEY_free(auth->peer_protocol_key);
3795e5b75505Sopenharmony_ci	auth->peer_protocol_key = pr;
3796e5b75505Sopenharmony_ci	pr = NULL;
3797e5b75505Sopenharmony_ci
3798e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3799e5b75505Sopenharmony_ci			auth->Nx, auth->secret_len);
3800e5b75505Sopenharmony_ci	auth->Nx_len = auth->secret_len;
3801e5b75505Sopenharmony_ci
3802e5b75505Sopenharmony_ci	if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3803e5b75505Sopenharmony_ci			  auth->curve->hash_len) < 0)
3804e5b75505Sopenharmony_ci		goto fail;
3805e5b75505Sopenharmony_ci
3806e5b75505Sopenharmony_ci	addr[0] = hdr;
3807e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
3808e5b75505Sopenharmony_ci	addr[1] = attr_start;
3809e5b75505Sopenharmony_ci	len[1] = attr_len;
3810e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3811e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3812e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3813e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3814e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3815e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
3816e5b75505Sopenharmony_ci	if (!unwrapped)
3817e5b75505Sopenharmony_ci		goto fail;
3818e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3819e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
3820e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
3821e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
3822e5b75505Sopenharmony_ci		goto fail;
3823e5b75505Sopenharmony_ci	}
3824e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3825e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
3826e5b75505Sopenharmony_ci
3827e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3828e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3829e5b75505Sopenharmony_ci		goto fail;
3830e5b75505Sopenharmony_ci	}
3831e5b75505Sopenharmony_ci
3832e5b75505Sopenharmony_ci	r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3833e5b75505Sopenharmony_ci			       &r_nonce_len);
3834e5b75505Sopenharmony_ci	if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3835e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3836e5b75505Sopenharmony_ci		goto fail;
3837e5b75505Sopenharmony_ci	}
3838e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3839e5b75505Sopenharmony_ci	os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3840e5b75505Sopenharmony_ci
3841e5b75505Sopenharmony_ci	i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3842e5b75505Sopenharmony_ci			       &i_nonce_len);
3843e5b75505Sopenharmony_ci	if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3844e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid I-nonce");
3845e5b75505Sopenharmony_ci		goto fail;
3846e5b75505Sopenharmony_ci	}
3847e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3848e5b75505Sopenharmony_ci	if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
3849e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "I-nonce mismatch");
3850e5b75505Sopenharmony_ci		goto fail;
3851e5b75505Sopenharmony_ci	}
3852e5b75505Sopenharmony_ci
3853e5b75505Sopenharmony_ci	if (auth->own_bi) {
3854e5b75505Sopenharmony_ci		/* Mutual authentication */
3855e5b75505Sopenharmony_ci		if (dpp_auth_derive_l_initiator(auth) < 0)
3856e5b75505Sopenharmony_ci			goto fail;
3857e5b75505Sopenharmony_ci	}
3858e5b75505Sopenharmony_ci
3859e5b75505Sopenharmony_ci	r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3860e5b75505Sopenharmony_ci			       DPP_ATTR_R_CAPABILITIES,
3861e5b75505Sopenharmony_ci			       &r_capab_len);
3862e5b75505Sopenharmony_ci	if (!r_capab || r_capab_len < 1) {
3863e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3864e5b75505Sopenharmony_ci		goto fail;
3865e5b75505Sopenharmony_ci	}
3866e5b75505Sopenharmony_ci	auth->r_capab = r_capab[0];
3867e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3868e5b75505Sopenharmony_ci	role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3869e5b75505Sopenharmony_ci	if ((auth->allowed_roles ==
3870e5b75505Sopenharmony_ci	     (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3871e5b75505Sopenharmony_ci	    (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3872e5b75505Sopenharmony_ci		/* Peer selected its role, so move from "either role" to the
3873e5b75505Sopenharmony_ci		 * role that is compatible with peer's selection. */
3874e5b75505Sopenharmony_ci		auth->configurator = role == DPP_CAPAB_ENROLLEE;
3875e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3876e5b75505Sopenharmony_ci			   auth->configurator ? "Configurator" : "Enrollee");
3877e5b75505Sopenharmony_ci	} else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3878e5b75505Sopenharmony_ci		   (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3879e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
3880e5b75505Sopenharmony_ci		wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3881e5b75505Sopenharmony_ci			"Unexpected role in R-capabilities 0x%02x",
3882e5b75505Sopenharmony_ci			role);
3883e5b75505Sopenharmony_ci		if (role != DPP_CAPAB_ENROLLEE &&
3884e5b75505Sopenharmony_ci		    role != DPP_CAPAB_CONFIGURATOR)
3885e5b75505Sopenharmony_ci			goto fail;
3886e5b75505Sopenharmony_ci		bin_clear_free(unwrapped, unwrapped_len);
3887e5b75505Sopenharmony_ci		auth->remove_on_tx_status = 1;
3888e5b75505Sopenharmony_ci		return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
3889e5b75505Sopenharmony_ci	}
3890e5b75505Sopenharmony_ci
3891e5b75505Sopenharmony_ci	wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3892e5b75505Sopenharmony_ci				DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3893e5b75505Sopenharmony_ci	if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
3894e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3895e5b75505Sopenharmony_ci			      "Missing or invalid Secondary Wrapped Data");
3896e5b75505Sopenharmony_ci		goto fail;
3897e5b75505Sopenharmony_ci	}
3898e5b75505Sopenharmony_ci
3899e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3900e5b75505Sopenharmony_ci		    wrapped2, wrapped2_len);
3901e5b75505Sopenharmony_ci
3902e5b75505Sopenharmony_ci	if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3903e5b75505Sopenharmony_ci		goto fail;
3904e5b75505Sopenharmony_ci
3905e5b75505Sopenharmony_ci	unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3906e5b75505Sopenharmony_ci	unwrapped2 = os_malloc(unwrapped2_len);
3907e5b75505Sopenharmony_ci	if (!unwrapped2)
3908e5b75505Sopenharmony_ci		goto fail;
3909e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3910e5b75505Sopenharmony_ci			    wrapped2, wrapped2_len,
3911e5b75505Sopenharmony_ci			    0, NULL, NULL, unwrapped2) < 0) {
3912e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
3913e5b75505Sopenharmony_ci		goto fail;
3914e5b75505Sopenharmony_ci	}
3915e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3916e5b75505Sopenharmony_ci		    unwrapped2, unwrapped2_len);
3917e5b75505Sopenharmony_ci
3918e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
3919e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3920e5b75505Sopenharmony_ci			      "Invalid attribute in secondary unwrapped data");
3921e5b75505Sopenharmony_ci		goto fail;
3922e5b75505Sopenharmony_ci	}
3923e5b75505Sopenharmony_ci
3924e5b75505Sopenharmony_ci	r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3925e5b75505Sopenharmony_ci			       &r_auth_len);
3926e5b75505Sopenharmony_ci	if (!r_auth || r_auth_len != auth->curve->hash_len) {
3927e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
3928e5b75505Sopenharmony_ci			      "Missing or invalid Responder Authenticating Tag");
3929e5b75505Sopenharmony_ci		goto fail;
3930e5b75505Sopenharmony_ci	}
3931e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3932e5b75505Sopenharmony_ci		    r_auth, r_auth_len);
3933e5b75505Sopenharmony_ci	/* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3934e5b75505Sopenharmony_ci	if (dpp_gen_r_auth(auth, r_auth2) < 0)
3935e5b75505Sopenharmony_ci		goto fail;
3936e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3937e5b75505Sopenharmony_ci		    r_auth2, r_auth_len);
3938e5b75505Sopenharmony_ci	if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
3939e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
3940e5b75505Sopenharmony_ci		bin_clear_free(unwrapped, unwrapped_len);
3941e5b75505Sopenharmony_ci		bin_clear_free(unwrapped2, unwrapped2_len);
3942e5b75505Sopenharmony_ci		auth->remove_on_tx_status = 1;
3943e5b75505Sopenharmony_ci		return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
3944e5b75505Sopenharmony_ci	}
3945e5b75505Sopenharmony_ci
3946e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
3947e5b75505Sopenharmony_ci	bin_clear_free(unwrapped2, unwrapped2_len);
3948e5b75505Sopenharmony_ci
3949e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
3950e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3951e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
3952e5b75505Sopenharmony_ci			   "DPP: TESTING - Authentication Response in place of Confirm");
3953e5b75505Sopenharmony_ci		if (dpp_auth_build_resp_ok(auth) < 0)
3954e5b75505Sopenharmony_ci			return NULL;
3955e5b75505Sopenharmony_ci		return wpabuf_dup(auth->resp_msg);
3956e5b75505Sopenharmony_ci	}
3957e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
3958e5b75505Sopenharmony_ci
3959e5b75505Sopenharmony_ci	return dpp_auth_build_conf(auth, DPP_STATUS_OK);
3960e5b75505Sopenharmony_ci
3961e5b75505Sopenharmony_cifail:
3962e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
3963e5b75505Sopenharmony_ci	bin_clear_free(unwrapped2, unwrapped2_len);
3964e5b75505Sopenharmony_ci	EVP_PKEY_free(pr);
3965e5b75505Sopenharmony_ci	return NULL;
3966e5b75505Sopenharmony_ci}
3967e5b75505Sopenharmony_ci
3968e5b75505Sopenharmony_ci
3969e5b75505Sopenharmony_cistatic int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3970e5b75505Sopenharmony_ci				    const u8 *hdr,
3971e5b75505Sopenharmony_ci				    const u8 *attr_start, size_t attr_len,
3972e5b75505Sopenharmony_ci				    const u8 *wrapped_data,
3973e5b75505Sopenharmony_ci				    u16 wrapped_data_len,
3974e5b75505Sopenharmony_ci				    enum dpp_status_error status)
3975e5b75505Sopenharmony_ci{
3976e5b75505Sopenharmony_ci	const u8 *addr[2];
3977e5b75505Sopenharmony_ci	size_t len[2];
3978e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
3979e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
3980e5b75505Sopenharmony_ci	const u8 *r_nonce;
3981e5b75505Sopenharmony_ci	u16 r_nonce_len;
3982e5b75505Sopenharmony_ci
3983e5b75505Sopenharmony_ci	/* Authentication Confirm failure cases are expected to include
3984e5b75505Sopenharmony_ci	 * {R-nonce}k2 in the Wrapped Data attribute. */
3985e5b75505Sopenharmony_ci
3986e5b75505Sopenharmony_ci	addr[0] = hdr;
3987e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
3988e5b75505Sopenharmony_ci	addr[1] = attr_start;
3989e5b75505Sopenharmony_ci	len[1] = attr_len;
3990e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3991e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3992e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3993e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
3994e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3995e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
3996e5b75505Sopenharmony_ci	if (!unwrapped) {
3997e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Authentication failed");
3998e5b75505Sopenharmony_ci		goto fail;
3999e5b75505Sopenharmony_ci	}
4000e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4001e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
4002e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
4003e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
4004e5b75505Sopenharmony_ci		goto fail;
4005e5b75505Sopenharmony_ci	}
4006e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4007e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
4008e5b75505Sopenharmony_ci
4009e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4010e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4011e5b75505Sopenharmony_ci		goto fail;
4012e5b75505Sopenharmony_ci	}
4013e5b75505Sopenharmony_ci
4014e5b75505Sopenharmony_ci	r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4015e5b75505Sopenharmony_ci			       &r_nonce_len);
4016e5b75505Sopenharmony_ci	if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
4017e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
4018e5b75505Sopenharmony_ci		goto fail;
4019e5b75505Sopenharmony_ci	}
4020e5b75505Sopenharmony_ci	if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
4021e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
4022e5b75505Sopenharmony_ci			    r_nonce, r_nonce_len);
4023e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
4024e5b75505Sopenharmony_ci			    auth->r_nonce, r_nonce_len);
4025e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "R-nonce mismatch");
4026e5b75505Sopenharmony_ci		goto fail;
4027e5b75505Sopenharmony_ci	}
4028e5b75505Sopenharmony_ci
4029e5b75505Sopenharmony_ci	if (status == DPP_STATUS_NOT_COMPATIBLE)
4030e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
4031e5b75505Sopenharmony_ci	else if (status == DPP_STATUS_AUTH_FAILURE)
4032e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Peer reported authentication failure)");
4033e5b75505Sopenharmony_ci
4034e5b75505Sopenharmony_cifail:
4035e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
4036e5b75505Sopenharmony_ci	return -1;
4037e5b75505Sopenharmony_ci}
4038e5b75505Sopenharmony_ci
4039e5b75505Sopenharmony_ci
4040e5b75505Sopenharmony_ciint dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
4041e5b75505Sopenharmony_ci		     const u8 *attr_start, size_t attr_len)
4042e5b75505Sopenharmony_ci{
4043e5b75505Sopenharmony_ci	const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
4044e5b75505Sopenharmony_ci	u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
4045e5b75505Sopenharmony_ci		i_auth_len;
4046e5b75505Sopenharmony_ci	const u8 *addr[2];
4047e5b75505Sopenharmony_ci	size_t len[2];
4048e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
4049e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
4050e5b75505Sopenharmony_ci	u8 i_auth2[DPP_MAX_HASH_LEN];
4051e5b75505Sopenharmony_ci
4052e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4053e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
4054e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
4055e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Authentication Confirm");
4056e5b75505Sopenharmony_ci		return -1;
4057e5b75505Sopenharmony_ci	}
4058e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4059e5b75505Sopenharmony_ci
4060e5b75505Sopenharmony_ci	if (auth->initiator || !auth->own_bi) {
4061e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unexpected Authentication Confirm");
4062e5b75505Sopenharmony_ci		return -1;
4063e5b75505Sopenharmony_ci	}
4064e5b75505Sopenharmony_ci
4065e5b75505Sopenharmony_ci	auth->waiting_auth_conf = 0;
4066e5b75505Sopenharmony_ci
4067e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4068e5b75505Sopenharmony_ci				    &wrapped_data_len);
4069e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4070e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4071e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
4072e5b75505Sopenharmony_ci		return -1;
4073e5b75505Sopenharmony_ci	}
4074e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
4075e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
4076e5b75505Sopenharmony_ci
4077e5b75505Sopenharmony_ci	attr_len = wrapped_data - 4 - attr_start;
4078e5b75505Sopenharmony_ci
4079e5b75505Sopenharmony_ci	r_bootstrap = dpp_get_attr(attr_start, attr_len,
4080e5b75505Sopenharmony_ci				   DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
4081e5b75505Sopenharmony_ci				   &r_bootstrap_len);
4082e5b75505Sopenharmony_ci	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
4083e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4084e5b75505Sopenharmony_ci			      "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4085e5b75505Sopenharmony_ci		return -1;
4086e5b75505Sopenharmony_ci	}
4087e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
4088e5b75505Sopenharmony_ci		    r_bootstrap, r_bootstrap_len);
4089e5b75505Sopenharmony_ci	if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
4090e5b75505Sopenharmony_ci		      SHA256_MAC_LEN) != 0) {
4091e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG,
4092e5b75505Sopenharmony_ci			    "DPP: Expected Responder Bootstrapping Key Hash",
4093e5b75505Sopenharmony_ci			    auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
4094e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4095e5b75505Sopenharmony_ci			      "Responder Bootstrapping Key Hash mismatch");
4096e5b75505Sopenharmony_ci		return -1;
4097e5b75505Sopenharmony_ci	}
4098e5b75505Sopenharmony_ci
4099e5b75505Sopenharmony_ci	i_bootstrap = dpp_get_attr(attr_start, attr_len,
4100e5b75505Sopenharmony_ci				   DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
4101e5b75505Sopenharmony_ci				   &i_bootstrap_len);
4102e5b75505Sopenharmony_ci	if (i_bootstrap) {
4103e5b75505Sopenharmony_ci		if (i_bootstrap_len != SHA256_MAC_LEN) {
4104e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
4105e5b75505Sopenharmony_ci				      "Invalid Initiator Bootstrapping Key Hash attribute");
4106e5b75505Sopenharmony_ci			return -1;
4107e5b75505Sopenharmony_ci		}
4108e5b75505Sopenharmony_ci		wpa_hexdump(MSG_MSGDUMP,
4109e5b75505Sopenharmony_ci			    "DPP: Initiator Bootstrapping Key Hash",
4110e5b75505Sopenharmony_ci			    i_bootstrap, i_bootstrap_len);
4111e5b75505Sopenharmony_ci		if (!auth->peer_bi ||
4112e5b75505Sopenharmony_ci		    os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
4113e5b75505Sopenharmony_ci			      SHA256_MAC_LEN) != 0) {
4114e5b75505Sopenharmony_ci			dpp_auth_fail(auth,
4115e5b75505Sopenharmony_ci				      "Initiator Bootstrapping Key Hash mismatch");
4116e5b75505Sopenharmony_ci			return -1;
4117e5b75505Sopenharmony_ci		}
4118e5b75505Sopenharmony_ci	} else if (auth->peer_bi) {
4119e5b75505Sopenharmony_ci		/* Mutual authentication and peer did not include its
4120e5b75505Sopenharmony_ci		 * Bootstrapping Key Hash attribute. */
4121e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4122e5b75505Sopenharmony_ci			      "Missing Initiator Bootstrapping Key Hash attribute");
4123e5b75505Sopenharmony_ci		return -1;
4124e5b75505Sopenharmony_ci	}
4125e5b75505Sopenharmony_ci
4126e5b75505Sopenharmony_ci	status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
4127e5b75505Sopenharmony_ci			      &status_len);
4128e5b75505Sopenharmony_ci	if (!status || status_len < 1) {
4129e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4130e5b75505Sopenharmony_ci			      "Missing or invalid required DPP Status attribute");
4131e5b75505Sopenharmony_ci		return -1;
4132e5b75505Sopenharmony_ci	}
4133e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
4134e5b75505Sopenharmony_ci	if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
4135e5b75505Sopenharmony_ci	    status[0] == DPP_STATUS_AUTH_FAILURE)
4136e5b75505Sopenharmony_ci		return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
4137e5b75505Sopenharmony_ci						attr_len, wrapped_data,
4138e5b75505Sopenharmony_ci						wrapped_data_len, status[0]);
4139e5b75505Sopenharmony_ci
4140e5b75505Sopenharmony_ci	if (status[0] != DPP_STATUS_OK) {
4141e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Authentication failed");
4142e5b75505Sopenharmony_ci		return -1;
4143e5b75505Sopenharmony_ci	}
4144e5b75505Sopenharmony_ci
4145e5b75505Sopenharmony_ci	addr[0] = hdr;
4146e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
4147e5b75505Sopenharmony_ci	addr[1] = attr_start;
4148e5b75505Sopenharmony_ci	len[1] = attr_len;
4149e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4150e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4151e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4152e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
4153e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4154e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
4155e5b75505Sopenharmony_ci	if (!unwrapped)
4156e5b75505Sopenharmony_ci		return -1;
4157e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4158e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
4159e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
4160e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
4161e5b75505Sopenharmony_ci		goto fail;
4162e5b75505Sopenharmony_ci	}
4163e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4164e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
4165e5b75505Sopenharmony_ci
4166e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4167e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4168e5b75505Sopenharmony_ci		goto fail;
4169e5b75505Sopenharmony_ci	}
4170e5b75505Sopenharmony_ci
4171e5b75505Sopenharmony_ci	i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
4172e5b75505Sopenharmony_ci			      &i_auth_len);
4173e5b75505Sopenharmony_ci	if (!i_auth || i_auth_len != auth->curve->hash_len) {
4174e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
4175e5b75505Sopenharmony_ci			      "Missing or invalid Initiator Authenticating Tag");
4176e5b75505Sopenharmony_ci		goto fail;
4177e5b75505Sopenharmony_ci	}
4178e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
4179e5b75505Sopenharmony_ci		    i_auth, i_auth_len);
4180e5b75505Sopenharmony_ci	/* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4181e5b75505Sopenharmony_ci	if (dpp_gen_i_auth(auth, i_auth2) < 0)
4182e5b75505Sopenharmony_ci		goto fail;
4183e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
4184e5b75505Sopenharmony_ci		    i_auth2, i_auth_len);
4185e5b75505Sopenharmony_ci	if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
4186e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
4187e5b75505Sopenharmony_ci		goto fail;
4188e5b75505Sopenharmony_ci	}
4189e5b75505Sopenharmony_ci
4190e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
4191e5b75505Sopenharmony_ci	dpp_auth_success(auth);
4192e5b75505Sopenharmony_ci	return 0;
4193e5b75505Sopenharmony_cifail:
4194e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
4195e5b75505Sopenharmony_ci	return -1;
4196e5b75505Sopenharmony_ci}
4197e5b75505Sopenharmony_ci
4198e5b75505Sopenharmony_ci
4199e5b75505Sopenharmony_cistatic int bin_str_eq(const char *val, size_t len, const char *cmp)
4200e5b75505Sopenharmony_ci{
4201e5b75505Sopenharmony_ci	return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
4202e5b75505Sopenharmony_ci}
4203e5b75505Sopenharmony_ci
4204e5b75505Sopenharmony_ci
4205e5b75505Sopenharmony_cistruct dpp_configuration * dpp_configuration_alloc(const char *type)
4206e5b75505Sopenharmony_ci{
4207e5b75505Sopenharmony_ci	struct dpp_configuration *conf;
4208e5b75505Sopenharmony_ci	const char *end;
4209e5b75505Sopenharmony_ci	size_t len;
4210e5b75505Sopenharmony_ci
4211e5b75505Sopenharmony_ci	conf = os_zalloc(sizeof(*conf));
4212e5b75505Sopenharmony_ci	if (!conf)
4213e5b75505Sopenharmony_ci		goto fail;
4214e5b75505Sopenharmony_ci
4215e5b75505Sopenharmony_ci	end = os_strchr(type, ' ');
4216e5b75505Sopenharmony_ci	if (end)
4217e5b75505Sopenharmony_ci		len = end - type;
4218e5b75505Sopenharmony_ci	else
4219e5b75505Sopenharmony_ci		len = os_strlen(type);
4220e5b75505Sopenharmony_ci
4221e5b75505Sopenharmony_ci	if (bin_str_eq(type, len, "psk"))
4222e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_PSK;
4223e5b75505Sopenharmony_ci	else if (bin_str_eq(type, len, "sae"))
4224e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_SAE;
4225e5b75505Sopenharmony_ci	else if (bin_str_eq(type, len, "psk-sae") ||
4226e5b75505Sopenharmony_ci		 bin_str_eq(type, len, "psk+sae"))
4227e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_PSK_SAE;
4228e5b75505Sopenharmony_ci	else if (bin_str_eq(type, len, "sae-dpp") ||
4229e5b75505Sopenharmony_ci		 bin_str_eq(type, len, "dpp+sae"))
4230e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_SAE_DPP;
4231e5b75505Sopenharmony_ci	else if (bin_str_eq(type, len, "psk-sae-dpp") ||
4232e5b75505Sopenharmony_ci		 bin_str_eq(type, len, "dpp+psk+sae"))
4233e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_PSK_SAE_DPP;
4234e5b75505Sopenharmony_ci	else if (bin_str_eq(type, len, "dpp"))
4235e5b75505Sopenharmony_ci		conf->akm = DPP_AKM_DPP;
4236e5b75505Sopenharmony_ci	else
4237e5b75505Sopenharmony_ci		goto fail;
4238e5b75505Sopenharmony_ci
4239e5b75505Sopenharmony_ci	return conf;
4240e5b75505Sopenharmony_cifail:
4241e5b75505Sopenharmony_ci	dpp_configuration_free(conf);
4242e5b75505Sopenharmony_ci	return NULL;
4243e5b75505Sopenharmony_ci}
4244e5b75505Sopenharmony_ci
4245e5b75505Sopenharmony_ci
4246e5b75505Sopenharmony_ciint dpp_akm_psk(enum dpp_akm akm)
4247e5b75505Sopenharmony_ci{
4248e5b75505Sopenharmony_ci	return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4249e5b75505Sopenharmony_ci		akm == DPP_AKM_PSK_SAE_DPP;
4250e5b75505Sopenharmony_ci}
4251e5b75505Sopenharmony_ci
4252e5b75505Sopenharmony_ci
4253e5b75505Sopenharmony_ciint dpp_akm_sae(enum dpp_akm akm)
4254e5b75505Sopenharmony_ci{
4255e5b75505Sopenharmony_ci	return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
4256e5b75505Sopenharmony_ci		akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4257e5b75505Sopenharmony_ci}
4258e5b75505Sopenharmony_ci
4259e5b75505Sopenharmony_ci
4260e5b75505Sopenharmony_ciint dpp_akm_legacy(enum dpp_akm akm)
4261e5b75505Sopenharmony_ci{
4262e5b75505Sopenharmony_ci	return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4263e5b75505Sopenharmony_ci		akm == DPP_AKM_SAE;
4264e5b75505Sopenharmony_ci}
4265e5b75505Sopenharmony_ci
4266e5b75505Sopenharmony_ci
4267e5b75505Sopenharmony_ciint dpp_akm_dpp(enum dpp_akm akm)
4268e5b75505Sopenharmony_ci{
4269e5b75505Sopenharmony_ci	return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
4270e5b75505Sopenharmony_ci		akm == DPP_AKM_PSK_SAE_DPP;
4271e5b75505Sopenharmony_ci}
4272e5b75505Sopenharmony_ci
4273e5b75505Sopenharmony_ci
4274e5b75505Sopenharmony_ciint dpp_akm_ver2(enum dpp_akm akm)
4275e5b75505Sopenharmony_ci{
4276e5b75505Sopenharmony_ci	return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4277e5b75505Sopenharmony_ci}
4278e5b75505Sopenharmony_ci
4279e5b75505Sopenharmony_ci
4280e5b75505Sopenharmony_ciint dpp_configuration_valid(const struct dpp_configuration *conf)
4281e5b75505Sopenharmony_ci{
4282e5b75505Sopenharmony_ci	if (conf->ssid_len == 0)
4283e5b75505Sopenharmony_ci		return 0;
4284e5b75505Sopenharmony_ci	if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
4285e5b75505Sopenharmony_ci		return 0;
4286e5b75505Sopenharmony_ci	if (dpp_akm_sae(conf->akm) && !conf->passphrase)
4287e5b75505Sopenharmony_ci		return 0;
4288e5b75505Sopenharmony_ci	return 1;
4289e5b75505Sopenharmony_ci}
4290e5b75505Sopenharmony_ci
4291e5b75505Sopenharmony_ci
4292e5b75505Sopenharmony_civoid dpp_configuration_free(struct dpp_configuration *conf)
4293e5b75505Sopenharmony_ci{
4294e5b75505Sopenharmony_ci	if (!conf)
4295e5b75505Sopenharmony_ci		return;
4296e5b75505Sopenharmony_ci	str_clear_free(conf->passphrase);
4297e5b75505Sopenharmony_ci	os_free(conf->group_id);
4298e5b75505Sopenharmony_ci	bin_clear_free(conf, sizeof(*conf));
4299e5b75505Sopenharmony_ci}
4300e5b75505Sopenharmony_ci
4301e5b75505Sopenharmony_ci
4302e5b75505Sopenharmony_cistatic int dpp_configuration_parse(struct dpp_authentication *auth,
4303e5b75505Sopenharmony_ci				   const char *cmd)
4304e5b75505Sopenharmony_ci{
4305e5b75505Sopenharmony_ci	const char *pos, *end;
4306e5b75505Sopenharmony_ci	struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
4307e5b75505Sopenharmony_ci	struct dpp_configuration *conf = NULL;
4308e5b75505Sopenharmony_ci
4309e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " conf=sta-");
4310e5b75505Sopenharmony_ci	if (pos) {
4311e5b75505Sopenharmony_ci		conf_sta = dpp_configuration_alloc(pos + 10);
4312e5b75505Sopenharmony_ci		if (!conf_sta)
4313e5b75505Sopenharmony_ci			goto fail;
4314e5b75505Sopenharmony_ci		conf = conf_sta;
4315e5b75505Sopenharmony_ci	}
4316e5b75505Sopenharmony_ci
4317e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " conf=ap-");
4318e5b75505Sopenharmony_ci	if (pos) {
4319e5b75505Sopenharmony_ci		conf_ap = dpp_configuration_alloc(pos + 9);
4320e5b75505Sopenharmony_ci		if (!conf_ap)
4321e5b75505Sopenharmony_ci			goto fail;
4322e5b75505Sopenharmony_ci		conf = conf_ap;
4323e5b75505Sopenharmony_ci	}
4324e5b75505Sopenharmony_ci
4325e5b75505Sopenharmony_ci	if (!conf)
4326e5b75505Sopenharmony_ci		return 0;
4327e5b75505Sopenharmony_ci
4328e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " ssid=");
4329e5b75505Sopenharmony_ci	if (pos) {
4330e5b75505Sopenharmony_ci		pos += 6;
4331e5b75505Sopenharmony_ci		end = os_strchr(pos, ' ');
4332e5b75505Sopenharmony_ci		conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
4333e5b75505Sopenharmony_ci		conf->ssid_len /= 2;
4334e5b75505Sopenharmony_ci		if (conf->ssid_len > sizeof(conf->ssid) ||
4335e5b75505Sopenharmony_ci		    hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
4336e5b75505Sopenharmony_ci			goto fail;
4337e5b75505Sopenharmony_ci	} else {
4338e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4339e5b75505Sopenharmony_ci		/* use a default SSID for legacy testing reasons */
4340e5b75505Sopenharmony_ci		os_memcpy(conf->ssid, "test", 4);
4341e5b75505Sopenharmony_ci		conf->ssid_len = 4;
4342e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
4343e5b75505Sopenharmony_ci		goto fail;
4344e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4345e5b75505Sopenharmony_ci	}
4346e5b75505Sopenharmony_ci
4347e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " pass=");
4348e5b75505Sopenharmony_ci	if (pos) {
4349e5b75505Sopenharmony_ci		size_t pass_len;
4350e5b75505Sopenharmony_ci
4351e5b75505Sopenharmony_ci		pos += 6;
4352e5b75505Sopenharmony_ci		end = os_strchr(pos, ' ');
4353e5b75505Sopenharmony_ci		pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
4354e5b75505Sopenharmony_ci		pass_len /= 2;
4355e5b75505Sopenharmony_ci		if (pass_len > 63 || pass_len < 8)
4356e5b75505Sopenharmony_ci			goto fail;
4357e5b75505Sopenharmony_ci		conf->passphrase = os_zalloc(pass_len + 1);
4358e5b75505Sopenharmony_ci		if (!conf->passphrase ||
4359e5b75505Sopenharmony_ci		    hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
4360e5b75505Sopenharmony_ci			goto fail;
4361e5b75505Sopenharmony_ci	}
4362e5b75505Sopenharmony_ci
4363e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " psk=");
4364e5b75505Sopenharmony_ci	if (pos) {
4365e5b75505Sopenharmony_ci		pos += 5;
4366e5b75505Sopenharmony_ci		if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
4367e5b75505Sopenharmony_ci			goto fail;
4368e5b75505Sopenharmony_ci		conf->psk_set = 1;
4369e5b75505Sopenharmony_ci	}
4370e5b75505Sopenharmony_ci
4371e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " group_id=");
4372e5b75505Sopenharmony_ci	if (pos) {
4373e5b75505Sopenharmony_ci		size_t group_id_len;
4374e5b75505Sopenharmony_ci
4375e5b75505Sopenharmony_ci		pos += 10;
4376e5b75505Sopenharmony_ci		end = os_strchr(pos, ' ');
4377e5b75505Sopenharmony_ci		group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
4378e5b75505Sopenharmony_ci		conf->group_id = os_malloc(group_id_len + 1);
4379e5b75505Sopenharmony_ci		if (!conf->group_id)
4380e5b75505Sopenharmony_ci			goto fail;
4381e5b75505Sopenharmony_ci		os_memcpy(conf->group_id, pos, group_id_len);
4382e5b75505Sopenharmony_ci		conf->group_id[group_id_len] = '\0';
4383e5b75505Sopenharmony_ci	}
4384e5b75505Sopenharmony_ci
4385e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " expiry=");
4386e5b75505Sopenharmony_ci	if (pos) {
4387e5b75505Sopenharmony_ci		long int val;
4388e5b75505Sopenharmony_ci
4389e5b75505Sopenharmony_ci		pos += 8;
4390e5b75505Sopenharmony_ci		val = strtol(pos, NULL, 0);
4391e5b75505Sopenharmony_ci		if (val <= 0)
4392e5b75505Sopenharmony_ci			goto fail;
4393e5b75505Sopenharmony_ci		conf->netaccesskey_expiry = val;
4394e5b75505Sopenharmony_ci	}
4395e5b75505Sopenharmony_ci
4396e5b75505Sopenharmony_ci	if (!dpp_configuration_valid(conf))
4397e5b75505Sopenharmony_ci		goto fail;
4398e5b75505Sopenharmony_ci
4399e5b75505Sopenharmony_ci	auth->conf_sta = conf_sta;
4400e5b75505Sopenharmony_ci	auth->conf_ap = conf_ap;
4401e5b75505Sopenharmony_ci	return 0;
4402e5b75505Sopenharmony_ci
4403e5b75505Sopenharmony_cifail:
4404e5b75505Sopenharmony_ci	dpp_configuration_free(conf_sta);
4405e5b75505Sopenharmony_ci	dpp_configuration_free(conf_ap);
4406e5b75505Sopenharmony_ci	return -1;
4407e5b75505Sopenharmony_ci}
4408e5b75505Sopenharmony_ci
4409e5b75505Sopenharmony_ci
4410e5b75505Sopenharmony_cistatic struct dpp_configurator *
4411e5b75505Sopenharmony_cidpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
4412e5b75505Sopenharmony_ci{
4413e5b75505Sopenharmony_ci	struct dpp_configurator *conf;
4414e5b75505Sopenharmony_ci
4415e5b75505Sopenharmony_ci	if (!dpp)
4416e5b75505Sopenharmony_ci		return NULL;
4417e5b75505Sopenharmony_ci
4418e5b75505Sopenharmony_ci	dl_list_for_each(conf, &dpp->configurator,
4419e5b75505Sopenharmony_ci			 struct dpp_configurator, list) {
4420e5b75505Sopenharmony_ci		if (conf->id == id)
4421e5b75505Sopenharmony_ci			return conf;
4422e5b75505Sopenharmony_ci	}
4423e5b75505Sopenharmony_ci	return NULL;
4424e5b75505Sopenharmony_ci}
4425e5b75505Sopenharmony_ci
4426e5b75505Sopenharmony_ci
4427e5b75505Sopenharmony_ciint dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
4428e5b75505Sopenharmony_ci			 struct dpp_authentication *auth,
4429e5b75505Sopenharmony_ci			 const char *cmd)
4430e5b75505Sopenharmony_ci{
4431e5b75505Sopenharmony_ci	const char *pos;
4432e5b75505Sopenharmony_ci
4433e5b75505Sopenharmony_ci	if (!cmd)
4434e5b75505Sopenharmony_ci		return 0;
4435e5b75505Sopenharmony_ci
4436e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
4437e5b75505Sopenharmony_ci
4438e5b75505Sopenharmony_ci	pos = os_strstr(cmd, " configurator=");
4439e5b75505Sopenharmony_ci	if (pos) {
4440e5b75505Sopenharmony_ci		pos += 14;
4441e5b75505Sopenharmony_ci		auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
4442e5b75505Sopenharmony_ci		if (!auth->conf) {
4443e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
4444e5b75505Sopenharmony_ci				   "DPP: Could not find the specified configurator");
4445e5b75505Sopenharmony_ci			return -1;
4446e5b75505Sopenharmony_ci		}
4447e5b75505Sopenharmony_ci	}
4448e5b75505Sopenharmony_ci
4449e5b75505Sopenharmony_ci	if (dpp_configuration_parse(auth, cmd) < 0) {
4450e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO,
4451e5b75505Sopenharmony_ci			"DPP: Failed to set configurator parameters");
4452e5b75505Sopenharmony_ci		return -1;
4453e5b75505Sopenharmony_ci	}
4454e5b75505Sopenharmony_ci	return 0;
4455e5b75505Sopenharmony_ci}
4456e5b75505Sopenharmony_ci
4457e5b75505Sopenharmony_ci
4458e5b75505Sopenharmony_civoid dpp_auth_deinit(struct dpp_authentication *auth)
4459e5b75505Sopenharmony_ci{
4460e5b75505Sopenharmony_ci	if (!auth)
4461e5b75505Sopenharmony_ci		return;
4462e5b75505Sopenharmony_ci	dpp_configuration_free(auth->conf_ap);
4463e5b75505Sopenharmony_ci	dpp_configuration_free(auth->conf_sta);
4464e5b75505Sopenharmony_ci	EVP_PKEY_free(auth->own_protocol_key);
4465e5b75505Sopenharmony_ci	EVP_PKEY_free(auth->peer_protocol_key);
4466e5b75505Sopenharmony_ci	wpabuf_free(auth->req_msg);
4467e5b75505Sopenharmony_ci	wpabuf_free(auth->resp_msg);
4468e5b75505Sopenharmony_ci	wpabuf_free(auth->conf_req);
4469e5b75505Sopenharmony_ci	os_free(auth->connector);
4470e5b75505Sopenharmony_ci	wpabuf_free(auth->net_access_key);
4471e5b75505Sopenharmony_ci	wpabuf_free(auth->c_sign_key);
4472e5b75505Sopenharmony_ci	dpp_bootstrap_info_free(auth->tmp_own_bi);
4473e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4474e5b75505Sopenharmony_ci	os_free(auth->config_obj_override);
4475e5b75505Sopenharmony_ci	os_free(auth->discovery_override);
4476e5b75505Sopenharmony_ci	os_free(auth->groups_override);
4477e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4478e5b75505Sopenharmony_ci	bin_clear_free(auth, sizeof(*auth));
4479e5b75505Sopenharmony_ci}
4480e5b75505Sopenharmony_ci
4481e5b75505Sopenharmony_ci
4482e5b75505Sopenharmony_cistatic struct wpabuf *
4483e5b75505Sopenharmony_cidpp_build_conf_start(struct dpp_authentication *auth,
4484e5b75505Sopenharmony_ci		     struct dpp_configuration *conf, size_t tailroom)
4485e5b75505Sopenharmony_ci{
4486e5b75505Sopenharmony_ci	struct wpabuf *buf;
4487e5b75505Sopenharmony_ci	char ssid[6 * sizeof(conf->ssid) + 1];
4488e5b75505Sopenharmony_ci
4489e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4490e5b75505Sopenharmony_ci	if (auth->discovery_override)
4491e5b75505Sopenharmony_ci		tailroom += os_strlen(auth->discovery_override);
4492e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4493e5b75505Sopenharmony_ci
4494e5b75505Sopenharmony_ci	buf = wpabuf_alloc(200 + tailroom);
4495e5b75505Sopenharmony_ci	if (!buf)
4496e5b75505Sopenharmony_ci		return NULL;
4497e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4498e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4499e5b75505Sopenharmony_ci	if (auth->discovery_override) {
4500e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4501e5b75505Sopenharmony_ci			   auth->discovery_override);
4502e5b75505Sopenharmony_ci		wpabuf_put_str(buf, auth->discovery_override);
4503e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, ',');
4504e5b75505Sopenharmony_ci		return buf;
4505e5b75505Sopenharmony_ci	}
4506e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4507e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "{\"ssid\":\"");
4508e5b75505Sopenharmony_ci	json_escape_string(ssid, sizeof(ssid),
4509e5b75505Sopenharmony_ci			   (const char *) conf->ssid, conf->ssid_len);
4510e5b75505Sopenharmony_ci	wpabuf_put_str(buf, ssid);
4511e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\"},");
4512e5b75505Sopenharmony_ci
4513e5b75505Sopenharmony_ci	return buf;
4514e5b75505Sopenharmony_ci}
4515e5b75505Sopenharmony_ci
4516e5b75505Sopenharmony_ci
4517e5b75505Sopenharmony_cistatic int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4518e5b75505Sopenharmony_ci			 const char *kid, const struct dpp_curve_params *curve)
4519e5b75505Sopenharmony_ci{
4520e5b75505Sopenharmony_ci	struct wpabuf *pub;
4521e5b75505Sopenharmony_ci	const u8 *pos;
4522e5b75505Sopenharmony_ci	char *x = NULL, *y = NULL;
4523e5b75505Sopenharmony_ci	int ret = -1;
4524e5b75505Sopenharmony_ci
4525e5b75505Sopenharmony_ci	pub = dpp_get_pubkey_point(key, 0);
4526e5b75505Sopenharmony_ci	if (!pub)
4527e5b75505Sopenharmony_ci		goto fail;
4528e5b75505Sopenharmony_ci	pos = wpabuf_head(pub);
4529e5b75505Sopenharmony_ci	x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4530e5b75505Sopenharmony_ci	pos += curve->prime_len;
4531e5b75505Sopenharmony_ci	y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
4532e5b75505Sopenharmony_ci	if (!x || !y)
4533e5b75505Sopenharmony_ci		goto fail;
4534e5b75505Sopenharmony_ci
4535e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\"");
4536e5b75505Sopenharmony_ci	wpabuf_put_str(buf, name);
4537e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
4538e5b75505Sopenharmony_ci	wpabuf_put_str(buf, curve->jwk_crv);
4539e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\",\"x\":\"");
4540e5b75505Sopenharmony_ci	wpabuf_put_str(buf, x);
4541e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\",\"y\":\"");
4542e5b75505Sopenharmony_ci	wpabuf_put_str(buf, y);
4543e5b75505Sopenharmony_ci	if (kid) {
4544e5b75505Sopenharmony_ci		wpabuf_put_str(buf, "\",\"kid\":\"");
4545e5b75505Sopenharmony_ci		wpabuf_put_str(buf, kid);
4546e5b75505Sopenharmony_ci	}
4547e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\"}");
4548e5b75505Sopenharmony_ci	ret = 0;
4549e5b75505Sopenharmony_cifail:
4550e5b75505Sopenharmony_ci	wpabuf_free(pub);
4551e5b75505Sopenharmony_ci	os_free(x);
4552e5b75505Sopenharmony_ci	os_free(y);
4553e5b75505Sopenharmony_ci	return ret;
4554e5b75505Sopenharmony_ci}
4555e5b75505Sopenharmony_ci
4556e5b75505Sopenharmony_ci
4557e5b75505Sopenharmony_cistatic void dpp_build_legacy_cred_params(struct wpabuf *buf,
4558e5b75505Sopenharmony_ci					 struct dpp_configuration *conf)
4559e5b75505Sopenharmony_ci{
4560e5b75505Sopenharmony_ci	if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
4561e5b75505Sopenharmony_ci		char pass[63 * 6 + 1];
4562e5b75505Sopenharmony_ci
4563e5b75505Sopenharmony_ci		json_escape_string(pass, sizeof(pass), conf->passphrase,
4564e5b75505Sopenharmony_ci				   os_strlen(conf->passphrase));
4565e5b75505Sopenharmony_ci		wpabuf_put_str(buf, "\"pass\":\"");
4566e5b75505Sopenharmony_ci		wpabuf_put_str(buf, pass);
4567e5b75505Sopenharmony_ci		wpabuf_put_str(buf, "\"");
4568e5b75505Sopenharmony_ci		os_memset(pass, 0, sizeof(pass));
4569e5b75505Sopenharmony_ci	} else if (conf->psk_set) {
4570e5b75505Sopenharmony_ci		char psk[2 * sizeof(conf->psk) + 1];
4571e5b75505Sopenharmony_ci
4572e5b75505Sopenharmony_ci		wpa_snprintf_hex(psk, sizeof(psk),
4573e5b75505Sopenharmony_ci				 conf->psk, sizeof(conf->psk));
4574e5b75505Sopenharmony_ci		wpabuf_put_str(buf, "\"psk_hex\":\"");
4575e5b75505Sopenharmony_ci		wpabuf_put_str(buf, psk);
4576e5b75505Sopenharmony_ci		wpabuf_put_str(buf, "\"");
4577e5b75505Sopenharmony_ci		os_memset(psk, 0, sizeof(psk));
4578e5b75505Sopenharmony_ci	}
4579e5b75505Sopenharmony_ci}
4580e5b75505Sopenharmony_ci
4581e5b75505Sopenharmony_ci
4582e5b75505Sopenharmony_cistatic struct wpabuf *
4583e5b75505Sopenharmony_cidpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
4584e5b75505Sopenharmony_ci		       struct dpp_configuration *conf)
4585e5b75505Sopenharmony_ci{
4586e5b75505Sopenharmony_ci	struct wpabuf *buf = NULL;
4587e5b75505Sopenharmony_ci	char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4588e5b75505Sopenharmony_ci	size_t tailroom;
4589e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve;
4590e5b75505Sopenharmony_ci	char jws_prot_hdr[100];
4591e5b75505Sopenharmony_ci	size_t signed1_len, signed2_len, signed3_len;
4592e5b75505Sopenharmony_ci	struct wpabuf *dppcon = NULL;
4593e5b75505Sopenharmony_ci	unsigned char *signature = NULL;
4594e5b75505Sopenharmony_ci	const unsigned char *p;
4595e5b75505Sopenharmony_ci	size_t signature_len;
4596e5b75505Sopenharmony_ci	EVP_MD_CTX *md_ctx = NULL;
4597e5b75505Sopenharmony_ci	ECDSA_SIG *sig = NULL;
4598e5b75505Sopenharmony_ci	char *dot = ".";
4599e5b75505Sopenharmony_ci	const EVP_MD *sign_md;
4600e5b75505Sopenharmony_ci	const BIGNUM *r, *s;
4601e5b75505Sopenharmony_ci	size_t extra_len = 1000;
4602e5b75505Sopenharmony_ci	int incl_legacy;
4603e5b75505Sopenharmony_ci	enum dpp_akm akm;
4604e5b75505Sopenharmony_ci
4605e5b75505Sopenharmony_ci	if (!auth->conf) {
4606e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
4607e5b75505Sopenharmony_ci			   "DPP: No configurator specified - cannot generate DPP config object");
4608e5b75505Sopenharmony_ci		goto fail;
4609e5b75505Sopenharmony_ci	}
4610e5b75505Sopenharmony_ci	curve = auth->conf->curve;
4611e5b75505Sopenharmony_ci	if (curve->hash_len == SHA256_MAC_LEN) {
4612e5b75505Sopenharmony_ci		sign_md = EVP_sha256();
4613e5b75505Sopenharmony_ci	} else if (curve->hash_len == SHA384_MAC_LEN) {
4614e5b75505Sopenharmony_ci		sign_md = EVP_sha384();
4615e5b75505Sopenharmony_ci	} else if (curve->hash_len == SHA512_MAC_LEN) {
4616e5b75505Sopenharmony_ci		sign_md = EVP_sha512();
4617e5b75505Sopenharmony_ci	} else {
4618e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4619e5b75505Sopenharmony_ci		goto fail;
4620e5b75505Sopenharmony_ci	}
4621e5b75505Sopenharmony_ci
4622e5b75505Sopenharmony_ci	akm = conf->akm;
4623e5b75505Sopenharmony_ci	if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4624e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
4625e5b75505Sopenharmony_ci			   "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4626e5b75505Sopenharmony_ci		akm = DPP_AKM_DPP;
4627e5b75505Sopenharmony_ci	}
4628e5b75505Sopenharmony_ci
4629e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4630e5b75505Sopenharmony_ci	if (auth->groups_override)
4631e5b75505Sopenharmony_ci		extra_len += os_strlen(auth->groups_override);
4632e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4633e5b75505Sopenharmony_ci
4634e5b75505Sopenharmony_ci	if (conf->group_id)
4635e5b75505Sopenharmony_ci		extra_len += os_strlen(conf->group_id);
4636e5b75505Sopenharmony_ci
4637e5b75505Sopenharmony_ci	/* Connector (JSON dppCon object) */
4638e5b75505Sopenharmony_ci	dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4639e5b75505Sopenharmony_ci	if (!dppcon)
4640e5b75505Sopenharmony_ci		goto fail;
4641e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4642e5b75505Sopenharmony_ci	if (auth->groups_override) {
4643e5b75505Sopenharmony_ci		wpabuf_put_u8(dppcon, '{');
4644e5b75505Sopenharmony_ci		if (auth->groups_override) {
4645e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
4646e5b75505Sopenharmony_ci				   "DPP: TESTING - groups override: '%s'",
4647e5b75505Sopenharmony_ci				   auth->groups_override);
4648e5b75505Sopenharmony_ci			wpabuf_put_str(dppcon, "\"groups\":");
4649e5b75505Sopenharmony_ci			wpabuf_put_str(dppcon, auth->groups_override);
4650e5b75505Sopenharmony_ci			wpabuf_put_u8(dppcon, ',');
4651e5b75505Sopenharmony_ci		}
4652e5b75505Sopenharmony_ci		goto skip_groups;
4653e5b75505Sopenharmony_ci	}
4654e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4655e5b75505Sopenharmony_ci	wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
4656e5b75505Sopenharmony_ci		      conf->group_id ? conf->group_id : "*");
4657e5b75505Sopenharmony_ci	wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
4658e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4659e5b75505Sopenharmony_ciskip_groups:
4660e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4661e5b75505Sopenharmony_ci	if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4662e5b75505Sopenharmony_ci			  auth->curve) < 0) {
4663e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4664e5b75505Sopenharmony_ci		goto fail;
4665e5b75505Sopenharmony_ci	}
4666e5b75505Sopenharmony_ci	if (conf->netaccesskey_expiry) {
4667e5b75505Sopenharmony_ci		struct os_tm tm;
4668e5b75505Sopenharmony_ci
4669e5b75505Sopenharmony_ci		if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4670e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
4671e5b75505Sopenharmony_ci				   "DPP: Failed to generate expiry string");
4672e5b75505Sopenharmony_ci			goto fail;
4673e5b75505Sopenharmony_ci		}
4674e5b75505Sopenharmony_ci		wpabuf_printf(dppcon,
4675e5b75505Sopenharmony_ci			      ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4676e5b75505Sopenharmony_ci			      tm.year, tm.month, tm.day,
4677e5b75505Sopenharmony_ci			      tm.hour, tm.min, tm.sec);
4678e5b75505Sopenharmony_ci	}
4679e5b75505Sopenharmony_ci	wpabuf_put_u8(dppcon, '}');
4680e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
4681e5b75505Sopenharmony_ci		   (const char *) wpabuf_head(dppcon));
4682e5b75505Sopenharmony_ci
4683e5b75505Sopenharmony_ci	os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
4684e5b75505Sopenharmony_ci		    "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4685e5b75505Sopenharmony_ci		    auth->conf->kid, curve->jws_alg);
4686e5b75505Sopenharmony_ci	signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
4687e5b75505Sopenharmony_ci					     os_strlen(jws_prot_hdr),
4688e5b75505Sopenharmony_ci					     &signed1_len, 0);
4689e5b75505Sopenharmony_ci	signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
4690e5b75505Sopenharmony_ci					     wpabuf_len(dppcon),
4691e5b75505Sopenharmony_ci					     &signed2_len, 0);
4692e5b75505Sopenharmony_ci	if (!signed1 || !signed2)
4693e5b75505Sopenharmony_ci		goto fail;
4694e5b75505Sopenharmony_ci
4695e5b75505Sopenharmony_ci	md_ctx = EVP_MD_CTX_create();
4696e5b75505Sopenharmony_ci	if (!md_ctx)
4697e5b75505Sopenharmony_ci		goto fail;
4698e5b75505Sopenharmony_ci
4699e5b75505Sopenharmony_ci	ERR_clear_error();
4700e5b75505Sopenharmony_ci	if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
4701e5b75505Sopenharmony_ci			       auth->conf->csign) != 1) {
4702e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
4703e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
4704e5b75505Sopenharmony_ci		goto fail;
4705e5b75505Sopenharmony_ci	}
4706e5b75505Sopenharmony_ci	if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
4707e5b75505Sopenharmony_ci	    EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
4708e5b75505Sopenharmony_ci	    EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
4709e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
4710e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
4711e5b75505Sopenharmony_ci		goto fail;
4712e5b75505Sopenharmony_ci	}
4713e5b75505Sopenharmony_ci	if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
4714e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4715e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
4716e5b75505Sopenharmony_ci		goto fail;
4717e5b75505Sopenharmony_ci	}
4718e5b75505Sopenharmony_ci	signature = os_malloc(signature_len);
4719e5b75505Sopenharmony_ci	if (!signature)
4720e5b75505Sopenharmony_ci		goto fail;
4721e5b75505Sopenharmony_ci	if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
4722e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
4723e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
4724e5b75505Sopenharmony_ci		goto fail;
4725e5b75505Sopenharmony_ci	}
4726e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
4727e5b75505Sopenharmony_ci		    signature, signature_len);
4728e5b75505Sopenharmony_ci	/* Convert to raw coordinates r,s */
4729e5b75505Sopenharmony_ci	p = signature;
4730e5b75505Sopenharmony_ci	sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
4731e5b75505Sopenharmony_ci	if (!sig)
4732e5b75505Sopenharmony_ci		goto fail;
4733e5b75505Sopenharmony_ci	ECDSA_SIG_get0(sig, &r, &s);
4734e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4735e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(s, signature + curve->prime_len,
4736e5b75505Sopenharmony_ci			   curve->prime_len) < 0)
4737e5b75505Sopenharmony_ci		goto fail;
4738e5b75505Sopenharmony_ci	signature_len = 2 * curve->prime_len;
4739e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4740e5b75505Sopenharmony_ci		    signature, signature_len);
4741e5b75505Sopenharmony_ci	signed3 = (char *) base64_url_encode(signature, signature_len,
4742e5b75505Sopenharmony_ci					     &signed3_len, 0);
4743e5b75505Sopenharmony_ci	if (!signed3)
4744e5b75505Sopenharmony_ci		goto fail;
4745e5b75505Sopenharmony_ci
4746e5b75505Sopenharmony_ci	incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
4747e5b75505Sopenharmony_ci	tailroom = 1000;
4748e5b75505Sopenharmony_ci	tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4749e5b75505Sopenharmony_ci	tailroom += signed1_len + signed2_len + signed3_len;
4750e5b75505Sopenharmony_ci	if (incl_legacy)
4751e5b75505Sopenharmony_ci		tailroom += 1000;
4752e5b75505Sopenharmony_ci	buf = dpp_build_conf_start(auth, conf, tailroom);
4753e5b75505Sopenharmony_ci	if (!buf)
4754e5b75505Sopenharmony_ci		goto fail;
4755e5b75505Sopenharmony_ci
4756e5b75505Sopenharmony_ci	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
4757e5b75505Sopenharmony_ci	if (incl_legacy) {
4758e5b75505Sopenharmony_ci		dpp_build_legacy_cred_params(buf, conf);
4759e5b75505Sopenharmony_ci		wpabuf_put_str(buf, ",");
4760e5b75505Sopenharmony_ci	}
4761e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\"signedConnector\":\"");
4762e5b75505Sopenharmony_ci	wpabuf_put_str(buf, signed1);
4763e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, '.');
4764e5b75505Sopenharmony_ci	wpabuf_put_str(buf, signed2);
4765e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, '.');
4766e5b75505Sopenharmony_ci	wpabuf_put_str(buf, signed3);
4767e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "\",");
4768e5b75505Sopenharmony_ci	if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4769e5b75505Sopenharmony_ci			  curve) < 0) {
4770e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4771e5b75505Sopenharmony_ci		goto fail;
4772e5b75505Sopenharmony_ci	}
4773e5b75505Sopenharmony_ci
4774e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "}}");
4775e5b75505Sopenharmony_ci
4776e5b75505Sopenharmony_ci	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4777e5b75505Sopenharmony_ci			      wpabuf_head(buf), wpabuf_len(buf));
4778e5b75505Sopenharmony_ci
4779e5b75505Sopenharmony_ciout:
4780e5b75505Sopenharmony_ci	EVP_MD_CTX_destroy(md_ctx);
4781e5b75505Sopenharmony_ci	ECDSA_SIG_free(sig);
4782e5b75505Sopenharmony_ci	os_free(signed1);
4783e5b75505Sopenharmony_ci	os_free(signed2);
4784e5b75505Sopenharmony_ci	os_free(signed3);
4785e5b75505Sopenharmony_ci	os_free(signature);
4786e5b75505Sopenharmony_ci	wpabuf_free(dppcon);
4787e5b75505Sopenharmony_ci	return buf;
4788e5b75505Sopenharmony_cifail:
4789e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4790e5b75505Sopenharmony_ci	wpabuf_free(buf);
4791e5b75505Sopenharmony_ci	buf = NULL;
4792e5b75505Sopenharmony_ci	goto out;
4793e5b75505Sopenharmony_ci}
4794e5b75505Sopenharmony_ci
4795e5b75505Sopenharmony_ci
4796e5b75505Sopenharmony_cistatic struct wpabuf *
4797e5b75505Sopenharmony_cidpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
4798e5b75505Sopenharmony_ci			  struct dpp_configuration *conf)
4799e5b75505Sopenharmony_ci{
4800e5b75505Sopenharmony_ci	struct wpabuf *buf;
4801e5b75505Sopenharmony_ci
4802e5b75505Sopenharmony_ci	buf = dpp_build_conf_start(auth, conf, 1000);
4803e5b75505Sopenharmony_ci	if (!buf)
4804e5b75505Sopenharmony_ci		return NULL;
4805e5b75505Sopenharmony_ci
4806e5b75505Sopenharmony_ci	wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
4807e5b75505Sopenharmony_ci	dpp_build_legacy_cred_params(buf, conf);
4808e5b75505Sopenharmony_ci	wpabuf_put_str(buf, "}}");
4809e5b75505Sopenharmony_ci
4810e5b75505Sopenharmony_ci	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4811e5b75505Sopenharmony_ci			      wpabuf_head(buf), wpabuf_len(buf));
4812e5b75505Sopenharmony_ci
4813e5b75505Sopenharmony_ci	return buf;
4814e5b75505Sopenharmony_ci}
4815e5b75505Sopenharmony_ci
4816e5b75505Sopenharmony_ci
4817e5b75505Sopenharmony_cistatic struct wpabuf *
4818e5b75505Sopenharmony_cidpp_build_conf_obj(struct dpp_authentication *auth, int ap)
4819e5b75505Sopenharmony_ci{
4820e5b75505Sopenharmony_ci	struct dpp_configuration *conf;
4821e5b75505Sopenharmony_ci
4822e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4823e5b75505Sopenharmony_ci	if (auth->config_obj_override) {
4824e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4825e5b75505Sopenharmony_ci		return wpabuf_alloc_copy(auth->config_obj_override,
4826e5b75505Sopenharmony_ci					 os_strlen(auth->config_obj_override));
4827e5b75505Sopenharmony_ci	}
4828e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4829e5b75505Sopenharmony_ci
4830e5b75505Sopenharmony_ci	conf = ap ? auth->conf_ap : auth->conf_sta;
4831e5b75505Sopenharmony_ci	if (!conf) {
4832e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
4833e5b75505Sopenharmony_ci			   "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4834e5b75505Sopenharmony_ci			   ap ? "ap" : "sta");
4835e5b75505Sopenharmony_ci		return NULL;
4836e5b75505Sopenharmony_ci	}
4837e5b75505Sopenharmony_ci
4838e5b75505Sopenharmony_ci	if (dpp_akm_dpp(conf->akm))
4839e5b75505Sopenharmony_ci		return dpp_build_conf_obj_dpp(auth, ap, conf);
4840e5b75505Sopenharmony_ci	return dpp_build_conf_obj_legacy(auth, ap, conf);
4841e5b75505Sopenharmony_ci}
4842e5b75505Sopenharmony_ci
4843e5b75505Sopenharmony_ci
4844e5b75505Sopenharmony_cistatic struct wpabuf *
4845e5b75505Sopenharmony_cidpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4846e5b75505Sopenharmony_ci		    u16 e_nonce_len, int ap)
4847e5b75505Sopenharmony_ci{
4848e5b75505Sopenharmony_ci	struct wpabuf *conf;
4849e5b75505Sopenharmony_ci	size_t clear_len, attr_len;
4850e5b75505Sopenharmony_ci	struct wpabuf *clear = NULL, *msg = NULL;
4851e5b75505Sopenharmony_ci	u8 *wrapped;
4852e5b75505Sopenharmony_ci	const u8 *addr[1];
4853e5b75505Sopenharmony_ci	size_t len[1];
4854e5b75505Sopenharmony_ci	enum dpp_status_error status;
4855e5b75505Sopenharmony_ci
4856e5b75505Sopenharmony_ci	conf = dpp_build_conf_obj(auth, ap);
4857e5b75505Sopenharmony_ci	if (conf) {
4858e5b75505Sopenharmony_ci		wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4859e5b75505Sopenharmony_ci				  wpabuf_head(conf), wpabuf_len(conf));
4860e5b75505Sopenharmony_ci	}
4861e5b75505Sopenharmony_ci	status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4862e5b75505Sopenharmony_ci	auth->conf_resp_status = status;
4863e5b75505Sopenharmony_ci
4864e5b75505Sopenharmony_ci	/* { E-nonce, configurationObject}ke */
4865e5b75505Sopenharmony_ci	clear_len = 4 + e_nonce_len;
4866e5b75505Sopenharmony_ci	if (conf)
4867e5b75505Sopenharmony_ci		clear_len += 4 + wpabuf_len(conf);
4868e5b75505Sopenharmony_ci	clear = wpabuf_alloc(clear_len);
4869e5b75505Sopenharmony_ci	attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4870e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4871e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4872e5b75505Sopenharmony_ci		attr_len += 5;
4873e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4874e5b75505Sopenharmony_ci	msg = wpabuf_alloc(attr_len);
4875e5b75505Sopenharmony_ci	if (!clear || !msg)
4876e5b75505Sopenharmony_ci		goto fail;
4877e5b75505Sopenharmony_ci
4878e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4879e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4880e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4881e5b75505Sopenharmony_ci		goto skip_e_nonce;
4882e5b75505Sopenharmony_ci	}
4883e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4884e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4885e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4886e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, e_nonce_len);
4887e5b75505Sopenharmony_ci		wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4888e5b75505Sopenharmony_ci		wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4889e5b75505Sopenharmony_ci		goto skip_e_nonce;
4890e5b75505Sopenharmony_ci	}
4891e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4892e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4893e5b75505Sopenharmony_ci		goto skip_wrapped_data;
4894e5b75505Sopenharmony_ci	}
4895e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4896e5b75505Sopenharmony_ci
4897e5b75505Sopenharmony_ci	/* E-nonce */
4898e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4899e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, e_nonce_len);
4900e5b75505Sopenharmony_ci	wpabuf_put_data(clear, e_nonce, e_nonce_len);
4901e5b75505Sopenharmony_ci
4902e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4903e5b75505Sopenharmony_ciskip_e_nonce:
4904e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4905e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4906e5b75505Sopenharmony_ci		goto skip_config_obj;
4907e5b75505Sopenharmony_ci	}
4908e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4909e5b75505Sopenharmony_ci
4910e5b75505Sopenharmony_ci	if (conf) {
4911e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4912e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, wpabuf_len(conf));
4913e5b75505Sopenharmony_ci		wpabuf_put_buf(clear, conf);
4914e5b75505Sopenharmony_ci	}
4915e5b75505Sopenharmony_ci
4916e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4917e5b75505Sopenharmony_ciskip_config_obj:
4918e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4919e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4920e5b75505Sopenharmony_ci		goto skip_status;
4921e5b75505Sopenharmony_ci	}
4922e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4923e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4924e5b75505Sopenharmony_ci		status = 255;
4925e5b75505Sopenharmony_ci	}
4926e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4927e5b75505Sopenharmony_ci
4928e5b75505Sopenharmony_ci	/* DPP Status */
4929e5b75505Sopenharmony_ci	dpp_build_attr_status(msg, status);
4930e5b75505Sopenharmony_ci
4931e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4932e5b75505Sopenharmony_ciskip_status:
4933e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4934e5b75505Sopenharmony_ci
4935e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(msg);
4936e5b75505Sopenharmony_ci	len[0] = wpabuf_len(msg);
4937e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4938e5b75505Sopenharmony_ci
4939e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4940e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4941e5b75505Sopenharmony_ci	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4942e5b75505Sopenharmony_ci
4943e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4944e5b75505Sopenharmony_ci	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4945e5b75505Sopenharmony_ci			    wpabuf_head(clear), wpabuf_len(clear),
4946e5b75505Sopenharmony_ci			    1, addr, len, wrapped) < 0)
4947e5b75505Sopenharmony_ci		goto fail;
4948e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4949e5b75505Sopenharmony_ci		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
4950e5b75505Sopenharmony_ci
4951e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4952e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4953e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4954e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
4955e5b75505Sopenharmony_ci	}
4956e5b75505Sopenharmony_ciskip_wrapped_data:
4957e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4958e5b75505Sopenharmony_ci
4959e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG,
4960e5b75505Sopenharmony_ci			"DPP: Configuration Response attributes", msg);
4961e5b75505Sopenharmony_ciout:
4962e5b75505Sopenharmony_ci	wpabuf_free(conf);
4963e5b75505Sopenharmony_ci	wpabuf_free(clear);
4964e5b75505Sopenharmony_ci
4965e5b75505Sopenharmony_ci	return msg;
4966e5b75505Sopenharmony_cifail:
4967e5b75505Sopenharmony_ci	wpabuf_free(msg);
4968e5b75505Sopenharmony_ci	msg = NULL;
4969e5b75505Sopenharmony_ci	goto out;
4970e5b75505Sopenharmony_ci}
4971e5b75505Sopenharmony_ci
4972e5b75505Sopenharmony_ci
4973e5b75505Sopenharmony_cistruct wpabuf *
4974e5b75505Sopenharmony_cidpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4975e5b75505Sopenharmony_ci		size_t attr_len)
4976e5b75505Sopenharmony_ci{
4977e5b75505Sopenharmony_ci	const u8 *wrapped_data, *e_nonce, *config_attr;
4978e5b75505Sopenharmony_ci	u16 wrapped_data_len, e_nonce_len, config_attr_len;
4979e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
4980e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
4981e5b75505Sopenharmony_ci	struct wpabuf *resp = NULL;
4982e5b75505Sopenharmony_ci	struct json_token *root = NULL, *token;
4983e5b75505Sopenharmony_ci	int ap;
4984e5b75505Sopenharmony_ci
4985e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
4986e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
4987e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
4988e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Config Request");
4989e5b75505Sopenharmony_ci		return NULL;
4990e5b75505Sopenharmony_ci	}
4991e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
4992e5b75505Sopenharmony_ci
4993e5b75505Sopenharmony_ci	if (dpp_check_attrs(attr_start, attr_len) < 0) {
4994e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in config request");
4995e5b75505Sopenharmony_ci		return NULL;
4996e5b75505Sopenharmony_ci	}
4997e5b75505Sopenharmony_ci
4998e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4999e5b75505Sopenharmony_ci				    &wrapped_data_len);
5000e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5001e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5002e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
5003e5b75505Sopenharmony_ci		return NULL;
5004e5b75505Sopenharmony_ci	}
5005e5b75505Sopenharmony_ci
5006e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5007e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
5008e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5009e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
5010e5b75505Sopenharmony_ci	if (!unwrapped)
5011e5b75505Sopenharmony_ci		return NULL;
5012e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5013e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
5014e5b75505Sopenharmony_ci			    0, NULL, NULL, unwrapped) < 0) {
5015e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
5016e5b75505Sopenharmony_ci		goto fail;
5017e5b75505Sopenharmony_ci	}
5018e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5019e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
5020e5b75505Sopenharmony_ci
5021e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5022e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5023e5b75505Sopenharmony_ci		goto fail;
5024e5b75505Sopenharmony_ci	}
5025e5b75505Sopenharmony_ci
5026e5b75505Sopenharmony_ci	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5027e5b75505Sopenharmony_ci			       DPP_ATTR_ENROLLEE_NONCE,
5028e5b75505Sopenharmony_ci			       &e_nonce_len);
5029e5b75505Sopenharmony_ci	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5030e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5031e5b75505Sopenharmony_ci			      "Missing or invalid Enrollee Nonce attribute");
5032e5b75505Sopenharmony_ci		goto fail;
5033e5b75505Sopenharmony_ci	}
5034e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5035e5b75505Sopenharmony_ci	os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
5036e5b75505Sopenharmony_ci
5037e5b75505Sopenharmony_ci	config_attr = dpp_get_attr(unwrapped, unwrapped_len,
5038e5b75505Sopenharmony_ci				   DPP_ATTR_CONFIG_ATTR_OBJ,
5039e5b75505Sopenharmony_ci				   &config_attr_len);
5040e5b75505Sopenharmony_ci	if (!config_attr) {
5041e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5042e5b75505Sopenharmony_ci			      "Missing or invalid Config Attributes attribute");
5043e5b75505Sopenharmony_ci		goto fail;
5044e5b75505Sopenharmony_ci	}
5045e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
5046e5b75505Sopenharmony_ci			  config_attr, config_attr_len);
5047e5b75505Sopenharmony_ci
5048e5b75505Sopenharmony_ci	root = json_parse((const char *) config_attr, config_attr_len);
5049e5b75505Sopenharmony_ci	if (!root) {
5050e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Could not parse Config Attributes");
5051e5b75505Sopenharmony_ci		goto fail;
5052e5b75505Sopenharmony_ci	}
5053e5b75505Sopenharmony_ci
5054e5b75505Sopenharmony_ci	token = json_get_member(root, "name");
5055e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5056e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No Config Attributes - name");
5057e5b75505Sopenharmony_ci		goto fail;
5058e5b75505Sopenharmony_ci	}
5059e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
5060e5b75505Sopenharmony_ci
5061e5b75505Sopenharmony_ci	token = json_get_member(root, "wi-fi_tech");
5062e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5063e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
5064e5b75505Sopenharmony_ci		goto fail;
5065e5b75505Sopenharmony_ci	}
5066e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
5067e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "infra") != 0) {
5068e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
5069e5b75505Sopenharmony_ci			   token->string);
5070e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unsupported wi-fi_tech");
5071e5b75505Sopenharmony_ci		goto fail;
5072e5b75505Sopenharmony_ci	}
5073e5b75505Sopenharmony_ci
5074e5b75505Sopenharmony_ci	token = json_get_member(root, "netRole");
5075e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5076e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No Config Attributes - netRole");
5077e5b75505Sopenharmony_ci		goto fail;
5078e5b75505Sopenharmony_ci	}
5079e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
5080e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "sta") == 0) {
5081e5b75505Sopenharmony_ci		ap = 0;
5082e5b75505Sopenharmony_ci	} else if (os_strcmp(token->string, "ap") == 0) {
5083e5b75505Sopenharmony_ci		ap = 1;
5084e5b75505Sopenharmony_ci	} else {
5085e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
5086e5b75505Sopenharmony_ci			   token->string);
5087e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unsupported netRole");
5088e5b75505Sopenharmony_ci		goto fail;
5089e5b75505Sopenharmony_ci	}
5090e5b75505Sopenharmony_ci
5091e5b75505Sopenharmony_ci	resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
5092e5b75505Sopenharmony_ci
5093e5b75505Sopenharmony_cifail:
5094e5b75505Sopenharmony_ci	json_free(root);
5095e5b75505Sopenharmony_ci	os_free(unwrapped);
5096e5b75505Sopenharmony_ci	return resp;
5097e5b75505Sopenharmony_ci}
5098e5b75505Sopenharmony_ci
5099e5b75505Sopenharmony_ci
5100e5b75505Sopenharmony_cistatic struct wpabuf *
5101e5b75505Sopenharmony_cidpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
5102e5b75505Sopenharmony_ci		       const u8 *prot_hdr, u16 prot_hdr_len,
5103e5b75505Sopenharmony_ci		       const EVP_MD **ret_md)
5104e5b75505Sopenharmony_ci{
5105e5b75505Sopenharmony_ci	struct json_token *root, *token;
5106e5b75505Sopenharmony_ci	struct wpabuf *kid = NULL;
5107e5b75505Sopenharmony_ci
5108e5b75505Sopenharmony_ci	root = json_parse((const char *) prot_hdr, prot_hdr_len);
5109e5b75505Sopenharmony_ci	if (!root) {
5110e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5111e5b75505Sopenharmony_ci			   "DPP: JSON parsing failed for JWS Protected Header");
5112e5b75505Sopenharmony_ci		goto fail;
5113e5b75505Sopenharmony_ci	}
5114e5b75505Sopenharmony_ci
5115e5b75505Sopenharmony_ci	if (root->type != JSON_OBJECT) {
5116e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5117e5b75505Sopenharmony_ci			   "DPP: JWS Protected Header root is not an object");
5118e5b75505Sopenharmony_ci		goto fail;
5119e5b75505Sopenharmony_ci	}
5120e5b75505Sopenharmony_ci
5121e5b75505Sopenharmony_ci	token = json_get_member(root, "typ");
5122e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5123e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
5124e5b75505Sopenharmony_ci		goto fail;
5125e5b75505Sopenharmony_ci	}
5126e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
5127e5b75505Sopenharmony_ci		   token->string);
5128e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "dppCon") != 0) {
5129e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5130e5b75505Sopenharmony_ci			   "DPP: Unsupported JWS Protected Header typ=%s",
5131e5b75505Sopenharmony_ci			   token->string);
5132e5b75505Sopenharmony_ci		goto fail;
5133e5b75505Sopenharmony_ci	}
5134e5b75505Sopenharmony_ci
5135e5b75505Sopenharmony_ci	token = json_get_member(root, "alg");
5136e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5137e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
5138e5b75505Sopenharmony_ci		goto fail;
5139e5b75505Sopenharmony_ci	}
5140e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
5141e5b75505Sopenharmony_ci		   token->string);
5142e5b75505Sopenharmony_ci	if (os_strcmp(token->string, curve->jws_alg) != 0) {
5143e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5144e5b75505Sopenharmony_ci			   "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5145e5b75505Sopenharmony_ci			   token->string, curve->jws_alg);
5146e5b75505Sopenharmony_ci		goto fail;
5147e5b75505Sopenharmony_ci	}
5148e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "ES256") == 0 ||
5149e5b75505Sopenharmony_ci	    os_strcmp(token->string, "BS256") == 0)
5150e5b75505Sopenharmony_ci		*ret_md = EVP_sha256();
5151e5b75505Sopenharmony_ci	else if (os_strcmp(token->string, "ES384") == 0 ||
5152e5b75505Sopenharmony_ci		 os_strcmp(token->string, "BS384") == 0)
5153e5b75505Sopenharmony_ci		*ret_md = EVP_sha384();
5154e5b75505Sopenharmony_ci	else if (os_strcmp(token->string, "ES512") == 0 ||
5155e5b75505Sopenharmony_ci		 os_strcmp(token->string, "BS512") == 0)
5156e5b75505Sopenharmony_ci		*ret_md = EVP_sha512();
5157e5b75505Sopenharmony_ci	else
5158e5b75505Sopenharmony_ci		*ret_md = NULL;
5159e5b75505Sopenharmony_ci	if (!*ret_md) {
5160e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5161e5b75505Sopenharmony_ci			   "DPP: Unsupported JWS Protected Header alg=%s",
5162e5b75505Sopenharmony_ci			   token->string);
5163e5b75505Sopenharmony_ci		goto fail;
5164e5b75505Sopenharmony_ci	}
5165e5b75505Sopenharmony_ci
5166e5b75505Sopenharmony_ci	kid = json_get_member_base64url(root, "kid");
5167e5b75505Sopenharmony_ci	if (!kid) {
5168e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
5169e5b75505Sopenharmony_ci		goto fail;
5170e5b75505Sopenharmony_ci	}
5171e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
5172e5b75505Sopenharmony_ci			kid);
5173e5b75505Sopenharmony_ci
5174e5b75505Sopenharmony_cifail:
5175e5b75505Sopenharmony_ci	json_free(root);
5176e5b75505Sopenharmony_ci	return kid;
5177e5b75505Sopenharmony_ci}
5178e5b75505Sopenharmony_ci
5179e5b75505Sopenharmony_ci
5180e5b75505Sopenharmony_cistatic int dpp_parse_cred_legacy(struct dpp_authentication *auth,
5181e5b75505Sopenharmony_ci				 struct json_token *cred)
5182e5b75505Sopenharmony_ci{
5183e5b75505Sopenharmony_ci	struct json_token *pass, *psk_hex;
5184e5b75505Sopenharmony_ci
5185e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
5186e5b75505Sopenharmony_ci
5187e5b75505Sopenharmony_ci	pass = json_get_member(cred, "pass");
5188e5b75505Sopenharmony_ci	psk_hex = json_get_member(cred, "psk_hex");
5189e5b75505Sopenharmony_ci
5190e5b75505Sopenharmony_ci	if (pass && pass->type == JSON_STRING) {
5191e5b75505Sopenharmony_ci		size_t len = os_strlen(pass->string);
5192e5b75505Sopenharmony_ci
5193e5b75505Sopenharmony_ci		wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
5194e5b75505Sopenharmony_ci				      pass->string, len);
5195e5b75505Sopenharmony_ci		if (len < 8 || len > 63)
5196e5b75505Sopenharmony_ci			return -1;
5197e5b75505Sopenharmony_ci		os_strlcpy(auth->passphrase, pass->string,
5198e5b75505Sopenharmony_ci			   sizeof(auth->passphrase));
5199e5b75505Sopenharmony_ci	} else if (psk_hex && psk_hex->type == JSON_STRING) {
5200e5b75505Sopenharmony_ci		if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
5201e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
5202e5b75505Sopenharmony_ci				   "DPP: Unexpected psk_hex with akm=sae");
5203e5b75505Sopenharmony_ci			return -1;
5204e5b75505Sopenharmony_ci		}
5205e5b75505Sopenharmony_ci		if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
5206e5b75505Sopenharmony_ci		    hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
5207e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
5208e5b75505Sopenharmony_ci			return -1;
5209e5b75505Sopenharmony_ci		}
5210e5b75505Sopenharmony_ci		wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
5211e5b75505Sopenharmony_ci				auth->psk, PMK_LEN);
5212e5b75505Sopenharmony_ci		auth->psk_set = 1;
5213e5b75505Sopenharmony_ci	} else {
5214e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
5215e5b75505Sopenharmony_ci		return -1;
5216e5b75505Sopenharmony_ci	}
5217e5b75505Sopenharmony_ci
5218e5b75505Sopenharmony_ci	if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
5219e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
5220e5b75505Sopenharmony_ci		return -1;
5221e5b75505Sopenharmony_ci	}
5222e5b75505Sopenharmony_ci
5223e5b75505Sopenharmony_ci	return 0;
5224e5b75505Sopenharmony_ci}
5225e5b75505Sopenharmony_ci
5226e5b75505Sopenharmony_ci
5227e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
5228e5b75505Sopenharmony_ci				const struct dpp_curve_params **key_curve)
5229e5b75505Sopenharmony_ci{
5230e5b75505Sopenharmony_ci	struct json_token *token;
5231e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve;
5232e5b75505Sopenharmony_ci	struct wpabuf *x = NULL, *y = NULL;
5233e5b75505Sopenharmony_ci	EC_GROUP *group;
5234e5b75505Sopenharmony_ci	EVP_PKEY *pkey = NULL;
5235e5b75505Sopenharmony_ci
5236e5b75505Sopenharmony_ci	token = json_get_member(jwk, "kty");
5237e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5238e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
5239e5b75505Sopenharmony_ci		goto fail;
5240e5b75505Sopenharmony_ci	}
5241e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "EC") != 0) {
5242e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
5243e5b75505Sopenharmony_ci			   token->string);
5244e5b75505Sopenharmony_ci		goto fail;
5245e5b75505Sopenharmony_ci	}
5246e5b75505Sopenharmony_ci
5247e5b75505Sopenharmony_ci	token = json_get_member(jwk, "crv");
5248e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5249e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
5250e5b75505Sopenharmony_ci		goto fail;
5251e5b75505Sopenharmony_ci	}
5252e5b75505Sopenharmony_ci	curve = dpp_get_curve_jwk_crv(token->string);
5253e5b75505Sopenharmony_ci	if (!curve) {
5254e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
5255e5b75505Sopenharmony_ci			   token->string);
5256e5b75505Sopenharmony_ci		goto fail;
5257e5b75505Sopenharmony_ci	}
5258e5b75505Sopenharmony_ci
5259e5b75505Sopenharmony_ci	x = json_get_member_base64url(jwk, "x");
5260e5b75505Sopenharmony_ci	if (!x) {
5261e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
5262e5b75505Sopenharmony_ci		goto fail;
5263e5b75505Sopenharmony_ci	}
5264e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
5265e5b75505Sopenharmony_ci	if (wpabuf_len(x) != curve->prime_len) {
5266e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5267e5b75505Sopenharmony_ci			   "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5268e5b75505Sopenharmony_ci			   (unsigned int) wpabuf_len(x),
5269e5b75505Sopenharmony_ci			   (unsigned int) curve->prime_len, curve->name);
5270e5b75505Sopenharmony_ci		goto fail;
5271e5b75505Sopenharmony_ci	}
5272e5b75505Sopenharmony_ci
5273e5b75505Sopenharmony_ci	y = json_get_member_base64url(jwk, "y");
5274e5b75505Sopenharmony_ci	if (!y) {
5275e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
5276e5b75505Sopenharmony_ci		goto fail;
5277e5b75505Sopenharmony_ci	}
5278e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
5279e5b75505Sopenharmony_ci	if (wpabuf_len(y) != curve->prime_len) {
5280e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5281e5b75505Sopenharmony_ci			   "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5282e5b75505Sopenharmony_ci			   (unsigned int) wpabuf_len(y),
5283e5b75505Sopenharmony_ci			   (unsigned int) curve->prime_len, curve->name);
5284e5b75505Sopenharmony_ci		goto fail;
5285e5b75505Sopenharmony_ci	}
5286e5b75505Sopenharmony_ci
5287e5b75505Sopenharmony_ci	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
5288e5b75505Sopenharmony_ci	if (!group) {
5289e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
5290e5b75505Sopenharmony_ci		goto fail;
5291e5b75505Sopenharmony_ci	}
5292e5b75505Sopenharmony_ci
5293e5b75505Sopenharmony_ci	pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
5294e5b75505Sopenharmony_ci					  wpabuf_len(x));
5295e5b75505Sopenharmony_ci	EC_GROUP_free(group);
5296e5b75505Sopenharmony_ci	*key_curve = curve;
5297e5b75505Sopenharmony_ci
5298e5b75505Sopenharmony_cifail:
5299e5b75505Sopenharmony_ci	wpabuf_free(x);
5300e5b75505Sopenharmony_ci	wpabuf_free(y);
5301e5b75505Sopenharmony_ci
5302e5b75505Sopenharmony_ci	return pkey;
5303e5b75505Sopenharmony_ci}
5304e5b75505Sopenharmony_ci
5305e5b75505Sopenharmony_ci
5306e5b75505Sopenharmony_ciint dpp_key_expired(const char *timestamp, os_time_t *expiry)
5307e5b75505Sopenharmony_ci{
5308e5b75505Sopenharmony_ci	struct os_time now;
5309e5b75505Sopenharmony_ci	unsigned int year, month, day, hour, min, sec;
5310e5b75505Sopenharmony_ci	os_time_t utime;
5311e5b75505Sopenharmony_ci	const char *pos;
5312e5b75505Sopenharmony_ci
5313e5b75505Sopenharmony_ci	/* ISO 8601 date and time:
5314e5b75505Sopenharmony_ci	 * <date>T<time>
5315e5b75505Sopenharmony_ci	 * YYYY-MM-DDTHH:MM:SSZ
5316e5b75505Sopenharmony_ci	 * YYYY-MM-DDTHH:MM:SS+03:00
5317e5b75505Sopenharmony_ci	 */
5318e5b75505Sopenharmony_ci	if (os_strlen(timestamp) < 19) {
5319e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5320e5b75505Sopenharmony_ci			   "DPP: Too short timestamp - assume expired key");
5321e5b75505Sopenharmony_ci		return 1;
5322e5b75505Sopenharmony_ci	}
5323e5b75505Sopenharmony_ci	if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
5324e5b75505Sopenharmony_ci		   &year, &month, &day, &hour, &min, &sec) != 6) {
5325e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5326e5b75505Sopenharmony_ci			   "DPP: Failed to parse expiration day - assume expired key");
5327e5b75505Sopenharmony_ci		return 1;
5328e5b75505Sopenharmony_ci	}
5329e5b75505Sopenharmony_ci
5330e5b75505Sopenharmony_ci	if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
5331e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5332e5b75505Sopenharmony_ci			   "DPP: Invalid date/time information - assume expired key");
5333e5b75505Sopenharmony_ci		return 1;
5334e5b75505Sopenharmony_ci	}
5335e5b75505Sopenharmony_ci
5336e5b75505Sopenharmony_ci	pos = timestamp + 19;
5337e5b75505Sopenharmony_ci	if (*pos == 'Z' || *pos == '\0') {
5338e5b75505Sopenharmony_ci		/* In UTC - no need to adjust */
5339e5b75505Sopenharmony_ci	} else if (*pos == '-' || *pos == '+') {
5340e5b75505Sopenharmony_ci		int items;
5341e5b75505Sopenharmony_ci
5342e5b75505Sopenharmony_ci		/* Adjust local time to UTC */
5343e5b75505Sopenharmony_ci		items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
5344e5b75505Sopenharmony_ci		if (items < 1) {
5345e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
5346e5b75505Sopenharmony_ci				   "DPP: Invalid time zone designator (%s) - assume expired key",
5347e5b75505Sopenharmony_ci				   pos);
5348e5b75505Sopenharmony_ci			return 1;
5349e5b75505Sopenharmony_ci		}
5350e5b75505Sopenharmony_ci		if (*pos == '-')
5351e5b75505Sopenharmony_ci			utime += 3600 * hour;
5352e5b75505Sopenharmony_ci		if (*pos == '+')
5353e5b75505Sopenharmony_ci			utime -= 3600 * hour;
5354e5b75505Sopenharmony_ci		if (items > 1) {
5355e5b75505Sopenharmony_ci			if (*pos == '-')
5356e5b75505Sopenharmony_ci				utime += 60 * min;
5357e5b75505Sopenharmony_ci			if (*pos == '+')
5358e5b75505Sopenharmony_ci				utime -= 60 * min;
5359e5b75505Sopenharmony_ci		}
5360e5b75505Sopenharmony_ci	} else {
5361e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5362e5b75505Sopenharmony_ci			   "DPP: Invalid time zone designator (%s) - assume expired key",
5363e5b75505Sopenharmony_ci			   pos);
5364e5b75505Sopenharmony_ci		return 1;
5365e5b75505Sopenharmony_ci	}
5366e5b75505Sopenharmony_ci	if (expiry)
5367e5b75505Sopenharmony_ci		*expiry = utime;
5368e5b75505Sopenharmony_ci
5369e5b75505Sopenharmony_ci	if (os_get_time(&now) < 0) {
5370e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5371e5b75505Sopenharmony_ci			   "DPP: Cannot get current time - assume expired key");
5372e5b75505Sopenharmony_ci		return 1;
5373e5b75505Sopenharmony_ci	}
5374e5b75505Sopenharmony_ci
5375e5b75505Sopenharmony_ci	if (now.sec > utime) {
5376e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
5377e5b75505Sopenharmony_ci			   utime, now.sec);
5378e5b75505Sopenharmony_ci		return 1;
5379e5b75505Sopenharmony_ci	}
5380e5b75505Sopenharmony_ci
5381e5b75505Sopenharmony_ci	return 0;
5382e5b75505Sopenharmony_ci}
5383e5b75505Sopenharmony_ci
5384e5b75505Sopenharmony_ci
5385e5b75505Sopenharmony_cistatic int dpp_parse_connector(struct dpp_authentication *auth,
5386e5b75505Sopenharmony_ci			       const unsigned char *payload,
5387e5b75505Sopenharmony_ci			       u16 payload_len)
5388e5b75505Sopenharmony_ci{
5389e5b75505Sopenharmony_ci	struct json_token *root, *groups, *netkey, *token;
5390e5b75505Sopenharmony_ci	int ret = -1;
5391e5b75505Sopenharmony_ci	EVP_PKEY *key = NULL;
5392e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve;
5393e5b75505Sopenharmony_ci	unsigned int rules = 0;
5394e5b75505Sopenharmony_ci
5395e5b75505Sopenharmony_ci	root = json_parse((const char *) payload, payload_len);
5396e5b75505Sopenharmony_ci	if (!root) {
5397e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5398e5b75505Sopenharmony_ci		goto fail;
5399e5b75505Sopenharmony_ci	}
5400e5b75505Sopenharmony_ci
5401e5b75505Sopenharmony_ci	groups = json_get_member(root, "groups");
5402e5b75505Sopenharmony_ci	if (!groups || groups->type != JSON_ARRAY) {
5403e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No groups array found");
5404e5b75505Sopenharmony_ci		goto skip_groups;
5405e5b75505Sopenharmony_ci	}
5406e5b75505Sopenharmony_ci	for (token = groups->child; token; token = token->sibling) {
5407e5b75505Sopenharmony_ci		struct json_token *id, *role;
5408e5b75505Sopenharmony_ci
5409e5b75505Sopenharmony_ci		id = json_get_member(token, "groupId");
5410e5b75505Sopenharmony_ci		if (!id || id->type != JSON_STRING) {
5411e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
5412e5b75505Sopenharmony_ci			goto fail;
5413e5b75505Sopenharmony_ci		}
5414e5b75505Sopenharmony_ci
5415e5b75505Sopenharmony_ci		role = json_get_member(token, "netRole");
5416e5b75505Sopenharmony_ci		if (!role || role->type != JSON_STRING) {
5417e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
5418e5b75505Sopenharmony_ci			goto fail;
5419e5b75505Sopenharmony_ci		}
5420e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5421e5b75505Sopenharmony_ci			   "DPP: connector group: groupId='%s' netRole='%s'",
5422e5b75505Sopenharmony_ci			   id->string, role->string);
5423e5b75505Sopenharmony_ci		rules++;
5424e5b75505Sopenharmony_ci	}
5425e5b75505Sopenharmony_ciskip_groups:
5426e5b75505Sopenharmony_ci
5427e5b75505Sopenharmony_ci	if (!rules) {
5428e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5429e5b75505Sopenharmony_ci			   "DPP: Connector includes no groups");
5430e5b75505Sopenharmony_ci		goto fail;
5431e5b75505Sopenharmony_ci	}
5432e5b75505Sopenharmony_ci
5433e5b75505Sopenharmony_ci	token = json_get_member(root, "expiry");
5434e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5435e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5436e5b75505Sopenharmony_ci			   "DPP: No expiry string found - connector does not expire");
5437e5b75505Sopenharmony_ci	} else {
5438e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5439e5b75505Sopenharmony_ci		if (dpp_key_expired(token->string,
5440e5b75505Sopenharmony_ci				    &auth->net_access_key_expiry)) {
5441e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
5442e5b75505Sopenharmony_ci				   "DPP: Connector (netAccessKey) has expired");
5443e5b75505Sopenharmony_ci			goto fail;
5444e5b75505Sopenharmony_ci		}
5445e5b75505Sopenharmony_ci	}
5446e5b75505Sopenharmony_ci
5447e5b75505Sopenharmony_ci	netkey = json_get_member(root, "netAccessKey");
5448e5b75505Sopenharmony_ci	if (!netkey || netkey->type != JSON_OBJECT) {
5449e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5450e5b75505Sopenharmony_ci		goto fail;
5451e5b75505Sopenharmony_ci	}
5452e5b75505Sopenharmony_ci
5453e5b75505Sopenharmony_ci	key = dpp_parse_jwk(netkey, &curve);
5454e5b75505Sopenharmony_ci	if (!key)
5455e5b75505Sopenharmony_ci		goto fail;
5456e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Received netAccessKey", key);
5457e5b75505Sopenharmony_ci
5458e5b75505Sopenharmony_ci	if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
5459e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5460e5b75505Sopenharmony_ci			   "DPP: netAccessKey in connector does not match own protocol key");
5461e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
5462e5b75505Sopenharmony_ci		if (auth->ignore_netaccesskey_mismatch) {
5463e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
5464e5b75505Sopenharmony_ci				   "DPP: TESTING - skip netAccessKey mismatch");
5465e5b75505Sopenharmony_ci		} else {
5466e5b75505Sopenharmony_ci			goto fail;
5467e5b75505Sopenharmony_ci		}
5468e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
5469e5b75505Sopenharmony_ci		goto fail;
5470e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
5471e5b75505Sopenharmony_ci	}
5472e5b75505Sopenharmony_ci
5473e5b75505Sopenharmony_ci	ret = 0;
5474e5b75505Sopenharmony_cifail:
5475e5b75505Sopenharmony_ci	EVP_PKEY_free(key);
5476e5b75505Sopenharmony_ci	json_free(root);
5477e5b75505Sopenharmony_ci	return ret;
5478e5b75505Sopenharmony_ci}
5479e5b75505Sopenharmony_ci
5480e5b75505Sopenharmony_ci
5481e5b75505Sopenharmony_cistatic int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
5482e5b75505Sopenharmony_ci{
5483e5b75505Sopenharmony_ci	struct wpabuf *uncomp;
5484e5b75505Sopenharmony_ci	int res;
5485e5b75505Sopenharmony_ci	u8 hash[SHA256_MAC_LEN];
5486e5b75505Sopenharmony_ci	const u8 *addr[1];
5487e5b75505Sopenharmony_ci	size_t len[1];
5488e5b75505Sopenharmony_ci
5489e5b75505Sopenharmony_ci	if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
5490e5b75505Sopenharmony_ci		return -1;
5491e5b75505Sopenharmony_ci	uncomp = dpp_get_pubkey_point(pub, 1);
5492e5b75505Sopenharmony_ci	if (!uncomp)
5493e5b75505Sopenharmony_ci		return -1;
5494e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(uncomp);
5495e5b75505Sopenharmony_ci	len[0] = wpabuf_len(uncomp);
5496e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
5497e5b75505Sopenharmony_ci		    addr[0], len[0]);
5498e5b75505Sopenharmony_ci	res = sha256_vector(1, addr, len, hash);
5499e5b75505Sopenharmony_ci	wpabuf_free(uncomp);
5500e5b75505Sopenharmony_ci	if (res < 0)
5501e5b75505Sopenharmony_ci		return -1;
5502e5b75505Sopenharmony_ci	if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
5503e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5504e5b75505Sopenharmony_ci			   "DPP: Received hash value does not match calculated public key hash value");
5505e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
5506e5b75505Sopenharmony_ci			    hash, SHA256_MAC_LEN);
5507e5b75505Sopenharmony_ci		return -1;
5508e5b75505Sopenharmony_ci	}
5509e5b75505Sopenharmony_ci	return 0;
5510e5b75505Sopenharmony_ci}
5511e5b75505Sopenharmony_ci
5512e5b75505Sopenharmony_ci
5513e5b75505Sopenharmony_cistatic void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
5514e5b75505Sopenharmony_ci{
5515e5b75505Sopenharmony_ci	unsigned char *der = NULL;
5516e5b75505Sopenharmony_ci	int der_len;
5517e5b75505Sopenharmony_ci
5518e5b75505Sopenharmony_ci	der_len = i2d_PUBKEY(csign, &der);
5519e5b75505Sopenharmony_ci	if (der_len <= 0)
5520e5b75505Sopenharmony_ci		return;
5521e5b75505Sopenharmony_ci	wpabuf_free(auth->c_sign_key);
5522e5b75505Sopenharmony_ci	auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
5523e5b75505Sopenharmony_ci	OPENSSL_free(der);
5524e5b75505Sopenharmony_ci}
5525e5b75505Sopenharmony_ci
5526e5b75505Sopenharmony_ci
5527e5b75505Sopenharmony_cistatic void dpp_copy_netaccesskey(struct dpp_authentication *auth)
5528e5b75505Sopenharmony_ci{
5529e5b75505Sopenharmony_ci	unsigned char *der = NULL;
5530e5b75505Sopenharmony_ci	int der_len;
5531e5b75505Sopenharmony_ci	EC_KEY *eckey;
5532e5b75505Sopenharmony_ci
5533e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
5534e5b75505Sopenharmony_ci	if (!eckey)
5535e5b75505Sopenharmony_ci		return;
5536e5b75505Sopenharmony_ci
5537e5b75505Sopenharmony_ci	der_len = i2d_ECPrivateKey(eckey, &der);
5538e5b75505Sopenharmony_ci	if (der_len <= 0) {
5539e5b75505Sopenharmony_ci		EC_KEY_free(eckey);
5540e5b75505Sopenharmony_ci		return;
5541e5b75505Sopenharmony_ci	}
5542e5b75505Sopenharmony_ci	wpabuf_free(auth->net_access_key);
5543e5b75505Sopenharmony_ci	auth->net_access_key = wpabuf_alloc_copy(der, der_len);
5544e5b75505Sopenharmony_ci	OPENSSL_free(der);
5545e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
5546e5b75505Sopenharmony_ci}
5547e5b75505Sopenharmony_ci
5548e5b75505Sopenharmony_ci
5549e5b75505Sopenharmony_cistruct dpp_signed_connector_info {
5550e5b75505Sopenharmony_ci	unsigned char *payload;
5551e5b75505Sopenharmony_ci	size_t payload_len;
5552e5b75505Sopenharmony_ci};
5553e5b75505Sopenharmony_ci
5554e5b75505Sopenharmony_cistatic enum dpp_status_error
5555e5b75505Sopenharmony_cidpp_process_signed_connector(struct dpp_signed_connector_info *info,
5556e5b75505Sopenharmony_ci			     EVP_PKEY *csign_pub, const char *connector)
5557e5b75505Sopenharmony_ci{
5558e5b75505Sopenharmony_ci	enum dpp_status_error ret = 255;
5559e5b75505Sopenharmony_ci	const char *pos, *end, *signed_start, *signed_end;
5560e5b75505Sopenharmony_ci	struct wpabuf *kid = NULL;
5561e5b75505Sopenharmony_ci	unsigned char *prot_hdr = NULL, *signature = NULL;
5562e5b75505Sopenharmony_ci	size_t prot_hdr_len = 0, signature_len = 0;
5563e5b75505Sopenharmony_ci	const EVP_MD *sign_md = NULL;
5564e5b75505Sopenharmony_ci	unsigned char *der = NULL;
5565e5b75505Sopenharmony_ci	int der_len;
5566e5b75505Sopenharmony_ci	int res;
5567e5b75505Sopenharmony_ci	EVP_MD_CTX *md_ctx = NULL;
5568e5b75505Sopenharmony_ci	ECDSA_SIG *sig = NULL;
5569e5b75505Sopenharmony_ci	BIGNUM *r = NULL, *s = NULL;
5570e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve;
5571e5b75505Sopenharmony_ci	EC_KEY *eckey;
5572e5b75505Sopenharmony_ci	const EC_GROUP *group;
5573e5b75505Sopenharmony_ci	int nid;
5574e5b75505Sopenharmony_ci
5575e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
5576e5b75505Sopenharmony_ci	if (!eckey)
5577e5b75505Sopenharmony_ci		goto fail;
5578e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(eckey);
5579e5b75505Sopenharmony_ci	if (!group)
5580e5b75505Sopenharmony_ci		goto fail;
5581e5b75505Sopenharmony_ci	nid = EC_GROUP_get_curve_name(group);
5582e5b75505Sopenharmony_ci	curve = dpp_get_curve_nid(nid);
5583e5b75505Sopenharmony_ci	if (!curve)
5584e5b75505Sopenharmony_ci		goto fail;
5585e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5586e5b75505Sopenharmony_ci	os_memset(info, 0, sizeof(*info));
5587e5b75505Sopenharmony_ci
5588e5b75505Sopenharmony_ci	signed_start = pos = connector;
5589e5b75505Sopenharmony_ci	end = os_strchr(pos, '.');
5590e5b75505Sopenharmony_ci	if (!end) {
5591e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
5592e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5593e5b75505Sopenharmony_ci		goto fail;
5594e5b75505Sopenharmony_ci	}
5595e5b75505Sopenharmony_ci	prot_hdr = base64_url_decode((const unsigned char *) pos,
5596e5b75505Sopenharmony_ci				     end - pos, &prot_hdr_len);
5597e5b75505Sopenharmony_ci	if (!prot_hdr) {
5598e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5599e5b75505Sopenharmony_ci			   "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5600e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5601e5b75505Sopenharmony_ci		goto fail;
5602e5b75505Sopenharmony_ci	}
5603e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG,
5604e5b75505Sopenharmony_ci			  "DPP: signedConnector - JWS Protected Header",
5605e5b75505Sopenharmony_ci			  prot_hdr, prot_hdr_len);
5606e5b75505Sopenharmony_ci	kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
5607e5b75505Sopenharmony_ci	if (!kid) {
5608e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5609e5b75505Sopenharmony_ci		goto fail;
5610e5b75505Sopenharmony_ci	}
5611e5b75505Sopenharmony_ci	if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5612e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5613e5b75505Sopenharmony_ci			   "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5614e5b75505Sopenharmony_ci			   (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
5615e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5616e5b75505Sopenharmony_ci		goto fail;
5617e5b75505Sopenharmony_ci	}
5618e5b75505Sopenharmony_ci
5619e5b75505Sopenharmony_ci	pos = end + 1;
5620e5b75505Sopenharmony_ci	end = os_strchr(pos, '.');
5621e5b75505Sopenharmony_ci	if (!end) {
5622e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5623e5b75505Sopenharmony_ci			   "DPP: Missing dot(2) in signedConnector");
5624e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5625e5b75505Sopenharmony_ci		goto fail;
5626e5b75505Sopenharmony_ci	}
5627e5b75505Sopenharmony_ci	signed_end = end - 1;
5628e5b75505Sopenharmony_ci	info->payload = base64_url_decode((const unsigned char *) pos,
5629e5b75505Sopenharmony_ci					  end - pos, &info->payload_len);
5630e5b75505Sopenharmony_ci	if (!info->payload) {
5631e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5632e5b75505Sopenharmony_ci			   "DPP: Failed to base64url decode signedConnector JWS Payload");
5633e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5634e5b75505Sopenharmony_ci		goto fail;
5635e5b75505Sopenharmony_ci	}
5636e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG,
5637e5b75505Sopenharmony_ci			  "DPP: signedConnector - JWS Payload",
5638e5b75505Sopenharmony_ci			  info->payload, info->payload_len);
5639e5b75505Sopenharmony_ci	pos = end + 1;
5640e5b75505Sopenharmony_ci	signature = base64_url_decode((const unsigned char *) pos,
5641e5b75505Sopenharmony_ci				      os_strlen(pos), &signature_len);
5642e5b75505Sopenharmony_ci	if (!signature) {
5643e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5644e5b75505Sopenharmony_ci			   "DPP: Failed to base64url decode signedConnector signature");
5645e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5646e5b75505Sopenharmony_ci		goto fail;
5647e5b75505Sopenharmony_ci		}
5648e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5649e5b75505Sopenharmony_ci		    signature, signature_len);
5650e5b75505Sopenharmony_ci
5651e5b75505Sopenharmony_ci	if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5652e5b75505Sopenharmony_ci		ret = DPP_STATUS_NO_MATCH;
5653e5b75505Sopenharmony_ci		goto fail;
5654e5b75505Sopenharmony_ci	}
5655e5b75505Sopenharmony_ci
5656e5b75505Sopenharmony_ci	if (signature_len & 0x01) {
5657e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5658e5b75505Sopenharmony_ci			   "DPP: Unexpected signedConnector signature length (%d)",
5659e5b75505Sopenharmony_ci			   (int) signature_len);
5660e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5661e5b75505Sopenharmony_ci		goto fail;
5662e5b75505Sopenharmony_ci	}
5663e5b75505Sopenharmony_ci
5664e5b75505Sopenharmony_ci	/* JWS Signature encodes the signature (r,s) as two octet strings. Need
5665e5b75505Sopenharmony_ci	 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5666e5b75505Sopenharmony_ci	r = BN_bin2bn(signature, signature_len / 2, NULL);
5667e5b75505Sopenharmony_ci	s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
5668e5b75505Sopenharmony_ci	sig = ECDSA_SIG_new();
5669e5b75505Sopenharmony_ci	if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
5670e5b75505Sopenharmony_ci		goto fail;
5671e5b75505Sopenharmony_ci	r = NULL;
5672e5b75505Sopenharmony_ci	s = NULL;
5673e5b75505Sopenharmony_ci
5674e5b75505Sopenharmony_ci	der_len = i2d_ECDSA_SIG(sig, &der);
5675e5b75505Sopenharmony_ci	if (der_len <= 0) {
5676e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
5677e5b75505Sopenharmony_ci		goto fail;
5678e5b75505Sopenharmony_ci	}
5679e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
5680e5b75505Sopenharmony_ci	md_ctx = EVP_MD_CTX_create();
5681e5b75505Sopenharmony_ci	if (!md_ctx)
5682e5b75505Sopenharmony_ci		goto fail;
5683e5b75505Sopenharmony_ci
5684e5b75505Sopenharmony_ci	ERR_clear_error();
5685e5b75505Sopenharmony_ci	if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
5686e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
5687e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
5688e5b75505Sopenharmony_ci		goto fail;
5689e5b75505Sopenharmony_ci	}
5690e5b75505Sopenharmony_ci	if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
5691e5b75505Sopenharmony_ci				   signed_end - signed_start + 1) != 1) {
5692e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
5693e5b75505Sopenharmony_ci			   ERR_error_string(ERR_get_error(), NULL));
5694e5b75505Sopenharmony_ci		goto fail;
5695e5b75505Sopenharmony_ci	}
5696e5b75505Sopenharmony_ci	res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
5697e5b75505Sopenharmony_ci	if (res != 1) {
5698e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5699e5b75505Sopenharmony_ci			   "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5700e5b75505Sopenharmony_ci			   res, ERR_error_string(ERR_get_error(), NULL));
5701e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
5702e5b75505Sopenharmony_ci		goto fail;
5703e5b75505Sopenharmony_ci	}
5704e5b75505Sopenharmony_ci
5705e5b75505Sopenharmony_ci	ret = DPP_STATUS_OK;
5706e5b75505Sopenharmony_cifail:
5707e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
5708e5b75505Sopenharmony_ci	EVP_MD_CTX_destroy(md_ctx);
5709e5b75505Sopenharmony_ci	os_free(prot_hdr);
5710e5b75505Sopenharmony_ci	wpabuf_free(kid);
5711e5b75505Sopenharmony_ci	os_free(signature);
5712e5b75505Sopenharmony_ci	ECDSA_SIG_free(sig);
5713e5b75505Sopenharmony_ci	BN_free(r);
5714e5b75505Sopenharmony_ci	BN_free(s);
5715e5b75505Sopenharmony_ci	OPENSSL_free(der);
5716e5b75505Sopenharmony_ci	return ret;
5717e5b75505Sopenharmony_ci}
5718e5b75505Sopenharmony_ci
5719e5b75505Sopenharmony_ci
5720e5b75505Sopenharmony_cistatic int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5721e5b75505Sopenharmony_ci			      struct json_token *cred)
5722e5b75505Sopenharmony_ci{
5723e5b75505Sopenharmony_ci	struct dpp_signed_connector_info info;
5724e5b75505Sopenharmony_ci	struct json_token *token, *csign;
5725e5b75505Sopenharmony_ci	int ret = -1;
5726e5b75505Sopenharmony_ci	EVP_PKEY *csign_pub = NULL;
5727e5b75505Sopenharmony_ci	const struct dpp_curve_params *key_curve = NULL;
5728e5b75505Sopenharmony_ci	const char *signed_connector;
5729e5b75505Sopenharmony_ci
5730e5b75505Sopenharmony_ci	os_memset(&info, 0, sizeof(info));
5731e5b75505Sopenharmony_ci
5732e5b75505Sopenharmony_ci	if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
5733e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5734e5b75505Sopenharmony_ci			   "DPP: Legacy credential included in Connector credential");
5735e5b75505Sopenharmony_ci		if (dpp_parse_cred_legacy(auth, cred) < 0)
5736e5b75505Sopenharmony_ci			return -1;
5737e5b75505Sopenharmony_ci	}
5738e5b75505Sopenharmony_ci
5739e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5740e5b75505Sopenharmony_ci
5741e5b75505Sopenharmony_ci	csign = json_get_member(cred, "csign");
5742e5b75505Sopenharmony_ci	if (!csign || csign->type != JSON_OBJECT) {
5743e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5744e5b75505Sopenharmony_ci		goto fail;
5745e5b75505Sopenharmony_ci	}
5746e5b75505Sopenharmony_ci
5747e5b75505Sopenharmony_ci	csign_pub = dpp_parse_jwk(csign, &key_curve);
5748e5b75505Sopenharmony_ci	if (!csign_pub) {
5749e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5750e5b75505Sopenharmony_ci		goto fail;
5751e5b75505Sopenharmony_ci	}
5752e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5753e5b75505Sopenharmony_ci
5754e5b75505Sopenharmony_ci	token = json_get_member(cred, "signedConnector");
5755e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5756e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5757e5b75505Sopenharmony_ci		goto fail;
5758e5b75505Sopenharmony_ci	}
5759e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5760e5b75505Sopenharmony_ci			  token->string, os_strlen(token->string));
5761e5b75505Sopenharmony_ci	signed_connector = token->string;
5762e5b75505Sopenharmony_ci
5763e5b75505Sopenharmony_ci	if (os_strchr(signed_connector, '"') ||
5764e5b75505Sopenharmony_ci	    os_strchr(signed_connector, '\n')) {
5765e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
5766e5b75505Sopenharmony_ci			   "DPP: Unexpected character in signedConnector");
5767e5b75505Sopenharmony_ci		goto fail;
5768e5b75505Sopenharmony_ci	}
5769e5b75505Sopenharmony_ci
5770e5b75505Sopenharmony_ci	if (dpp_process_signed_connector(&info, csign_pub,
5771e5b75505Sopenharmony_ci					 signed_connector) != DPP_STATUS_OK)
5772e5b75505Sopenharmony_ci		goto fail;
5773e5b75505Sopenharmony_ci
5774e5b75505Sopenharmony_ci	if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
5775e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5776e5b75505Sopenharmony_ci		goto fail;
5777e5b75505Sopenharmony_ci	}
5778e5b75505Sopenharmony_ci
5779e5b75505Sopenharmony_ci	os_free(auth->connector);
5780e5b75505Sopenharmony_ci	auth->connector = os_strdup(signed_connector);
5781e5b75505Sopenharmony_ci
5782e5b75505Sopenharmony_ci	dpp_copy_csign(auth, csign_pub);
5783e5b75505Sopenharmony_ci	dpp_copy_netaccesskey(auth);
5784e5b75505Sopenharmony_ci
5785e5b75505Sopenharmony_ci	ret = 0;
5786e5b75505Sopenharmony_cifail:
5787e5b75505Sopenharmony_ci	EVP_PKEY_free(csign_pub);
5788e5b75505Sopenharmony_ci	os_free(info.payload);
5789e5b75505Sopenharmony_ci	return ret;
5790e5b75505Sopenharmony_ci}
5791e5b75505Sopenharmony_ci
5792e5b75505Sopenharmony_ci
5793e5b75505Sopenharmony_ciconst char * dpp_akm_str(enum dpp_akm akm)
5794e5b75505Sopenharmony_ci{
5795e5b75505Sopenharmony_ci	switch (akm) {
5796e5b75505Sopenharmony_ci	case DPP_AKM_DPP:
5797e5b75505Sopenharmony_ci		return "dpp";
5798e5b75505Sopenharmony_ci	case DPP_AKM_PSK:
5799e5b75505Sopenharmony_ci		return "psk";
5800e5b75505Sopenharmony_ci	case DPP_AKM_SAE:
5801e5b75505Sopenharmony_ci		return "sae";
5802e5b75505Sopenharmony_ci	case DPP_AKM_PSK_SAE:
5803e5b75505Sopenharmony_ci		return "psk+sae";
5804e5b75505Sopenharmony_ci	case DPP_AKM_SAE_DPP:
5805e5b75505Sopenharmony_ci		return "dpp+sae";
5806e5b75505Sopenharmony_ci	case DPP_AKM_PSK_SAE_DPP:
5807e5b75505Sopenharmony_ci		return "dpp+psk+sae";
5808e5b75505Sopenharmony_ci	default:
5809e5b75505Sopenharmony_ci		return "??";
5810e5b75505Sopenharmony_ci	}
5811e5b75505Sopenharmony_ci}
5812e5b75505Sopenharmony_ci
5813e5b75505Sopenharmony_ci
5814e5b75505Sopenharmony_cistatic enum dpp_akm dpp_akm_from_str(const char *akm)
5815e5b75505Sopenharmony_ci{
5816e5b75505Sopenharmony_ci	if (os_strcmp(akm, "psk") == 0)
5817e5b75505Sopenharmony_ci		return DPP_AKM_PSK;
5818e5b75505Sopenharmony_ci	if (os_strcmp(akm, "sae") == 0)
5819e5b75505Sopenharmony_ci		return DPP_AKM_SAE;
5820e5b75505Sopenharmony_ci	if (os_strcmp(akm, "psk+sae") == 0)
5821e5b75505Sopenharmony_ci		return DPP_AKM_PSK_SAE;
5822e5b75505Sopenharmony_ci	if (os_strcmp(akm, "dpp") == 0)
5823e5b75505Sopenharmony_ci		return DPP_AKM_DPP;
5824e5b75505Sopenharmony_ci	if (os_strcmp(akm, "dpp+sae") == 0)
5825e5b75505Sopenharmony_ci		return DPP_AKM_SAE_DPP;
5826e5b75505Sopenharmony_ci	if (os_strcmp(akm, "dpp+psk+sae") == 0)
5827e5b75505Sopenharmony_ci		return DPP_AKM_PSK_SAE_DPP;
5828e5b75505Sopenharmony_ci	return DPP_AKM_UNKNOWN;
5829e5b75505Sopenharmony_ci}
5830e5b75505Sopenharmony_ci
5831e5b75505Sopenharmony_ci
5832e5b75505Sopenharmony_cistatic int dpp_parse_conf_obj(struct dpp_authentication *auth,
5833e5b75505Sopenharmony_ci			      const u8 *conf_obj, u16 conf_obj_len)
5834e5b75505Sopenharmony_ci{
5835e5b75505Sopenharmony_ci	int ret = -1;
5836e5b75505Sopenharmony_ci	struct json_token *root, *token, *discovery, *cred;
5837e5b75505Sopenharmony_ci
5838e5b75505Sopenharmony_ci	root = json_parse((const char *) conf_obj, conf_obj_len);
5839e5b75505Sopenharmony_ci	if (!root)
5840e5b75505Sopenharmony_ci		return -1;
5841e5b75505Sopenharmony_ci	if (root->type != JSON_OBJECT) {
5842e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "JSON root is not an object");
5843e5b75505Sopenharmony_ci		goto fail;
5844e5b75505Sopenharmony_ci	}
5845e5b75505Sopenharmony_ci
5846e5b75505Sopenharmony_ci	token = json_get_member(root, "wi-fi_tech");
5847e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5848e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No wi-fi_tech string value found");
5849e5b75505Sopenharmony_ci		goto fail;
5850e5b75505Sopenharmony_ci	}
5851e5b75505Sopenharmony_ci	if (os_strcmp(token->string, "infra") != 0) {
5852e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5853e5b75505Sopenharmony_ci			   token->string);
5854e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
5855e5b75505Sopenharmony_ci		goto fail;
5856e5b75505Sopenharmony_ci	}
5857e5b75505Sopenharmony_ci
5858e5b75505Sopenharmony_ci	discovery = json_get_member(root, "discovery");
5859e5b75505Sopenharmony_ci	if (!discovery || discovery->type != JSON_OBJECT) {
5860e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No discovery object in JSON");
5861e5b75505Sopenharmony_ci		goto fail;
5862e5b75505Sopenharmony_ci	}
5863e5b75505Sopenharmony_ci
5864e5b75505Sopenharmony_ci	token = json_get_member(discovery, "ssid");
5865e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5866e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No discovery::ssid string value found");
5867e5b75505Sopenharmony_ci		goto fail;
5868e5b75505Sopenharmony_ci	}
5869e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5870e5b75505Sopenharmony_ci			  token->string, os_strlen(token->string));
5871e5b75505Sopenharmony_ci	if (os_strlen(token->string) > SSID_MAX_LEN) {
5872e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Too long discovery::ssid string value");
5873e5b75505Sopenharmony_ci		goto fail;
5874e5b75505Sopenharmony_ci	}
5875e5b75505Sopenharmony_ci	auth->ssid_len = os_strlen(token->string);
5876e5b75505Sopenharmony_ci	os_memcpy(auth->ssid, token->string, auth->ssid_len);
5877e5b75505Sopenharmony_ci
5878e5b75505Sopenharmony_ci	cred = json_get_member(root, "cred");
5879e5b75505Sopenharmony_ci	if (!cred || cred->type != JSON_OBJECT) {
5880e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No cred object in JSON");
5881e5b75505Sopenharmony_ci		goto fail;
5882e5b75505Sopenharmony_ci	}
5883e5b75505Sopenharmony_ci
5884e5b75505Sopenharmony_ci	token = json_get_member(cred, "akm");
5885e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
5886e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "No cred::akm string value found");
5887e5b75505Sopenharmony_ci		goto fail;
5888e5b75505Sopenharmony_ci	}
5889e5b75505Sopenharmony_ci	auth->akm = dpp_akm_from_str(token->string);
5890e5b75505Sopenharmony_ci
5891e5b75505Sopenharmony_ci	if (dpp_akm_legacy(auth->akm)) {
5892e5b75505Sopenharmony_ci		if (dpp_parse_cred_legacy(auth, cred) < 0)
5893e5b75505Sopenharmony_ci			goto fail;
5894e5b75505Sopenharmony_ci	} else if (dpp_akm_dpp(auth->akm)) {
5895e5b75505Sopenharmony_ci		if (dpp_parse_cred_dpp(auth, cred) < 0)
5896e5b75505Sopenharmony_ci			goto fail;
5897e5b75505Sopenharmony_ci	} else {
5898e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5899e5b75505Sopenharmony_ci			   token->string);
5900e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Unsupported akm");
5901e5b75505Sopenharmony_ci		goto fail;
5902e5b75505Sopenharmony_ci	}
5903e5b75505Sopenharmony_ci
5904e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5905e5b75505Sopenharmony_ci	ret = 0;
5906e5b75505Sopenharmony_cifail:
5907e5b75505Sopenharmony_ci	json_free(root);
5908e5b75505Sopenharmony_ci	return ret;
5909e5b75505Sopenharmony_ci}
5910e5b75505Sopenharmony_ci
5911e5b75505Sopenharmony_ci
5912e5b75505Sopenharmony_ciint dpp_conf_resp_rx(struct dpp_authentication *auth,
5913e5b75505Sopenharmony_ci		     const struct wpabuf *resp)
5914e5b75505Sopenharmony_ci{
5915e5b75505Sopenharmony_ci	const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5916e5b75505Sopenharmony_ci	u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5917e5b75505Sopenharmony_ci	const u8 *addr[1];
5918e5b75505Sopenharmony_ci	size_t len[1];
5919e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
5920e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
5921e5b75505Sopenharmony_ci	int ret = -1;
5922e5b75505Sopenharmony_ci
5923e5b75505Sopenharmony_ci	auth->conf_resp_status = 255;
5924e5b75505Sopenharmony_ci
5925e5b75505Sopenharmony_ci	if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
5926e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in config response");
5927e5b75505Sopenharmony_ci		return -1;
5928e5b75505Sopenharmony_ci	}
5929e5b75505Sopenharmony_ci
5930e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5931e5b75505Sopenharmony_ci				    DPP_ATTR_WRAPPED_DATA,
5932e5b75505Sopenharmony_ci				    &wrapped_data_len);
5933e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5934e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5935e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
5936e5b75505Sopenharmony_ci		return -1;
5937e5b75505Sopenharmony_ci	}
5938e5b75505Sopenharmony_ci
5939e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5940e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
5941e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5942e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
5943e5b75505Sopenharmony_ci	if (!unwrapped)
5944e5b75505Sopenharmony_ci		return -1;
5945e5b75505Sopenharmony_ci
5946e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(resp);
5947e5b75505Sopenharmony_ci	len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
5948e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5949e5b75505Sopenharmony_ci
5950e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5951e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
5952e5b75505Sopenharmony_ci			    1, addr, len, unwrapped) < 0) {
5953e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
5954e5b75505Sopenharmony_ci		goto fail;
5955e5b75505Sopenharmony_ci	}
5956e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5957e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
5958e5b75505Sopenharmony_ci
5959e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5960e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5961e5b75505Sopenharmony_ci		goto fail;
5962e5b75505Sopenharmony_ci	}
5963e5b75505Sopenharmony_ci
5964e5b75505Sopenharmony_ci	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5965e5b75505Sopenharmony_ci			       DPP_ATTR_ENROLLEE_NONCE,
5966e5b75505Sopenharmony_ci			       &e_nonce_len);
5967e5b75505Sopenharmony_ci	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5968e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5969e5b75505Sopenharmony_ci			      "Missing or invalid Enrollee Nonce attribute");
5970e5b75505Sopenharmony_ci		goto fail;
5971e5b75505Sopenharmony_ci	}
5972e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5973e5b75505Sopenharmony_ci	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
5974e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
5975e5b75505Sopenharmony_ci		goto fail;
5976e5b75505Sopenharmony_ci	}
5977e5b75505Sopenharmony_ci
5978e5b75505Sopenharmony_ci	status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
5979e5b75505Sopenharmony_ci			      DPP_ATTR_STATUS, &status_len);
5980e5b75505Sopenharmony_ci	if (!status || status_len < 1) {
5981e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5982e5b75505Sopenharmony_ci			      "Missing or invalid required DPP Status attribute");
5983e5b75505Sopenharmony_ci		goto fail;
5984e5b75505Sopenharmony_ci	}
5985e5b75505Sopenharmony_ci	auth->conf_resp_status = status[0];
5986e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5987e5b75505Sopenharmony_ci	if (status[0] != DPP_STATUS_OK) {
5988e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Configurator rejected configuration");
5989e5b75505Sopenharmony_ci		goto fail;
5990e5b75505Sopenharmony_ci	}
5991e5b75505Sopenharmony_ci
5992e5b75505Sopenharmony_ci	conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
5993e5b75505Sopenharmony_ci				DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
5994e5b75505Sopenharmony_ci	if (!conf_obj) {
5995e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
5996e5b75505Sopenharmony_ci			      "Missing required Configuration Object attribute");
5997e5b75505Sopenharmony_ci		goto fail;
5998e5b75505Sopenharmony_ci	}
5999e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
6000e5b75505Sopenharmony_ci			  conf_obj, conf_obj_len);
6001e5b75505Sopenharmony_ci	if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
6002e5b75505Sopenharmony_ci		goto fail;
6003e5b75505Sopenharmony_ci
6004e5b75505Sopenharmony_ci	ret = 0;
6005e5b75505Sopenharmony_ci
6006e5b75505Sopenharmony_cifail:
6007e5b75505Sopenharmony_ci	os_free(unwrapped);
6008e5b75505Sopenharmony_ci	return ret;
6009e5b75505Sopenharmony_ci}
6010e5b75505Sopenharmony_ci
6011e5b75505Sopenharmony_ci
6012e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
6013e5b75505Sopenharmony_cienum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
6014e5b75505Sopenharmony_ci					 const u8 *hdr,
6015e5b75505Sopenharmony_ci					 const u8 *attr_start, size_t attr_len)
6016e5b75505Sopenharmony_ci{
6017e5b75505Sopenharmony_ci	const u8 *wrapped_data, *status, *e_nonce;
6018e5b75505Sopenharmony_ci	u16 wrapped_data_len, status_len, e_nonce_len;
6019e5b75505Sopenharmony_ci	const u8 *addr[2];
6020e5b75505Sopenharmony_ci	size_t len[2];
6021e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
6022e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
6023e5b75505Sopenharmony_ci	enum dpp_status_error ret = 256;
6024e5b75505Sopenharmony_ci
6025e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
6026e5b75505Sopenharmony_ci				    &wrapped_data_len);
6027e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
6028e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
6029e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
6030e5b75505Sopenharmony_ci		goto fail;
6031e5b75505Sopenharmony_ci	}
6032e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
6033e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
6034e5b75505Sopenharmony_ci
6035e5b75505Sopenharmony_ci	attr_len = wrapped_data - 4 - attr_start;
6036e5b75505Sopenharmony_ci
6037e5b75505Sopenharmony_ci	addr[0] = hdr;
6038e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
6039e5b75505Sopenharmony_ci	addr[1] = attr_start;
6040e5b75505Sopenharmony_ci	len[1] = attr_len;
6041e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6042e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6043e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
6044e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
6045e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
6046e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
6047e5b75505Sopenharmony_ci	if (!unwrapped)
6048e5b75505Sopenharmony_ci		goto fail;
6049e5b75505Sopenharmony_ci	if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
6050e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
6051e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
6052e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "AES-SIV decryption failed");
6053e5b75505Sopenharmony_ci		goto fail;
6054e5b75505Sopenharmony_ci	}
6055e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
6056e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
6057e5b75505Sopenharmony_ci
6058e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
6059e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
6060e5b75505Sopenharmony_ci		goto fail;
6061e5b75505Sopenharmony_ci	}
6062e5b75505Sopenharmony_ci
6063e5b75505Sopenharmony_ci	e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
6064e5b75505Sopenharmony_ci			       DPP_ATTR_ENROLLEE_NONCE,
6065e5b75505Sopenharmony_ci			       &e_nonce_len);
6066e5b75505Sopenharmony_ci	if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
6067e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
6068e5b75505Sopenharmony_ci			      "Missing or invalid Enrollee Nonce attribute");
6069e5b75505Sopenharmony_ci		goto fail;
6070e5b75505Sopenharmony_ci	}
6071e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
6072e5b75505Sopenharmony_ci	if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
6073e5b75505Sopenharmony_ci		dpp_auth_fail(auth, "Enrollee Nonce mismatch");
6074e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
6075e5b75505Sopenharmony_ci			    auth->e_nonce, e_nonce_len);
6076e5b75505Sopenharmony_ci		goto fail;
6077e5b75505Sopenharmony_ci	}
6078e5b75505Sopenharmony_ci
6079e5b75505Sopenharmony_ci	status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
6080e5b75505Sopenharmony_ci			      &status_len);
6081e5b75505Sopenharmony_ci	if (!status || status_len < 1) {
6082e5b75505Sopenharmony_ci		dpp_auth_fail(auth,
6083e5b75505Sopenharmony_ci			      "Missing or invalid required DPP Status attribute");
6084e5b75505Sopenharmony_ci		goto fail;
6085e5b75505Sopenharmony_ci	}
6086e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
6087e5b75505Sopenharmony_ci	ret = status[0];
6088e5b75505Sopenharmony_ci
6089e5b75505Sopenharmony_cifail:
6090e5b75505Sopenharmony_ci	bin_clear_free(unwrapped, unwrapped_len);
6091e5b75505Sopenharmony_ci	return ret;
6092e5b75505Sopenharmony_ci}
6093e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
6094e5b75505Sopenharmony_ci
6095e5b75505Sopenharmony_ci
6096e5b75505Sopenharmony_cistruct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
6097e5b75505Sopenharmony_ci				      enum dpp_status_error status)
6098e5b75505Sopenharmony_ci{
6099e5b75505Sopenharmony_ci	struct wpabuf *msg, *clear;
6100e5b75505Sopenharmony_ci	size_t nonce_len, clear_len, attr_len;
6101e5b75505Sopenharmony_ci	const u8 *addr[2];
6102e5b75505Sopenharmony_ci	size_t len[2];
6103e5b75505Sopenharmony_ci	u8 *wrapped;
6104e5b75505Sopenharmony_ci
6105e5b75505Sopenharmony_ci	nonce_len = auth->curve->nonce_len;
6106e5b75505Sopenharmony_ci	clear_len = 5 + 4 + nonce_len;
6107e5b75505Sopenharmony_ci	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
6108e5b75505Sopenharmony_ci	clear = wpabuf_alloc(clear_len);
6109e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
6110e5b75505Sopenharmony_ci	if (!clear || !msg)
6111e5b75505Sopenharmony_ci		return NULL;
6112e5b75505Sopenharmony_ci
6113e5b75505Sopenharmony_ci	/* DPP Status */
6114e5b75505Sopenharmony_ci	dpp_build_attr_status(clear, status);
6115e5b75505Sopenharmony_ci
6116e5b75505Sopenharmony_ci	/* E-nonce */
6117e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
6118e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, nonce_len);
6119e5b75505Sopenharmony_ci	wpabuf_put_data(clear, auth->e_nonce, nonce_len);
6120e5b75505Sopenharmony_ci
6121e5b75505Sopenharmony_ci	/* OUI, OUI type, Crypto Suite, DPP frame type */
6122e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
6123e5b75505Sopenharmony_ci	len[0] = 3 + 1 + 1 + 1;
6124e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
6125e5b75505Sopenharmony_ci
6126e5b75505Sopenharmony_ci	/* Attributes before Wrapped Data (none) */
6127e5b75505Sopenharmony_ci	addr[1] = wpabuf_put(msg, 0);
6128e5b75505Sopenharmony_ci	len[1] = 0;
6129e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
6130e5b75505Sopenharmony_ci
6131e5b75505Sopenharmony_ci	/* Wrapped Data */
6132e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
6133e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6134e5b75505Sopenharmony_ci	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
6135e5b75505Sopenharmony_ci
6136e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
6137e5b75505Sopenharmony_ci	if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
6138e5b75505Sopenharmony_ci			    wpabuf_head(clear), wpabuf_len(clear),
6139e5b75505Sopenharmony_ci			    2, addr, len, wrapped) < 0)
6140e5b75505Sopenharmony_ci		goto fail;
6141e5b75505Sopenharmony_ci
6142e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
6143e5b75505Sopenharmony_ci	wpabuf_free(clear);
6144e5b75505Sopenharmony_ci	return msg;
6145e5b75505Sopenharmony_cifail:
6146e5b75505Sopenharmony_ci	wpabuf_free(clear);
6147e5b75505Sopenharmony_ci	wpabuf_free(msg);
6148e5b75505Sopenharmony_ci	return NULL;
6149e5b75505Sopenharmony_ci}
6150e5b75505Sopenharmony_ci
6151e5b75505Sopenharmony_ci
6152e5b75505Sopenharmony_civoid dpp_configurator_free(struct dpp_configurator *conf)
6153e5b75505Sopenharmony_ci{
6154e5b75505Sopenharmony_ci	if (!conf)
6155e5b75505Sopenharmony_ci		return;
6156e5b75505Sopenharmony_ci	EVP_PKEY_free(conf->csign);
6157e5b75505Sopenharmony_ci	os_free(conf->kid);
6158e5b75505Sopenharmony_ci	os_free(conf);
6159e5b75505Sopenharmony_ci}
6160e5b75505Sopenharmony_ci
6161e5b75505Sopenharmony_ci
6162e5b75505Sopenharmony_ciint dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
6163e5b75505Sopenharmony_ci			     size_t buflen)
6164e5b75505Sopenharmony_ci{
6165e5b75505Sopenharmony_ci	EC_KEY *eckey;
6166e5b75505Sopenharmony_ci	int key_len, ret = -1;
6167e5b75505Sopenharmony_ci	unsigned char *key = NULL;
6168e5b75505Sopenharmony_ci
6169e5b75505Sopenharmony_ci	if (!conf->csign)
6170e5b75505Sopenharmony_ci		return -1;
6171e5b75505Sopenharmony_ci
6172e5b75505Sopenharmony_ci	eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
6173e5b75505Sopenharmony_ci	if (!eckey)
6174e5b75505Sopenharmony_ci		return -1;
6175e5b75505Sopenharmony_ci
6176e5b75505Sopenharmony_ci	key_len = i2d_ECPrivateKey(eckey, &key);
6177e5b75505Sopenharmony_ci	if (key_len > 0)
6178e5b75505Sopenharmony_ci		ret = wpa_snprintf_hex(buf, buflen, key, key_len);
6179e5b75505Sopenharmony_ci
6180e5b75505Sopenharmony_ci	EC_KEY_free(eckey);
6181e5b75505Sopenharmony_ci	OPENSSL_free(key);
6182e5b75505Sopenharmony_ci	return ret;
6183e5b75505Sopenharmony_ci}
6184e5b75505Sopenharmony_ci
6185e5b75505Sopenharmony_ci
6186e5b75505Sopenharmony_cistruct dpp_configurator *
6187e5b75505Sopenharmony_cidpp_keygen_configurator(const char *curve, const u8 *privkey,
6188e5b75505Sopenharmony_ci			size_t privkey_len)
6189e5b75505Sopenharmony_ci{
6190e5b75505Sopenharmony_ci	struct dpp_configurator *conf;
6191e5b75505Sopenharmony_ci	struct wpabuf *csign_pub = NULL;
6192e5b75505Sopenharmony_ci	u8 kid_hash[SHA256_MAC_LEN];
6193e5b75505Sopenharmony_ci	const u8 *addr[1];
6194e5b75505Sopenharmony_ci	size_t len[1];
6195e5b75505Sopenharmony_ci
6196e5b75505Sopenharmony_ci	conf = os_zalloc(sizeof(*conf));
6197e5b75505Sopenharmony_ci	if (!conf)
6198e5b75505Sopenharmony_ci		return NULL;
6199e5b75505Sopenharmony_ci
6200e5b75505Sopenharmony_ci	if (!curve) {
6201e5b75505Sopenharmony_ci		conf->curve = &dpp_curves[0];
6202e5b75505Sopenharmony_ci	} else {
6203e5b75505Sopenharmony_ci		conf->curve = dpp_get_curve_name(curve);
6204e5b75505Sopenharmony_ci		if (!conf->curve) {
6205e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6206e5b75505Sopenharmony_ci				   curve);
6207e5b75505Sopenharmony_ci			os_free(conf);
6208e5b75505Sopenharmony_ci			return NULL;
6209e5b75505Sopenharmony_ci		}
6210e5b75505Sopenharmony_ci	}
6211e5b75505Sopenharmony_ci	if (privkey)
6212e5b75505Sopenharmony_ci		conf->csign = dpp_set_keypair(&conf->curve, privkey,
6213e5b75505Sopenharmony_ci					      privkey_len);
6214e5b75505Sopenharmony_ci	else
6215e5b75505Sopenharmony_ci		conf->csign = dpp_gen_keypair(conf->curve);
6216e5b75505Sopenharmony_ci	if (!conf->csign)
6217e5b75505Sopenharmony_ci		goto fail;
6218e5b75505Sopenharmony_ci	conf->own = 1;
6219e5b75505Sopenharmony_ci
6220e5b75505Sopenharmony_ci	csign_pub = dpp_get_pubkey_point(conf->csign, 1);
6221e5b75505Sopenharmony_ci	if (!csign_pub) {
6222e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
6223e5b75505Sopenharmony_ci		goto fail;
6224e5b75505Sopenharmony_ci	}
6225e5b75505Sopenharmony_ci
6226e5b75505Sopenharmony_ci	/* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6227e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(csign_pub);
6228e5b75505Sopenharmony_ci	len[0] = wpabuf_len(csign_pub);
6229e5b75505Sopenharmony_ci	if (sha256_vector(1, addr, len, kid_hash) < 0) {
6230e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6231e5b75505Sopenharmony_ci			   "DPP: Failed to derive kid for C-sign-key");
6232e5b75505Sopenharmony_ci		goto fail;
6233e5b75505Sopenharmony_ci	}
6234e5b75505Sopenharmony_ci
6235e5b75505Sopenharmony_ci	conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
6236e5b75505Sopenharmony_ci					       NULL, 0);
6237e5b75505Sopenharmony_ci	if (!conf->kid)
6238e5b75505Sopenharmony_ci		goto fail;
6239e5b75505Sopenharmony_ciout:
6240e5b75505Sopenharmony_ci	wpabuf_free(csign_pub);
6241e5b75505Sopenharmony_ci	return conf;
6242e5b75505Sopenharmony_cifail:
6243e5b75505Sopenharmony_ci	dpp_configurator_free(conf);
6244e5b75505Sopenharmony_ci	conf = NULL;
6245e5b75505Sopenharmony_ci	goto out;
6246e5b75505Sopenharmony_ci}
6247e5b75505Sopenharmony_ci
6248e5b75505Sopenharmony_ci
6249e5b75505Sopenharmony_ciint dpp_configurator_own_config(struct dpp_authentication *auth,
6250e5b75505Sopenharmony_ci				const char *curve, int ap)
6251e5b75505Sopenharmony_ci{
6252e5b75505Sopenharmony_ci	struct wpabuf *conf_obj;
6253e5b75505Sopenharmony_ci	int ret = -1;
6254e5b75505Sopenharmony_ci
6255e5b75505Sopenharmony_ci	if (!auth->conf) {
6256e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
6257e5b75505Sopenharmony_ci		return -1;
6258e5b75505Sopenharmony_ci	}
6259e5b75505Sopenharmony_ci
6260e5b75505Sopenharmony_ci	if (!curve) {
6261e5b75505Sopenharmony_ci		auth->curve = &dpp_curves[0];
6262e5b75505Sopenharmony_ci	} else {
6263e5b75505Sopenharmony_ci		auth->curve = dpp_get_curve_name(curve);
6264e5b75505Sopenharmony_ci		if (!auth->curve) {
6265e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
6266e5b75505Sopenharmony_ci				   curve);
6267e5b75505Sopenharmony_ci			return -1;
6268e5b75505Sopenharmony_ci		}
6269e5b75505Sopenharmony_ci	}
6270e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
6271e5b75505Sopenharmony_ci		   "DPP: Building own configuration/connector with curve %s",
6272e5b75505Sopenharmony_ci		   auth->curve->name);
6273e5b75505Sopenharmony_ci
6274e5b75505Sopenharmony_ci	auth->own_protocol_key = dpp_gen_keypair(auth->curve);
6275e5b75505Sopenharmony_ci	if (!auth->own_protocol_key)
6276e5b75505Sopenharmony_ci		return -1;
6277e5b75505Sopenharmony_ci	dpp_copy_netaccesskey(auth);
6278e5b75505Sopenharmony_ci	auth->peer_protocol_key = auth->own_protocol_key;
6279e5b75505Sopenharmony_ci	dpp_copy_csign(auth, auth->conf->csign);
6280e5b75505Sopenharmony_ci
6281e5b75505Sopenharmony_ci	conf_obj = dpp_build_conf_obj(auth, ap);
6282e5b75505Sopenharmony_ci	if (!conf_obj)
6283e5b75505Sopenharmony_ci		goto fail;
6284e5b75505Sopenharmony_ci	ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
6285e5b75505Sopenharmony_ci				 wpabuf_len(conf_obj));
6286e5b75505Sopenharmony_cifail:
6287e5b75505Sopenharmony_ci	wpabuf_free(conf_obj);
6288e5b75505Sopenharmony_ci	auth->peer_protocol_key = NULL;
6289e5b75505Sopenharmony_ci	return ret;
6290e5b75505Sopenharmony_ci}
6291e5b75505Sopenharmony_ci
6292e5b75505Sopenharmony_ci
6293e5b75505Sopenharmony_cistatic int dpp_compatible_netrole(const char *role1, const char *role2)
6294e5b75505Sopenharmony_ci{
6295e5b75505Sopenharmony_ci	return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
6296e5b75505Sopenharmony_ci		(os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
6297e5b75505Sopenharmony_ci}
6298e5b75505Sopenharmony_ci
6299e5b75505Sopenharmony_ci
6300e5b75505Sopenharmony_cistatic int dpp_connector_compatible_group(struct json_token *root,
6301e5b75505Sopenharmony_ci					  const char *group_id,
6302e5b75505Sopenharmony_ci					  const char *net_role)
6303e5b75505Sopenharmony_ci{
6304e5b75505Sopenharmony_ci	struct json_token *groups, *token;
6305e5b75505Sopenharmony_ci
6306e5b75505Sopenharmony_ci	groups = json_get_member(root, "groups");
6307e5b75505Sopenharmony_ci	if (!groups || groups->type != JSON_ARRAY)
6308e5b75505Sopenharmony_ci		return 0;
6309e5b75505Sopenharmony_ci
6310e5b75505Sopenharmony_ci	for (token = groups->child; token; token = token->sibling) {
6311e5b75505Sopenharmony_ci		struct json_token *id, *role;
6312e5b75505Sopenharmony_ci
6313e5b75505Sopenharmony_ci		id = json_get_member(token, "groupId");
6314e5b75505Sopenharmony_ci		if (!id || id->type != JSON_STRING)
6315e5b75505Sopenharmony_ci			continue;
6316e5b75505Sopenharmony_ci
6317e5b75505Sopenharmony_ci		role = json_get_member(token, "netRole");
6318e5b75505Sopenharmony_ci		if (!role || role->type != JSON_STRING)
6319e5b75505Sopenharmony_ci			continue;
6320e5b75505Sopenharmony_ci
6321e5b75505Sopenharmony_ci		if (os_strcmp(id->string, "*") != 0 &&
6322e5b75505Sopenharmony_ci		    os_strcmp(group_id, "*") != 0 &&
6323e5b75505Sopenharmony_ci		    os_strcmp(id->string, group_id) != 0)
6324e5b75505Sopenharmony_ci			continue;
6325e5b75505Sopenharmony_ci
6326e5b75505Sopenharmony_ci		if (dpp_compatible_netrole(role->string, net_role))
6327e5b75505Sopenharmony_ci			return 1;
6328e5b75505Sopenharmony_ci	}
6329e5b75505Sopenharmony_ci
6330e5b75505Sopenharmony_ci	return 0;
6331e5b75505Sopenharmony_ci}
6332e5b75505Sopenharmony_ci
6333e5b75505Sopenharmony_ci
6334e5b75505Sopenharmony_cistatic int dpp_connector_match_groups(struct json_token *own_root,
6335e5b75505Sopenharmony_ci				      struct json_token *peer_root)
6336e5b75505Sopenharmony_ci{
6337e5b75505Sopenharmony_ci	struct json_token *groups, *token;
6338e5b75505Sopenharmony_ci
6339e5b75505Sopenharmony_ci	groups = json_get_member(peer_root, "groups");
6340e5b75505Sopenharmony_ci	if (!groups || groups->type != JSON_ARRAY) {
6341e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
6342e5b75505Sopenharmony_ci		return 0;
6343e5b75505Sopenharmony_ci	}
6344e5b75505Sopenharmony_ci
6345e5b75505Sopenharmony_ci	for (token = groups->child; token; token = token->sibling) {
6346e5b75505Sopenharmony_ci		struct json_token *id, *role;
6347e5b75505Sopenharmony_ci
6348e5b75505Sopenharmony_ci		id = json_get_member(token, "groupId");
6349e5b75505Sopenharmony_ci		if (!id || id->type != JSON_STRING) {
6350e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
6351e5b75505Sopenharmony_ci				   "DPP: Missing peer groupId string");
6352e5b75505Sopenharmony_ci			continue;
6353e5b75505Sopenharmony_ci		}
6354e5b75505Sopenharmony_ci
6355e5b75505Sopenharmony_ci		role = json_get_member(token, "netRole");
6356e5b75505Sopenharmony_ci		if (!role || role->type != JSON_STRING) {
6357e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
6358e5b75505Sopenharmony_ci				   "DPP: Missing peer groups::netRole string");
6359e5b75505Sopenharmony_ci			continue;
6360e5b75505Sopenharmony_ci		}
6361e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6362e5b75505Sopenharmony_ci			   "DPP: peer connector group: groupId='%s' netRole='%s'",
6363e5b75505Sopenharmony_ci			   id->string, role->string);
6364e5b75505Sopenharmony_ci		if (dpp_connector_compatible_group(own_root, id->string,
6365e5b75505Sopenharmony_ci						   role->string)) {
6366e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
6367e5b75505Sopenharmony_ci				   "DPP: Compatible group/netRole in own connector");
6368e5b75505Sopenharmony_ci			return 1;
6369e5b75505Sopenharmony_ci		}
6370e5b75505Sopenharmony_ci	}
6371e5b75505Sopenharmony_ci
6372e5b75505Sopenharmony_ci	return 0;
6373e5b75505Sopenharmony_ci}
6374e5b75505Sopenharmony_ci
6375e5b75505Sopenharmony_ci
6376e5b75505Sopenharmony_cistatic int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
6377e5b75505Sopenharmony_ci			  unsigned int hash_len)
6378e5b75505Sopenharmony_ci{
6379e5b75505Sopenharmony_ci	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
6380e5b75505Sopenharmony_ci	const char *info = "DPP PMK";
6381e5b75505Sopenharmony_ci	int res;
6382e5b75505Sopenharmony_ci
6383e5b75505Sopenharmony_ci	/* PMK = HKDF(<>, "DPP PMK", N.x) */
6384e5b75505Sopenharmony_ci
6385e5b75505Sopenharmony_ci	/* HKDF-Extract(<>, N.x) */
6386e5b75505Sopenharmony_ci	os_memset(salt, 0, hash_len);
6387e5b75505Sopenharmony_ci	if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
6388e5b75505Sopenharmony_ci		return -1;
6389e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6390e5b75505Sopenharmony_ci			prk, hash_len);
6391e5b75505Sopenharmony_ci
6392e5b75505Sopenharmony_ci	/* HKDF-Expand(PRK, info, L) */
6393e5b75505Sopenharmony_ci	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
6394e5b75505Sopenharmony_ci	os_memset(prk, 0, hash_len);
6395e5b75505Sopenharmony_ci	if (res < 0)
6396e5b75505Sopenharmony_ci		return -1;
6397e5b75505Sopenharmony_ci
6398e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6399e5b75505Sopenharmony_ci			pmk, hash_len);
6400e5b75505Sopenharmony_ci	return 0;
6401e5b75505Sopenharmony_ci}
6402e5b75505Sopenharmony_ci
6403e5b75505Sopenharmony_ci
6404e5b75505Sopenharmony_cistatic int dpp_derive_pmkid(const struct dpp_curve_params *curve,
6405e5b75505Sopenharmony_ci			    EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
6406e5b75505Sopenharmony_ci{
6407e5b75505Sopenharmony_ci	struct wpabuf *nkx, *pkx;
6408e5b75505Sopenharmony_ci	int ret = -1, res;
6409e5b75505Sopenharmony_ci	const u8 *addr[2];
6410e5b75505Sopenharmony_ci	size_t len[2];
6411e5b75505Sopenharmony_ci	u8 hash[SHA256_MAC_LEN];
6412e5b75505Sopenharmony_ci
6413e5b75505Sopenharmony_ci	/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6414e5b75505Sopenharmony_ci	nkx = dpp_get_pubkey_point(own_key, 0);
6415e5b75505Sopenharmony_ci	pkx = dpp_get_pubkey_point(peer_key, 0);
6416e5b75505Sopenharmony_ci	if (!nkx || !pkx)
6417e5b75505Sopenharmony_ci		goto fail;
6418e5b75505Sopenharmony_ci	addr[0] = wpabuf_head(nkx);
6419e5b75505Sopenharmony_ci	len[0] = wpabuf_len(nkx) / 2;
6420e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(pkx);
6421e5b75505Sopenharmony_ci	len[1] = wpabuf_len(pkx) / 2;
6422e5b75505Sopenharmony_ci	if (len[0] != len[1])
6423e5b75505Sopenharmony_ci		goto fail;
6424e5b75505Sopenharmony_ci	if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
6425e5b75505Sopenharmony_ci		addr[0] = wpabuf_head(pkx);
6426e5b75505Sopenharmony_ci		addr[1] = wpabuf_head(nkx);
6427e5b75505Sopenharmony_ci	}
6428e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
6429e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
6430e5b75505Sopenharmony_ci	res = sha256_vector(2, addr, len, hash);
6431e5b75505Sopenharmony_ci	if (res < 0)
6432e5b75505Sopenharmony_ci		goto fail;
6433e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
6434e5b75505Sopenharmony_ci	os_memcpy(pmkid, hash, PMKID_LEN);
6435e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
6436e5b75505Sopenharmony_ci	ret = 0;
6437e5b75505Sopenharmony_cifail:
6438e5b75505Sopenharmony_ci	wpabuf_free(nkx);
6439e5b75505Sopenharmony_ci	wpabuf_free(pkx);
6440e5b75505Sopenharmony_ci	return ret;
6441e5b75505Sopenharmony_ci}
6442e5b75505Sopenharmony_ci
6443e5b75505Sopenharmony_ci
6444e5b75505Sopenharmony_cienum dpp_status_error
6445e5b75505Sopenharmony_cidpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
6446e5b75505Sopenharmony_ci	       const u8 *net_access_key, size_t net_access_key_len,
6447e5b75505Sopenharmony_ci	       const u8 *csign_key, size_t csign_key_len,
6448e5b75505Sopenharmony_ci	       const u8 *peer_connector, size_t peer_connector_len,
6449e5b75505Sopenharmony_ci	       os_time_t *expiry)
6450e5b75505Sopenharmony_ci{
6451e5b75505Sopenharmony_ci	struct json_token *root = NULL, *netkey, *token;
6452e5b75505Sopenharmony_ci	struct json_token *own_root = NULL;
6453e5b75505Sopenharmony_ci	enum dpp_status_error ret = 255, res;
6454e5b75505Sopenharmony_ci	EVP_PKEY *own_key = NULL, *peer_key = NULL;
6455e5b75505Sopenharmony_ci	struct wpabuf *own_key_pub = NULL;
6456e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve, *own_curve;
6457e5b75505Sopenharmony_ci	struct dpp_signed_connector_info info;
6458e5b75505Sopenharmony_ci	const unsigned char *p;
6459e5b75505Sopenharmony_ci	EVP_PKEY *csign = NULL;
6460e5b75505Sopenharmony_ci	char *signed_connector = NULL;
6461e5b75505Sopenharmony_ci	const char *pos, *end;
6462e5b75505Sopenharmony_ci	unsigned char *own_conn = NULL;
6463e5b75505Sopenharmony_ci	size_t own_conn_len;
6464e5b75505Sopenharmony_ci	size_t Nx_len;
6465e5b75505Sopenharmony_ci	u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
6466e5b75505Sopenharmony_ci
6467e5b75505Sopenharmony_ci	os_memset(intro, 0, sizeof(*intro));
6468e5b75505Sopenharmony_ci	os_memset(&info, 0, sizeof(info));
6469e5b75505Sopenharmony_ci	if (expiry)
6470e5b75505Sopenharmony_ci		*expiry = 0;
6471e5b75505Sopenharmony_ci
6472e5b75505Sopenharmony_ci	p = csign_key;
6473e5b75505Sopenharmony_ci	csign = d2i_PUBKEY(NULL, &p, csign_key_len);
6474e5b75505Sopenharmony_ci	if (!csign) {
6475e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR,
6476e5b75505Sopenharmony_ci			   "DPP: Failed to parse local C-sign-key information");
6477e5b75505Sopenharmony_ci		goto fail;
6478e5b75505Sopenharmony_ci	}
6479e5b75505Sopenharmony_ci
6480e5b75505Sopenharmony_ci	own_key = dpp_set_keypair(&own_curve, net_access_key,
6481e5b75505Sopenharmony_ci				  net_access_key_len);
6482e5b75505Sopenharmony_ci	if (!own_key) {
6483e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
6484e5b75505Sopenharmony_ci		goto fail;
6485e5b75505Sopenharmony_ci	}
6486e5b75505Sopenharmony_ci
6487e5b75505Sopenharmony_ci	pos = os_strchr(own_connector, '.');
6488e5b75505Sopenharmony_ci	if (!pos) {
6489e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
6490e5b75505Sopenharmony_ci		goto fail;
6491e5b75505Sopenharmony_ci	}
6492e5b75505Sopenharmony_ci	pos++;
6493e5b75505Sopenharmony_ci	end = os_strchr(pos, '.');
6494e5b75505Sopenharmony_ci	if (!end) {
6495e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
6496e5b75505Sopenharmony_ci		goto fail;
6497e5b75505Sopenharmony_ci	}
6498e5b75505Sopenharmony_ci	own_conn = base64_url_decode((const unsigned char *) pos,
6499e5b75505Sopenharmony_ci				     end - pos, &own_conn_len);
6500e5b75505Sopenharmony_ci	if (!own_conn) {
6501e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6502e5b75505Sopenharmony_ci			   "DPP: Failed to base64url decode own signedConnector JWS Payload");
6503e5b75505Sopenharmony_ci		goto fail;
6504e5b75505Sopenharmony_ci	}
6505e5b75505Sopenharmony_ci
6506e5b75505Sopenharmony_ci	own_root = json_parse((const char *) own_conn, own_conn_len);
6507e5b75505Sopenharmony_ci	if (!own_root) {
6508e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
6509e5b75505Sopenharmony_ci		goto fail;
6510e5b75505Sopenharmony_ci	}
6511e5b75505Sopenharmony_ci
6512e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
6513e5b75505Sopenharmony_ci			  peer_connector, peer_connector_len);
6514e5b75505Sopenharmony_ci	signed_connector = os_malloc(peer_connector_len + 1);
6515e5b75505Sopenharmony_ci	if (!signed_connector)
6516e5b75505Sopenharmony_ci		goto fail;
6517e5b75505Sopenharmony_ci	os_memcpy(signed_connector, peer_connector, peer_connector_len);
6518e5b75505Sopenharmony_ci	signed_connector[peer_connector_len] = '\0';
6519e5b75505Sopenharmony_ci
6520e5b75505Sopenharmony_ci	res = dpp_process_signed_connector(&info, csign, signed_connector);
6521e5b75505Sopenharmony_ci	if (res != DPP_STATUS_OK) {
6522e5b75505Sopenharmony_ci		ret = res;
6523e5b75505Sopenharmony_ci		goto fail;
6524e5b75505Sopenharmony_ci	}
6525e5b75505Sopenharmony_ci
6526e5b75505Sopenharmony_ci	root = json_parse((const char *) info.payload, info.payload_len);
6527e5b75505Sopenharmony_ci	if (!root) {
6528e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
6529e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
6530e5b75505Sopenharmony_ci		goto fail;
6531e5b75505Sopenharmony_ci	}
6532e5b75505Sopenharmony_ci
6533e5b75505Sopenharmony_ci	if (!dpp_connector_match_groups(own_root, root)) {
6534e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6535e5b75505Sopenharmony_ci			   "DPP: Peer connector does not include compatible group netrole with own connector");
6536e5b75505Sopenharmony_ci		ret = DPP_STATUS_NO_MATCH;
6537e5b75505Sopenharmony_ci		goto fail;
6538e5b75505Sopenharmony_ci	}
6539e5b75505Sopenharmony_ci
6540e5b75505Sopenharmony_ci	token = json_get_member(root, "expiry");
6541e5b75505Sopenharmony_ci	if (!token || token->type != JSON_STRING) {
6542e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6543e5b75505Sopenharmony_ci			   "DPP: No expiry string found - connector does not expire");
6544e5b75505Sopenharmony_ci	} else {
6545e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
6546e5b75505Sopenharmony_ci		if (dpp_key_expired(token->string, expiry)) {
6547e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
6548e5b75505Sopenharmony_ci				   "DPP: Connector (netAccessKey) has expired");
6549e5b75505Sopenharmony_ci			ret = DPP_STATUS_INVALID_CONNECTOR;
6550e5b75505Sopenharmony_ci			goto fail;
6551e5b75505Sopenharmony_ci		}
6552e5b75505Sopenharmony_ci	}
6553e5b75505Sopenharmony_ci
6554e5b75505Sopenharmony_ci	netkey = json_get_member(root, "netAccessKey");
6555e5b75505Sopenharmony_ci	if (!netkey || netkey->type != JSON_OBJECT) {
6556e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
6557e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
6558e5b75505Sopenharmony_ci		goto fail;
6559e5b75505Sopenharmony_ci	}
6560e5b75505Sopenharmony_ci
6561e5b75505Sopenharmony_ci	peer_key = dpp_parse_jwk(netkey, &curve);
6562e5b75505Sopenharmony_ci	if (!peer_key) {
6563e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
6564e5b75505Sopenharmony_ci		goto fail;
6565e5b75505Sopenharmony_ci	}
6566e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
6567e5b75505Sopenharmony_ci
6568e5b75505Sopenharmony_ci	if (own_curve != curve) {
6569e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
6570e5b75505Sopenharmony_ci			   "DPP: Mismatching netAccessKey curves (%s != %s)",
6571e5b75505Sopenharmony_ci			   own_curve->name, curve->name);
6572e5b75505Sopenharmony_ci		ret = DPP_STATUS_INVALID_CONNECTOR;
6573e5b75505Sopenharmony_ci		goto fail;
6574e5b75505Sopenharmony_ci	}
6575e5b75505Sopenharmony_ci
6576e5b75505Sopenharmony_ci	/* ECDH: N = nk * PK */
6577e5b75505Sopenharmony_ci	if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
6578e5b75505Sopenharmony_ci		goto fail;
6579e5b75505Sopenharmony_ci
6580e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
6581e5b75505Sopenharmony_ci			Nx, Nx_len);
6582e5b75505Sopenharmony_ci
6583e5b75505Sopenharmony_ci	/* PMK = HKDF(<>, "DPP PMK", N.x) */
6584e5b75505Sopenharmony_ci	if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
6585e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
6586e5b75505Sopenharmony_ci		goto fail;
6587e5b75505Sopenharmony_ci	}
6588e5b75505Sopenharmony_ci	intro->pmk_len = curve->hash_len;
6589e5b75505Sopenharmony_ci
6590e5b75505Sopenharmony_ci	/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6591e5b75505Sopenharmony_ci	if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
6592e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
6593e5b75505Sopenharmony_ci		goto fail;
6594e5b75505Sopenharmony_ci	}
6595e5b75505Sopenharmony_ci
6596e5b75505Sopenharmony_ci	ret = DPP_STATUS_OK;
6597e5b75505Sopenharmony_cifail:
6598e5b75505Sopenharmony_ci	if (ret != DPP_STATUS_OK)
6599e5b75505Sopenharmony_ci		os_memset(intro, 0, sizeof(*intro));
6600e5b75505Sopenharmony_ci	os_memset(Nx, 0, sizeof(Nx));
6601e5b75505Sopenharmony_ci	os_free(own_conn);
6602e5b75505Sopenharmony_ci	os_free(signed_connector);
6603e5b75505Sopenharmony_ci	os_free(info.payload);
6604e5b75505Sopenharmony_ci	EVP_PKEY_free(own_key);
6605e5b75505Sopenharmony_ci	wpabuf_free(own_key_pub);
6606e5b75505Sopenharmony_ci	EVP_PKEY_free(peer_key);
6607e5b75505Sopenharmony_ci	EVP_PKEY_free(csign);
6608e5b75505Sopenharmony_ci	json_free(root);
6609e5b75505Sopenharmony_ci	json_free(own_root);
6610e5b75505Sopenharmony_ci	return ret;
6611e5b75505Sopenharmony_ci}
6612e5b75505Sopenharmony_ci
6613e5b75505Sopenharmony_ci
6614e5b75505Sopenharmony_cistatic EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
6615e5b75505Sopenharmony_ci					 int init)
6616e5b75505Sopenharmony_ci{
6617e5b75505Sopenharmony_ci	EC_GROUP *group;
6618e5b75505Sopenharmony_ci	size_t len = curve->prime_len;
6619e5b75505Sopenharmony_ci	const u8 *x, *y;
6620e5b75505Sopenharmony_ci	EVP_PKEY *res;
6621e5b75505Sopenharmony_ci
6622e5b75505Sopenharmony_ci	switch (curve->ike_group) {
6623e5b75505Sopenharmony_ci	case 19:
6624e5b75505Sopenharmony_ci		x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
6625e5b75505Sopenharmony_ci		y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
6626e5b75505Sopenharmony_ci		break;
6627e5b75505Sopenharmony_ci	case 20:
6628e5b75505Sopenharmony_ci		x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
6629e5b75505Sopenharmony_ci		y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
6630e5b75505Sopenharmony_ci		break;
6631e5b75505Sopenharmony_ci	case 21:
6632e5b75505Sopenharmony_ci		x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
6633e5b75505Sopenharmony_ci		y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
6634e5b75505Sopenharmony_ci		break;
6635e5b75505Sopenharmony_ci	case 28:
6636e5b75505Sopenharmony_ci		x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
6637e5b75505Sopenharmony_ci		y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
6638e5b75505Sopenharmony_ci		break;
6639e5b75505Sopenharmony_ci	case 29:
6640e5b75505Sopenharmony_ci		x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
6641e5b75505Sopenharmony_ci		y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
6642e5b75505Sopenharmony_ci		break;
6643e5b75505Sopenharmony_ci	case 30:
6644e5b75505Sopenharmony_ci		x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
6645e5b75505Sopenharmony_ci		y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
6646e5b75505Sopenharmony_ci		break;
6647e5b75505Sopenharmony_ci	default:
6648e5b75505Sopenharmony_ci		return NULL;
6649e5b75505Sopenharmony_ci	}
6650e5b75505Sopenharmony_ci
6651e5b75505Sopenharmony_ci	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6652e5b75505Sopenharmony_ci	if (!group)
6653e5b75505Sopenharmony_ci		return NULL;
6654e5b75505Sopenharmony_ci	res = dpp_set_pubkey_point_group(group, x, y, len);
6655e5b75505Sopenharmony_ci	EC_GROUP_free(group);
6656e5b75505Sopenharmony_ci	return res;
6657e5b75505Sopenharmony_ci}
6658e5b75505Sopenharmony_ci
6659e5b75505Sopenharmony_ci
6660e5b75505Sopenharmony_cistatic EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
6661e5b75505Sopenharmony_ci				     const u8 *mac_init, const char *code,
6662e5b75505Sopenharmony_ci				     const char *identifier, BN_CTX *bnctx,
6663e5b75505Sopenharmony_ci				     EC_GROUP **ret_group)
6664e5b75505Sopenharmony_ci{
6665e5b75505Sopenharmony_ci	u8 hash[DPP_MAX_HASH_LEN];
6666e5b75505Sopenharmony_ci	const u8 *addr[3];
6667e5b75505Sopenharmony_ci	size_t len[3];
6668e5b75505Sopenharmony_ci	unsigned int num_elem = 0;
6669e5b75505Sopenharmony_ci	EC_POINT *Qi = NULL;
6670e5b75505Sopenharmony_ci	EVP_PKEY *Pi = NULL;
6671e5b75505Sopenharmony_ci	EC_KEY *Pi_ec = NULL;
6672e5b75505Sopenharmony_ci	const EC_POINT *Pi_point;
6673e5b75505Sopenharmony_ci	BIGNUM *hash_bn = NULL;
6674e5b75505Sopenharmony_ci	const EC_GROUP *group = NULL;
6675e5b75505Sopenharmony_ci	EC_GROUP *group2 = NULL;
6676e5b75505Sopenharmony_ci
6677e5b75505Sopenharmony_ci	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6678e5b75505Sopenharmony_ci
6679e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
6680e5b75505Sopenharmony_ci	addr[num_elem] = mac_init;
6681e5b75505Sopenharmony_ci	len[num_elem] = ETH_ALEN;
6682e5b75505Sopenharmony_ci	num_elem++;
6683e5b75505Sopenharmony_ci	if (identifier) {
6684e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6685e5b75505Sopenharmony_ci			   identifier);
6686e5b75505Sopenharmony_ci		addr[num_elem] = (const u8 *) identifier;
6687e5b75505Sopenharmony_ci		len[num_elem] = os_strlen(identifier);
6688e5b75505Sopenharmony_ci		num_elem++;
6689e5b75505Sopenharmony_ci	}
6690e5b75505Sopenharmony_ci	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6691e5b75505Sopenharmony_ci	addr[num_elem] = (const u8 *) code;
6692e5b75505Sopenharmony_ci	len[num_elem] = os_strlen(code);
6693e5b75505Sopenharmony_ci	num_elem++;
6694e5b75505Sopenharmony_ci	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6695e5b75505Sopenharmony_ci		goto fail;
6696e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG,
6697e5b75505Sopenharmony_ci			"DPP: H(MAC-Initiator | [identifier |] code)",
6698e5b75505Sopenharmony_ci			hash, curve->hash_len);
6699e5b75505Sopenharmony_ci	Pi = dpp_pkex_get_role_elem(curve, 1);
6700e5b75505Sopenharmony_ci	if (!Pi)
6701e5b75505Sopenharmony_ci		goto fail;
6702e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Pi", Pi);
6703e5b75505Sopenharmony_ci	Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
6704e5b75505Sopenharmony_ci	if (!Pi_ec)
6705e5b75505Sopenharmony_ci		goto fail;
6706e5b75505Sopenharmony_ci	Pi_point = EC_KEY_get0_public_key(Pi_ec);
6707e5b75505Sopenharmony_ci
6708e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(Pi_ec);
6709e5b75505Sopenharmony_ci	if (!group)
6710e5b75505Sopenharmony_ci		goto fail;
6711e5b75505Sopenharmony_ci	group2 = EC_GROUP_dup(group);
6712e5b75505Sopenharmony_ci	if (!group2)
6713e5b75505Sopenharmony_ci		goto fail;
6714e5b75505Sopenharmony_ci	Qi = EC_POINT_new(group2);
6715e5b75505Sopenharmony_ci	if (!Qi) {
6716e5b75505Sopenharmony_ci		EC_GROUP_free(group2);
6717e5b75505Sopenharmony_ci		goto fail;
6718e5b75505Sopenharmony_ci	}
6719e5b75505Sopenharmony_ci	hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6720e5b75505Sopenharmony_ci	if (!hash_bn ||
6721e5b75505Sopenharmony_ci	    EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
6722e5b75505Sopenharmony_ci		goto fail;
6723e5b75505Sopenharmony_ci	if (EC_POINT_is_at_infinity(group, Qi)) {
6724e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
6725e5b75505Sopenharmony_ci		goto fail;
6726e5b75505Sopenharmony_ci	}
6727e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: Qi", group, Qi);
6728e5b75505Sopenharmony_ciout:
6729e5b75505Sopenharmony_ci	EC_KEY_free(Pi_ec);
6730e5b75505Sopenharmony_ci	EVP_PKEY_free(Pi);
6731e5b75505Sopenharmony_ci	BN_clear_free(hash_bn);
6732e5b75505Sopenharmony_ci	if (ret_group && Qi)
6733e5b75505Sopenharmony_ci		*ret_group = group2;
6734e5b75505Sopenharmony_ci	else
6735e5b75505Sopenharmony_ci		EC_GROUP_free(group2);
6736e5b75505Sopenharmony_ci	return Qi;
6737e5b75505Sopenharmony_cifail:
6738e5b75505Sopenharmony_ci	EC_POINT_free(Qi);
6739e5b75505Sopenharmony_ci	Qi = NULL;
6740e5b75505Sopenharmony_ci	goto out;
6741e5b75505Sopenharmony_ci}
6742e5b75505Sopenharmony_ci
6743e5b75505Sopenharmony_ci
6744e5b75505Sopenharmony_cistatic EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
6745e5b75505Sopenharmony_ci				     const u8 *mac_resp, const char *code,
6746e5b75505Sopenharmony_ci				     const char *identifier, BN_CTX *bnctx,
6747e5b75505Sopenharmony_ci				     EC_GROUP **ret_group)
6748e5b75505Sopenharmony_ci{
6749e5b75505Sopenharmony_ci	u8 hash[DPP_MAX_HASH_LEN];
6750e5b75505Sopenharmony_ci	const u8 *addr[3];
6751e5b75505Sopenharmony_ci	size_t len[3];
6752e5b75505Sopenharmony_ci	unsigned int num_elem = 0;
6753e5b75505Sopenharmony_ci	EC_POINT *Qr = NULL;
6754e5b75505Sopenharmony_ci	EVP_PKEY *Pr = NULL;
6755e5b75505Sopenharmony_ci	EC_KEY *Pr_ec = NULL;
6756e5b75505Sopenharmony_ci	const EC_POINT *Pr_point;
6757e5b75505Sopenharmony_ci	BIGNUM *hash_bn = NULL;
6758e5b75505Sopenharmony_ci	const EC_GROUP *group = NULL;
6759e5b75505Sopenharmony_ci	EC_GROUP *group2 = NULL;
6760e5b75505Sopenharmony_ci
6761e5b75505Sopenharmony_ci	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6762e5b75505Sopenharmony_ci
6763e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
6764e5b75505Sopenharmony_ci	addr[num_elem] = mac_resp;
6765e5b75505Sopenharmony_ci	len[num_elem] = ETH_ALEN;
6766e5b75505Sopenharmony_ci	num_elem++;
6767e5b75505Sopenharmony_ci	if (identifier) {
6768e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
6769e5b75505Sopenharmony_ci			   identifier);
6770e5b75505Sopenharmony_ci		addr[num_elem] = (const u8 *) identifier;
6771e5b75505Sopenharmony_ci		len[num_elem] = os_strlen(identifier);
6772e5b75505Sopenharmony_ci		num_elem++;
6773e5b75505Sopenharmony_ci	}
6774e5b75505Sopenharmony_ci	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
6775e5b75505Sopenharmony_ci	addr[num_elem] = (const u8 *) code;
6776e5b75505Sopenharmony_ci	len[num_elem] = os_strlen(code);
6777e5b75505Sopenharmony_ci	num_elem++;
6778e5b75505Sopenharmony_ci	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
6779e5b75505Sopenharmony_ci		goto fail;
6780e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG,
6781e5b75505Sopenharmony_ci			"DPP: H(MAC-Responder | [identifier |] code)",
6782e5b75505Sopenharmony_ci			hash, curve->hash_len);
6783e5b75505Sopenharmony_ci	Pr = dpp_pkex_get_role_elem(curve, 0);
6784e5b75505Sopenharmony_ci	if (!Pr)
6785e5b75505Sopenharmony_ci		goto fail;
6786e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Pr", Pr);
6787e5b75505Sopenharmony_ci	Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
6788e5b75505Sopenharmony_ci	if (!Pr_ec)
6789e5b75505Sopenharmony_ci		goto fail;
6790e5b75505Sopenharmony_ci	Pr_point = EC_KEY_get0_public_key(Pr_ec);
6791e5b75505Sopenharmony_ci
6792e5b75505Sopenharmony_ci	group = EC_KEY_get0_group(Pr_ec);
6793e5b75505Sopenharmony_ci	if (!group)
6794e5b75505Sopenharmony_ci		goto fail;
6795e5b75505Sopenharmony_ci	group2 = EC_GROUP_dup(group);
6796e5b75505Sopenharmony_ci	if (!group2)
6797e5b75505Sopenharmony_ci		goto fail;
6798e5b75505Sopenharmony_ci	Qr = EC_POINT_new(group2);
6799e5b75505Sopenharmony_ci	if (!Qr) {
6800e5b75505Sopenharmony_ci		EC_GROUP_free(group2);
6801e5b75505Sopenharmony_ci		goto fail;
6802e5b75505Sopenharmony_ci	}
6803e5b75505Sopenharmony_ci	hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
6804e5b75505Sopenharmony_ci	if (!hash_bn ||
6805e5b75505Sopenharmony_ci	    EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
6806e5b75505Sopenharmony_ci		goto fail;
6807e5b75505Sopenharmony_ci	if (EC_POINT_is_at_infinity(group, Qr)) {
6808e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
6809e5b75505Sopenharmony_ci		goto fail;
6810e5b75505Sopenharmony_ci	}
6811e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: Qr", group, Qr);
6812e5b75505Sopenharmony_ciout:
6813e5b75505Sopenharmony_ci	EC_KEY_free(Pr_ec);
6814e5b75505Sopenharmony_ci	EVP_PKEY_free(Pr);
6815e5b75505Sopenharmony_ci	BN_clear_free(hash_bn);
6816e5b75505Sopenharmony_ci	if (ret_group && Qr)
6817e5b75505Sopenharmony_ci		*ret_group = group2;
6818e5b75505Sopenharmony_ci	else
6819e5b75505Sopenharmony_ci		EC_GROUP_free(group2);
6820e5b75505Sopenharmony_ci	return Qr;
6821e5b75505Sopenharmony_cifail:
6822e5b75505Sopenharmony_ci	EC_POINT_free(Qr);
6823e5b75505Sopenharmony_ci	Qr = NULL;
6824e5b75505Sopenharmony_ci	goto out;
6825e5b75505Sopenharmony_ci}
6826e5b75505Sopenharmony_ci
6827e5b75505Sopenharmony_ci
6828e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6829e5b75505Sopenharmony_cistatic int dpp_test_gen_invalid_key(struct wpabuf *msg,
6830e5b75505Sopenharmony_ci				    const struct dpp_curve_params *curve)
6831e5b75505Sopenharmony_ci{
6832e5b75505Sopenharmony_ci	BN_CTX *ctx;
6833e5b75505Sopenharmony_ci	BIGNUM *x, *y;
6834e5b75505Sopenharmony_ci	int ret = -1;
6835e5b75505Sopenharmony_ci	EC_GROUP *group;
6836e5b75505Sopenharmony_ci	EC_POINT *point;
6837e5b75505Sopenharmony_ci
6838e5b75505Sopenharmony_ci	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6839e5b75505Sopenharmony_ci	if (!group)
6840e5b75505Sopenharmony_ci		return -1;
6841e5b75505Sopenharmony_ci
6842e5b75505Sopenharmony_ci	ctx = BN_CTX_new();
6843e5b75505Sopenharmony_ci	point = EC_POINT_new(group);
6844e5b75505Sopenharmony_ci	x = BN_new();
6845e5b75505Sopenharmony_ci	y = BN_new();
6846e5b75505Sopenharmony_ci	if (!ctx || !point || !x || !y)
6847e5b75505Sopenharmony_ci		goto fail;
6848e5b75505Sopenharmony_ci
6849e5b75505Sopenharmony_ci	if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
6850e5b75505Sopenharmony_ci		goto fail;
6851e5b75505Sopenharmony_ci
6852e5b75505Sopenharmony_ci	/* Generate a random y coordinate that results in a point that is not
6853e5b75505Sopenharmony_ci	 * on the curve. */
6854e5b75505Sopenharmony_ci	for (;;) {
6855e5b75505Sopenharmony_ci		if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
6856e5b75505Sopenharmony_ci			goto fail;
6857e5b75505Sopenharmony_ci
6858e5b75505Sopenharmony_ci		if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
6859e5b75505Sopenharmony_ci							ctx) != 1) {
6860e5b75505Sopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6861e5b75505Sopenharmony_ci		/* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6862e5b75505Sopenharmony_ci		 * return an error from EC_POINT_set_affine_coordinates_GFp()
6863e5b75505Sopenharmony_ci		 * when the point is not on the curve. */
6864e5b75505Sopenharmony_ci			break;
6865e5b75505Sopenharmony_ci#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6866e5b75505Sopenharmony_ci			goto fail;
6867e5b75505Sopenharmony_ci#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6868e5b75505Sopenharmony_ci		}
6869e5b75505Sopenharmony_ci
6870e5b75505Sopenharmony_ci		if (!EC_POINT_is_on_curve(group, point, ctx))
6871e5b75505Sopenharmony_ci			break;
6872e5b75505Sopenharmony_ci	}
6873e5b75505Sopenharmony_ci
6874e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
6875e5b75505Sopenharmony_ci			   curve->prime_len) < 0 ||
6876e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
6877e5b75505Sopenharmony_ci			   curve->prime_len) < 0)
6878e5b75505Sopenharmony_ci		goto fail;
6879e5b75505Sopenharmony_ci
6880e5b75505Sopenharmony_ci	ret = 0;
6881e5b75505Sopenharmony_cifail:
6882e5b75505Sopenharmony_ci	if (ret < 0)
6883e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
6884e5b75505Sopenharmony_ci	BN_free(x);
6885e5b75505Sopenharmony_ci	BN_free(y);
6886e5b75505Sopenharmony_ci	EC_POINT_free(point);
6887e5b75505Sopenharmony_ci	BN_CTX_free(ctx);
6888e5b75505Sopenharmony_ci	EC_GROUP_free(group);
6889e5b75505Sopenharmony_ci
6890e5b75505Sopenharmony_ci	return ret;
6891e5b75505Sopenharmony_ci}
6892e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
6893e5b75505Sopenharmony_ci
6894e5b75505Sopenharmony_ci
6895e5b75505Sopenharmony_cistatic struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
6896e5b75505Sopenharmony_ci{
6897e5b75505Sopenharmony_ci	EC_KEY *X_ec = NULL;
6898e5b75505Sopenharmony_ci	const EC_POINT *X_point;
6899e5b75505Sopenharmony_ci	BN_CTX *bnctx = NULL;
6900e5b75505Sopenharmony_ci	EC_GROUP *group = NULL;
6901e5b75505Sopenharmony_ci	EC_POINT *Qi = NULL, *M = NULL;
6902e5b75505Sopenharmony_ci	struct wpabuf *M_buf = NULL;
6903e5b75505Sopenharmony_ci	BIGNUM *Mx = NULL, *My = NULL;
6904e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL;
6905e5b75505Sopenharmony_ci	size_t attr_len;
6906e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
6907e5b75505Sopenharmony_ci
6908e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
6909e5b75505Sopenharmony_ci
6910e5b75505Sopenharmony_ci	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6911e5b75505Sopenharmony_ci	bnctx = BN_CTX_new();
6912e5b75505Sopenharmony_ci	if (!bnctx)
6913e5b75505Sopenharmony_ci		goto fail;
6914e5b75505Sopenharmony_ci	Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
6915e5b75505Sopenharmony_ci				pkex->identifier, bnctx, &group);
6916e5b75505Sopenharmony_ci	if (!Qi)
6917e5b75505Sopenharmony_ci		goto fail;
6918e5b75505Sopenharmony_ci
6919e5b75505Sopenharmony_ci	/* Generate a random ephemeral keypair x/X */
6920e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6921e5b75505Sopenharmony_ci	if (dpp_pkex_ephemeral_key_override_len) {
6922e5b75505Sopenharmony_ci		const struct dpp_curve_params *tmp_curve;
6923e5b75505Sopenharmony_ci
6924e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
6925e5b75505Sopenharmony_ci			   "DPP: TESTING - override ephemeral key x/X");
6926e5b75505Sopenharmony_ci		pkex->x = dpp_set_keypair(&tmp_curve,
6927e5b75505Sopenharmony_ci					  dpp_pkex_ephemeral_key_override,
6928e5b75505Sopenharmony_ci					  dpp_pkex_ephemeral_key_override_len);
6929e5b75505Sopenharmony_ci	} else {
6930e5b75505Sopenharmony_ci		pkex->x = dpp_gen_keypair(curve);
6931e5b75505Sopenharmony_ci	}
6932e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
6933e5b75505Sopenharmony_ci	pkex->x = dpp_gen_keypair(curve);
6934e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
6935e5b75505Sopenharmony_ci	if (!pkex->x)
6936e5b75505Sopenharmony_ci		goto fail;
6937e5b75505Sopenharmony_ci
6938e5b75505Sopenharmony_ci	/* M = X + Qi */
6939e5b75505Sopenharmony_ci	X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
6940e5b75505Sopenharmony_ci	if (!X_ec)
6941e5b75505Sopenharmony_ci		goto fail;
6942e5b75505Sopenharmony_ci	X_point = EC_KEY_get0_public_key(X_ec);
6943e5b75505Sopenharmony_ci	if (!X_point)
6944e5b75505Sopenharmony_ci		goto fail;
6945e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: X", group, X_point);
6946e5b75505Sopenharmony_ci	M = EC_POINT_new(group);
6947e5b75505Sopenharmony_ci	Mx = BN_new();
6948e5b75505Sopenharmony_ci	My = BN_new();
6949e5b75505Sopenharmony_ci	if (!M || !Mx || !My ||
6950e5b75505Sopenharmony_ci	    EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
6951e5b75505Sopenharmony_ci	    EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
6952e5b75505Sopenharmony_ci		goto fail;
6953e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: M", group, M);
6954e5b75505Sopenharmony_ci
6955e5b75505Sopenharmony_ci	/* Initiator -> Responder: group, [identifier,] M */
6956e5b75505Sopenharmony_ci	attr_len = 4 + 2;
6957e5b75505Sopenharmony_ci	if (pkex->identifier)
6958e5b75505Sopenharmony_ci		attr_len += 4 + os_strlen(pkex->identifier);
6959e5b75505Sopenharmony_ci	attr_len += 4 + 2 * curve->prime_len;
6960e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
6961e5b75505Sopenharmony_ci	if (!msg)
6962e5b75505Sopenharmony_ci		goto fail;
6963e5b75505Sopenharmony_ci
6964e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6965e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
6966e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
6967e5b75505Sopenharmony_ci		goto skip_finite_cyclic_group;
6968e5b75505Sopenharmony_ci	}
6969e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
6970e5b75505Sopenharmony_ci
6971e5b75505Sopenharmony_ci	/* Finite Cyclic Group attribute */
6972e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
6973e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 2);
6974e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, curve->ike_group);
6975e5b75505Sopenharmony_ci
6976e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6977e5b75505Sopenharmony_ciskip_finite_cyclic_group:
6978e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
6979e5b75505Sopenharmony_ci
6980e5b75505Sopenharmony_ci	/* Code Identifier attribute */
6981e5b75505Sopenharmony_ci	if (pkex->identifier) {
6982e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
6983e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
6984e5b75505Sopenharmony_ci		wpabuf_put_str(msg, pkex->identifier);
6985e5b75505Sopenharmony_ci	}
6986e5b75505Sopenharmony_ci
6987e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6988e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
6989e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
6990e5b75505Sopenharmony_ci		goto out;
6991e5b75505Sopenharmony_ci	}
6992e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
6993e5b75505Sopenharmony_ci
6994e5b75505Sopenharmony_ci	/* M in Encrypted Key attribute */
6995e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
6996e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 2 * curve->prime_len);
6997e5b75505Sopenharmony_ci
6998e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
6999e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
7000e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7001e5b75505Sopenharmony_ci		if (dpp_test_gen_invalid_key(msg, curve) < 0)
7002e5b75505Sopenharmony_ci			goto fail;
7003e5b75505Sopenharmony_ci		goto out;
7004e5b75505Sopenharmony_ci	}
7005e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7006e5b75505Sopenharmony_ci
7007e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
7008e5b75505Sopenharmony_ci			   curve->prime_len) < 0 ||
7009e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
7010e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
7011e5b75505Sopenharmony_ci			   curve->prime_len) < 0)
7012e5b75505Sopenharmony_ci		goto fail;
7013e5b75505Sopenharmony_ci
7014e5b75505Sopenharmony_ciout:
7015e5b75505Sopenharmony_ci	wpabuf_free(M_buf);
7016e5b75505Sopenharmony_ci	EC_KEY_free(X_ec);
7017e5b75505Sopenharmony_ci	EC_POINT_free(M);
7018e5b75505Sopenharmony_ci	EC_POINT_free(Qi);
7019e5b75505Sopenharmony_ci	BN_clear_free(Mx);
7020e5b75505Sopenharmony_ci	BN_clear_free(My);
7021e5b75505Sopenharmony_ci	BN_CTX_free(bnctx);
7022e5b75505Sopenharmony_ci	EC_GROUP_free(group);
7023e5b75505Sopenharmony_ci	return msg;
7024e5b75505Sopenharmony_cifail:
7025e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
7026e5b75505Sopenharmony_ci	wpabuf_free(msg);
7027e5b75505Sopenharmony_ci	msg = NULL;
7028e5b75505Sopenharmony_ci	goto out;
7029e5b75505Sopenharmony_ci}
7030e5b75505Sopenharmony_ci
7031e5b75505Sopenharmony_ci
7032e5b75505Sopenharmony_cistatic void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
7033e5b75505Sopenharmony_ci{
7034e5b75505Sopenharmony_ci	wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
7035e5b75505Sopenharmony_ci}
7036e5b75505Sopenharmony_ci
7037e5b75505Sopenharmony_ci
7038e5b75505Sopenharmony_cistruct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
7039e5b75505Sopenharmony_ci				const u8 *own_mac,
7040e5b75505Sopenharmony_ci				const char *identifier,
7041e5b75505Sopenharmony_ci				const char *code)
7042e5b75505Sopenharmony_ci{
7043e5b75505Sopenharmony_ci	struct dpp_pkex *pkex;
7044e5b75505Sopenharmony_ci
7045e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7046e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7047e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7048e5b75505Sopenharmony_ci			   MAC2STR(dpp_pkex_own_mac_override));
7049e5b75505Sopenharmony_ci		own_mac = dpp_pkex_own_mac_override;
7050e5b75505Sopenharmony_ci	}
7051e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7052e5b75505Sopenharmony_ci
7053e5b75505Sopenharmony_ci	pkex = os_zalloc(sizeof(*pkex));
7054e5b75505Sopenharmony_ci	if (!pkex)
7055e5b75505Sopenharmony_ci		return NULL;
7056e5b75505Sopenharmony_ci	pkex->msg_ctx = msg_ctx;
7057e5b75505Sopenharmony_ci	pkex->initiator = 1;
7058e5b75505Sopenharmony_ci	pkex->own_bi = bi;
7059e5b75505Sopenharmony_ci	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7060e5b75505Sopenharmony_ci	if (identifier) {
7061e5b75505Sopenharmony_ci		pkex->identifier = os_strdup(identifier);
7062e5b75505Sopenharmony_ci		if (!pkex->identifier)
7063e5b75505Sopenharmony_ci			goto fail;
7064e5b75505Sopenharmony_ci	}
7065e5b75505Sopenharmony_ci	pkex->code = os_strdup(code);
7066e5b75505Sopenharmony_ci	if (!pkex->code)
7067e5b75505Sopenharmony_ci		goto fail;
7068e5b75505Sopenharmony_ci	pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
7069e5b75505Sopenharmony_ci	if (!pkex->exchange_req)
7070e5b75505Sopenharmony_ci		goto fail;
7071e5b75505Sopenharmony_ci	return pkex;
7072e5b75505Sopenharmony_cifail:
7073e5b75505Sopenharmony_ci	dpp_pkex_free(pkex);
7074e5b75505Sopenharmony_ci	return NULL;
7075e5b75505Sopenharmony_ci}
7076e5b75505Sopenharmony_ci
7077e5b75505Sopenharmony_ci
7078e5b75505Sopenharmony_cistatic struct wpabuf *
7079e5b75505Sopenharmony_cidpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
7080e5b75505Sopenharmony_ci			     enum dpp_status_error status,
7081e5b75505Sopenharmony_ci			     const BIGNUM *Nx, const BIGNUM *Ny)
7082e5b75505Sopenharmony_ci{
7083e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL;
7084e5b75505Sopenharmony_ci	size_t attr_len;
7085e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7086e5b75505Sopenharmony_ci
7087e5b75505Sopenharmony_ci	/* Initiator -> Responder: DPP Status, [identifier,] N */
7088e5b75505Sopenharmony_ci	attr_len = 4 + 1;
7089e5b75505Sopenharmony_ci	if (pkex->identifier)
7090e5b75505Sopenharmony_ci		attr_len += 4 + os_strlen(pkex->identifier);
7091e5b75505Sopenharmony_ci	attr_len += 4 + 2 * curve->prime_len;
7092e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
7093e5b75505Sopenharmony_ci	if (!msg)
7094e5b75505Sopenharmony_ci		goto fail;
7095e5b75505Sopenharmony_ci
7096e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7097e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
7098e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
7099e5b75505Sopenharmony_ci		goto skip_status;
7100e5b75505Sopenharmony_ci	}
7101e5b75505Sopenharmony_ci
7102e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
7103e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
7104e5b75505Sopenharmony_ci		status = 255;
7105e5b75505Sopenharmony_ci	}
7106e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7107e5b75505Sopenharmony_ci
7108e5b75505Sopenharmony_ci	/* DPP Status */
7109e5b75505Sopenharmony_ci	dpp_build_attr_status(msg, status);
7110e5b75505Sopenharmony_ci
7111e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7112e5b75505Sopenharmony_ciskip_status:
7113e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7114e5b75505Sopenharmony_ci
7115e5b75505Sopenharmony_ci	/* Code Identifier attribute */
7116e5b75505Sopenharmony_ci	if (pkex->identifier) {
7117e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
7118e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, os_strlen(pkex->identifier));
7119e5b75505Sopenharmony_ci		wpabuf_put_str(msg, pkex->identifier);
7120e5b75505Sopenharmony_ci	}
7121e5b75505Sopenharmony_ci
7122e5b75505Sopenharmony_ci	if (status != DPP_STATUS_OK)
7123e5b75505Sopenharmony_ci		goto skip_encrypted_key;
7124e5b75505Sopenharmony_ci
7125e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7126e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7127e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
7128e5b75505Sopenharmony_ci		goto skip_encrypted_key;
7129e5b75505Sopenharmony_ci	}
7130e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7131e5b75505Sopenharmony_ci
7132e5b75505Sopenharmony_ci	/* N in Encrypted Key attribute */
7133e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
7134e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, 2 * curve->prime_len);
7135e5b75505Sopenharmony_ci
7136e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7137e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
7138e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
7139e5b75505Sopenharmony_ci		if (dpp_test_gen_invalid_key(msg, curve) < 0)
7140e5b75505Sopenharmony_ci			goto fail;
7141e5b75505Sopenharmony_ci		goto skip_encrypted_key;
7142e5b75505Sopenharmony_ci	}
7143e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7144e5b75505Sopenharmony_ci
7145e5b75505Sopenharmony_ci	if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
7146e5b75505Sopenharmony_ci			   curve->prime_len) < 0 ||
7147e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
7148e5b75505Sopenharmony_ci	    dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
7149e5b75505Sopenharmony_ci			   curve->prime_len) < 0)
7150e5b75505Sopenharmony_ci		goto fail;
7151e5b75505Sopenharmony_ci
7152e5b75505Sopenharmony_ciskip_encrypted_key:
7153e5b75505Sopenharmony_ci	if (status == DPP_STATUS_BAD_GROUP) {
7154e5b75505Sopenharmony_ci		/* Finite Cyclic Group attribute */
7155e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
7156e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, 2);
7157e5b75505Sopenharmony_ci		wpabuf_put_le16(msg, curve->ike_group);
7158e5b75505Sopenharmony_ci	}
7159e5b75505Sopenharmony_ci
7160e5b75505Sopenharmony_ci	return msg;
7161e5b75505Sopenharmony_cifail:
7162e5b75505Sopenharmony_ci	wpabuf_free(msg);
7163e5b75505Sopenharmony_ci	return NULL;
7164e5b75505Sopenharmony_ci}
7165e5b75505Sopenharmony_ci
7166e5b75505Sopenharmony_ci
7167e5b75505Sopenharmony_cistatic int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
7168e5b75505Sopenharmony_ci			     const u8 *Mx, size_t Mx_len,
7169e5b75505Sopenharmony_ci			     const u8 *Nx, size_t Nx_len,
7170e5b75505Sopenharmony_ci			     const char *code,
7171e5b75505Sopenharmony_ci			     const u8 *Kx, size_t Kx_len,
7172e5b75505Sopenharmony_ci			     u8 *z, unsigned int hash_len)
7173e5b75505Sopenharmony_ci{
7174e5b75505Sopenharmony_ci	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
7175e5b75505Sopenharmony_ci	int res;
7176e5b75505Sopenharmony_ci	u8 *info, *pos;
7177e5b75505Sopenharmony_ci	size_t info_len;
7178e5b75505Sopenharmony_ci
7179e5b75505Sopenharmony_ci	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7180e5b75505Sopenharmony_ci	 */
7181e5b75505Sopenharmony_ci
7182e5b75505Sopenharmony_ci	/* HKDF-Extract(<>, IKM=K.x) */
7183e5b75505Sopenharmony_ci	os_memset(salt, 0, hash_len);
7184e5b75505Sopenharmony_ci	if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
7185e5b75505Sopenharmony_ci		return -1;
7186e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
7187e5b75505Sopenharmony_ci			prk, hash_len);
7188e5b75505Sopenharmony_ci	info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
7189e5b75505Sopenharmony_ci	info = os_malloc(info_len);
7190e5b75505Sopenharmony_ci	if (!info)
7191e5b75505Sopenharmony_ci		return -1;
7192e5b75505Sopenharmony_ci	pos = info;
7193e5b75505Sopenharmony_ci	os_memcpy(pos, mac_init, ETH_ALEN);
7194e5b75505Sopenharmony_ci	pos += ETH_ALEN;
7195e5b75505Sopenharmony_ci	os_memcpy(pos, mac_resp, ETH_ALEN);
7196e5b75505Sopenharmony_ci	pos += ETH_ALEN;
7197e5b75505Sopenharmony_ci	os_memcpy(pos, Mx, Mx_len);
7198e5b75505Sopenharmony_ci	pos += Mx_len;
7199e5b75505Sopenharmony_ci	os_memcpy(pos, Nx, Nx_len);
7200e5b75505Sopenharmony_ci	pos += Nx_len;
7201e5b75505Sopenharmony_ci	os_memcpy(pos, code, os_strlen(code));
7202e5b75505Sopenharmony_ci
7203e5b75505Sopenharmony_ci	/* HKDF-Expand(PRK, info, L) */
7204e5b75505Sopenharmony_ci	if (hash_len == 32)
7205e5b75505Sopenharmony_ci		res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
7206e5b75505Sopenharmony_ci				      z, hash_len);
7207e5b75505Sopenharmony_ci	else if (hash_len == 48)
7208e5b75505Sopenharmony_ci		res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
7209e5b75505Sopenharmony_ci				      z, hash_len);
7210e5b75505Sopenharmony_ci	else if (hash_len == 64)
7211e5b75505Sopenharmony_ci		res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
7212e5b75505Sopenharmony_ci				      z, hash_len);
7213e5b75505Sopenharmony_ci	else
7214e5b75505Sopenharmony_ci		res = -1;
7215e5b75505Sopenharmony_ci	os_free(info);
7216e5b75505Sopenharmony_ci	os_memset(prk, 0, hash_len);
7217e5b75505Sopenharmony_ci	if (res < 0)
7218e5b75505Sopenharmony_ci		return -1;
7219e5b75505Sopenharmony_ci
7220e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
7221e5b75505Sopenharmony_ci			z, hash_len);
7222e5b75505Sopenharmony_ci	return 0;
7223e5b75505Sopenharmony_ci}
7224e5b75505Sopenharmony_ci
7225e5b75505Sopenharmony_ci
7226e5b75505Sopenharmony_cistatic int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
7227e5b75505Sopenharmony_ci				     const char *identifier)
7228e5b75505Sopenharmony_ci{
7229e5b75505Sopenharmony_ci	if (!attr_id && identifier) {
7230e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
7231e5b75505Sopenharmony_ci			   "DPP: No PKEX code identifier received, but expected one");
7232e5b75505Sopenharmony_ci		return 0;
7233e5b75505Sopenharmony_ci	}
7234e5b75505Sopenharmony_ci
7235e5b75505Sopenharmony_ci	if (attr_id && !identifier) {
7236e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
7237e5b75505Sopenharmony_ci			   "DPP: PKEX code identifier received, but not expecting one");
7238e5b75505Sopenharmony_ci		return 0;
7239e5b75505Sopenharmony_ci	}
7240e5b75505Sopenharmony_ci
7241e5b75505Sopenharmony_ci	if (attr_id && identifier &&
7242e5b75505Sopenharmony_ci	    (os_strlen(identifier) != attr_id_len ||
7243e5b75505Sopenharmony_ci	     os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
7244e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
7245e5b75505Sopenharmony_ci		return 0;
7246e5b75505Sopenharmony_ci	}
7247e5b75505Sopenharmony_ci
7248e5b75505Sopenharmony_ci	return 1;
7249e5b75505Sopenharmony_ci}
7250e5b75505Sopenharmony_ci
7251e5b75505Sopenharmony_ci
7252e5b75505Sopenharmony_cistruct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
7253e5b75505Sopenharmony_ci					   struct dpp_bootstrap_info *bi,
7254e5b75505Sopenharmony_ci					   const u8 *own_mac,
7255e5b75505Sopenharmony_ci					   const u8 *peer_mac,
7256e5b75505Sopenharmony_ci					   const char *identifier,
7257e5b75505Sopenharmony_ci					   const char *code,
7258e5b75505Sopenharmony_ci					   const u8 *buf, size_t len)
7259e5b75505Sopenharmony_ci{
7260e5b75505Sopenharmony_ci	const u8 *attr_group, *attr_id, *attr_key;
7261e5b75505Sopenharmony_ci	u16 attr_group_len, attr_id_len, attr_key_len;
7262e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = bi->curve;
7263e5b75505Sopenharmony_ci	u16 ike_group;
7264e5b75505Sopenharmony_ci	struct dpp_pkex *pkex = NULL;
7265e5b75505Sopenharmony_ci	EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
7266e5b75505Sopenharmony_ci	BN_CTX *bnctx = NULL;
7267e5b75505Sopenharmony_ci	EC_GROUP *group = NULL;
7268e5b75505Sopenharmony_ci	BIGNUM *Mx = NULL, *My = NULL;
7269e5b75505Sopenharmony_ci	EC_KEY *Y_ec = NULL, *X_ec = NULL;;
7270e5b75505Sopenharmony_ci	const EC_POINT *Y_point;
7271e5b75505Sopenharmony_ci	BIGNUM *Nx = NULL, *Ny = NULL;
7272e5b75505Sopenharmony_ci	u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
7273e5b75505Sopenharmony_ci	size_t Kx_len;
7274e5b75505Sopenharmony_ci	int res;
7275e5b75505Sopenharmony_ci
7276e5b75505Sopenharmony_ci	if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
7277e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7278e5b75505Sopenharmony_ci			"PKEX counter t limit reached - ignore message");
7279e5b75505Sopenharmony_ci		return NULL;
7280e5b75505Sopenharmony_ci	}
7281e5b75505Sopenharmony_ci
7282e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7283e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7284e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7285e5b75505Sopenharmony_ci			   MAC2STR(dpp_pkex_peer_mac_override));
7286e5b75505Sopenharmony_ci		peer_mac = dpp_pkex_peer_mac_override;
7287e5b75505Sopenharmony_ci	}
7288e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
7289e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
7290e5b75505Sopenharmony_ci			   MAC2STR(dpp_pkex_own_mac_override));
7291e5b75505Sopenharmony_ci		own_mac = dpp_pkex_own_mac_override;
7292e5b75505Sopenharmony_ci	}
7293e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7294e5b75505Sopenharmony_ci
7295e5b75505Sopenharmony_ci	attr_id_len = 0;
7296e5b75505Sopenharmony_ci	attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
7297e5b75505Sopenharmony_ci			       &attr_id_len);
7298e5b75505Sopenharmony_ci	if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
7299e5b75505Sopenharmony_ci		return NULL;
7300e5b75505Sopenharmony_ci
7301e5b75505Sopenharmony_ci	attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
7302e5b75505Sopenharmony_ci				  &attr_group_len);
7303e5b75505Sopenharmony_ci	if (!attr_group || attr_group_len != 2) {
7304e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7305e5b75505Sopenharmony_ci			"Missing or invalid Finite Cyclic Group attribute");
7306e5b75505Sopenharmony_ci		return NULL;
7307e5b75505Sopenharmony_ci	}
7308e5b75505Sopenharmony_ci	ike_group = WPA_GET_LE16(attr_group);
7309e5b75505Sopenharmony_ci	if (ike_group != curve->ike_group) {
7310e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7311e5b75505Sopenharmony_ci			"Mismatching PKEX curve: peer=%u own=%u",
7312e5b75505Sopenharmony_ci			ike_group, curve->ike_group);
7313e5b75505Sopenharmony_ci		pkex = os_zalloc(sizeof(*pkex));
7314e5b75505Sopenharmony_ci		if (!pkex)
7315e5b75505Sopenharmony_ci			goto fail;
7316e5b75505Sopenharmony_ci		pkex->own_bi = bi;
7317e5b75505Sopenharmony_ci		pkex->failed = 1;
7318e5b75505Sopenharmony_ci		pkex->exchange_resp = dpp_pkex_build_exchange_resp(
7319e5b75505Sopenharmony_ci			pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
7320e5b75505Sopenharmony_ci		if (!pkex->exchange_resp)
7321e5b75505Sopenharmony_ci			goto fail;
7322e5b75505Sopenharmony_ci		return pkex;
7323e5b75505Sopenharmony_ci	}
7324e5b75505Sopenharmony_ci
7325e5b75505Sopenharmony_ci	/* M in Encrypted Key attribute */
7326e5b75505Sopenharmony_ci	attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
7327e5b75505Sopenharmony_ci				&attr_key_len);
7328e5b75505Sopenharmony_ci	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
7329e5b75505Sopenharmony_ci	    attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
7330e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7331e5b75505Sopenharmony_ci			"Missing Encrypted Key attribute");
7332e5b75505Sopenharmony_ci		return NULL;
7333e5b75505Sopenharmony_ci	}
7334e5b75505Sopenharmony_ci
7335e5b75505Sopenharmony_ci	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7336e5b75505Sopenharmony_ci	bnctx = BN_CTX_new();
7337e5b75505Sopenharmony_ci	if (!bnctx)
7338e5b75505Sopenharmony_ci		goto fail;
7339e5b75505Sopenharmony_ci	Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
7340e5b75505Sopenharmony_ci				&group);
7341e5b75505Sopenharmony_ci	if (!Qi)
7342e5b75505Sopenharmony_ci		goto fail;
7343e5b75505Sopenharmony_ci
7344e5b75505Sopenharmony_ci	/* X' = M - Qi */
7345e5b75505Sopenharmony_ci	X = EC_POINT_new(group);
7346e5b75505Sopenharmony_ci	M = EC_POINT_new(group);
7347e5b75505Sopenharmony_ci	Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7348e5b75505Sopenharmony_ci	My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7349e5b75505Sopenharmony_ci	if (!X || !M || !Mx || !My ||
7350e5b75505Sopenharmony_ci	    EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
7351e5b75505Sopenharmony_ci	    EC_POINT_is_at_infinity(group, M) ||
7352e5b75505Sopenharmony_ci	    !EC_POINT_is_on_curve(group, M, bnctx) ||
7353e5b75505Sopenharmony_ci	    EC_POINT_invert(group, Qi, bnctx) != 1 ||
7354e5b75505Sopenharmony_ci	    EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
7355e5b75505Sopenharmony_ci	    EC_POINT_is_at_infinity(group, X) ||
7356e5b75505Sopenharmony_ci	    !EC_POINT_is_on_curve(group, X, bnctx)) {
7357e5b75505Sopenharmony_ci		wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7358e5b75505Sopenharmony_ci			"Invalid Encrypted Key value");
7359e5b75505Sopenharmony_ci		bi->pkex_t++;
7360e5b75505Sopenharmony_ci		goto fail;
7361e5b75505Sopenharmony_ci	}
7362e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: M", group, M);
7363e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: X'", group, X);
7364e5b75505Sopenharmony_ci
7365e5b75505Sopenharmony_ci	pkex = os_zalloc(sizeof(*pkex));
7366e5b75505Sopenharmony_ci	if (!pkex)
7367e5b75505Sopenharmony_ci		goto fail;
7368e5b75505Sopenharmony_ci	pkex->t = bi->pkex_t;
7369e5b75505Sopenharmony_ci	pkex->msg_ctx = msg_ctx;
7370e5b75505Sopenharmony_ci	pkex->own_bi = bi;
7371e5b75505Sopenharmony_ci	os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
7372e5b75505Sopenharmony_ci	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7373e5b75505Sopenharmony_ci	if (identifier) {
7374e5b75505Sopenharmony_ci		pkex->identifier = os_strdup(identifier);
7375e5b75505Sopenharmony_ci		if (!pkex->identifier)
7376e5b75505Sopenharmony_ci			goto fail;
7377e5b75505Sopenharmony_ci	}
7378e5b75505Sopenharmony_ci	pkex->code = os_strdup(code);
7379e5b75505Sopenharmony_ci	if (!pkex->code)
7380e5b75505Sopenharmony_ci		goto fail;
7381e5b75505Sopenharmony_ci
7382e5b75505Sopenharmony_ci	os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
7383e5b75505Sopenharmony_ci
7384e5b75505Sopenharmony_ci	X_ec = EC_KEY_new();
7385e5b75505Sopenharmony_ci	if (!X_ec ||
7386e5b75505Sopenharmony_ci	    EC_KEY_set_group(X_ec, group) != 1 ||
7387e5b75505Sopenharmony_ci	    EC_KEY_set_public_key(X_ec, X) != 1)
7388e5b75505Sopenharmony_ci		goto fail;
7389e5b75505Sopenharmony_ci	pkex->x = EVP_PKEY_new();
7390e5b75505Sopenharmony_ci	if (!pkex->x ||
7391e5b75505Sopenharmony_ci	    EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
7392e5b75505Sopenharmony_ci		goto fail;
7393e5b75505Sopenharmony_ci
7394e5b75505Sopenharmony_ci	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7395e5b75505Sopenharmony_ci	Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
7396e5b75505Sopenharmony_ci	if (!Qr)
7397e5b75505Sopenharmony_ci		goto fail;
7398e5b75505Sopenharmony_ci
7399e5b75505Sopenharmony_ci	/* Generate a random ephemeral keypair y/Y */
7400e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7401e5b75505Sopenharmony_ci	if (dpp_pkex_ephemeral_key_override_len) {
7402e5b75505Sopenharmony_ci		const struct dpp_curve_params *tmp_curve;
7403e5b75505Sopenharmony_ci
7404e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
7405e5b75505Sopenharmony_ci			   "DPP: TESTING - override ephemeral key y/Y");
7406e5b75505Sopenharmony_ci		pkex->y = dpp_set_keypair(&tmp_curve,
7407e5b75505Sopenharmony_ci					  dpp_pkex_ephemeral_key_override,
7408e5b75505Sopenharmony_ci					  dpp_pkex_ephemeral_key_override_len);
7409e5b75505Sopenharmony_ci	} else {
7410e5b75505Sopenharmony_ci		pkex->y = dpp_gen_keypair(curve);
7411e5b75505Sopenharmony_ci	}
7412e5b75505Sopenharmony_ci#else /* CONFIG_TESTING_OPTIONS */
7413e5b75505Sopenharmony_ci	pkex->y = dpp_gen_keypair(curve);
7414e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7415e5b75505Sopenharmony_ci	if (!pkex->y)
7416e5b75505Sopenharmony_ci		goto fail;
7417e5b75505Sopenharmony_ci
7418e5b75505Sopenharmony_ci	/* N = Y + Qr */
7419e5b75505Sopenharmony_ci	Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
7420e5b75505Sopenharmony_ci	if (!Y_ec)
7421e5b75505Sopenharmony_ci		goto fail;
7422e5b75505Sopenharmony_ci	Y_point = EC_KEY_get0_public_key(Y_ec);
7423e5b75505Sopenharmony_ci	if (!Y_point)
7424e5b75505Sopenharmony_ci		goto fail;
7425e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: Y", group, Y_point);
7426e5b75505Sopenharmony_ci	N = EC_POINT_new(group);
7427e5b75505Sopenharmony_ci	Nx = BN_new();
7428e5b75505Sopenharmony_ci	Ny = BN_new();
7429e5b75505Sopenharmony_ci	if (!N || !Nx || !Ny ||
7430e5b75505Sopenharmony_ci	    EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
7431e5b75505Sopenharmony_ci	    EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
7432e5b75505Sopenharmony_ci		goto fail;
7433e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: N", group, N);
7434e5b75505Sopenharmony_ci
7435e5b75505Sopenharmony_ci	pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
7436e5b75505Sopenharmony_ci							   Nx, Ny);
7437e5b75505Sopenharmony_ci	if (!pkex->exchange_resp)
7438e5b75505Sopenharmony_ci		goto fail;
7439e5b75505Sopenharmony_ci
7440e5b75505Sopenharmony_ci	/* K = y * X' */
7441e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
7442e5b75505Sopenharmony_ci		goto fail;
7443e5b75505Sopenharmony_ci
7444e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7445e5b75505Sopenharmony_ci			Kx, Kx_len);
7446e5b75505Sopenharmony_ci
7447e5b75505Sopenharmony_ci	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7448e5b75505Sopenharmony_ci	 */
7449e5b75505Sopenharmony_ci	res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
7450e5b75505Sopenharmony_ci				pkex->Mx, curve->prime_len,
7451e5b75505Sopenharmony_ci				pkex->Nx, curve->prime_len, pkex->code,
7452e5b75505Sopenharmony_ci				Kx, Kx_len, pkex->z, curve->hash_len);
7453e5b75505Sopenharmony_ci	os_memset(Kx, 0, Kx_len);
7454e5b75505Sopenharmony_ci	if (res < 0)
7455e5b75505Sopenharmony_ci		goto fail;
7456e5b75505Sopenharmony_ci
7457e5b75505Sopenharmony_ci	pkex->exchange_done = 1;
7458e5b75505Sopenharmony_ci
7459e5b75505Sopenharmony_ciout:
7460e5b75505Sopenharmony_ci	BN_CTX_free(bnctx);
7461e5b75505Sopenharmony_ci	EC_POINT_free(Qi);
7462e5b75505Sopenharmony_ci	EC_POINT_free(Qr);
7463e5b75505Sopenharmony_ci	BN_free(Mx);
7464e5b75505Sopenharmony_ci	BN_free(My);
7465e5b75505Sopenharmony_ci	BN_free(Nx);
7466e5b75505Sopenharmony_ci	BN_free(Ny);
7467e5b75505Sopenharmony_ci	EC_POINT_free(M);
7468e5b75505Sopenharmony_ci	EC_POINT_free(N);
7469e5b75505Sopenharmony_ci	EC_POINT_free(X);
7470e5b75505Sopenharmony_ci	EC_KEY_free(X_ec);
7471e5b75505Sopenharmony_ci	EC_KEY_free(Y_ec);
7472e5b75505Sopenharmony_ci	EC_GROUP_free(group);
7473e5b75505Sopenharmony_ci	return pkex;
7474e5b75505Sopenharmony_cifail:
7475e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
7476e5b75505Sopenharmony_ci	dpp_pkex_free(pkex);
7477e5b75505Sopenharmony_ci	pkex = NULL;
7478e5b75505Sopenharmony_ci	goto out;
7479e5b75505Sopenharmony_ci}
7480e5b75505Sopenharmony_ci
7481e5b75505Sopenharmony_ci
7482e5b75505Sopenharmony_cistatic struct wpabuf *
7483e5b75505Sopenharmony_cidpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
7484e5b75505Sopenharmony_ci				 const struct wpabuf *A_pub, const u8 *u)
7485e5b75505Sopenharmony_ci{
7486e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7487e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL;
7488e5b75505Sopenharmony_ci	size_t clear_len, attr_len;
7489e5b75505Sopenharmony_ci	struct wpabuf *clear = NULL;
7490e5b75505Sopenharmony_ci	u8 *wrapped;
7491e5b75505Sopenharmony_ci	u8 octet;
7492e5b75505Sopenharmony_ci	const u8 *addr[2];
7493e5b75505Sopenharmony_ci	size_t len[2];
7494e5b75505Sopenharmony_ci
7495e5b75505Sopenharmony_ci	/* {A, u, [bootstrapping info]}z */
7496e5b75505Sopenharmony_ci	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
7497e5b75505Sopenharmony_ci	clear = wpabuf_alloc(clear_len);
7498e5b75505Sopenharmony_ci	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7499e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7500e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
7501e5b75505Sopenharmony_ci		attr_len += 5;
7502e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7503e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
7504e5b75505Sopenharmony_ci	if (!clear || !msg)
7505e5b75505Sopenharmony_ci		goto fail;
7506e5b75505Sopenharmony_ci
7507e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7508e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
7509e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
7510e5b75505Sopenharmony_ci		goto skip_bootstrap_key;
7511e5b75505Sopenharmony_ci	}
7512e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
7513e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
7514e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7515e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, 2 * curve->prime_len);
7516e5b75505Sopenharmony_ci		if (dpp_test_gen_invalid_key(clear, curve) < 0)
7517e5b75505Sopenharmony_ci			goto fail;
7518e5b75505Sopenharmony_ci		goto skip_bootstrap_key;
7519e5b75505Sopenharmony_ci	}
7520e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7521e5b75505Sopenharmony_ci
7522e5b75505Sopenharmony_ci	/* A in Bootstrap Key attribute */
7523e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7524e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, wpabuf_len(A_pub));
7525e5b75505Sopenharmony_ci	wpabuf_put_buf(clear, A_pub);
7526e5b75505Sopenharmony_ci
7527e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7528e5b75505Sopenharmony_ciskip_bootstrap_key:
7529e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
7530e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
7531e5b75505Sopenharmony_ci		goto skip_i_auth_tag;
7532e5b75505Sopenharmony_ci	}
7533e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
7534e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
7535e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
7536e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, curve->hash_len);
7537e5b75505Sopenharmony_ci		wpabuf_put_data(clear, u, curve->hash_len - 1);
7538e5b75505Sopenharmony_ci		wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
7539e5b75505Sopenharmony_ci		goto skip_i_auth_tag;
7540e5b75505Sopenharmony_ci	}
7541e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7542e5b75505Sopenharmony_ci
7543e5b75505Sopenharmony_ci	/* u in I-Auth tag attribute */
7544e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
7545e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, curve->hash_len);
7546e5b75505Sopenharmony_ci	wpabuf_put_data(clear, u, curve->hash_len);
7547e5b75505Sopenharmony_ci
7548e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7549e5b75505Sopenharmony_ciskip_i_auth_tag:
7550e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
7551e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
7552e5b75505Sopenharmony_ci		goto skip_wrapped_data;
7553e5b75505Sopenharmony_ci	}
7554e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7555e5b75505Sopenharmony_ci
7556e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
7557e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
7558e5b75505Sopenharmony_ci	octet = 0;
7559e5b75505Sopenharmony_ci	addr[1] = &octet;
7560e5b75505Sopenharmony_ci	len[1] = sizeof(octet);
7561e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7562e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7563e5b75505Sopenharmony_ci
7564e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7565e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7566e5b75505Sopenharmony_ci	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7567e5b75505Sopenharmony_ci
7568e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7569e5b75505Sopenharmony_ci	if (aes_siv_encrypt(pkex->z, curve->hash_len,
7570e5b75505Sopenharmony_ci			    wpabuf_head(clear), wpabuf_len(clear),
7571e5b75505Sopenharmony_ci			    2, addr, len, wrapped) < 0)
7572e5b75505Sopenharmony_ci		goto fail;
7573e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7574e5b75505Sopenharmony_ci		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7575e5b75505Sopenharmony_ci
7576e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7577e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
7578e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
7579e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
7580e5b75505Sopenharmony_ci	}
7581e5b75505Sopenharmony_ciskip_wrapped_data:
7582e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7583e5b75505Sopenharmony_ci
7584e5b75505Sopenharmony_ciout:
7585e5b75505Sopenharmony_ci	wpabuf_free(clear);
7586e5b75505Sopenharmony_ci	return msg;
7587e5b75505Sopenharmony_ci
7588e5b75505Sopenharmony_cifail:
7589e5b75505Sopenharmony_ci	wpabuf_free(msg);
7590e5b75505Sopenharmony_ci	msg = NULL;
7591e5b75505Sopenharmony_ci	goto out;
7592e5b75505Sopenharmony_ci}
7593e5b75505Sopenharmony_ci
7594e5b75505Sopenharmony_ci
7595e5b75505Sopenharmony_cistruct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
7596e5b75505Sopenharmony_ci					  const u8 *peer_mac,
7597e5b75505Sopenharmony_ci					  const u8 *buf, size_t buflen)
7598e5b75505Sopenharmony_ci{
7599e5b75505Sopenharmony_ci	const u8 *attr_status, *attr_id, *attr_key, *attr_group;
7600e5b75505Sopenharmony_ci	u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
7601e5b75505Sopenharmony_ci	EC_GROUP *group = NULL;
7602e5b75505Sopenharmony_ci	BN_CTX *bnctx = NULL;
7603e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7604e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7605e5b75505Sopenharmony_ci	EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
7606e5b75505Sopenharmony_ci	BIGNUM *Nx = NULL, *Ny = NULL;
7607e5b75505Sopenharmony_ci	EC_KEY *Y_ec = NULL;
7608e5b75505Sopenharmony_ci	size_t Jx_len, Kx_len;
7609e5b75505Sopenharmony_ci	u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
7610e5b75505Sopenharmony_ci	const u8 *addr[4];
7611e5b75505Sopenharmony_ci	size_t len[4];
7612e5b75505Sopenharmony_ci	u8 u[DPP_MAX_HASH_LEN];
7613e5b75505Sopenharmony_ci	int res;
7614e5b75505Sopenharmony_ci
7615e5b75505Sopenharmony_ci	if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
7616e5b75505Sopenharmony_ci		return NULL;
7617e5b75505Sopenharmony_ci
7618e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7619e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
7620e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
7621e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at PKEX Exchange Response");
7622e5b75505Sopenharmony_ci		pkex->failed = 1;
7623e5b75505Sopenharmony_ci		return NULL;
7624e5b75505Sopenharmony_ci	}
7625e5b75505Sopenharmony_ci
7626e5b75505Sopenharmony_ci	if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
7627e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
7628e5b75505Sopenharmony_ci			   MAC2STR(dpp_pkex_peer_mac_override));
7629e5b75505Sopenharmony_ci		peer_mac = dpp_pkex_peer_mac_override;
7630e5b75505Sopenharmony_ci	}
7631e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7632e5b75505Sopenharmony_ci
7633e5b75505Sopenharmony_ci	os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
7634e5b75505Sopenharmony_ci
7635e5b75505Sopenharmony_ci	attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
7636e5b75505Sopenharmony_ci				   &attr_status_len);
7637e5b75505Sopenharmony_ci	if (!attr_status || attr_status_len != 1) {
7638e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "No DPP Status attribute");
7639e5b75505Sopenharmony_ci		return NULL;
7640e5b75505Sopenharmony_ci	}
7641e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
7642e5b75505Sopenharmony_ci
7643e5b75505Sopenharmony_ci	if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
7644e5b75505Sopenharmony_ci		attr_group = dpp_get_attr(buf, buflen,
7645e5b75505Sopenharmony_ci					  DPP_ATTR_FINITE_CYCLIC_GROUP,
7646e5b75505Sopenharmony_ci					  &attr_group_len);
7647e5b75505Sopenharmony_ci		if (attr_group && attr_group_len == 2) {
7648e5b75505Sopenharmony_ci			wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
7649e5b75505Sopenharmony_ci				"Peer indicated mismatching PKEX group - proposed %u",
7650e5b75505Sopenharmony_ci				WPA_GET_LE16(attr_group));
7651e5b75505Sopenharmony_ci			return NULL;
7652e5b75505Sopenharmony_ci		}
7653e5b75505Sopenharmony_ci	}
7654e5b75505Sopenharmony_ci
7655e5b75505Sopenharmony_ci	if (attr_status[0] != DPP_STATUS_OK) {
7656e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
7657e5b75505Sopenharmony_ci		return NULL;
7658e5b75505Sopenharmony_ci	}
7659e5b75505Sopenharmony_ci
7660e5b75505Sopenharmony_ci	attr_id_len = 0;
7661e5b75505Sopenharmony_ci	attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
7662e5b75505Sopenharmony_ci			       &attr_id_len);
7663e5b75505Sopenharmony_ci	if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
7664e5b75505Sopenharmony_ci				       pkex->identifier)) {
7665e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
7666e5b75505Sopenharmony_ci		return NULL;
7667e5b75505Sopenharmony_ci	}
7668e5b75505Sopenharmony_ci
7669e5b75505Sopenharmony_ci	/* N in Encrypted Key attribute */
7670e5b75505Sopenharmony_ci	attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
7671e5b75505Sopenharmony_ci				&attr_key_len);
7672e5b75505Sopenharmony_ci	if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
7673e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
7674e5b75505Sopenharmony_ci		return NULL;
7675e5b75505Sopenharmony_ci	}
7676e5b75505Sopenharmony_ci
7677e5b75505Sopenharmony_ci	/* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7678e5b75505Sopenharmony_ci	bnctx = BN_CTX_new();
7679e5b75505Sopenharmony_ci	if (!bnctx)
7680e5b75505Sopenharmony_ci		goto fail;
7681e5b75505Sopenharmony_ci	Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
7682e5b75505Sopenharmony_ci				pkex->identifier, bnctx, &group);
7683e5b75505Sopenharmony_ci	if (!Qr)
7684e5b75505Sopenharmony_ci		goto fail;
7685e5b75505Sopenharmony_ci
7686e5b75505Sopenharmony_ci	/* Y' = N - Qr */
7687e5b75505Sopenharmony_ci	Y = EC_POINT_new(group);
7688e5b75505Sopenharmony_ci	N = EC_POINT_new(group);
7689e5b75505Sopenharmony_ci	Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
7690e5b75505Sopenharmony_ci	Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
7691e5b75505Sopenharmony_ci	if (!Y || !N || !Nx || !Ny ||
7692e5b75505Sopenharmony_ci	    EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
7693e5b75505Sopenharmony_ci	    EC_POINT_is_at_infinity(group, N) ||
7694e5b75505Sopenharmony_ci	    !EC_POINT_is_on_curve(group, N, bnctx) ||
7695e5b75505Sopenharmony_ci	    EC_POINT_invert(group, Qr, bnctx) != 1 ||
7696e5b75505Sopenharmony_ci	    EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
7697e5b75505Sopenharmony_ci	    EC_POINT_is_at_infinity(group, Y) ||
7698e5b75505Sopenharmony_ci	    !EC_POINT_is_on_curve(group, Y, bnctx)) {
7699e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
7700e5b75505Sopenharmony_ci		pkex->t++;
7701e5b75505Sopenharmony_ci		goto fail;
7702e5b75505Sopenharmony_ci	}
7703e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: N", group, N);
7704e5b75505Sopenharmony_ci	dpp_debug_print_point("DPP: Y'", group, Y);
7705e5b75505Sopenharmony_ci
7706e5b75505Sopenharmony_ci	pkex->exchange_done = 1;
7707e5b75505Sopenharmony_ci
7708e5b75505Sopenharmony_ci	/* ECDH: J = a * Y’ */
7709e5b75505Sopenharmony_ci	Y_ec = EC_KEY_new();
7710e5b75505Sopenharmony_ci	if (!Y_ec ||
7711e5b75505Sopenharmony_ci	    EC_KEY_set_group(Y_ec, group) != 1 ||
7712e5b75505Sopenharmony_ci	    EC_KEY_set_public_key(Y_ec, Y) != 1)
7713e5b75505Sopenharmony_ci		goto fail;
7714e5b75505Sopenharmony_ci	pkex->y = EVP_PKEY_new();
7715e5b75505Sopenharmony_ci	if (!pkex->y ||
7716e5b75505Sopenharmony_ci	    EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
7717e5b75505Sopenharmony_ci		goto fail;
7718e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
7719e5b75505Sopenharmony_ci		goto fail;
7720e5b75505Sopenharmony_ci
7721e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7722e5b75505Sopenharmony_ci			Jx, Jx_len);
7723e5b75505Sopenharmony_ci
7724e5b75505Sopenharmony_ci	/* u = HMAC(J.x,  MAC-Initiator | A.x | Y’.x | X.x ) */
7725e5b75505Sopenharmony_ci	A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
7726e5b75505Sopenharmony_ci	Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7727e5b75505Sopenharmony_ci	X_pub = dpp_get_pubkey_point(pkex->x, 0);
7728e5b75505Sopenharmony_ci	if (!A_pub || !Y_pub || !X_pub)
7729e5b75505Sopenharmony_ci		goto fail;
7730e5b75505Sopenharmony_ci	addr[0] = pkex->own_mac;
7731e5b75505Sopenharmony_ci	len[0] = ETH_ALEN;
7732e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(A_pub);
7733e5b75505Sopenharmony_ci	len[1] = wpabuf_len(A_pub) / 2;
7734e5b75505Sopenharmony_ci	addr[2] = wpabuf_head(Y_pub);
7735e5b75505Sopenharmony_ci	len[2] = wpabuf_len(Y_pub) / 2;
7736e5b75505Sopenharmony_ci	addr[3] = wpabuf_head(X_pub);
7737e5b75505Sopenharmony_ci	len[3] = wpabuf_len(X_pub) / 2;
7738e5b75505Sopenharmony_ci	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
7739e5b75505Sopenharmony_ci		goto fail;
7740e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
7741e5b75505Sopenharmony_ci
7742e5b75505Sopenharmony_ci	/* K = x * Y’ */
7743e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
7744e5b75505Sopenharmony_ci		goto fail;
7745e5b75505Sopenharmony_ci
7746e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
7747e5b75505Sopenharmony_ci			Kx, Kx_len);
7748e5b75505Sopenharmony_ci
7749e5b75505Sopenharmony_ci	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7750e5b75505Sopenharmony_ci	 */
7751e5b75505Sopenharmony_ci	res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
7752e5b75505Sopenharmony_ci				pkex->Mx, curve->prime_len,
7753e5b75505Sopenharmony_ci				attr_key /* N.x */, attr_key_len / 2,
7754e5b75505Sopenharmony_ci				pkex->code, Kx, Kx_len,
7755e5b75505Sopenharmony_ci				pkex->z, curve->hash_len);
7756e5b75505Sopenharmony_ci	os_memset(Kx, 0, Kx_len);
7757e5b75505Sopenharmony_ci	if (res < 0)
7758e5b75505Sopenharmony_ci		goto fail;
7759e5b75505Sopenharmony_ci
7760e5b75505Sopenharmony_ci	msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
7761e5b75505Sopenharmony_ci	if (!msg)
7762e5b75505Sopenharmony_ci		goto fail;
7763e5b75505Sopenharmony_ci
7764e5b75505Sopenharmony_ciout:
7765e5b75505Sopenharmony_ci	wpabuf_free(A_pub);
7766e5b75505Sopenharmony_ci	wpabuf_free(X_pub);
7767e5b75505Sopenharmony_ci	wpabuf_free(Y_pub);
7768e5b75505Sopenharmony_ci	EC_POINT_free(Qr);
7769e5b75505Sopenharmony_ci	EC_POINT_free(Y);
7770e5b75505Sopenharmony_ci	EC_POINT_free(N);
7771e5b75505Sopenharmony_ci	BN_free(Nx);
7772e5b75505Sopenharmony_ci	BN_free(Ny);
7773e5b75505Sopenharmony_ci	EC_KEY_free(Y_ec);
7774e5b75505Sopenharmony_ci	BN_CTX_free(bnctx);
7775e5b75505Sopenharmony_ci	EC_GROUP_free(group);
7776e5b75505Sopenharmony_ci	return msg;
7777e5b75505Sopenharmony_cifail:
7778e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
7779e5b75505Sopenharmony_ci	goto out;
7780e5b75505Sopenharmony_ci}
7781e5b75505Sopenharmony_ci
7782e5b75505Sopenharmony_ci
7783e5b75505Sopenharmony_cistatic struct wpabuf *
7784e5b75505Sopenharmony_cidpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
7785e5b75505Sopenharmony_ci				  const struct wpabuf *B_pub, const u8 *v)
7786e5b75505Sopenharmony_ci{
7787e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7788e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL;
7789e5b75505Sopenharmony_ci	const u8 *addr[2];
7790e5b75505Sopenharmony_ci	size_t len[2];
7791e5b75505Sopenharmony_ci	u8 octet;
7792e5b75505Sopenharmony_ci	u8 *wrapped;
7793e5b75505Sopenharmony_ci	struct wpabuf *clear = NULL;
7794e5b75505Sopenharmony_ci	size_t clear_len, attr_len;
7795e5b75505Sopenharmony_ci
7796e5b75505Sopenharmony_ci	/* {B, v [bootstrapping info]}z */
7797e5b75505Sopenharmony_ci	clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
7798e5b75505Sopenharmony_ci	clear = wpabuf_alloc(clear_len);
7799e5b75505Sopenharmony_ci	attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7800e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7801e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
7802e5b75505Sopenharmony_ci		attr_len += 5;
7803e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7804e5b75505Sopenharmony_ci	msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
7805e5b75505Sopenharmony_ci	if (!clear || !msg)
7806e5b75505Sopenharmony_ci		goto fail;
7807e5b75505Sopenharmony_ci
7808e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7809e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7810e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
7811e5b75505Sopenharmony_ci		goto skip_bootstrap_key;
7812e5b75505Sopenharmony_ci	}
7813e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
7814e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
7815e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7816e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, 2 * curve->prime_len);
7817e5b75505Sopenharmony_ci		if (dpp_test_gen_invalid_key(clear, curve) < 0)
7818e5b75505Sopenharmony_ci			goto fail;
7819e5b75505Sopenharmony_ci		goto skip_bootstrap_key;
7820e5b75505Sopenharmony_ci	}
7821e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7822e5b75505Sopenharmony_ci
7823e5b75505Sopenharmony_ci	/* B in Bootstrap Key attribute */
7824e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
7825e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, wpabuf_len(B_pub));
7826e5b75505Sopenharmony_ci	wpabuf_put_buf(clear, B_pub);
7827e5b75505Sopenharmony_ci
7828e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7829e5b75505Sopenharmony_ciskip_bootstrap_key:
7830e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
7831e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
7832e5b75505Sopenharmony_ci		goto skip_r_auth_tag;
7833e5b75505Sopenharmony_ci	}
7834e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
7835e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
7836e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
7837e5b75505Sopenharmony_ci		wpabuf_put_le16(clear, curve->hash_len);
7838e5b75505Sopenharmony_ci		wpabuf_put_data(clear, v, curve->hash_len - 1);
7839e5b75505Sopenharmony_ci		wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
7840e5b75505Sopenharmony_ci		goto skip_r_auth_tag;
7841e5b75505Sopenharmony_ci	}
7842e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7843e5b75505Sopenharmony_ci
7844e5b75505Sopenharmony_ci	/* v in R-Auth tag attribute */
7845e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
7846e5b75505Sopenharmony_ci	wpabuf_put_le16(clear, curve->hash_len);
7847e5b75505Sopenharmony_ci	wpabuf_put_data(clear, v, curve->hash_len);
7848e5b75505Sopenharmony_ci
7849e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7850e5b75505Sopenharmony_ciskip_r_auth_tag:
7851e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
7852e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
7853e5b75505Sopenharmony_ci		goto skip_wrapped_data;
7854e5b75505Sopenharmony_ci	}
7855e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7856e5b75505Sopenharmony_ci
7857e5b75505Sopenharmony_ci	addr[0] = wpabuf_head_u8(msg) + 2;
7858e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
7859e5b75505Sopenharmony_ci	octet = 1;
7860e5b75505Sopenharmony_ci	addr[1] = &octet;
7861e5b75505Sopenharmony_ci	len[1] = sizeof(octet);
7862e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7863e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7864e5b75505Sopenharmony_ci
7865e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7866e5b75505Sopenharmony_ci	wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7867e5b75505Sopenharmony_ci	wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7868e5b75505Sopenharmony_ci
7869e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7870e5b75505Sopenharmony_ci	if (aes_siv_encrypt(pkex->z, curve->hash_len,
7871e5b75505Sopenharmony_ci			    wpabuf_head(clear), wpabuf_len(clear),
7872e5b75505Sopenharmony_ci			    2, addr, len, wrapped) < 0)
7873e5b75505Sopenharmony_ci		goto fail;
7874e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7875e5b75505Sopenharmony_ci		    wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
7876e5b75505Sopenharmony_ci
7877e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7878e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
7879e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
7880e5b75505Sopenharmony_ci		dpp_build_attr_status(msg, DPP_STATUS_OK);
7881e5b75505Sopenharmony_ci	}
7882e5b75505Sopenharmony_ciskip_wrapped_data:
7883e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7884e5b75505Sopenharmony_ci
7885e5b75505Sopenharmony_ciout:
7886e5b75505Sopenharmony_ci	wpabuf_free(clear);
7887e5b75505Sopenharmony_ci	return msg;
7888e5b75505Sopenharmony_ci
7889e5b75505Sopenharmony_cifail:
7890e5b75505Sopenharmony_ci	wpabuf_free(msg);
7891e5b75505Sopenharmony_ci	msg = NULL;
7892e5b75505Sopenharmony_ci	goto out;
7893e5b75505Sopenharmony_ci}
7894e5b75505Sopenharmony_ci
7895e5b75505Sopenharmony_ci
7896e5b75505Sopenharmony_cistruct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
7897e5b75505Sopenharmony_ci					      const u8 *hdr,
7898e5b75505Sopenharmony_ci					      const u8 *buf, size_t buflen)
7899e5b75505Sopenharmony_ci{
7900e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
7901e5b75505Sopenharmony_ci	size_t Jx_len, Lx_len;
7902e5b75505Sopenharmony_ci	u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
7903e5b75505Sopenharmony_ci	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
7904e5b75505Sopenharmony_ci	const u8 *wrapped_data, *b_key, *peer_u;
7905e5b75505Sopenharmony_ci	u16 wrapped_data_len, b_key_len, peer_u_len = 0;
7906e5b75505Sopenharmony_ci	const u8 *addr[4];
7907e5b75505Sopenharmony_ci	size_t len[4];
7908e5b75505Sopenharmony_ci	u8 octet;
7909e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
7910e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
7911e5b75505Sopenharmony_ci	struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
7912e5b75505Sopenharmony_ci	struct wpabuf *B_pub = NULL;
7913e5b75505Sopenharmony_ci	u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
7914e5b75505Sopenharmony_ci
7915e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
7916e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
7917e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
7918e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at PKEX CR Request");
7919e5b75505Sopenharmony_ci		pkex->failed = 1;
7920e5b75505Sopenharmony_ci		return NULL;
7921e5b75505Sopenharmony_ci	}
7922e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
7923e5b75505Sopenharmony_ci
7924e5b75505Sopenharmony_ci	if (!pkex->exchange_done || pkex->failed ||
7925e5b75505Sopenharmony_ci	    pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
7926e5b75505Sopenharmony_ci		goto fail;
7927e5b75505Sopenharmony_ci
7928e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
7929e5b75505Sopenharmony_ci				    &wrapped_data_len);
7930e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7931e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex,
7932e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
7933e5b75505Sopenharmony_ci		goto fail;
7934e5b75505Sopenharmony_ci	}
7935e5b75505Sopenharmony_ci
7936e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7937e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
7938e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7939e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
7940e5b75505Sopenharmony_ci	if (!unwrapped)
7941e5b75505Sopenharmony_ci		goto fail;
7942e5b75505Sopenharmony_ci
7943e5b75505Sopenharmony_ci	addr[0] = hdr;
7944e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
7945e5b75505Sopenharmony_ci	octet = 0;
7946e5b75505Sopenharmony_ci	addr[1] = &octet;
7947e5b75505Sopenharmony_ci	len[1] = sizeof(octet);
7948e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7949e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7950e5b75505Sopenharmony_ci
7951e5b75505Sopenharmony_ci	if (aes_siv_decrypt(pkex->z, curve->hash_len,
7952e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
7953e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
7954e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex,
7955e5b75505Sopenharmony_ci			      "AES-SIV decryption failed - possible PKEX code mismatch");
7956e5b75505Sopenharmony_ci		pkex->failed = 1;
7957e5b75505Sopenharmony_ci		pkex->t++;
7958e5b75505Sopenharmony_ci		goto fail;
7959e5b75505Sopenharmony_ci	}
7960e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7961e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
7962e5b75505Sopenharmony_ci
7963e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7964e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
7965e5b75505Sopenharmony_ci		goto fail;
7966e5b75505Sopenharmony_ci	}
7967e5b75505Sopenharmony_ci
7968e5b75505Sopenharmony_ci	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
7969e5b75505Sopenharmony_ci			     &b_key_len);
7970e5b75505Sopenharmony_ci	if (!b_key || b_key_len != 2 * curve->prime_len) {
7971e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
7972e5b75505Sopenharmony_ci		goto fail;
7973e5b75505Sopenharmony_ci	}
7974e5b75505Sopenharmony_ci	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
7975e5b75505Sopenharmony_ci							b_key_len);
7976e5b75505Sopenharmony_ci	if (!pkex->peer_bootstrap_key) {
7977e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
7978e5b75505Sopenharmony_ci		goto fail;
7979e5b75505Sopenharmony_ci	}
7980e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Peer bootstrap public key",
7981e5b75505Sopenharmony_ci			    pkex->peer_bootstrap_key);
7982e5b75505Sopenharmony_ci
7983e5b75505Sopenharmony_ci	/* ECDH: J' = y * A' */
7984e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
7985e5b75505Sopenharmony_ci		goto fail;
7986e5b75505Sopenharmony_ci
7987e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
7988e5b75505Sopenharmony_ci			Jx, Jx_len);
7989e5b75505Sopenharmony_ci
7990e5b75505Sopenharmony_ci	/* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7991e5b75505Sopenharmony_ci	A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
7992e5b75505Sopenharmony_ci	Y_pub = dpp_get_pubkey_point(pkex->y, 0);
7993e5b75505Sopenharmony_ci	X_pub = dpp_get_pubkey_point(pkex->x, 0);
7994e5b75505Sopenharmony_ci	if (!A_pub || !Y_pub || !X_pub)
7995e5b75505Sopenharmony_ci		goto fail;
7996e5b75505Sopenharmony_ci	addr[0] = pkex->peer_mac;
7997e5b75505Sopenharmony_ci	len[0] = ETH_ALEN;
7998e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(A_pub);
7999e5b75505Sopenharmony_ci	len[1] = wpabuf_len(A_pub) / 2;
8000e5b75505Sopenharmony_ci	addr[2] = wpabuf_head(Y_pub);
8001e5b75505Sopenharmony_ci	len[2] = wpabuf_len(Y_pub) / 2;
8002e5b75505Sopenharmony_ci	addr[3] = wpabuf_head(X_pub);
8003e5b75505Sopenharmony_ci	len[3] = wpabuf_len(X_pub) / 2;
8004e5b75505Sopenharmony_ci	if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
8005e5b75505Sopenharmony_ci		goto fail;
8006e5b75505Sopenharmony_ci
8007e5b75505Sopenharmony_ci	peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
8008e5b75505Sopenharmony_ci			      &peer_u_len);
8009e5b75505Sopenharmony_ci	if (!peer_u || peer_u_len != curve->hash_len ||
8010e5b75505Sopenharmony_ci	    os_memcmp(peer_u, u, curve->hash_len) != 0) {
8011e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
8012e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
8013e5b75505Sopenharmony_ci			    u, curve->hash_len);
8014e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
8015e5b75505Sopenharmony_ci		pkex->t++;
8016e5b75505Sopenharmony_ci		goto fail;
8017e5b75505Sopenharmony_ci	}
8018e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
8019e5b75505Sopenharmony_ci
8020e5b75505Sopenharmony_ci	/* ECDH: L = b * X' */
8021e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
8022e5b75505Sopenharmony_ci		goto fail;
8023e5b75505Sopenharmony_ci
8024e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8025e5b75505Sopenharmony_ci			Lx, Lx_len);
8026e5b75505Sopenharmony_ci
8027e5b75505Sopenharmony_ci	/* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8028e5b75505Sopenharmony_ci	B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
8029e5b75505Sopenharmony_ci	if (!B_pub)
8030e5b75505Sopenharmony_ci		goto fail;
8031e5b75505Sopenharmony_ci	addr[0] = pkex->own_mac;
8032e5b75505Sopenharmony_ci	len[0] = ETH_ALEN;
8033e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(B_pub);
8034e5b75505Sopenharmony_ci	len[1] = wpabuf_len(B_pub) / 2;
8035e5b75505Sopenharmony_ci	addr[2] = wpabuf_head(X_pub);
8036e5b75505Sopenharmony_ci	len[2] = wpabuf_len(X_pub) / 2;
8037e5b75505Sopenharmony_ci	addr[3] = wpabuf_head(Y_pub);
8038e5b75505Sopenharmony_ci	len[3] = wpabuf_len(Y_pub) / 2;
8039e5b75505Sopenharmony_ci	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8040e5b75505Sopenharmony_ci		goto fail;
8041e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
8042e5b75505Sopenharmony_ci
8043e5b75505Sopenharmony_ci	msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
8044e5b75505Sopenharmony_ci	if (!msg)
8045e5b75505Sopenharmony_ci		goto fail;
8046e5b75505Sopenharmony_ci
8047e5b75505Sopenharmony_ciout:
8048e5b75505Sopenharmony_ci	os_free(unwrapped);
8049e5b75505Sopenharmony_ci	wpabuf_free(A_pub);
8050e5b75505Sopenharmony_ci	wpabuf_free(B_pub);
8051e5b75505Sopenharmony_ci	wpabuf_free(X_pub);
8052e5b75505Sopenharmony_ci	wpabuf_free(Y_pub);
8053e5b75505Sopenharmony_ci	return msg;
8054e5b75505Sopenharmony_cifail:
8055e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
8056e5b75505Sopenharmony_ci		   "DPP: PKEX Commit-Reveal Request processing failed");
8057e5b75505Sopenharmony_ci	goto out;
8058e5b75505Sopenharmony_ci}
8059e5b75505Sopenharmony_ci
8060e5b75505Sopenharmony_ci
8061e5b75505Sopenharmony_ciint dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
8062e5b75505Sopenharmony_ci				   const u8 *buf, size_t buflen)
8063e5b75505Sopenharmony_ci{
8064e5b75505Sopenharmony_ci	const struct dpp_curve_params *curve = pkex->own_bi->curve;
8065e5b75505Sopenharmony_ci	const u8 *wrapped_data, *b_key, *peer_v;
8066e5b75505Sopenharmony_ci	u16 wrapped_data_len, b_key_len, peer_v_len = 0;
8067e5b75505Sopenharmony_ci	const u8 *addr[4];
8068e5b75505Sopenharmony_ci	size_t len[4];
8069e5b75505Sopenharmony_ci	u8 octet;
8070e5b75505Sopenharmony_ci	u8 *unwrapped = NULL;
8071e5b75505Sopenharmony_ci	size_t unwrapped_len = 0;
8072e5b75505Sopenharmony_ci	int ret = -1;
8073e5b75505Sopenharmony_ci	u8 v[DPP_MAX_HASH_LEN];
8074e5b75505Sopenharmony_ci	size_t Lx_len;
8075e5b75505Sopenharmony_ci	u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
8076e5b75505Sopenharmony_ci	struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
8077e5b75505Sopenharmony_ci
8078e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
8079e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
8080e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
8081e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at PKEX CR Response");
8082e5b75505Sopenharmony_ci		pkex->failed = 1;
8083e5b75505Sopenharmony_ci		goto fail;
8084e5b75505Sopenharmony_ci	}
8085e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
8086e5b75505Sopenharmony_ci
8087e5b75505Sopenharmony_ci	if (!pkex->exchange_done || pkex->failed ||
8088e5b75505Sopenharmony_ci	    pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
8089e5b75505Sopenharmony_ci		goto fail;
8090e5b75505Sopenharmony_ci
8091e5b75505Sopenharmony_ci	wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
8092e5b75505Sopenharmony_ci				    &wrapped_data_len);
8093e5b75505Sopenharmony_ci	if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8094e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex,
8095e5b75505Sopenharmony_ci			      "Missing or invalid required Wrapped Data attribute");
8096e5b75505Sopenharmony_ci		goto fail;
8097e5b75505Sopenharmony_ci	}
8098e5b75505Sopenharmony_ci
8099e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
8100e5b75505Sopenharmony_ci		    wrapped_data, wrapped_data_len);
8101e5b75505Sopenharmony_ci	unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
8102e5b75505Sopenharmony_ci	unwrapped = os_malloc(unwrapped_len);
8103e5b75505Sopenharmony_ci	if (!unwrapped)
8104e5b75505Sopenharmony_ci		goto fail;
8105e5b75505Sopenharmony_ci
8106e5b75505Sopenharmony_ci	addr[0] = hdr;
8107e5b75505Sopenharmony_ci	len[0] = DPP_HDR_LEN;
8108e5b75505Sopenharmony_ci	octet = 1;
8109e5b75505Sopenharmony_ci	addr[1] = &octet;
8110e5b75505Sopenharmony_ci	len[1] = sizeof(octet);
8111e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8112e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8113e5b75505Sopenharmony_ci
8114e5b75505Sopenharmony_ci	if (aes_siv_decrypt(pkex->z, curve->hash_len,
8115e5b75505Sopenharmony_ci			    wrapped_data, wrapped_data_len,
8116e5b75505Sopenharmony_ci			    2, addr, len, unwrapped) < 0) {
8117e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex,
8118e5b75505Sopenharmony_ci			      "AES-SIV decryption failed - possible PKEX code mismatch");
8119e5b75505Sopenharmony_ci		pkex->t++;
8120e5b75505Sopenharmony_ci		goto fail;
8121e5b75505Sopenharmony_ci	}
8122e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
8123e5b75505Sopenharmony_ci		    unwrapped, unwrapped_len);
8124e5b75505Sopenharmony_ci
8125e5b75505Sopenharmony_ci	if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8126e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
8127e5b75505Sopenharmony_ci		goto fail;
8128e5b75505Sopenharmony_ci	}
8129e5b75505Sopenharmony_ci
8130e5b75505Sopenharmony_ci	b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
8131e5b75505Sopenharmony_ci			     &b_key_len);
8132e5b75505Sopenharmony_ci	if (!b_key || b_key_len != 2 * curve->prime_len) {
8133e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
8134e5b75505Sopenharmony_ci		goto fail;
8135e5b75505Sopenharmony_ci	}
8136e5b75505Sopenharmony_ci	pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
8137e5b75505Sopenharmony_ci							b_key_len);
8138e5b75505Sopenharmony_ci	if (!pkex->peer_bootstrap_key) {
8139e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
8140e5b75505Sopenharmony_ci		goto fail;
8141e5b75505Sopenharmony_ci	}
8142e5b75505Sopenharmony_ci	dpp_debug_print_key("DPP: Peer bootstrap public key",
8143e5b75505Sopenharmony_ci			    pkex->peer_bootstrap_key);
8144e5b75505Sopenharmony_ci
8145e5b75505Sopenharmony_ci	/* ECDH: L' = x * B' */
8146e5b75505Sopenharmony_ci	if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
8147e5b75505Sopenharmony_ci		goto fail;
8148e5b75505Sopenharmony_ci
8149e5b75505Sopenharmony_ci	wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
8150e5b75505Sopenharmony_ci			Lx, Lx_len);
8151e5b75505Sopenharmony_ci
8152e5b75505Sopenharmony_ci	/* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8153e5b75505Sopenharmony_ci	B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
8154e5b75505Sopenharmony_ci	X_pub = dpp_get_pubkey_point(pkex->x, 0);
8155e5b75505Sopenharmony_ci	Y_pub = dpp_get_pubkey_point(pkex->y, 0);
8156e5b75505Sopenharmony_ci	if (!B_pub || !X_pub || !Y_pub)
8157e5b75505Sopenharmony_ci		goto fail;
8158e5b75505Sopenharmony_ci	addr[0] = pkex->peer_mac;
8159e5b75505Sopenharmony_ci	len[0] = ETH_ALEN;
8160e5b75505Sopenharmony_ci	addr[1] = wpabuf_head(B_pub);
8161e5b75505Sopenharmony_ci	len[1] = wpabuf_len(B_pub) / 2;
8162e5b75505Sopenharmony_ci	addr[2] = wpabuf_head(X_pub);
8163e5b75505Sopenharmony_ci	len[2] = wpabuf_len(X_pub) / 2;
8164e5b75505Sopenharmony_ci	addr[3] = wpabuf_head(Y_pub);
8165e5b75505Sopenharmony_ci	len[3] = wpabuf_len(Y_pub) / 2;
8166e5b75505Sopenharmony_ci	if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
8167e5b75505Sopenharmony_ci		goto fail;
8168e5b75505Sopenharmony_ci
8169e5b75505Sopenharmony_ci	peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
8170e5b75505Sopenharmony_ci			      &peer_v_len);
8171e5b75505Sopenharmony_ci	if (!peer_v || peer_v_len != curve->hash_len ||
8172e5b75505Sopenharmony_ci	    os_memcmp(peer_v, v, curve->hash_len) != 0) {
8173e5b75505Sopenharmony_ci		dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
8174e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
8175e5b75505Sopenharmony_ci			    v, curve->hash_len);
8176e5b75505Sopenharmony_ci		wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
8177e5b75505Sopenharmony_ci		pkex->t++;
8178e5b75505Sopenharmony_ci		goto fail;
8179e5b75505Sopenharmony_ci	}
8180e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
8181e5b75505Sopenharmony_ci
8182e5b75505Sopenharmony_ci	ret = 0;
8183e5b75505Sopenharmony_ciout:
8184e5b75505Sopenharmony_ci	wpabuf_free(B_pub);
8185e5b75505Sopenharmony_ci	wpabuf_free(X_pub);
8186e5b75505Sopenharmony_ci	wpabuf_free(Y_pub);
8187e5b75505Sopenharmony_ci	os_free(unwrapped);
8188e5b75505Sopenharmony_ci	return ret;
8189e5b75505Sopenharmony_cifail:
8190e5b75505Sopenharmony_ci	goto out;
8191e5b75505Sopenharmony_ci}
8192e5b75505Sopenharmony_ci
8193e5b75505Sopenharmony_ci
8194e5b75505Sopenharmony_civoid dpp_pkex_free(struct dpp_pkex *pkex)
8195e5b75505Sopenharmony_ci{
8196e5b75505Sopenharmony_ci	if (!pkex)
8197e5b75505Sopenharmony_ci		return;
8198e5b75505Sopenharmony_ci
8199e5b75505Sopenharmony_ci	os_free(pkex->identifier);
8200e5b75505Sopenharmony_ci	os_free(pkex->code);
8201e5b75505Sopenharmony_ci	EVP_PKEY_free(pkex->x);
8202e5b75505Sopenharmony_ci	EVP_PKEY_free(pkex->y);
8203e5b75505Sopenharmony_ci	EVP_PKEY_free(pkex->peer_bootstrap_key);
8204e5b75505Sopenharmony_ci	wpabuf_free(pkex->exchange_req);
8205e5b75505Sopenharmony_ci	wpabuf_free(pkex->exchange_resp);
8206e5b75505Sopenharmony_ci	os_free(pkex);
8207e5b75505Sopenharmony_ci}
8208e5b75505Sopenharmony_ci
8209e5b75505Sopenharmony_ci
8210e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
8211e5b75505Sopenharmony_cichar * dpp_corrupt_connector_signature(const char *connector)
8212e5b75505Sopenharmony_ci{
8213e5b75505Sopenharmony_ci	char *tmp, *pos, *signed3 = NULL;
8214e5b75505Sopenharmony_ci	unsigned char *signature = NULL;
8215e5b75505Sopenharmony_ci	size_t signature_len = 0, signed3_len;
8216e5b75505Sopenharmony_ci
8217e5b75505Sopenharmony_ci	tmp = os_zalloc(os_strlen(connector) + 5);
8218e5b75505Sopenharmony_ci	if (!tmp)
8219e5b75505Sopenharmony_ci		goto fail;
8220e5b75505Sopenharmony_ci	os_memcpy(tmp, connector, os_strlen(connector));
8221e5b75505Sopenharmony_ci
8222e5b75505Sopenharmony_ci	pos = os_strchr(tmp, '.');
8223e5b75505Sopenharmony_ci	if (!pos)
8224e5b75505Sopenharmony_ci		goto fail;
8225e5b75505Sopenharmony_ci
8226e5b75505Sopenharmony_ci	pos = os_strchr(pos + 1, '.');
8227e5b75505Sopenharmony_ci	if (!pos)
8228e5b75505Sopenharmony_ci		goto fail;
8229e5b75505Sopenharmony_ci	pos++;
8230e5b75505Sopenharmony_ci
8231e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
8232e5b75505Sopenharmony_ci		   pos);
8233e5b75505Sopenharmony_ci	signature = base64_url_decode((const unsigned char *) pos,
8234e5b75505Sopenharmony_ci				      os_strlen(pos), &signature_len);
8235e5b75505Sopenharmony_ci	if (!signature || signature_len == 0)
8236e5b75505Sopenharmony_ci		goto fail;
8237e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
8238e5b75505Sopenharmony_ci		    signature, signature_len);
8239e5b75505Sopenharmony_ci	signature[signature_len - 1] ^= 0x01;
8240e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
8241e5b75505Sopenharmony_ci		    signature, signature_len);
8242e5b75505Sopenharmony_ci	signed3 = (char *) base64_url_encode(signature, signature_len,
8243e5b75505Sopenharmony_ci					     &signed3_len, 0);
8244e5b75505Sopenharmony_ci	if (!signed3)
8245e5b75505Sopenharmony_ci		goto fail;
8246e5b75505Sopenharmony_ci	os_memcpy(pos, signed3, signed3_len);
8247e5b75505Sopenharmony_ci	pos[signed3_len] = '\0';
8248e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
8249e5b75505Sopenharmony_ci		   pos);
8250e5b75505Sopenharmony_ci
8251e5b75505Sopenharmony_ciout:
8252e5b75505Sopenharmony_ci	os_free(signature);
8253e5b75505Sopenharmony_ci	os_free(signed3);
8254e5b75505Sopenharmony_ci	return tmp;
8255e5b75505Sopenharmony_cifail:
8256e5b75505Sopenharmony_ci	os_free(tmp);
8257e5b75505Sopenharmony_ci	tmp = NULL;
8258e5b75505Sopenharmony_ci	goto out;
8259e5b75505Sopenharmony_ci}
8260e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
8261e5b75505Sopenharmony_ci
8262e5b75505Sopenharmony_ci
8263e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8264e5b75505Sopenharmony_ci
8265e5b75505Sopenharmony_cistruct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
8266e5b75505Sopenharmony_ci			      size_t net_access_key_len)
8267e5b75505Sopenharmony_ci{
8268e5b75505Sopenharmony_ci	struct wpabuf *pub = NULL;
8269e5b75505Sopenharmony_ci	EVP_PKEY *own_key;
8270e5b75505Sopenharmony_ci	struct dpp_pfs *pfs;
8271e5b75505Sopenharmony_ci
8272e5b75505Sopenharmony_ci	pfs = os_zalloc(sizeof(*pfs));
8273e5b75505Sopenharmony_ci	if (!pfs)
8274e5b75505Sopenharmony_ci		return NULL;
8275e5b75505Sopenharmony_ci
8276e5b75505Sopenharmony_ci	own_key = dpp_set_keypair(&pfs->curve, net_access_key,
8277e5b75505Sopenharmony_ci				  net_access_key_len);
8278e5b75505Sopenharmony_ci	if (!own_key) {
8279e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8280e5b75505Sopenharmony_ci		goto fail;
8281e5b75505Sopenharmony_ci	}
8282e5b75505Sopenharmony_ci	EVP_PKEY_free(own_key);
8283e5b75505Sopenharmony_ci
8284e5b75505Sopenharmony_ci	pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
8285e5b75505Sopenharmony_ci	if (!pfs->ecdh)
8286e5b75505Sopenharmony_ci		goto fail;
8287e5b75505Sopenharmony_ci
8288e5b75505Sopenharmony_ci	pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
8289e5b75505Sopenharmony_ci	pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
8290e5b75505Sopenharmony_ci	if (!pub)
8291e5b75505Sopenharmony_ci		goto fail;
8292e5b75505Sopenharmony_ci
8293e5b75505Sopenharmony_ci	pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
8294e5b75505Sopenharmony_ci	if (!pfs->ie)
8295e5b75505Sopenharmony_ci		goto fail;
8296e5b75505Sopenharmony_ci	wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
8297e5b75505Sopenharmony_ci	wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
8298e5b75505Sopenharmony_ci	wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
8299e5b75505Sopenharmony_ci	wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
8300e5b75505Sopenharmony_ci	wpabuf_put_buf(pfs->ie, pub);
8301e5b75505Sopenharmony_ci	wpabuf_free(pub);
8302e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
8303e5b75505Sopenharmony_ci			pfs->ie);
8304e5b75505Sopenharmony_ci
8305e5b75505Sopenharmony_ci	return pfs;
8306e5b75505Sopenharmony_cifail:
8307e5b75505Sopenharmony_ci	wpabuf_free(pub);
8308e5b75505Sopenharmony_ci	dpp_pfs_free(pfs);
8309e5b75505Sopenharmony_ci	return NULL;
8310e5b75505Sopenharmony_ci}
8311e5b75505Sopenharmony_ci
8312e5b75505Sopenharmony_ci
8313e5b75505Sopenharmony_ciint dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
8314e5b75505Sopenharmony_ci{
8315e5b75505Sopenharmony_ci	if (peer_ie_len < 2)
8316e5b75505Sopenharmony_ci		return -1;
8317e5b75505Sopenharmony_ci	if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
8318e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
8319e5b75505Sopenharmony_ci		return -1;
8320e5b75505Sopenharmony_ci	}
8321e5b75505Sopenharmony_ci
8322e5b75505Sopenharmony_ci	pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
8323e5b75505Sopenharmony_ci					      peer_ie_len - 2);
8324e5b75505Sopenharmony_ci	pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
8325e5b75505Sopenharmony_ci	if (!pfs->secret) {
8326e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
8327e5b75505Sopenharmony_ci		return -1;
8328e5b75505Sopenharmony_ci	}
8329e5b75505Sopenharmony_ci	wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
8330e5b75505Sopenharmony_ci	return 0;
8331e5b75505Sopenharmony_ci}
8332e5b75505Sopenharmony_ci
8333e5b75505Sopenharmony_ci
8334e5b75505Sopenharmony_civoid dpp_pfs_free(struct dpp_pfs *pfs)
8335e5b75505Sopenharmony_ci{
8336e5b75505Sopenharmony_ci	if (!pfs)
8337e5b75505Sopenharmony_ci		return;
8338e5b75505Sopenharmony_ci	crypto_ecdh_deinit(pfs->ecdh);
8339e5b75505Sopenharmony_ci	wpabuf_free(pfs->ie);
8340e5b75505Sopenharmony_ci	wpabuf_clear_free(pfs->secret);
8341e5b75505Sopenharmony_ci	os_free(pfs);
8342e5b75505Sopenharmony_ci}
8343e5b75505Sopenharmony_ci
8344e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
8345e5b75505Sopenharmony_ci
8346e5b75505Sopenharmony_ci
8347e5b75505Sopenharmony_cistatic unsigned int dpp_next_id(struct dpp_global *dpp)
8348e5b75505Sopenharmony_ci{
8349e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8350e5b75505Sopenharmony_ci	unsigned int max_id = 0;
8351e5b75505Sopenharmony_ci
8352e5b75505Sopenharmony_ci	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8353e5b75505Sopenharmony_ci		if (bi->id > max_id)
8354e5b75505Sopenharmony_ci			max_id = bi->id;
8355e5b75505Sopenharmony_ci	}
8356e5b75505Sopenharmony_ci	return max_id + 1;
8357e5b75505Sopenharmony_ci}
8358e5b75505Sopenharmony_ci
8359e5b75505Sopenharmony_ci
8360e5b75505Sopenharmony_cistatic int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
8361e5b75505Sopenharmony_ci{
8362e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi, *tmp;
8363e5b75505Sopenharmony_ci	int found = 0;
8364e5b75505Sopenharmony_ci
8365e5b75505Sopenharmony_ci	if (!dpp)
8366e5b75505Sopenharmony_ci		return -1;
8367e5b75505Sopenharmony_ci
8368e5b75505Sopenharmony_ci	dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
8369e5b75505Sopenharmony_ci			      struct dpp_bootstrap_info, list) {
8370e5b75505Sopenharmony_ci		if (id && bi->id != id)
8371e5b75505Sopenharmony_ci			continue;
8372e5b75505Sopenharmony_ci		found = 1;
8373e5b75505Sopenharmony_ci		dl_list_del(&bi->list);
8374e5b75505Sopenharmony_ci		dpp_bootstrap_info_free(bi);
8375e5b75505Sopenharmony_ci	}
8376e5b75505Sopenharmony_ci
8377e5b75505Sopenharmony_ci	if (id == 0)
8378e5b75505Sopenharmony_ci		return 0; /* flush succeeds regardless of entries found */
8379e5b75505Sopenharmony_ci	return found ? 0 : -1;
8380e5b75505Sopenharmony_ci}
8381e5b75505Sopenharmony_ci
8382e5b75505Sopenharmony_ci
8383e5b75505Sopenharmony_cistruct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
8384e5b75505Sopenharmony_ci					    const char *uri)
8385e5b75505Sopenharmony_ci{
8386e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8387e5b75505Sopenharmony_ci
8388e5b75505Sopenharmony_ci	if (!dpp)
8389e5b75505Sopenharmony_ci		return NULL;
8390e5b75505Sopenharmony_ci
8391e5b75505Sopenharmony_ci	bi = dpp_parse_qr_code(uri);
8392e5b75505Sopenharmony_ci	if (!bi)
8393e5b75505Sopenharmony_ci		return NULL;
8394e5b75505Sopenharmony_ci
8395e5b75505Sopenharmony_ci	bi->id = dpp_next_id(dpp);
8396e5b75505Sopenharmony_ci	dl_list_add(&dpp->bootstrap, &bi->list);
8397e5b75505Sopenharmony_ci	return bi;
8398e5b75505Sopenharmony_ci}
8399e5b75505Sopenharmony_ci
8400e5b75505Sopenharmony_ci
8401e5b75505Sopenharmony_ciint dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
8402e5b75505Sopenharmony_ci{
8403e5b75505Sopenharmony_ci	char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
8404e5b75505Sopenharmony_ci	char *key = NULL;
8405e5b75505Sopenharmony_ci	u8 *privkey = NULL;
8406e5b75505Sopenharmony_ci	size_t privkey_len = 0;
8407e5b75505Sopenharmony_ci	size_t len;
8408e5b75505Sopenharmony_ci	int ret = -1;
8409e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8410e5b75505Sopenharmony_ci
8411e5b75505Sopenharmony_ci	if (!dpp)
8412e5b75505Sopenharmony_ci		return -1;
8413e5b75505Sopenharmony_ci
8414e5b75505Sopenharmony_ci	bi = os_zalloc(sizeof(*bi));
8415e5b75505Sopenharmony_ci	if (!bi)
8416e5b75505Sopenharmony_ci		goto fail;
8417e5b75505Sopenharmony_ci
8418e5b75505Sopenharmony_ci	if (os_strstr(cmd, "type=qrcode"))
8419e5b75505Sopenharmony_ci		bi->type = DPP_BOOTSTRAP_QR_CODE;
8420e5b75505Sopenharmony_ci	else if (os_strstr(cmd, "type=pkex"))
8421e5b75505Sopenharmony_ci		bi->type = DPP_BOOTSTRAP_PKEX;
8422e5b75505Sopenharmony_ci	else
8423e5b75505Sopenharmony_ci		goto fail;
8424e5b75505Sopenharmony_ci
8425e5b75505Sopenharmony_ci	chan = get_param(cmd, " chan=");
8426e5b75505Sopenharmony_ci	mac = get_param(cmd, " mac=");
8427e5b75505Sopenharmony_ci	info = get_param(cmd, " info=");
8428e5b75505Sopenharmony_ci	curve = get_param(cmd, " curve=");
8429e5b75505Sopenharmony_ci	key = get_param(cmd, " key=");
8430e5b75505Sopenharmony_ci
8431e5b75505Sopenharmony_ci	if (key) {
8432e5b75505Sopenharmony_ci		privkey_len = os_strlen(key) / 2;
8433e5b75505Sopenharmony_ci		privkey = os_malloc(privkey_len);
8434e5b75505Sopenharmony_ci		if (!privkey ||
8435e5b75505Sopenharmony_ci		    hexstr2bin(key, privkey, privkey_len) < 0)
8436e5b75505Sopenharmony_ci			goto fail;
8437e5b75505Sopenharmony_ci	}
8438e5b75505Sopenharmony_ci
8439e5b75505Sopenharmony_ci	pk = dpp_keygen(bi, curve, privkey, privkey_len);
8440e5b75505Sopenharmony_ci	if (!pk)
8441e5b75505Sopenharmony_ci		goto fail;
8442e5b75505Sopenharmony_ci
8443e5b75505Sopenharmony_ci	len = 4; /* "DPP:" */
8444e5b75505Sopenharmony_ci	if (chan) {
8445e5b75505Sopenharmony_ci		if (dpp_parse_uri_chan_list(bi, chan) < 0)
8446e5b75505Sopenharmony_ci			goto fail;
8447e5b75505Sopenharmony_ci		len += 3 + os_strlen(chan); /* C:...; */
8448e5b75505Sopenharmony_ci	}
8449e5b75505Sopenharmony_ci	if (mac) {
8450e5b75505Sopenharmony_ci		if (dpp_parse_uri_mac(bi, mac) < 0)
8451e5b75505Sopenharmony_ci			goto fail;
8452e5b75505Sopenharmony_ci		len += 3 + os_strlen(mac); /* M:...; */
8453e5b75505Sopenharmony_ci	}
8454e5b75505Sopenharmony_ci	if (info) {
8455e5b75505Sopenharmony_ci		if (dpp_parse_uri_info(bi, info) < 0)
8456e5b75505Sopenharmony_ci			goto fail;
8457e5b75505Sopenharmony_ci		len += 3 + os_strlen(info); /* I:...; */
8458e5b75505Sopenharmony_ci	}
8459e5b75505Sopenharmony_ci	len += 4 + os_strlen(pk);
8460e5b75505Sopenharmony_ci	bi->uri = os_malloc(len + 1);
8461e5b75505Sopenharmony_ci	if (!bi->uri)
8462e5b75505Sopenharmony_ci		goto fail;
8463e5b75505Sopenharmony_ci	os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8464e5b75505Sopenharmony_ci		    chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
8465e5b75505Sopenharmony_ci		    mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
8466e5b75505Sopenharmony_ci		    info ? "I:" : "", info ? info : "", info ? ";" : "",
8467e5b75505Sopenharmony_ci		    pk);
8468e5b75505Sopenharmony_ci	bi->id = dpp_next_id(dpp);
8469e5b75505Sopenharmony_ci	dl_list_add(&dpp->bootstrap, &bi->list);
8470e5b75505Sopenharmony_ci	ret = bi->id;
8471e5b75505Sopenharmony_ci	bi = NULL;
8472e5b75505Sopenharmony_cifail:
8473e5b75505Sopenharmony_ci	os_free(curve);
8474e5b75505Sopenharmony_ci	os_free(pk);
8475e5b75505Sopenharmony_ci	os_free(chan);
8476e5b75505Sopenharmony_ci	os_free(mac);
8477e5b75505Sopenharmony_ci	os_free(info);
8478e5b75505Sopenharmony_ci	str_clear_free(key);
8479e5b75505Sopenharmony_ci	bin_clear_free(privkey, privkey_len);
8480e5b75505Sopenharmony_ci	dpp_bootstrap_info_free(bi);
8481e5b75505Sopenharmony_ci	return ret;
8482e5b75505Sopenharmony_ci}
8483e5b75505Sopenharmony_ci
8484e5b75505Sopenharmony_ci
8485e5b75505Sopenharmony_cistruct dpp_bootstrap_info *
8486e5b75505Sopenharmony_cidpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
8487e5b75505Sopenharmony_ci{
8488e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8489e5b75505Sopenharmony_ci
8490e5b75505Sopenharmony_ci	if (!dpp)
8491e5b75505Sopenharmony_ci		return NULL;
8492e5b75505Sopenharmony_ci
8493e5b75505Sopenharmony_ci	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8494e5b75505Sopenharmony_ci		if (bi->id == id)
8495e5b75505Sopenharmony_ci			return bi;
8496e5b75505Sopenharmony_ci	}
8497e5b75505Sopenharmony_ci	return NULL;
8498e5b75505Sopenharmony_ci}
8499e5b75505Sopenharmony_ci
8500e5b75505Sopenharmony_ci
8501e5b75505Sopenharmony_ciint dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
8502e5b75505Sopenharmony_ci{
8503e5b75505Sopenharmony_ci	unsigned int id_val;
8504e5b75505Sopenharmony_ci
8505e5b75505Sopenharmony_ci	if (os_strcmp(id, "*") == 0) {
8506e5b75505Sopenharmony_ci		id_val = 0;
8507e5b75505Sopenharmony_ci	} else {
8508e5b75505Sopenharmony_ci		id_val = atoi(id);
8509e5b75505Sopenharmony_ci		if (id_val == 0)
8510e5b75505Sopenharmony_ci			return -1;
8511e5b75505Sopenharmony_ci	}
8512e5b75505Sopenharmony_ci
8513e5b75505Sopenharmony_ci	return dpp_bootstrap_del(dpp, id_val);
8514e5b75505Sopenharmony_ci}
8515e5b75505Sopenharmony_ci
8516e5b75505Sopenharmony_ci
8517e5b75505Sopenharmony_cistruct dpp_bootstrap_info *
8518e5b75505Sopenharmony_cidpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
8519e5b75505Sopenharmony_ci		unsigned int freq)
8520e5b75505Sopenharmony_ci{
8521e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8522e5b75505Sopenharmony_ci
8523e5b75505Sopenharmony_ci	bi = os_zalloc(sizeof(*bi));
8524e5b75505Sopenharmony_ci	if (!bi)
8525e5b75505Sopenharmony_ci		return NULL;
8526e5b75505Sopenharmony_ci	bi->id = dpp_next_id(dpp);
8527e5b75505Sopenharmony_ci	bi->type = DPP_BOOTSTRAP_PKEX;
8528e5b75505Sopenharmony_ci	os_memcpy(bi->mac_addr, peer, ETH_ALEN);
8529e5b75505Sopenharmony_ci	bi->num_freq = 1;
8530e5b75505Sopenharmony_ci	bi->freq[0] = freq;
8531e5b75505Sopenharmony_ci	bi->curve = pkex->own_bi->curve;
8532e5b75505Sopenharmony_ci	bi->pubkey = pkex->peer_bootstrap_key;
8533e5b75505Sopenharmony_ci	pkex->peer_bootstrap_key = NULL;
8534e5b75505Sopenharmony_ci	if (dpp_bootstrap_key_hash(bi) < 0) {
8535e5b75505Sopenharmony_ci		dpp_bootstrap_info_free(bi);
8536e5b75505Sopenharmony_ci		return NULL;
8537e5b75505Sopenharmony_ci	}
8538e5b75505Sopenharmony_ci	dpp_pkex_free(pkex);
8539e5b75505Sopenharmony_ci	dl_list_add(&dpp->bootstrap, &bi->list);
8540e5b75505Sopenharmony_ci	return bi;
8541e5b75505Sopenharmony_ci}
8542e5b75505Sopenharmony_ci
8543e5b75505Sopenharmony_ci
8544e5b75505Sopenharmony_ciconst char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
8545e5b75505Sopenharmony_ci{
8546e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8547e5b75505Sopenharmony_ci
8548e5b75505Sopenharmony_ci	bi = dpp_bootstrap_get_id(dpp, id);
8549e5b75505Sopenharmony_ci	if (!bi)
8550e5b75505Sopenharmony_ci		return NULL;
8551e5b75505Sopenharmony_ci	return bi->uri;
8552e5b75505Sopenharmony_ci}
8553e5b75505Sopenharmony_ci
8554e5b75505Sopenharmony_ci
8555e5b75505Sopenharmony_ciint dpp_bootstrap_info(struct dpp_global *dpp, int id,
8556e5b75505Sopenharmony_ci		       char *reply, int reply_size)
8557e5b75505Sopenharmony_ci{
8558e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8559e5b75505Sopenharmony_ci	char pkhash[2 * SHA256_MAC_LEN + 1];
8560e5b75505Sopenharmony_ci
8561e5b75505Sopenharmony_ci	bi = dpp_bootstrap_get_id(dpp, id);
8562e5b75505Sopenharmony_ci	if (!bi)
8563e5b75505Sopenharmony_ci		return -1;
8564e5b75505Sopenharmony_ci	wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
8565e5b75505Sopenharmony_ci			 SHA256_MAC_LEN);
8566e5b75505Sopenharmony_ci	return os_snprintf(reply, reply_size, "type=%s\n"
8567e5b75505Sopenharmony_ci			   "mac_addr=" MACSTR "\n"
8568e5b75505Sopenharmony_ci			   "info=%s\n"
8569e5b75505Sopenharmony_ci			   "num_freq=%u\n"
8570e5b75505Sopenharmony_ci			   "curve=%s\n"
8571e5b75505Sopenharmony_ci			   "pkhash=%s\n",
8572e5b75505Sopenharmony_ci			   dpp_bootstrap_type_txt(bi->type),
8573e5b75505Sopenharmony_ci			   MAC2STR(bi->mac_addr),
8574e5b75505Sopenharmony_ci			   bi->info ? bi->info : "",
8575e5b75505Sopenharmony_ci			   bi->num_freq,
8576e5b75505Sopenharmony_ci			   bi->curve->name,
8577e5b75505Sopenharmony_ci			   pkhash);
8578e5b75505Sopenharmony_ci}
8579e5b75505Sopenharmony_ci
8580e5b75505Sopenharmony_ci
8581e5b75505Sopenharmony_civoid dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
8582e5b75505Sopenharmony_ci			     const u8 *r_bootstrap,
8583e5b75505Sopenharmony_ci			     struct dpp_bootstrap_info **own_bi,
8584e5b75505Sopenharmony_ci			     struct dpp_bootstrap_info **peer_bi)
8585e5b75505Sopenharmony_ci{
8586e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *bi;
8587e5b75505Sopenharmony_ci
8588e5b75505Sopenharmony_ci	*own_bi = NULL;
8589e5b75505Sopenharmony_ci	*peer_bi = NULL;
8590e5b75505Sopenharmony_ci	if (!dpp)
8591e5b75505Sopenharmony_ci		return;
8592e5b75505Sopenharmony_ci
8593e5b75505Sopenharmony_ci	dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
8594e5b75505Sopenharmony_ci		if (!*own_bi && bi->own &&
8595e5b75505Sopenharmony_ci		    os_memcmp(bi->pubkey_hash, r_bootstrap,
8596e5b75505Sopenharmony_ci			      SHA256_MAC_LEN) == 0) {
8597e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
8598e5b75505Sopenharmony_ci				   "DPP: Found matching own bootstrapping information");
8599e5b75505Sopenharmony_ci			*own_bi = bi;
8600e5b75505Sopenharmony_ci		}
8601e5b75505Sopenharmony_ci
8602e5b75505Sopenharmony_ci		if (!*peer_bi && !bi->own &&
8603e5b75505Sopenharmony_ci		    os_memcmp(bi->pubkey_hash, i_bootstrap,
8604e5b75505Sopenharmony_ci			      SHA256_MAC_LEN) == 0) {
8605e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
8606e5b75505Sopenharmony_ci				   "DPP: Found matching peer bootstrapping information");
8607e5b75505Sopenharmony_ci			*peer_bi = bi;
8608e5b75505Sopenharmony_ci		}
8609e5b75505Sopenharmony_ci
8610e5b75505Sopenharmony_ci		if (*own_bi && *peer_bi)
8611e5b75505Sopenharmony_ci			break;
8612e5b75505Sopenharmony_ci	}
8613e5b75505Sopenharmony_ci
8614e5b75505Sopenharmony_ci}
8615e5b75505Sopenharmony_ci
8616e5b75505Sopenharmony_ci
8617e5b75505Sopenharmony_cistatic unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
8618e5b75505Sopenharmony_ci{
8619e5b75505Sopenharmony_ci	struct dpp_configurator *conf;
8620e5b75505Sopenharmony_ci	unsigned int max_id = 0;
8621e5b75505Sopenharmony_ci
8622e5b75505Sopenharmony_ci	dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
8623e5b75505Sopenharmony_ci			 list) {
8624e5b75505Sopenharmony_ci		if (conf->id > max_id)
8625e5b75505Sopenharmony_ci			max_id = conf->id;
8626e5b75505Sopenharmony_ci	}
8627e5b75505Sopenharmony_ci	return max_id + 1;
8628e5b75505Sopenharmony_ci}
8629e5b75505Sopenharmony_ci
8630e5b75505Sopenharmony_ci
8631e5b75505Sopenharmony_ciint dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
8632e5b75505Sopenharmony_ci{
8633e5b75505Sopenharmony_ci	char *curve = NULL;
8634e5b75505Sopenharmony_ci	char *key = NULL;
8635e5b75505Sopenharmony_ci	u8 *privkey = NULL;
8636e5b75505Sopenharmony_ci	size_t privkey_len = 0;
8637e5b75505Sopenharmony_ci	int ret = -1;
8638e5b75505Sopenharmony_ci	struct dpp_configurator *conf = NULL;
8639e5b75505Sopenharmony_ci
8640e5b75505Sopenharmony_ci	curve = get_param(cmd, " curve=");
8641e5b75505Sopenharmony_ci	key = get_param(cmd, " key=");
8642e5b75505Sopenharmony_ci
8643e5b75505Sopenharmony_ci	if (key) {
8644e5b75505Sopenharmony_ci		privkey_len = os_strlen(key) / 2;
8645e5b75505Sopenharmony_ci		privkey = os_malloc(privkey_len);
8646e5b75505Sopenharmony_ci		if (!privkey ||
8647e5b75505Sopenharmony_ci		    hexstr2bin(key, privkey, privkey_len) < 0)
8648e5b75505Sopenharmony_ci			goto fail;
8649e5b75505Sopenharmony_ci	}
8650e5b75505Sopenharmony_ci
8651e5b75505Sopenharmony_ci	conf = dpp_keygen_configurator(curve, privkey, privkey_len);
8652e5b75505Sopenharmony_ci	if (!conf)
8653e5b75505Sopenharmony_ci		goto fail;
8654e5b75505Sopenharmony_ci
8655e5b75505Sopenharmony_ci	conf->id = dpp_next_configurator_id(dpp);
8656e5b75505Sopenharmony_ci	dl_list_add(&dpp->configurator, &conf->list);
8657e5b75505Sopenharmony_ci	ret = conf->id;
8658e5b75505Sopenharmony_ci	conf = NULL;
8659e5b75505Sopenharmony_cifail:
8660e5b75505Sopenharmony_ci	os_free(curve);
8661e5b75505Sopenharmony_ci	str_clear_free(key);
8662e5b75505Sopenharmony_ci	bin_clear_free(privkey, privkey_len);
8663e5b75505Sopenharmony_ci	dpp_configurator_free(conf);
8664e5b75505Sopenharmony_ci	return ret;
8665e5b75505Sopenharmony_ci}
8666e5b75505Sopenharmony_ci
8667e5b75505Sopenharmony_ci
8668e5b75505Sopenharmony_cistatic int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
8669e5b75505Sopenharmony_ci{
8670e5b75505Sopenharmony_ci	struct dpp_configurator *conf, *tmp;
8671e5b75505Sopenharmony_ci	int found = 0;
8672e5b75505Sopenharmony_ci
8673e5b75505Sopenharmony_ci	if (!dpp)
8674e5b75505Sopenharmony_ci		return -1;
8675e5b75505Sopenharmony_ci
8676e5b75505Sopenharmony_ci	dl_list_for_each_safe(conf, tmp, &dpp->configurator,
8677e5b75505Sopenharmony_ci			      struct dpp_configurator, list) {
8678e5b75505Sopenharmony_ci		if (id && conf->id != id)
8679e5b75505Sopenharmony_ci			continue;
8680e5b75505Sopenharmony_ci		found = 1;
8681e5b75505Sopenharmony_ci		dl_list_del(&conf->list);
8682e5b75505Sopenharmony_ci		dpp_configurator_free(conf);
8683e5b75505Sopenharmony_ci	}
8684e5b75505Sopenharmony_ci
8685e5b75505Sopenharmony_ci	if (id == 0)
8686e5b75505Sopenharmony_ci		return 0; /* flush succeeds regardless of entries found */
8687e5b75505Sopenharmony_ci	return found ? 0 : -1;
8688e5b75505Sopenharmony_ci}
8689e5b75505Sopenharmony_ci
8690e5b75505Sopenharmony_ci
8691e5b75505Sopenharmony_ciint dpp_configurator_remove(struct dpp_global *dpp, const char *id)
8692e5b75505Sopenharmony_ci{
8693e5b75505Sopenharmony_ci	unsigned int id_val;
8694e5b75505Sopenharmony_ci
8695e5b75505Sopenharmony_ci	if (os_strcmp(id, "*") == 0) {
8696e5b75505Sopenharmony_ci		id_val = 0;
8697e5b75505Sopenharmony_ci	} else {
8698e5b75505Sopenharmony_ci		id_val = atoi(id);
8699e5b75505Sopenharmony_ci		if (id_val == 0)
8700e5b75505Sopenharmony_ci			return -1;
8701e5b75505Sopenharmony_ci	}
8702e5b75505Sopenharmony_ci
8703e5b75505Sopenharmony_ci	return dpp_configurator_del(dpp, id_val);
8704e5b75505Sopenharmony_ci}
8705e5b75505Sopenharmony_ci
8706e5b75505Sopenharmony_ci
8707e5b75505Sopenharmony_ciint dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
8708e5b75505Sopenharmony_ci				char *buf, size_t buflen)
8709e5b75505Sopenharmony_ci{
8710e5b75505Sopenharmony_ci	struct dpp_configurator *conf;
8711e5b75505Sopenharmony_ci
8712e5b75505Sopenharmony_ci	conf = dpp_configurator_get_id(dpp, id);
8713e5b75505Sopenharmony_ci	if (!conf)
8714e5b75505Sopenharmony_ci		return -1;
8715e5b75505Sopenharmony_ci
8716e5b75505Sopenharmony_ci	return dpp_configurator_get_key(conf, buf, buflen);
8717e5b75505Sopenharmony_ci}
8718e5b75505Sopenharmony_ci
8719e5b75505Sopenharmony_ci
8720e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8721e5b75505Sopenharmony_ci
8722e5b75505Sopenharmony_cistatic void dpp_connection_free(struct dpp_connection *conn)
8723e5b75505Sopenharmony_ci{
8724e5b75505Sopenharmony_ci	if (conn->sock >= 0) {
8725e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
8726e5b75505Sopenharmony_ci			   conn->sock);
8727e5b75505Sopenharmony_ci		eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
8728e5b75505Sopenharmony_ci		eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
8729e5b75505Sopenharmony_ci		close(conn->sock);
8730e5b75505Sopenharmony_ci	}
8731e5b75505Sopenharmony_ci	wpabuf_free(conn->msg);
8732e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
8733e5b75505Sopenharmony_ci	dpp_auth_deinit(conn->auth);
8734e5b75505Sopenharmony_ci	os_free(conn);
8735e5b75505Sopenharmony_ci}
8736e5b75505Sopenharmony_ci
8737e5b75505Sopenharmony_ci
8738e5b75505Sopenharmony_cistatic void dpp_connection_remove(struct dpp_connection *conn)
8739e5b75505Sopenharmony_ci{
8740e5b75505Sopenharmony_ci	dl_list_del(&conn->list);
8741e5b75505Sopenharmony_ci	dpp_connection_free(conn);
8742e5b75505Sopenharmony_ci}
8743e5b75505Sopenharmony_ci
8744e5b75505Sopenharmony_ci
8745e5b75505Sopenharmony_cistatic void dpp_tcp_init_flush(struct dpp_global *dpp)
8746e5b75505Sopenharmony_ci{
8747e5b75505Sopenharmony_ci	struct dpp_connection *conn, *tmp;
8748e5b75505Sopenharmony_ci
8749e5b75505Sopenharmony_ci	dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
8750e5b75505Sopenharmony_ci			      list)
8751e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
8752e5b75505Sopenharmony_ci}
8753e5b75505Sopenharmony_ci
8754e5b75505Sopenharmony_ci
8755e5b75505Sopenharmony_cistatic void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
8756e5b75505Sopenharmony_ci{
8757e5b75505Sopenharmony_ci	struct dpp_connection *conn, *tmp;
8758e5b75505Sopenharmony_ci
8759e5b75505Sopenharmony_ci	dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
8760e5b75505Sopenharmony_ci			      list)
8761e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
8762e5b75505Sopenharmony_ci	os_free(ctrl);
8763e5b75505Sopenharmony_ci}
8764e5b75505Sopenharmony_ci
8765e5b75505Sopenharmony_ci
8766e5b75505Sopenharmony_cistatic void dpp_relay_flush_controllers(struct dpp_global *dpp)
8767e5b75505Sopenharmony_ci{
8768e5b75505Sopenharmony_ci	struct dpp_relay_controller *ctrl, *tmp;
8769e5b75505Sopenharmony_ci
8770e5b75505Sopenharmony_ci	if (!dpp)
8771e5b75505Sopenharmony_ci		return;
8772e5b75505Sopenharmony_ci
8773e5b75505Sopenharmony_ci	dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
8774e5b75505Sopenharmony_ci			      struct dpp_relay_controller, list) {
8775e5b75505Sopenharmony_ci		dl_list_del(&ctrl->list);
8776e5b75505Sopenharmony_ci		dpp_relay_controller_free(ctrl);
8777e5b75505Sopenharmony_ci	}
8778e5b75505Sopenharmony_ci}
8779e5b75505Sopenharmony_ci
8780e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
8781e5b75505Sopenharmony_ci
8782e5b75505Sopenharmony_ci
8783e5b75505Sopenharmony_cistruct dpp_global * dpp_global_init(struct dpp_global_config *config)
8784e5b75505Sopenharmony_ci{
8785e5b75505Sopenharmony_ci	struct dpp_global *dpp;
8786e5b75505Sopenharmony_ci
8787e5b75505Sopenharmony_ci	dpp = os_zalloc(sizeof(*dpp));
8788e5b75505Sopenharmony_ci	if (!dpp)
8789e5b75505Sopenharmony_ci		return NULL;
8790e5b75505Sopenharmony_ci	dpp->msg_ctx = config->msg_ctx;
8791e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8792e5b75505Sopenharmony_ci	dpp->cb_ctx = config->cb_ctx;
8793e5b75505Sopenharmony_ci	dpp->process_conf_obj = config->process_conf_obj;
8794e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
8795e5b75505Sopenharmony_ci
8796e5b75505Sopenharmony_ci	dl_list_init(&dpp->bootstrap);
8797e5b75505Sopenharmony_ci	dl_list_init(&dpp->configurator);
8798e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8799e5b75505Sopenharmony_ci	dl_list_init(&dpp->controllers);
8800e5b75505Sopenharmony_ci	dl_list_init(&dpp->tcp_init);
8801e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
8802e5b75505Sopenharmony_ci
8803e5b75505Sopenharmony_ci	return dpp;
8804e5b75505Sopenharmony_ci}
8805e5b75505Sopenharmony_ci
8806e5b75505Sopenharmony_ci
8807e5b75505Sopenharmony_civoid dpp_global_clear(struct dpp_global *dpp)
8808e5b75505Sopenharmony_ci{
8809e5b75505Sopenharmony_ci	if (!dpp)
8810e5b75505Sopenharmony_ci		return;
8811e5b75505Sopenharmony_ci
8812e5b75505Sopenharmony_ci	dpp_bootstrap_del(dpp, 0);
8813e5b75505Sopenharmony_ci	dpp_configurator_del(dpp, 0);
8814e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8815e5b75505Sopenharmony_ci	dpp_tcp_init_flush(dpp);
8816e5b75505Sopenharmony_ci	dpp_relay_flush_controllers(dpp);
8817e5b75505Sopenharmony_ci	dpp_controller_stop(dpp);
8818e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
8819e5b75505Sopenharmony_ci}
8820e5b75505Sopenharmony_ci
8821e5b75505Sopenharmony_ci
8822e5b75505Sopenharmony_civoid dpp_global_deinit(struct dpp_global *dpp)
8823e5b75505Sopenharmony_ci{
8824e5b75505Sopenharmony_ci	dpp_global_clear(dpp);
8825e5b75505Sopenharmony_ci	os_free(dpp);
8826e5b75505Sopenharmony_ci}
8827e5b75505Sopenharmony_ci
8828e5b75505Sopenharmony_ci
8829e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2
8830e5b75505Sopenharmony_ci
8831e5b75505Sopenharmony_cistatic void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
8832e5b75505Sopenharmony_cistatic void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
8833e5b75505Sopenharmony_cistatic void dpp_controller_auth_success(struct dpp_connection *conn,
8834e5b75505Sopenharmony_ci					int initiator);
8835e5b75505Sopenharmony_ci
8836e5b75505Sopenharmony_ci
8837e5b75505Sopenharmony_ciint dpp_relay_add_controller(struct dpp_global *dpp,
8838e5b75505Sopenharmony_ci			     struct dpp_relay_config *config)
8839e5b75505Sopenharmony_ci{
8840e5b75505Sopenharmony_ci	struct dpp_relay_controller *ctrl;
8841e5b75505Sopenharmony_ci
8842e5b75505Sopenharmony_ci	if (!dpp)
8843e5b75505Sopenharmony_ci		return -1;
8844e5b75505Sopenharmony_ci
8845e5b75505Sopenharmony_ci	ctrl = os_zalloc(sizeof(*ctrl));
8846e5b75505Sopenharmony_ci	if (!ctrl)
8847e5b75505Sopenharmony_ci		return -1;
8848e5b75505Sopenharmony_ci	dl_list_init(&ctrl->conn);
8849e5b75505Sopenharmony_ci	ctrl->global = dpp;
8850e5b75505Sopenharmony_ci	os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
8851e5b75505Sopenharmony_ci	os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
8852e5b75505Sopenharmony_ci	ctrl->cb_ctx = config->cb_ctx;
8853e5b75505Sopenharmony_ci	ctrl->tx = config->tx;
8854e5b75505Sopenharmony_ci	ctrl->gas_resp_tx = config->gas_resp_tx;
8855e5b75505Sopenharmony_ci	dl_list_add(&dpp->controllers, &ctrl->list);
8856e5b75505Sopenharmony_ci	return 0;
8857e5b75505Sopenharmony_ci}
8858e5b75505Sopenharmony_ci
8859e5b75505Sopenharmony_ci
8860e5b75505Sopenharmony_cistatic struct dpp_relay_controller *
8861e5b75505Sopenharmony_cidpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
8862e5b75505Sopenharmony_ci{
8863e5b75505Sopenharmony_ci	struct dpp_relay_controller *ctrl;
8864e5b75505Sopenharmony_ci
8865e5b75505Sopenharmony_ci	if (!dpp)
8866e5b75505Sopenharmony_ci		return NULL;
8867e5b75505Sopenharmony_ci
8868e5b75505Sopenharmony_ci	dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
8869e5b75505Sopenharmony_ci			 list) {
8870e5b75505Sopenharmony_ci		if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
8871e5b75505Sopenharmony_ci			return ctrl;
8872e5b75505Sopenharmony_ci	}
8873e5b75505Sopenharmony_ci
8874e5b75505Sopenharmony_ci	return NULL;
8875e5b75505Sopenharmony_ci}
8876e5b75505Sopenharmony_ci
8877e5b75505Sopenharmony_ci
8878e5b75505Sopenharmony_cistatic void dpp_controller_gas_done(struct dpp_connection *conn)
8879e5b75505Sopenharmony_ci{
8880e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
8881e5b75505Sopenharmony_ci
8882e5b75505Sopenharmony_ci	if (auth->peer_version >= 2 &&
8883e5b75505Sopenharmony_ci	    auth->conf_resp_status == DPP_STATUS_OK) {
8884e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
8885e5b75505Sopenharmony_ci		auth->waiting_conf_result = 1;
8886e5b75505Sopenharmony_ci		return;
8887e5b75505Sopenharmony_ci	}
8888e5b75505Sopenharmony_ci
8889e5b75505Sopenharmony_ci	wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
8890e5b75505Sopenharmony_ci	dpp_connection_remove(conn);
8891e5b75505Sopenharmony_ci}
8892e5b75505Sopenharmony_ci
8893e5b75505Sopenharmony_ci
8894e5b75505Sopenharmony_cistatic int dpp_tcp_send(struct dpp_connection *conn)
8895e5b75505Sopenharmony_ci{
8896e5b75505Sopenharmony_ci	int res;
8897e5b75505Sopenharmony_ci
8898e5b75505Sopenharmony_ci	if (!conn->msg_out) {
8899e5b75505Sopenharmony_ci		eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
8900e5b75505Sopenharmony_ci		conn->write_eloop = 0;
8901e5b75505Sopenharmony_ci		return -1;
8902e5b75505Sopenharmony_ci	}
8903e5b75505Sopenharmony_ci	res = send(conn->sock,
8904e5b75505Sopenharmony_ci		   wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
8905e5b75505Sopenharmony_ci		   wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
8906e5b75505Sopenharmony_ci	if (res < 0) {
8907e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
8908e5b75505Sopenharmony_ci			   strerror(errno));
8909e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
8910e5b75505Sopenharmony_ci		return -1;
8911e5b75505Sopenharmony_ci	}
8912e5b75505Sopenharmony_ci
8913e5b75505Sopenharmony_ci	conn->msg_out_pos += res;
8914e5b75505Sopenharmony_ci	if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
8915e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
8916e5b75505Sopenharmony_ci			   "DPP: %u/%u bytes of message sent to Controller",
8917e5b75505Sopenharmony_ci			   (unsigned int) conn->msg_out_pos,
8918e5b75505Sopenharmony_ci			   (unsigned int) wpabuf_len(conn->msg_out));
8919e5b75505Sopenharmony_ci		if (!conn->write_eloop &&
8920e5b75505Sopenharmony_ci		    eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
8921e5b75505Sopenharmony_ci					dpp_conn_tx_ready, conn, NULL) == 0)
8922e5b75505Sopenharmony_ci			conn->write_eloop = 1;
8923e5b75505Sopenharmony_ci		return 1;
8924e5b75505Sopenharmony_ci	}
8925e5b75505Sopenharmony_ci
8926e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
8927e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
8928e5b75505Sopenharmony_ci	conn->msg_out = NULL;
8929e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
8930e5b75505Sopenharmony_ci	eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
8931e5b75505Sopenharmony_ci	conn->write_eloop = 0;
8932e5b75505Sopenharmony_ci	if (!conn->read_eloop &&
8933e5b75505Sopenharmony_ci	    eloop_register_sock(conn->sock, EVENT_TYPE_READ,
8934e5b75505Sopenharmony_ci				dpp_controller_rx, conn, NULL) == 0)
8935e5b75505Sopenharmony_ci		conn->read_eloop = 1;
8936e5b75505Sopenharmony_ci	if (conn->on_tcp_tx_complete_remove) {
8937e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
8938e5b75505Sopenharmony_ci	} else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
8939e5b75505Sopenharmony_ci		   conn->auth) {
8940e5b75505Sopenharmony_ci		dpp_controller_gas_done(conn);
8941e5b75505Sopenharmony_ci	} else if (conn->on_tcp_tx_complete_auth_ok) {
8942e5b75505Sopenharmony_ci		conn->on_tcp_tx_complete_auth_ok = 0;
8943e5b75505Sopenharmony_ci		dpp_controller_auth_success(conn, 1);
8944e5b75505Sopenharmony_ci	}
8945e5b75505Sopenharmony_ci
8946e5b75505Sopenharmony_ci	return 0;
8947e5b75505Sopenharmony_ci}
8948e5b75505Sopenharmony_ci
8949e5b75505Sopenharmony_ci
8950e5b75505Sopenharmony_cistatic void dpp_controller_start_gas_client(struct dpp_connection *conn)
8951e5b75505Sopenharmony_ci{
8952e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
8953e5b75505Sopenharmony_ci	struct wpabuf *buf;
8954e5b75505Sopenharmony_ci	char json[100];
8955e5b75505Sopenharmony_ci	int netrole_ap = 0; /* TODO: make this configurable */
8956e5b75505Sopenharmony_ci
8957e5b75505Sopenharmony_ci	os_snprintf(json, sizeof(json),
8958e5b75505Sopenharmony_ci		    "{\"name\":\"Test\","
8959e5b75505Sopenharmony_ci		    "\"wi-fi_tech\":\"infra\","
8960e5b75505Sopenharmony_ci		    "\"netRole\":\"%s\"}",
8961e5b75505Sopenharmony_ci		    netrole_ap ? "ap" : "sta");
8962e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
8963e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
8964e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
8965e5b75505Sopenharmony_ci		json[29] = 'k'; /* replace "infra" with "knfra" */
8966e5b75505Sopenharmony_ci	}
8967e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
8968e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: GAS Config Attributes: %s", json);
8969e5b75505Sopenharmony_ci
8970e5b75505Sopenharmony_ci	buf = dpp_build_conf_req(auth, json);
8971e5b75505Sopenharmony_ci	if (!buf) {
8972e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
8973e5b75505Sopenharmony_ci			   "DPP: No configuration request data available");
8974e5b75505Sopenharmony_ci		return;
8975e5b75505Sopenharmony_ci	}
8976e5b75505Sopenharmony_ci
8977e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
8978e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
8979e5b75505Sopenharmony_ci	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
8980e5b75505Sopenharmony_ci	if (!conn->msg_out) {
8981e5b75505Sopenharmony_ci		wpabuf_free(buf);
8982e5b75505Sopenharmony_ci		return;
8983e5b75505Sopenharmony_ci	}
8984e5b75505Sopenharmony_ci	wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
8985e5b75505Sopenharmony_ci	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
8986e5b75505Sopenharmony_ci			wpabuf_len(buf) - 1);
8987e5b75505Sopenharmony_ci	wpabuf_free(buf);
8988e5b75505Sopenharmony_ci
8989e5b75505Sopenharmony_ci	if (dpp_tcp_send(conn) == 1) {
8990e5b75505Sopenharmony_ci		if (!conn->write_eloop) {
8991e5b75505Sopenharmony_ci			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
8992e5b75505Sopenharmony_ci						dpp_conn_tx_ready,
8993e5b75505Sopenharmony_ci						conn, NULL) < 0)
8994e5b75505Sopenharmony_ci				return;
8995e5b75505Sopenharmony_ci			conn->write_eloop = 1;
8996e5b75505Sopenharmony_ci		}
8997e5b75505Sopenharmony_ci	}
8998e5b75505Sopenharmony_ci}
8999e5b75505Sopenharmony_ci
9000e5b75505Sopenharmony_ci
9001e5b75505Sopenharmony_cistatic void dpp_controller_auth_success(struct dpp_connection *conn,
9002e5b75505Sopenharmony_ci					int initiator)
9003e5b75505Sopenharmony_ci{
9004e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9005e5b75505Sopenharmony_ci
9006e5b75505Sopenharmony_ci	if (!auth)
9007e5b75505Sopenharmony_ci		return;
9008e5b75505Sopenharmony_ci
9009e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
9010e5b75505Sopenharmony_ci	wpa_msg(conn->global->msg_ctx, MSG_INFO,
9011e5b75505Sopenharmony_ci		DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
9012e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS
9013e5b75505Sopenharmony_ci	if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
9014e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
9015e5b75505Sopenharmony_ci			   "DPP: TESTING - stop at Authentication Confirm");
9016e5b75505Sopenharmony_ci		if (auth->configurator) {
9017e5b75505Sopenharmony_ci			/* Prevent GAS response */
9018e5b75505Sopenharmony_ci			auth->auth_success = 0;
9019e5b75505Sopenharmony_ci		}
9020e5b75505Sopenharmony_ci		return;
9021e5b75505Sopenharmony_ci	}
9022e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */
9023e5b75505Sopenharmony_ci
9024e5b75505Sopenharmony_ci	if (!auth->configurator)
9025e5b75505Sopenharmony_ci		dpp_controller_start_gas_client(conn);
9026e5b75505Sopenharmony_ci}
9027e5b75505Sopenharmony_ci
9028e5b75505Sopenharmony_ci
9029e5b75505Sopenharmony_cistatic void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
9030e5b75505Sopenharmony_ci{
9031e5b75505Sopenharmony_ci	struct dpp_connection *conn = eloop_ctx;
9032e5b75505Sopenharmony_ci
9033e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
9034e5b75505Sopenharmony_ci	dpp_tcp_send(conn);
9035e5b75505Sopenharmony_ci}
9036e5b75505Sopenharmony_ci
9037e5b75505Sopenharmony_ci
9038e5b75505Sopenharmony_cistatic int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
9039e5b75505Sopenharmony_ci				  const struct hostapd_ip_addr *ipaddr,
9040e5b75505Sopenharmony_ci				  int port)
9041e5b75505Sopenharmony_ci{
9042e5b75505Sopenharmony_ci	struct sockaddr_in *dst;
9043e5b75505Sopenharmony_ci#ifdef CONFIG_IPV6
9044e5b75505Sopenharmony_ci	struct sockaddr_in6 *dst6;
9045e5b75505Sopenharmony_ci#endif /* CONFIG_IPV6 */
9046e5b75505Sopenharmony_ci
9047e5b75505Sopenharmony_ci	switch (ipaddr->af) {
9048e5b75505Sopenharmony_ci	case AF_INET:
9049e5b75505Sopenharmony_ci		dst = (struct sockaddr_in *) addr;
9050e5b75505Sopenharmony_ci		os_memset(dst, 0, sizeof(*dst));
9051e5b75505Sopenharmony_ci		dst->sin_family = AF_INET;
9052e5b75505Sopenharmony_ci		dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
9053e5b75505Sopenharmony_ci		dst->sin_port = htons(port);
9054e5b75505Sopenharmony_ci		*addrlen = sizeof(*dst);
9055e5b75505Sopenharmony_ci		break;
9056e5b75505Sopenharmony_ci#ifdef CONFIG_IPV6
9057e5b75505Sopenharmony_ci	case AF_INET6:
9058e5b75505Sopenharmony_ci		dst6 = (struct sockaddr_in6 *) addr;
9059e5b75505Sopenharmony_ci		os_memset(dst6, 0, sizeof(*dst6));
9060e5b75505Sopenharmony_ci		dst6->sin6_family = AF_INET6;
9061e5b75505Sopenharmony_ci		os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
9062e5b75505Sopenharmony_ci			  sizeof(struct in6_addr));
9063e5b75505Sopenharmony_ci		dst6->sin6_port = htons(port);
9064e5b75505Sopenharmony_ci		*addrlen = sizeof(*dst6);
9065e5b75505Sopenharmony_ci		break;
9066e5b75505Sopenharmony_ci#endif /* CONFIG_IPV6 */
9067e5b75505Sopenharmony_ci	default:
9068e5b75505Sopenharmony_ci		return -1;
9069e5b75505Sopenharmony_ci	}
9070e5b75505Sopenharmony_ci
9071e5b75505Sopenharmony_ci	return 0;
9072e5b75505Sopenharmony_ci}
9073e5b75505Sopenharmony_ci
9074e5b75505Sopenharmony_ci
9075e5b75505Sopenharmony_cistatic struct dpp_connection *
9076e5b75505Sopenharmony_cidpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
9077e5b75505Sopenharmony_ci		   unsigned int freq)
9078e5b75505Sopenharmony_ci{
9079e5b75505Sopenharmony_ci	struct dpp_connection *conn;
9080e5b75505Sopenharmony_ci	struct sockaddr_storage addr;
9081e5b75505Sopenharmony_ci	socklen_t addrlen;
9082e5b75505Sopenharmony_ci	char txt[100];
9083e5b75505Sopenharmony_ci
9084e5b75505Sopenharmony_ci	if (dl_list_len(&ctrl->conn) >= 15) {
9085e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9086e5b75505Sopenharmony_ci			   "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9087e5b75505Sopenharmony_ci		return NULL;
9088e5b75505Sopenharmony_ci	}
9089e5b75505Sopenharmony_ci
9090e5b75505Sopenharmony_ci	if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
9091e5b75505Sopenharmony_ci				   &ctrl->ipaddr, DPP_TCP_PORT) < 0)
9092e5b75505Sopenharmony_ci		return NULL;
9093e5b75505Sopenharmony_ci
9094e5b75505Sopenharmony_ci	conn = os_zalloc(sizeof(*conn));
9095e5b75505Sopenharmony_ci	if (!conn)
9096e5b75505Sopenharmony_ci		return NULL;
9097e5b75505Sopenharmony_ci
9098e5b75505Sopenharmony_ci	conn->global = ctrl->global;
9099e5b75505Sopenharmony_ci	conn->relay = ctrl;
9100e5b75505Sopenharmony_ci	os_memcpy(conn->mac_addr, src, ETH_ALEN);
9101e5b75505Sopenharmony_ci	conn->freq = freq;
9102e5b75505Sopenharmony_ci
9103e5b75505Sopenharmony_ci	conn->sock = socket(AF_INET, SOCK_STREAM, 0);
9104e5b75505Sopenharmony_ci	if (conn->sock < 0)
9105e5b75505Sopenharmony_ci		goto fail;
9106e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
9107e5b75505Sopenharmony_ci		   conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
9108e5b75505Sopenharmony_ci
9109e5b75505Sopenharmony_ci	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
9110e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
9111e5b75505Sopenharmony_ci			   strerror(errno));
9112e5b75505Sopenharmony_ci		goto fail;
9113e5b75505Sopenharmony_ci	}
9114e5b75505Sopenharmony_ci
9115e5b75505Sopenharmony_ci	if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
9116e5b75505Sopenharmony_ci		if (errno != EINPROGRESS) {
9117e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
9118e5b75505Sopenharmony_ci				   strerror(errno));
9119e5b75505Sopenharmony_ci			goto fail;
9120e5b75505Sopenharmony_ci		}
9121e5b75505Sopenharmony_ci
9122e5b75505Sopenharmony_ci		/*
9123e5b75505Sopenharmony_ci		 * Continue connecting in the background; eloop will call us
9124e5b75505Sopenharmony_ci		 * once the connection is ready (or failed).
9125e5b75505Sopenharmony_ci		 */
9126e5b75505Sopenharmony_ci	}
9127e5b75505Sopenharmony_ci
9128e5b75505Sopenharmony_ci	if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9129e5b75505Sopenharmony_ci				dpp_conn_tx_ready, conn, NULL) < 0)
9130e5b75505Sopenharmony_ci		goto fail;
9131e5b75505Sopenharmony_ci	conn->write_eloop = 1;
9132e5b75505Sopenharmony_ci
9133e5b75505Sopenharmony_ci	/* TODO: eloop timeout to clear a connection if it does not complete
9134e5b75505Sopenharmony_ci	 * properly */
9135e5b75505Sopenharmony_ci
9136e5b75505Sopenharmony_ci	dl_list_add(&ctrl->conn, &conn->list);
9137e5b75505Sopenharmony_ci	return conn;
9138e5b75505Sopenharmony_cifail:
9139e5b75505Sopenharmony_ci	dpp_connection_free(conn);
9140e5b75505Sopenharmony_ci	return NULL;
9141e5b75505Sopenharmony_ci}
9142e5b75505Sopenharmony_ci
9143e5b75505Sopenharmony_ci
9144e5b75505Sopenharmony_cistatic struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
9145e5b75505Sopenharmony_ci{
9146e5b75505Sopenharmony_ci	struct wpabuf *msg;
9147e5b75505Sopenharmony_ci
9148e5b75505Sopenharmony_ci	msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
9149e5b75505Sopenharmony_ci	if (!msg)
9150e5b75505Sopenharmony_ci		return NULL;
9151e5b75505Sopenharmony_ci	wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
9152e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
9153e5b75505Sopenharmony_ci	wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
9154e5b75505Sopenharmony_ci	wpabuf_put_data(msg, buf, len);
9155e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9156e5b75505Sopenharmony_ci	return msg;
9157e5b75505Sopenharmony_ci}
9158e5b75505Sopenharmony_ci
9159e5b75505Sopenharmony_ci
9160e5b75505Sopenharmony_cistatic int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
9161e5b75505Sopenharmony_ci			const u8 *buf, size_t len)
9162e5b75505Sopenharmony_ci{
9163e5b75505Sopenharmony_ci	u8 type = hdr[DPP_HDR_LEN - 1];
9164e5b75505Sopenharmony_ci
9165e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
9166e5b75505Sopenharmony_ci		   "DPP: Continue already established Relay/Controller connection for this session");
9167e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9168e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9169e5b75505Sopenharmony_ci	conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9170e5b75505Sopenharmony_ci	if (!conn->msg_out) {
9171e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9172e5b75505Sopenharmony_ci		return -1;
9173e5b75505Sopenharmony_ci	}
9174e5b75505Sopenharmony_ci
9175e5b75505Sopenharmony_ci	/* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9176e5b75505Sopenharmony_ci	 * TX status */
9177e5b75505Sopenharmony_ci	if (type == DPP_PA_CONFIGURATION_RESULT)
9178e5b75505Sopenharmony_ci		conn->on_tcp_tx_complete_remove = 1;
9179e5b75505Sopenharmony_ci	dpp_tcp_send(conn);
9180e5b75505Sopenharmony_ci	return 0;
9181e5b75505Sopenharmony_ci}
9182e5b75505Sopenharmony_ci
9183e5b75505Sopenharmony_ci
9184e5b75505Sopenharmony_ciint dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
9185e5b75505Sopenharmony_ci			const u8 *buf, size_t len, unsigned int freq,
9186e5b75505Sopenharmony_ci			const u8 *i_bootstrap, const u8 *r_bootstrap)
9187e5b75505Sopenharmony_ci{
9188e5b75505Sopenharmony_ci	struct dpp_relay_controller *ctrl;
9189e5b75505Sopenharmony_ci	struct dpp_connection *conn;
9190e5b75505Sopenharmony_ci	u8 type = hdr[DPP_HDR_LEN - 1];
9191e5b75505Sopenharmony_ci
9192e5b75505Sopenharmony_ci	/* Check if there is an already started session for this peer and if so,
9193e5b75505Sopenharmony_ci	 * continue that session (send this over TCP) and return 0.
9194e5b75505Sopenharmony_ci	 */
9195e5b75505Sopenharmony_ci	if (type != DPP_PA_PEER_DISCOVERY_REQ &&
9196e5b75505Sopenharmony_ci	    type != DPP_PA_PEER_DISCOVERY_RESP) {
9197e5b75505Sopenharmony_ci		dl_list_for_each(ctrl, &dpp->controllers,
9198e5b75505Sopenharmony_ci				 struct dpp_relay_controller, list) {
9199e5b75505Sopenharmony_ci			dl_list_for_each(conn, &ctrl->conn,
9200e5b75505Sopenharmony_ci					 struct dpp_connection, list) {
9201e5b75505Sopenharmony_ci				if (os_memcmp(src, conn->mac_addr,
9202e5b75505Sopenharmony_ci					      ETH_ALEN) == 0)
9203e5b75505Sopenharmony_ci					return dpp_relay_tx(conn, hdr, buf, len);
9204e5b75505Sopenharmony_ci			}
9205e5b75505Sopenharmony_ci		}
9206e5b75505Sopenharmony_ci	}
9207e5b75505Sopenharmony_ci
9208e5b75505Sopenharmony_ci	if (!r_bootstrap)
9209e5b75505Sopenharmony_ci		return -1;
9210e5b75505Sopenharmony_ci
9211e5b75505Sopenharmony_ci	ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
9212e5b75505Sopenharmony_ci	if (!ctrl)
9213e5b75505Sopenharmony_ci		return -1;
9214e5b75505Sopenharmony_ci
9215e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
9216e5b75505Sopenharmony_ci		   "DPP: Authentication Request for a configured Controller");
9217e5b75505Sopenharmony_ci	conn = dpp_relay_new_conn(ctrl, src, freq);
9218e5b75505Sopenharmony_ci	if (!conn)
9219e5b75505Sopenharmony_ci		return -1;
9220e5b75505Sopenharmony_ci
9221e5b75505Sopenharmony_ci	conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
9222e5b75505Sopenharmony_ci	if (!conn->msg_out) {
9223e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9224e5b75505Sopenharmony_ci		return -1;
9225e5b75505Sopenharmony_ci	}
9226e5b75505Sopenharmony_ci	/* Message will be sent in dpp_conn_tx_ready() */
9227e5b75505Sopenharmony_ci
9228e5b75505Sopenharmony_ci	return 0;
9229e5b75505Sopenharmony_ci}
9230e5b75505Sopenharmony_ci
9231e5b75505Sopenharmony_ci
9232e5b75505Sopenharmony_ciint dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
9233e5b75505Sopenharmony_ci			 size_t data_len)
9234e5b75505Sopenharmony_ci{
9235e5b75505Sopenharmony_ci	struct dpp_relay_controller *ctrl;
9236e5b75505Sopenharmony_ci	struct dpp_connection *conn, *found = NULL;
9237e5b75505Sopenharmony_ci	struct wpabuf *msg;
9238e5b75505Sopenharmony_ci
9239e5b75505Sopenharmony_ci	/* Check if there is a successfully completed authentication for this
9240e5b75505Sopenharmony_ci	 * and if so, continue that session (send this over TCP) and return 0.
9241e5b75505Sopenharmony_ci	 */
9242e5b75505Sopenharmony_ci	dl_list_for_each(ctrl, &dpp->controllers,
9243e5b75505Sopenharmony_ci			 struct dpp_relay_controller, list) {
9244e5b75505Sopenharmony_ci		if (found)
9245e5b75505Sopenharmony_ci			break;
9246e5b75505Sopenharmony_ci		dl_list_for_each(conn, &ctrl->conn,
9247e5b75505Sopenharmony_ci				 struct dpp_connection, list) {
9248e5b75505Sopenharmony_ci			if (os_memcmp(src, conn->mac_addr,
9249e5b75505Sopenharmony_ci				      ETH_ALEN) == 0) {
9250e5b75505Sopenharmony_ci				found = conn;
9251e5b75505Sopenharmony_ci				break;
9252e5b75505Sopenharmony_ci			}
9253e5b75505Sopenharmony_ci		}
9254e5b75505Sopenharmony_ci	}
9255e5b75505Sopenharmony_ci
9256e5b75505Sopenharmony_ci	if (!found)
9257e5b75505Sopenharmony_ci		return -1;
9258e5b75505Sopenharmony_ci
9259e5b75505Sopenharmony_ci	msg = wpabuf_alloc(4 + 1 + data_len);
9260e5b75505Sopenharmony_ci	if (!msg)
9261e5b75505Sopenharmony_ci		return -1;
9262e5b75505Sopenharmony_ci	wpabuf_put_be32(msg, 1 + data_len);
9263e5b75505Sopenharmony_ci	wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
9264e5b75505Sopenharmony_ci	wpabuf_put_data(msg, data, data_len);
9265e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
9266e5b75505Sopenharmony_ci
9267e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9268e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9269e5b75505Sopenharmony_ci	conn->msg_out = msg;
9270e5b75505Sopenharmony_ci	dpp_tcp_send(conn);
9271e5b75505Sopenharmony_ci	return 0;
9272e5b75505Sopenharmony_ci}
9273e5b75505Sopenharmony_ci
9274e5b75505Sopenharmony_ci
9275e5b75505Sopenharmony_cistatic void dpp_controller_free(struct dpp_controller *ctrl)
9276e5b75505Sopenharmony_ci{
9277e5b75505Sopenharmony_ci	struct dpp_connection *conn, *tmp;
9278e5b75505Sopenharmony_ci
9279e5b75505Sopenharmony_ci	if (!ctrl)
9280e5b75505Sopenharmony_ci		return;
9281e5b75505Sopenharmony_ci
9282e5b75505Sopenharmony_ci	dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
9283e5b75505Sopenharmony_ci			      list)
9284e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9285e5b75505Sopenharmony_ci
9286e5b75505Sopenharmony_ci	if (ctrl->sock >= 0) {
9287e5b75505Sopenharmony_ci		close(ctrl->sock);
9288e5b75505Sopenharmony_ci		eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
9289e5b75505Sopenharmony_ci	}
9290e5b75505Sopenharmony_ci	os_free(ctrl->configurator_params);
9291e5b75505Sopenharmony_ci	os_free(ctrl);
9292e5b75505Sopenharmony_ci}
9293e5b75505Sopenharmony_ci
9294e5b75505Sopenharmony_ci
9295e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_req(struct dpp_connection *conn,
9296e5b75505Sopenharmony_ci				      const u8 *hdr, const u8 *buf, size_t len)
9297e5b75505Sopenharmony_ci{
9298e5b75505Sopenharmony_ci	const u8 *r_bootstrap, *i_bootstrap;
9299e5b75505Sopenharmony_ci	u16 r_bootstrap_len, i_bootstrap_len;
9300e5b75505Sopenharmony_ci	struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
9301e5b75505Sopenharmony_ci
9302e5b75505Sopenharmony_ci	if (!conn->ctrl)
9303e5b75505Sopenharmony_ci		return 0;
9304e5b75505Sopenharmony_ci
9305e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
9306e5b75505Sopenharmony_ci
9307e5b75505Sopenharmony_ci	r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
9308e5b75505Sopenharmony_ci				   &r_bootstrap_len);
9309e5b75505Sopenharmony_ci	if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
9310e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
9311e5b75505Sopenharmony_ci			   "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9312e5b75505Sopenharmony_ci		return -1;
9313e5b75505Sopenharmony_ci	}
9314e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
9315e5b75505Sopenharmony_ci		    r_bootstrap, r_bootstrap_len);
9316e5b75505Sopenharmony_ci
9317e5b75505Sopenharmony_ci	i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
9318e5b75505Sopenharmony_ci				   &i_bootstrap_len);
9319e5b75505Sopenharmony_ci	if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
9320e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
9321e5b75505Sopenharmony_ci			   "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9322e5b75505Sopenharmony_ci		return -1;
9323e5b75505Sopenharmony_ci	}
9324e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
9325e5b75505Sopenharmony_ci		    i_bootstrap, i_bootstrap_len);
9326e5b75505Sopenharmony_ci
9327e5b75505Sopenharmony_ci	/* Try to find own and peer bootstrapping key matches based on the
9328e5b75505Sopenharmony_ci	 * received hash values */
9329e5b75505Sopenharmony_ci	dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
9330e5b75505Sopenharmony_ci				&own_bi, &peer_bi);
9331e5b75505Sopenharmony_ci	if (!own_bi) {
9332e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
9333e5b75505Sopenharmony_ci			"No matching own bootstrapping key found - ignore message");
9334e5b75505Sopenharmony_ci		return -1;
9335e5b75505Sopenharmony_ci	}
9336e5b75505Sopenharmony_ci
9337e5b75505Sopenharmony_ci	if (conn->auth) {
9338e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
9339e5b75505Sopenharmony_ci			   "Already in DPP authentication exchange - ignore new one");
9340e5b75505Sopenharmony_ci		return 0;
9341e5b75505Sopenharmony_ci	}
9342e5b75505Sopenharmony_ci
9343e5b75505Sopenharmony_ci	conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
9344e5b75505Sopenharmony_ci				     conn->ctrl->allowed_roles,
9345e5b75505Sopenharmony_ci				     conn->ctrl->qr_mutual,
9346e5b75505Sopenharmony_ci				     peer_bi, own_bi, -1, hdr, buf, len);
9347e5b75505Sopenharmony_ci	if (!conn->auth) {
9348e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No response generated");
9349e5b75505Sopenharmony_ci		return -1;
9350e5b75505Sopenharmony_ci	}
9351e5b75505Sopenharmony_ci
9352e5b75505Sopenharmony_ci	if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
9353e5b75505Sopenharmony_ci				 conn->auth,
9354e5b75505Sopenharmony_ci				 conn->ctrl->configurator_params) < 0) {
9355e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9356e5b75505Sopenharmony_ci		return -1;
9357e5b75505Sopenharmony_ci	}
9358e5b75505Sopenharmony_ci
9359e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9360e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9361e5b75505Sopenharmony_ci	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
9362e5b75505Sopenharmony_ci	if (!conn->msg_out)
9363e5b75505Sopenharmony_ci		return -1;
9364e5b75505Sopenharmony_ci	wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
9365e5b75505Sopenharmony_ci	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
9366e5b75505Sopenharmony_ci			wpabuf_len(conn->auth->resp_msg) - 1);
9367e5b75505Sopenharmony_ci
9368e5b75505Sopenharmony_ci	if (dpp_tcp_send(conn) == 1) {
9369e5b75505Sopenharmony_ci		if (!conn->write_eloop) {
9370e5b75505Sopenharmony_ci			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9371e5b75505Sopenharmony_ci						dpp_conn_tx_ready,
9372e5b75505Sopenharmony_ci						conn, NULL) < 0)
9373e5b75505Sopenharmony_ci				return -1;
9374e5b75505Sopenharmony_ci			conn->write_eloop = 1;
9375e5b75505Sopenharmony_ci		}
9376e5b75505Sopenharmony_ci	}
9377e5b75505Sopenharmony_ci
9378e5b75505Sopenharmony_ci	return 0;
9379e5b75505Sopenharmony_ci}
9380e5b75505Sopenharmony_ci
9381e5b75505Sopenharmony_ci
9382e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
9383e5b75505Sopenharmony_ci				       const u8 *hdr, const u8 *buf, size_t len)
9384e5b75505Sopenharmony_ci{
9385e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9386e5b75505Sopenharmony_ci	struct wpabuf *msg;
9387e5b75505Sopenharmony_ci
9388e5b75505Sopenharmony_ci	if (!auth)
9389e5b75505Sopenharmony_ci		return -1;
9390e5b75505Sopenharmony_ci
9391e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
9392e5b75505Sopenharmony_ci
9393e5b75505Sopenharmony_ci	msg = dpp_auth_resp_rx(auth, hdr, buf, len);
9394e5b75505Sopenharmony_ci	if (!msg) {
9395e5b75505Sopenharmony_ci		if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
9396e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
9397e5b75505Sopenharmony_ci				   "DPP: Start wait for full response");
9398e5b75505Sopenharmony_ci			return -1;
9399e5b75505Sopenharmony_ci		}
9400e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
9401e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9402e5b75505Sopenharmony_ci		return -1;
9403e5b75505Sopenharmony_ci	}
9404e5b75505Sopenharmony_ci
9405e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9406e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9407e5b75505Sopenharmony_ci	conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
9408e5b75505Sopenharmony_ci	if (!conn->msg_out) {
9409e5b75505Sopenharmony_ci		wpabuf_free(msg);
9410e5b75505Sopenharmony_ci		return -1;
9411e5b75505Sopenharmony_ci	}
9412e5b75505Sopenharmony_ci	wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
9413e5b75505Sopenharmony_ci	wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
9414e5b75505Sopenharmony_ci			wpabuf_len(msg) - 1);
9415e5b75505Sopenharmony_ci	wpabuf_free(msg);
9416e5b75505Sopenharmony_ci
9417e5b75505Sopenharmony_ci	conn->on_tcp_tx_complete_auth_ok = 1;
9418e5b75505Sopenharmony_ci	if (dpp_tcp_send(conn) == 1) {
9419e5b75505Sopenharmony_ci		if (!conn->write_eloop) {
9420e5b75505Sopenharmony_ci			if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9421e5b75505Sopenharmony_ci						dpp_conn_tx_ready,
9422e5b75505Sopenharmony_ci						conn, NULL) < 0)
9423e5b75505Sopenharmony_ci				return -1;
9424e5b75505Sopenharmony_ci			conn->write_eloop = 1;
9425e5b75505Sopenharmony_ci		}
9426e5b75505Sopenharmony_ci	}
9427e5b75505Sopenharmony_ci
9428e5b75505Sopenharmony_ci	return 0;
9429e5b75505Sopenharmony_ci}
9430e5b75505Sopenharmony_ci
9431e5b75505Sopenharmony_ci
9432e5b75505Sopenharmony_cistatic int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
9433e5b75505Sopenharmony_ci				       const u8 *hdr, const u8 *buf, size_t len)
9434e5b75505Sopenharmony_ci{
9435e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9436e5b75505Sopenharmony_ci
9437e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
9438e5b75505Sopenharmony_ci
9439e5b75505Sopenharmony_ci	if (!auth) {
9440e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9441e5b75505Sopenharmony_ci			   "DPP: No DPP Authentication in progress - drop");
9442e5b75505Sopenharmony_ci		return -1;
9443e5b75505Sopenharmony_ci	}
9444e5b75505Sopenharmony_ci
9445e5b75505Sopenharmony_ci	if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
9446e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
9447e5b75505Sopenharmony_ci		return -1;
9448e5b75505Sopenharmony_ci	}
9449e5b75505Sopenharmony_ci
9450e5b75505Sopenharmony_ci	dpp_controller_auth_success(conn, 0);
9451e5b75505Sopenharmony_ci	return 0;
9452e5b75505Sopenharmony_ci}
9453e5b75505Sopenharmony_ci
9454e5b75505Sopenharmony_ci
9455e5b75505Sopenharmony_cistatic int dpp_controller_rx_conf_result(struct dpp_connection *conn,
9456e5b75505Sopenharmony_ci					 const u8 *hdr, const u8 *buf,
9457e5b75505Sopenharmony_ci					 size_t len)
9458e5b75505Sopenharmony_ci{
9459e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9460e5b75505Sopenharmony_ci	enum dpp_status_error status;
9461e5b75505Sopenharmony_ci
9462e5b75505Sopenharmony_ci	if (!conn->ctrl)
9463e5b75505Sopenharmony_ci		return 0;
9464e5b75505Sopenharmony_ci
9465e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
9466e5b75505Sopenharmony_ci
9467e5b75505Sopenharmony_ci	if (!auth || !auth->waiting_conf_result) {
9468e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9469e5b75505Sopenharmony_ci			   "DPP: No DPP Configuration waiting for result - drop");
9470e5b75505Sopenharmony_ci		return -1;
9471e5b75505Sopenharmony_ci	}
9472e5b75505Sopenharmony_ci
9473e5b75505Sopenharmony_ci	status = dpp_conf_result_rx(auth, hdr, buf, len);
9474e5b75505Sopenharmony_ci	if (status == DPP_STATUS_OK)
9475e5b75505Sopenharmony_ci		wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
9476e5b75505Sopenharmony_ci			DPP_EVENT_CONF_SENT);
9477e5b75505Sopenharmony_ci	else
9478e5b75505Sopenharmony_ci		wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
9479e5b75505Sopenharmony_ci			DPP_EVENT_CONF_FAILED);
9480e5b75505Sopenharmony_ci	return -1; /* to remove the completed connection */
9481e5b75505Sopenharmony_ci}
9482e5b75505Sopenharmony_ci
9483e5b75505Sopenharmony_ci
9484e5b75505Sopenharmony_cistatic int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
9485e5b75505Sopenharmony_ci				    size_t len)
9486e5b75505Sopenharmony_ci{
9487e5b75505Sopenharmony_ci	const u8 *pos, *end;
9488e5b75505Sopenharmony_ci	u8 type;
9489e5b75505Sopenharmony_ci
9490e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
9491e5b75505Sopenharmony_ci	pos = msg;
9492e5b75505Sopenharmony_ci	end = msg + len;
9493e5b75505Sopenharmony_ci
9494e5b75505Sopenharmony_ci	if (end - pos < DPP_HDR_LEN ||
9495e5b75505Sopenharmony_ci	    WPA_GET_BE24(pos) != OUI_WFA ||
9496e5b75505Sopenharmony_ci	    pos[3] != DPP_OUI_TYPE) {
9497e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
9498e5b75505Sopenharmony_ci		return -1;
9499e5b75505Sopenharmony_ci	}
9500e5b75505Sopenharmony_ci
9501e5b75505Sopenharmony_ci	if (pos[4] != 1) {
9502e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
9503e5b75505Sopenharmony_ci			   pos[4]);
9504e5b75505Sopenharmony_ci		return -1;
9505e5b75505Sopenharmony_ci	}
9506e5b75505Sopenharmony_ci	type = pos[5];
9507e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
9508e5b75505Sopenharmony_ci	pos += DPP_HDR_LEN;
9509e5b75505Sopenharmony_ci
9510e5b75505Sopenharmony_ci	wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
9511e5b75505Sopenharmony_ci		    pos, end - pos);
9512e5b75505Sopenharmony_ci	if (dpp_check_attrs(pos, end - pos) < 0)
9513e5b75505Sopenharmony_ci		return -1;
9514e5b75505Sopenharmony_ci
9515e5b75505Sopenharmony_ci	if (conn->relay) {
9516e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
9517e5b75505Sopenharmony_ci		conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
9518e5b75505Sopenharmony_ci				conn->freq, msg, len);
9519e5b75505Sopenharmony_ci		return 0;
9520e5b75505Sopenharmony_ci	}
9521e5b75505Sopenharmony_ci
9522e5b75505Sopenharmony_ci	switch (type) {
9523e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_REQ:
9524e5b75505Sopenharmony_ci		return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
9525e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_RESP:
9526e5b75505Sopenharmony_ci		return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
9527e5b75505Sopenharmony_ci	case DPP_PA_AUTHENTICATION_CONF:
9528e5b75505Sopenharmony_ci		return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
9529e5b75505Sopenharmony_ci	case DPP_PA_CONFIGURATION_RESULT:
9530e5b75505Sopenharmony_ci		return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
9531e5b75505Sopenharmony_ci	default:
9532e5b75505Sopenharmony_ci		/* TODO: missing messages types */
9533e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9534e5b75505Sopenharmony_ci			   "DPP: Unsupported frame subtype %d", type);
9535e5b75505Sopenharmony_ci		return -1;
9536e5b75505Sopenharmony_ci	}
9537e5b75505Sopenharmony_ci}
9538e5b75505Sopenharmony_ci
9539e5b75505Sopenharmony_ci
9540e5b75505Sopenharmony_cistatic int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
9541e5b75505Sopenharmony_ci				     size_t len)
9542e5b75505Sopenharmony_ci{
9543e5b75505Sopenharmony_ci	const u8 *pos, *end, *next;
9544e5b75505Sopenharmony_ci	u8 dialog_token;
9545e5b75505Sopenharmony_ci	const u8 *adv_proto;
9546e5b75505Sopenharmony_ci	u16 slen;
9547e5b75505Sopenharmony_ci	struct wpabuf *resp, *buf;
9548e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9549e5b75505Sopenharmony_ci
9550e5b75505Sopenharmony_ci	if (len < 1 + 2)
9551e5b75505Sopenharmony_ci		return -1;
9552e5b75505Sopenharmony_ci
9553e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
9554e5b75505Sopenharmony_ci		   "DPP: Received DPP Configuration Request over TCP");
9555e5b75505Sopenharmony_ci
9556e5b75505Sopenharmony_ci	if (!conn->ctrl || !auth || !auth->auth_success) {
9557e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
9558e5b75505Sopenharmony_ci		return -1;
9559e5b75505Sopenharmony_ci	}
9560e5b75505Sopenharmony_ci
9561e5b75505Sopenharmony_ci	pos = msg;
9562e5b75505Sopenharmony_ci	end = msg + len;
9563e5b75505Sopenharmony_ci
9564e5b75505Sopenharmony_ci	dialog_token = *pos++;
9565e5b75505Sopenharmony_ci	adv_proto = pos++;
9566e5b75505Sopenharmony_ci	slen = *pos++;
9567e5b75505Sopenharmony_ci	if (*adv_proto != WLAN_EID_ADV_PROTO ||
9568e5b75505Sopenharmony_ci	    slen > end - pos || slen < 2)
9569e5b75505Sopenharmony_ci		return -1;
9570e5b75505Sopenharmony_ci
9571e5b75505Sopenharmony_ci	next = pos + slen;
9572e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
9573e5b75505Sopenharmony_ci
9574e5b75505Sopenharmony_ci	if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
9575e5b75505Sopenharmony_ci	    pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
9576e5b75505Sopenharmony_ci	    pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
9577e5b75505Sopenharmony_ci		return -1;
9578e5b75505Sopenharmony_ci
9579e5b75505Sopenharmony_ci	pos = next;
9580e5b75505Sopenharmony_ci	/* Query Request */
9581e5b75505Sopenharmony_ci	if (end - pos < 2)
9582e5b75505Sopenharmony_ci		return -1;
9583e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
9584e5b75505Sopenharmony_ci	pos += 2;
9585e5b75505Sopenharmony_ci	if (slen > end - pos)
9586e5b75505Sopenharmony_ci		return -1;
9587e5b75505Sopenharmony_ci
9588e5b75505Sopenharmony_ci	resp = dpp_conf_req_rx(auth, pos, slen);
9589e5b75505Sopenharmony_ci	if (!resp)
9590e5b75505Sopenharmony_ci		return -1;
9591e5b75505Sopenharmony_ci
9592e5b75505Sopenharmony_ci	buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
9593e5b75505Sopenharmony_ci	if (!buf) {
9594e5b75505Sopenharmony_ci		wpabuf_free(resp);
9595e5b75505Sopenharmony_ci		return -1;
9596e5b75505Sopenharmony_ci	}
9597e5b75505Sopenharmony_ci
9598e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
9599e5b75505Sopenharmony_ci
9600e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
9601e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, dialog_token);
9602e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
9603e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
9604e5b75505Sopenharmony_ci
9605e5b75505Sopenharmony_ci	dpp_write_adv_proto(buf);
9606e5b75505Sopenharmony_ci	dpp_write_gas_query(buf, resp);
9607e5b75505Sopenharmony_ci	wpabuf_free(resp);
9608e5b75505Sopenharmony_ci
9609e5b75505Sopenharmony_ci	/* Send Config Response over TCP; GAS fragmentation is taken care of by
9610e5b75505Sopenharmony_ci	 * the Relay */
9611e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
9612e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9613e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9614e5b75505Sopenharmony_ci	conn->msg_out = buf;
9615e5b75505Sopenharmony_ci	conn->on_tcp_tx_complete_gas_done = 1;
9616e5b75505Sopenharmony_ci	dpp_tcp_send(conn);
9617e5b75505Sopenharmony_ci	return 0;
9618e5b75505Sopenharmony_ci}
9619e5b75505Sopenharmony_ci
9620e5b75505Sopenharmony_ci
9621e5b75505Sopenharmony_cistatic int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
9622e5b75505Sopenharmony_ci{
9623e5b75505Sopenharmony_ci	struct dpp_authentication *auth = conn->auth;
9624e5b75505Sopenharmony_ci	int res;
9625e5b75505Sopenharmony_ci	struct wpabuf *msg, *encaps;
9626e5b75505Sopenharmony_ci	enum dpp_status_error status;
9627e5b75505Sopenharmony_ci
9628e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
9629e5b75505Sopenharmony_ci		   "DPP: Configuration Response for local stack from TCP");
9630e5b75505Sopenharmony_ci
9631e5b75505Sopenharmony_ci	res = dpp_conf_resp_rx(auth, resp);
9632e5b75505Sopenharmony_ci	wpabuf_free(resp);
9633e5b75505Sopenharmony_ci	if (res < 0) {
9634e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
9635e5b75505Sopenharmony_ci		return -1;
9636e5b75505Sopenharmony_ci	}
9637e5b75505Sopenharmony_ci
9638e5b75505Sopenharmony_ci	if (conn->global->process_conf_obj)
9639e5b75505Sopenharmony_ci		res = conn->global->process_conf_obj(conn->global->cb_ctx,
9640e5b75505Sopenharmony_ci						     auth);
9641e5b75505Sopenharmony_ci	else
9642e5b75505Sopenharmony_ci		res = 0;
9643e5b75505Sopenharmony_ci
9644e5b75505Sopenharmony_ci	if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
9645e5b75505Sopenharmony_ci		return -1;
9646e5b75505Sopenharmony_ci
9647e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
9648e5b75505Sopenharmony_ci	status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
9649e5b75505Sopenharmony_ci	msg = dpp_build_conf_result(auth, status);
9650e5b75505Sopenharmony_ci	if (!msg)
9651e5b75505Sopenharmony_ci		return -1;
9652e5b75505Sopenharmony_ci
9653e5b75505Sopenharmony_ci	encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
9654e5b75505Sopenharmony_ci	if (!encaps) {
9655e5b75505Sopenharmony_ci		wpabuf_free(msg);
9656e5b75505Sopenharmony_ci		return -1;
9657e5b75505Sopenharmony_ci	}
9658e5b75505Sopenharmony_ci	wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
9659e5b75505Sopenharmony_ci	wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
9660e5b75505Sopenharmony_ci	wpabuf_free(msg);
9661e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
9662e5b75505Sopenharmony_ci
9663e5b75505Sopenharmony_ci	wpabuf_free(conn->msg_out);
9664e5b75505Sopenharmony_ci	conn->msg_out_pos = 0;
9665e5b75505Sopenharmony_ci	conn->msg_out = encaps;
9666e5b75505Sopenharmony_ci	conn->on_tcp_tx_complete_remove = 1;
9667e5b75505Sopenharmony_ci	dpp_tcp_send(conn);
9668e5b75505Sopenharmony_ci
9669e5b75505Sopenharmony_ci	/* This exchange will be terminated in the TX status handler */
9670e5b75505Sopenharmony_ci
9671e5b75505Sopenharmony_ci	return 0;
9672e5b75505Sopenharmony_ci}
9673e5b75505Sopenharmony_ci
9674e5b75505Sopenharmony_ci
9675e5b75505Sopenharmony_cistatic int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
9676e5b75505Sopenharmony_ci			   size_t len)
9677e5b75505Sopenharmony_ci{
9678e5b75505Sopenharmony_ci	struct wpabuf *buf;
9679e5b75505Sopenharmony_ci	u8 dialog_token;
9680e5b75505Sopenharmony_ci	const u8 *pos, *end, *next, *adv_proto;
9681e5b75505Sopenharmony_ci	u16 status, slen;
9682e5b75505Sopenharmony_ci
9683e5b75505Sopenharmony_ci	if (len < 5 + 2)
9684e5b75505Sopenharmony_ci		return -1;
9685e5b75505Sopenharmony_ci
9686e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
9687e5b75505Sopenharmony_ci		   "DPP: Received DPP Configuration Response over TCP");
9688e5b75505Sopenharmony_ci
9689e5b75505Sopenharmony_ci	pos = msg;
9690e5b75505Sopenharmony_ci	end = msg + len;
9691e5b75505Sopenharmony_ci
9692e5b75505Sopenharmony_ci	dialog_token = *pos++;
9693e5b75505Sopenharmony_ci	status = WPA_GET_LE16(pos);
9694e5b75505Sopenharmony_ci	if (status != WLAN_STATUS_SUCCESS) {
9695e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
9696e5b75505Sopenharmony_ci		return -1;
9697e5b75505Sopenharmony_ci	}
9698e5b75505Sopenharmony_ci	pos += 2;
9699e5b75505Sopenharmony_ci	pos += 2; /* ignore GAS Comeback Delay */
9700e5b75505Sopenharmony_ci
9701e5b75505Sopenharmony_ci	adv_proto = pos++;
9702e5b75505Sopenharmony_ci	slen = *pos++;
9703e5b75505Sopenharmony_ci	if (*adv_proto != WLAN_EID_ADV_PROTO ||
9704e5b75505Sopenharmony_ci	    slen > end - pos || slen < 2)
9705e5b75505Sopenharmony_ci		return -1;
9706e5b75505Sopenharmony_ci
9707e5b75505Sopenharmony_ci	next = pos + slen;
9708e5b75505Sopenharmony_ci	pos++; /* skip QueryRespLenLimit and PAME-BI */
9709e5b75505Sopenharmony_ci
9710e5b75505Sopenharmony_ci	if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
9711e5b75505Sopenharmony_ci	    pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
9712e5b75505Sopenharmony_ci	    pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
9713e5b75505Sopenharmony_ci		return -1;
9714e5b75505Sopenharmony_ci
9715e5b75505Sopenharmony_ci	pos = next;
9716e5b75505Sopenharmony_ci	/* Query Response */
9717e5b75505Sopenharmony_ci	if (end - pos < 2)
9718e5b75505Sopenharmony_ci		return -1;
9719e5b75505Sopenharmony_ci	slen = WPA_GET_LE16(pos);
9720e5b75505Sopenharmony_ci	pos += 2;
9721e5b75505Sopenharmony_ci	if (slen > end - pos)
9722e5b75505Sopenharmony_ci		return -1;
9723e5b75505Sopenharmony_ci
9724e5b75505Sopenharmony_ci	buf = wpabuf_alloc(slen);
9725e5b75505Sopenharmony_ci	if (!buf)
9726e5b75505Sopenharmony_ci		return -1;
9727e5b75505Sopenharmony_ci	wpabuf_put_data(buf, pos, slen);
9728e5b75505Sopenharmony_ci
9729e5b75505Sopenharmony_ci	if (!conn->relay && !conn->ctrl)
9730e5b75505Sopenharmony_ci		return dpp_tcp_rx_gas_resp(conn, buf);
9731e5b75505Sopenharmony_ci
9732e5b75505Sopenharmony_ci	if (!conn->relay) {
9733e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
9734e5b75505Sopenharmony_ci		wpabuf_free(buf);
9735e5b75505Sopenharmony_ci		return -1;
9736e5b75505Sopenharmony_ci	}
9737e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
9738e5b75505Sopenharmony_ci	conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
9739e5b75505Sopenharmony_ci				 dialog_token, 0, buf);
9740e5b75505Sopenharmony_ci
9741e5b75505Sopenharmony_ci	return 0;
9742e5b75505Sopenharmony_ci}
9743e5b75505Sopenharmony_ci
9744e5b75505Sopenharmony_ci
9745e5b75505Sopenharmony_cistatic void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
9746e5b75505Sopenharmony_ci{
9747e5b75505Sopenharmony_ci	struct dpp_connection *conn = eloop_ctx;
9748e5b75505Sopenharmony_ci	int res;
9749e5b75505Sopenharmony_ci	const u8 *pos;
9750e5b75505Sopenharmony_ci
9751e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
9752e5b75505Sopenharmony_ci		   sd);
9753e5b75505Sopenharmony_ci
9754e5b75505Sopenharmony_ci	if (conn->msg_len_octets < 4) {
9755e5b75505Sopenharmony_ci		u32 msglen;
9756e5b75505Sopenharmony_ci
9757e5b75505Sopenharmony_ci		res = recv(sd, &conn->msg_len[conn->msg_len_octets],
9758e5b75505Sopenharmony_ci			   4 - conn->msg_len_octets, 0);
9759e5b75505Sopenharmony_ci		if (res < 0) {
9760e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
9761e5b75505Sopenharmony_ci				   strerror(errno));
9762e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9763e5b75505Sopenharmony_ci			return;
9764e5b75505Sopenharmony_ci		}
9765e5b75505Sopenharmony_ci		if (res == 0) {
9766e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
9767e5b75505Sopenharmony_ci				   "DPP: No more data available over TCP");
9768e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9769e5b75505Sopenharmony_ci			return;
9770e5b75505Sopenharmony_ci		}
9771e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9772e5b75505Sopenharmony_ci			   "DPP: Received %d/%d octet(s) of message length field",
9773e5b75505Sopenharmony_ci			   res, (int) (4 - conn->msg_len_octets));
9774e5b75505Sopenharmony_ci		conn->msg_len_octets += res;
9775e5b75505Sopenharmony_ci
9776e5b75505Sopenharmony_ci		if (conn->msg_len_octets < 4) {
9777e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
9778e5b75505Sopenharmony_ci				   "DPP: Need %d more octets of message length field",
9779e5b75505Sopenharmony_ci				   (int) (4 - conn->msg_len_octets));
9780e5b75505Sopenharmony_ci			return;
9781e5b75505Sopenharmony_ci		}
9782e5b75505Sopenharmony_ci
9783e5b75505Sopenharmony_ci		msglen = WPA_GET_BE32(conn->msg_len);
9784e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
9785e5b75505Sopenharmony_ci		if (msglen > 65535) {
9786e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
9787e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9788e5b75505Sopenharmony_ci			return;
9789e5b75505Sopenharmony_ci		}
9790e5b75505Sopenharmony_ci
9791e5b75505Sopenharmony_ci		wpabuf_free(conn->msg);
9792e5b75505Sopenharmony_ci		conn->msg = wpabuf_alloc(msglen);
9793e5b75505Sopenharmony_ci	}
9794e5b75505Sopenharmony_ci
9795e5b75505Sopenharmony_ci	if (!conn->msg) {
9796e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9797e5b75505Sopenharmony_ci			   "DPP: No buffer available for receiving the message");
9798e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9799e5b75505Sopenharmony_ci		return;
9800e5b75505Sopenharmony_ci	}
9801e5b75505Sopenharmony_ci
9802e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
9803e5b75505Sopenharmony_ci		   (unsigned int) wpabuf_tailroom(conn->msg));
9804e5b75505Sopenharmony_ci
9805e5b75505Sopenharmony_ci	res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
9806e5b75505Sopenharmony_ci	if (res < 0) {
9807e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
9808e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9809e5b75505Sopenharmony_ci		return;
9810e5b75505Sopenharmony_ci	}
9811e5b75505Sopenharmony_ci	if (res == 0) {
9812e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
9813e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9814e5b75505Sopenharmony_ci		return;
9815e5b75505Sopenharmony_ci	}
9816e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
9817e5b75505Sopenharmony_ci	wpabuf_put(conn->msg, res);
9818e5b75505Sopenharmony_ci
9819e5b75505Sopenharmony_ci	if (wpabuf_tailroom(conn->msg) > 0) {
9820e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9821e5b75505Sopenharmony_ci			   "DPP: Need %u more octets of message payload",
9822e5b75505Sopenharmony_ci			   (unsigned int) wpabuf_tailroom(conn->msg));
9823e5b75505Sopenharmony_ci		return;
9824e5b75505Sopenharmony_ci	}
9825e5b75505Sopenharmony_ci
9826e5b75505Sopenharmony_ci	conn->msg_len_octets = 0;
9827e5b75505Sopenharmony_ci	wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
9828e5b75505Sopenharmony_ci	if (wpabuf_len(conn->msg) < 1) {
9829e5b75505Sopenharmony_ci		dpp_connection_remove(conn);
9830e5b75505Sopenharmony_ci		return;
9831e5b75505Sopenharmony_ci	}
9832e5b75505Sopenharmony_ci
9833e5b75505Sopenharmony_ci	pos = wpabuf_head(conn->msg);
9834e5b75505Sopenharmony_ci	switch (*pos) {
9835e5b75505Sopenharmony_ci	case WLAN_PA_VENDOR_SPECIFIC:
9836e5b75505Sopenharmony_ci		if (dpp_controller_rx_action(conn, pos + 1,
9837e5b75505Sopenharmony_ci					     wpabuf_len(conn->msg) - 1) < 0)
9838e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9839e5b75505Sopenharmony_ci		break;
9840e5b75505Sopenharmony_ci	case WLAN_PA_GAS_INITIAL_REQ:
9841e5b75505Sopenharmony_ci		if (dpp_controller_rx_gas_req(conn, pos + 1,
9842e5b75505Sopenharmony_ci					      wpabuf_len(conn->msg) - 1) < 0)
9843e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9844e5b75505Sopenharmony_ci		break;
9845e5b75505Sopenharmony_ci	case WLAN_PA_GAS_INITIAL_RESP:
9846e5b75505Sopenharmony_ci		if (dpp_rx_gas_resp(conn, pos + 1,
9847e5b75505Sopenharmony_ci				    wpabuf_len(conn->msg) - 1) < 0)
9848e5b75505Sopenharmony_ci			dpp_connection_remove(conn);
9849e5b75505Sopenharmony_ci		break;
9850e5b75505Sopenharmony_ci	default:
9851e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
9852e5b75505Sopenharmony_ci			   *pos);
9853e5b75505Sopenharmony_ci		break;
9854e5b75505Sopenharmony_ci	}
9855e5b75505Sopenharmony_ci}
9856e5b75505Sopenharmony_ci
9857e5b75505Sopenharmony_ci
9858e5b75505Sopenharmony_cistatic void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
9859e5b75505Sopenharmony_ci{
9860e5b75505Sopenharmony_ci	struct dpp_controller *ctrl = eloop_ctx;
9861e5b75505Sopenharmony_ci	struct sockaddr_in addr;
9862e5b75505Sopenharmony_ci	socklen_t addr_len = sizeof(addr);
9863e5b75505Sopenharmony_ci	int fd;
9864e5b75505Sopenharmony_ci	struct dpp_connection *conn;
9865e5b75505Sopenharmony_ci
9866e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
9867e5b75505Sopenharmony_ci
9868e5b75505Sopenharmony_ci	fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
9869e5b75505Sopenharmony_ci	if (fd < 0) {
9870e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
9871e5b75505Sopenharmony_ci			   "DPP: Failed to accept new connection: %s",
9872e5b75505Sopenharmony_ci			   strerror(errno));
9873e5b75505Sopenharmony_ci		return;
9874e5b75505Sopenharmony_ci	}
9875e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
9876e5b75505Sopenharmony_ci		   inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
9877e5b75505Sopenharmony_ci
9878e5b75505Sopenharmony_ci	conn = os_zalloc(sizeof(*conn));
9879e5b75505Sopenharmony_ci	if (!conn)
9880e5b75505Sopenharmony_ci		goto fail;
9881e5b75505Sopenharmony_ci
9882e5b75505Sopenharmony_ci	conn->global = ctrl->global;
9883e5b75505Sopenharmony_ci	conn->ctrl = ctrl;
9884e5b75505Sopenharmony_ci	conn->sock = fd;
9885e5b75505Sopenharmony_ci
9886e5b75505Sopenharmony_ci	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
9887e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
9888e5b75505Sopenharmony_ci			   strerror(errno));
9889e5b75505Sopenharmony_ci		goto fail;
9890e5b75505Sopenharmony_ci	}
9891e5b75505Sopenharmony_ci
9892e5b75505Sopenharmony_ci	if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
9893e5b75505Sopenharmony_ci				dpp_controller_rx, conn, NULL) < 0)
9894e5b75505Sopenharmony_ci		goto fail;
9895e5b75505Sopenharmony_ci	conn->read_eloop = 1;
9896e5b75505Sopenharmony_ci
9897e5b75505Sopenharmony_ci	/* TODO: eloop timeout to expire connections that do not complete in
9898e5b75505Sopenharmony_ci	 * reasonable time */
9899e5b75505Sopenharmony_ci	dl_list_add(&ctrl->conn, &conn->list);
9900e5b75505Sopenharmony_ci	return;
9901e5b75505Sopenharmony_ci
9902e5b75505Sopenharmony_cifail:
9903e5b75505Sopenharmony_ci	close(fd);
9904e5b75505Sopenharmony_ci	os_free(conn);
9905e5b75505Sopenharmony_ci}
9906e5b75505Sopenharmony_ci
9907e5b75505Sopenharmony_ci
9908e5b75505Sopenharmony_ciint dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
9909e5b75505Sopenharmony_ci		 const struct hostapd_ip_addr *addr, int port)
9910e5b75505Sopenharmony_ci{
9911e5b75505Sopenharmony_ci	struct dpp_connection *conn;
9912e5b75505Sopenharmony_ci	struct sockaddr_storage saddr;
9913e5b75505Sopenharmony_ci	socklen_t addrlen;
9914e5b75505Sopenharmony_ci	const u8 *hdr, *pos, *end;
9915e5b75505Sopenharmony_ci	char txt[100];
9916e5b75505Sopenharmony_ci
9917e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
9918e5b75505Sopenharmony_ci		   hostapd_ip_txt(addr, txt, sizeof(txt)), port);
9919e5b75505Sopenharmony_ci	if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
9920e5b75505Sopenharmony_ci				   addr, port) < 0) {
9921e5b75505Sopenharmony_ci		dpp_auth_deinit(auth);
9922e5b75505Sopenharmony_ci		return -1;
9923e5b75505Sopenharmony_ci	}
9924e5b75505Sopenharmony_ci
9925e5b75505Sopenharmony_ci	conn = os_zalloc(sizeof(*conn));
9926e5b75505Sopenharmony_ci	if (!conn) {
9927e5b75505Sopenharmony_ci		dpp_auth_deinit(auth);
9928e5b75505Sopenharmony_ci		return -1;
9929e5b75505Sopenharmony_ci	}
9930e5b75505Sopenharmony_ci
9931e5b75505Sopenharmony_ci	conn->global = dpp;
9932e5b75505Sopenharmony_ci	conn->auth = auth;
9933e5b75505Sopenharmony_ci	conn->sock = socket(AF_INET, SOCK_STREAM, 0);
9934e5b75505Sopenharmony_ci	if (conn->sock < 0)
9935e5b75505Sopenharmony_ci		goto fail;
9936e5b75505Sopenharmony_ci
9937e5b75505Sopenharmony_ci	if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
9938e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
9939e5b75505Sopenharmony_ci			   strerror(errno));
9940e5b75505Sopenharmony_ci		goto fail;
9941e5b75505Sopenharmony_ci	}
9942e5b75505Sopenharmony_ci
9943e5b75505Sopenharmony_ci	if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
9944e5b75505Sopenharmony_ci		if (errno != EINPROGRESS) {
9945e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
9946e5b75505Sopenharmony_ci				   strerror(errno));
9947e5b75505Sopenharmony_ci			goto fail;
9948e5b75505Sopenharmony_ci		}
9949e5b75505Sopenharmony_ci
9950e5b75505Sopenharmony_ci		/*
9951e5b75505Sopenharmony_ci		 * Continue connecting in the background; eloop will call us
9952e5b75505Sopenharmony_ci		 * once the connection is ready (or failed).
9953e5b75505Sopenharmony_ci		 */
9954e5b75505Sopenharmony_ci	}
9955e5b75505Sopenharmony_ci
9956e5b75505Sopenharmony_ci	if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
9957e5b75505Sopenharmony_ci				dpp_conn_tx_ready, conn, NULL) < 0)
9958e5b75505Sopenharmony_ci		goto fail;
9959e5b75505Sopenharmony_ci	conn->write_eloop = 1;
9960e5b75505Sopenharmony_ci
9961e5b75505Sopenharmony_ci	hdr = wpabuf_head(auth->req_msg);
9962e5b75505Sopenharmony_ci	end = hdr + wpabuf_len(auth->req_msg);
9963e5b75505Sopenharmony_ci	hdr += 2; /* skip Category and Actiom */
9964e5b75505Sopenharmony_ci	pos = hdr + DPP_HDR_LEN;
9965e5b75505Sopenharmony_ci	conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
9966e5b75505Sopenharmony_ci	if (!conn->msg_out)
9967e5b75505Sopenharmony_ci		goto fail;
9968e5b75505Sopenharmony_ci	/* Message will be sent in dpp_conn_tx_ready() */
9969e5b75505Sopenharmony_ci
9970e5b75505Sopenharmony_ci	/* TODO: eloop timeout to clear a connection if it does not complete
9971e5b75505Sopenharmony_ci	 * properly */
9972e5b75505Sopenharmony_ci	dl_list_add(&dpp->tcp_init, &conn->list);
9973e5b75505Sopenharmony_ci	return 0;
9974e5b75505Sopenharmony_cifail:
9975e5b75505Sopenharmony_ci	dpp_connection_free(conn);
9976e5b75505Sopenharmony_ci	return -1;
9977e5b75505Sopenharmony_ci}
9978e5b75505Sopenharmony_ci
9979e5b75505Sopenharmony_ci
9980e5b75505Sopenharmony_ciint dpp_controller_start(struct dpp_global *dpp,
9981e5b75505Sopenharmony_ci			 struct dpp_controller_config *config)
9982e5b75505Sopenharmony_ci{
9983e5b75505Sopenharmony_ci	struct dpp_controller *ctrl;
9984e5b75505Sopenharmony_ci	int on = 1;
9985e5b75505Sopenharmony_ci	struct sockaddr_in sin;
9986e5b75505Sopenharmony_ci	int port;
9987e5b75505Sopenharmony_ci
9988e5b75505Sopenharmony_ci	if (!dpp || dpp->controller)
9989e5b75505Sopenharmony_ci		return -1;
9990e5b75505Sopenharmony_ci
9991e5b75505Sopenharmony_ci	ctrl = os_zalloc(sizeof(*ctrl));
9992e5b75505Sopenharmony_ci	if (!ctrl)
9993e5b75505Sopenharmony_ci		return -1;
9994e5b75505Sopenharmony_ci	ctrl->global = dpp;
9995e5b75505Sopenharmony_ci	if (config->configurator_params)
9996e5b75505Sopenharmony_ci		ctrl->configurator_params =
9997e5b75505Sopenharmony_ci			os_strdup(config->configurator_params);
9998e5b75505Sopenharmony_ci	dl_list_init(&ctrl->conn);
9999e5b75505Sopenharmony_ci	/* TODO: configure these somehow */
10000e5b75505Sopenharmony_ci	ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
10001e5b75505Sopenharmony_ci	ctrl->qr_mutual = 0;
10002e5b75505Sopenharmony_ci
10003e5b75505Sopenharmony_ci	ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
10004e5b75505Sopenharmony_ci	if (ctrl->sock < 0)
10005e5b75505Sopenharmony_ci		goto fail;
10006e5b75505Sopenharmony_ci
10007e5b75505Sopenharmony_ci	if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
10008e5b75505Sopenharmony_ci		       &on, sizeof(on)) < 0) {
10009e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
10010e5b75505Sopenharmony_ci			   "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10011e5b75505Sopenharmony_ci			   strerror(errno));
10012e5b75505Sopenharmony_ci		/* try to continue anyway */
10013e5b75505Sopenharmony_ci	}
10014e5b75505Sopenharmony_ci
10015e5b75505Sopenharmony_ci	if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
10016e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
10017e5b75505Sopenharmony_ci			   strerror(errno));
10018e5b75505Sopenharmony_ci		goto fail;
10019e5b75505Sopenharmony_ci	}
10020e5b75505Sopenharmony_ci
10021e5b75505Sopenharmony_ci	/* TODO: IPv6 */
10022e5b75505Sopenharmony_ci	os_memset(&sin, 0, sizeof(sin));
10023e5b75505Sopenharmony_ci	sin.sin_family = AF_INET;
10024e5b75505Sopenharmony_ci	sin.sin_addr.s_addr = INADDR_ANY;
10025e5b75505Sopenharmony_ci	port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
10026e5b75505Sopenharmony_ci	sin.sin_port = htons(port);
10027e5b75505Sopenharmony_ci	if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
10028e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
10029e5b75505Sopenharmony_ci			   "DPP: Failed to bind Controller TCP port: %s",
10030e5b75505Sopenharmony_ci			   strerror(errno));
10031e5b75505Sopenharmony_ci		goto fail;
10032e5b75505Sopenharmony_ci	}
10033e5b75505Sopenharmony_ci	if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
10034e5b75505Sopenharmony_ci	    fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
10035e5b75505Sopenharmony_ci	    eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
10036e5b75505Sopenharmony_ci				dpp_controller_tcp_cb, ctrl, NULL))
10037e5b75505Sopenharmony_ci		goto fail;
10038e5b75505Sopenharmony_ci
10039e5b75505Sopenharmony_ci	dpp->controller = ctrl;
10040e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
10041e5b75505Sopenharmony_ci	return 0;
10042e5b75505Sopenharmony_cifail:
10043e5b75505Sopenharmony_ci	dpp_controller_free(ctrl);
10044e5b75505Sopenharmony_ci	return -1;
10045e5b75505Sopenharmony_ci}
10046e5b75505Sopenharmony_ci
10047e5b75505Sopenharmony_ci
10048e5b75505Sopenharmony_civoid dpp_controller_stop(struct dpp_global *dpp)
10049e5b75505Sopenharmony_ci{
10050e5b75505Sopenharmony_ci	if (dpp) {
10051e5b75505Sopenharmony_ci		dpp_controller_free(dpp->controller);
10052e5b75505Sopenharmony_ci		dpp->controller = NULL;
10053e5b75505Sopenharmony_ci	}
10054e5b75505Sopenharmony_ci}
10055e5b75505Sopenharmony_ci
10056e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */
10057