xref: /freebsd/contrib/wpa/src/common/dpp_crypto.c (revision db0ac6ded61105caab4700aeac255328d4238dc4)
1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert  * DPP crypto functionality
3c1d255d3SCy Schubert  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert  * Copyright (c) 2018-2020, The Linux Foundation
5c1d255d3SCy Schubert  *
6c1d255d3SCy Schubert  * This software may be distributed under the terms of the BSD license.
7c1d255d3SCy Schubert  * See README for more details.
8c1d255d3SCy Schubert  */
9c1d255d3SCy Schubert 
10c1d255d3SCy Schubert #include "utils/includes.h"
11*db0ac6deSCy Schubert #include <openssl/opensslv.h>
12*db0ac6deSCy Schubert #include <openssl/err.h>
13*db0ac6deSCy Schubert #include <openssl/asn1.h>
14*db0ac6deSCy Schubert #include <openssl/asn1t.h>
15*db0ac6deSCy Schubert #include <openssl/pem.h>
16c1d255d3SCy Schubert 
17c1d255d3SCy Schubert #include "utils/common.h"
18c1d255d3SCy Schubert #include "utils/base64.h"
19c1d255d3SCy Schubert #include "utils/json.h"
20c1d255d3SCy Schubert #include "common/ieee802_11_defs.h"
21c1d255d3SCy Schubert #include "crypto/crypto.h"
22c1d255d3SCy Schubert #include "crypto/random.h"
23c1d255d3SCy Schubert #include "crypto/sha384.h"
24c1d255d3SCy Schubert #include "crypto/sha512.h"
25c1d255d3SCy Schubert #include "dpp.h"
26c1d255d3SCy Schubert #include "dpp_i.h"
27c1d255d3SCy Schubert 
28c1d255d3SCy Schubert 
29*db0ac6deSCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
30*db0ac6deSCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && \
31*db0ac6deSCy Schubert 	 LIBRESSL_VERSION_NUMBER < 0x20700000L)
32*db0ac6deSCy Schubert /* Compatibility wrappers for older versions. */
33*db0ac6deSCy Schubert 
34*db0ac6deSCy Schubert static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
35*db0ac6deSCy Schubert {
36*db0ac6deSCy Schubert 	sig->r = r;
37*db0ac6deSCy Schubert 	sig->s = s;
38*db0ac6deSCy Schubert 	return 1;
39*db0ac6deSCy Schubert }
40*db0ac6deSCy Schubert 
41*db0ac6deSCy Schubert 
42*db0ac6deSCy Schubert static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
43*db0ac6deSCy Schubert 			   const BIGNUM **ps)
44*db0ac6deSCy Schubert {
45*db0ac6deSCy Schubert 	if (pr)
46*db0ac6deSCy Schubert 		*pr = sig->r;
47*db0ac6deSCy Schubert 	if (ps)
48*db0ac6deSCy Schubert 		*ps = sig->s;
49*db0ac6deSCy Schubert }
50*db0ac6deSCy Schubert 
51*db0ac6deSCy Schubert 
52*db0ac6deSCy Schubert static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
53*db0ac6deSCy Schubert {
54*db0ac6deSCy Schubert 	if (pkey->type != EVP_PKEY_EC)
55*db0ac6deSCy Schubert 		return NULL;
56*db0ac6deSCy Schubert 	return pkey->pkey.ec;
57*db0ac6deSCy Schubert }
58*db0ac6deSCy Schubert 
59*db0ac6deSCy Schubert #endif
60*db0ac6deSCy Schubert 
61c1d255d3SCy Schubert static const struct dpp_curve_params dpp_curves[] = {
62c1d255d3SCy Schubert 	/* The mandatory to support and the default NIST P-256 curve needs to
63c1d255d3SCy Schubert 	 * be the first entry on this list. */
64c1d255d3SCy Schubert 	{ "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
65c1d255d3SCy Schubert 	{ "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
66c1d255d3SCy Schubert 	{ "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
67c1d255d3SCy Schubert 	{ "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
68c1d255d3SCy Schubert 	{ "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
69c1d255d3SCy Schubert 	{ "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
70c1d255d3SCy Schubert 	{ NULL, 0, 0, 0, 0, NULL, 0, NULL }
71c1d255d3SCy Schubert };
72c1d255d3SCy Schubert 
73c1d255d3SCy Schubert 
74c1d255d3SCy Schubert const struct dpp_curve_params * dpp_get_curve_name(const char *name)
75c1d255d3SCy Schubert {
76c1d255d3SCy Schubert 	int i;
77c1d255d3SCy Schubert 
78c1d255d3SCy Schubert 	if (!name)
79c1d255d3SCy Schubert 		return &dpp_curves[0];
80c1d255d3SCy Schubert 
81c1d255d3SCy Schubert 	for (i = 0; dpp_curves[i].name; i++) {
82c1d255d3SCy Schubert 		if (os_strcmp(name, dpp_curves[i].name) == 0 ||
83c1d255d3SCy Schubert 		    (dpp_curves[i].jwk_crv &&
84c1d255d3SCy Schubert 		     os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
85c1d255d3SCy Schubert 			return &dpp_curves[i];
86c1d255d3SCy Schubert 	}
87c1d255d3SCy Schubert 	return NULL;
88c1d255d3SCy Schubert }
89c1d255d3SCy Schubert 
90c1d255d3SCy Schubert 
91c1d255d3SCy Schubert const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name)
92c1d255d3SCy Schubert {
93c1d255d3SCy Schubert 	int i;
94c1d255d3SCy Schubert 
95c1d255d3SCy Schubert 	for (i = 0; dpp_curves[i].name; i++) {
96c1d255d3SCy Schubert 		if (dpp_curves[i].jwk_crv &&
97c1d255d3SCy Schubert 		    os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
98c1d255d3SCy Schubert 			return &dpp_curves[i];
99c1d255d3SCy Schubert 	}
100c1d255d3SCy Schubert 	return NULL;
101c1d255d3SCy Schubert }
102c1d255d3SCy Schubert 
103c1d255d3SCy Schubert 
104*db0ac6deSCy Schubert static const struct dpp_curve_params *
105*db0ac6deSCy Schubert dpp_get_curve_oid(const ASN1_OBJECT *poid)
106*db0ac6deSCy Schubert {
107*db0ac6deSCy Schubert 	ASN1_OBJECT *oid;
108*db0ac6deSCy Schubert 	int i;
109*db0ac6deSCy Schubert 
110*db0ac6deSCy Schubert 	for (i = 0; dpp_curves[i].name; i++) {
111*db0ac6deSCy Schubert 		oid = OBJ_txt2obj(dpp_curves[i].name, 0);
112*db0ac6deSCy Schubert 		if (oid && OBJ_cmp(poid, oid) == 0)
113*db0ac6deSCy Schubert 			return &dpp_curves[i];
114*db0ac6deSCy Schubert 	}
115*db0ac6deSCy Schubert 	return NULL;
116*db0ac6deSCy Schubert }
117*db0ac6deSCy Schubert 
118*db0ac6deSCy Schubert 
119*db0ac6deSCy Schubert const struct dpp_curve_params * dpp_get_curve_nid(int nid)
120*db0ac6deSCy Schubert {
121*db0ac6deSCy Schubert 	int i, tmp;
122*db0ac6deSCy Schubert 
123*db0ac6deSCy Schubert 	if (!nid)
124*db0ac6deSCy Schubert 		return NULL;
125*db0ac6deSCy Schubert 	for (i = 0; dpp_curves[i].name; i++) {
126*db0ac6deSCy Schubert 		tmp = OBJ_txt2nid(dpp_curves[i].name);
127*db0ac6deSCy Schubert 		if (tmp == nid)
128*db0ac6deSCy Schubert 			return &dpp_curves[i];
129*db0ac6deSCy Schubert 	}
130*db0ac6deSCy Schubert 	return NULL;
131*db0ac6deSCy Schubert }
132*db0ac6deSCy Schubert 
133*db0ac6deSCy Schubert 
134c1d255d3SCy Schubert const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
135c1d255d3SCy Schubert {
136c1d255d3SCy Schubert 	int i;
137c1d255d3SCy Schubert 
138c1d255d3SCy Schubert 	for (i = 0; dpp_curves[i].name; i++) {
139c1d255d3SCy Schubert 		if (dpp_curves[i].ike_group == group)
140c1d255d3SCy Schubert 			return &dpp_curves[i];
141c1d255d3SCy Schubert 	}
142c1d255d3SCy Schubert 	return NULL;
143c1d255d3SCy Schubert }
144c1d255d3SCy Schubert 
145c1d255d3SCy Schubert 
146*db0ac6deSCy Schubert void dpp_debug_print_point(const char *title, const EC_GROUP *group,
147*db0ac6deSCy Schubert 			   const EC_POINT *point)
148c1d255d3SCy Schubert {
149*db0ac6deSCy Schubert 	BIGNUM *x, *y;
150*db0ac6deSCy Schubert 	BN_CTX *ctx;
151*db0ac6deSCy Schubert 	char *x_str = NULL, *y_str = NULL;
152c1d255d3SCy Schubert 
153*db0ac6deSCy Schubert 	if (!wpa_debug_show_keys)
154*db0ac6deSCy Schubert 		return;
155c1d255d3SCy Schubert 
156*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
157*db0ac6deSCy Schubert 	x = BN_new();
158*db0ac6deSCy Schubert 	y = BN_new();
159*db0ac6deSCy Schubert 	if (!ctx || !x || !y ||
160*db0ac6deSCy Schubert 	    EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
161*db0ac6deSCy Schubert 		goto fail;
162*db0ac6deSCy Schubert 
163*db0ac6deSCy Schubert 	x_str = BN_bn2hex(x);
164*db0ac6deSCy Schubert 	y_str = BN_bn2hex(y);
165*db0ac6deSCy Schubert 	if (!x_str || !y_str)
166*db0ac6deSCy Schubert 		goto fail;
167*db0ac6deSCy Schubert 
168*db0ac6deSCy Schubert 	wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
169*db0ac6deSCy Schubert 
170*db0ac6deSCy Schubert fail:
171*db0ac6deSCy Schubert 	OPENSSL_free(x_str);
172*db0ac6deSCy Schubert 	OPENSSL_free(y_str);
173*db0ac6deSCy Schubert 	BN_free(x);
174*db0ac6deSCy Schubert 	BN_free(y);
175*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
176c1d255d3SCy Schubert }
177c1d255d3SCy Schubert 
178*db0ac6deSCy Schubert 
179*db0ac6deSCy Schubert void dpp_debug_print_key(const char *title, EVP_PKEY *key)
180*db0ac6deSCy Schubert {
181*db0ac6deSCy Schubert 	EC_KEY *eckey;
182*db0ac6deSCy Schubert 	BIO *out;
183*db0ac6deSCy Schubert 	size_t rlen;
184*db0ac6deSCy Schubert 	char *txt;
185*db0ac6deSCy Schubert 	int res;
186*db0ac6deSCy Schubert 	unsigned char *der = NULL;
187*db0ac6deSCy Schubert 	int der_len;
188*db0ac6deSCy Schubert 	const EC_GROUP *group;
189*db0ac6deSCy Schubert 	const EC_POINT *point;
190*db0ac6deSCy Schubert 
191*db0ac6deSCy Schubert 	out = BIO_new(BIO_s_mem());
192*db0ac6deSCy Schubert 	if (!out)
193*db0ac6deSCy Schubert 		return;
194*db0ac6deSCy Schubert 
195*db0ac6deSCy Schubert 	EVP_PKEY_print_private(out, key, 0, NULL);
196*db0ac6deSCy Schubert 	rlen = BIO_ctrl_pending(out);
197*db0ac6deSCy Schubert 	txt = os_malloc(rlen + 1);
198*db0ac6deSCy Schubert 	if (txt) {
199*db0ac6deSCy Schubert 		res = BIO_read(out, txt, rlen);
200*db0ac6deSCy Schubert 		if (res > 0) {
201*db0ac6deSCy Schubert 			txt[res] = '\0';
202*db0ac6deSCy Schubert 			wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
203*db0ac6deSCy Schubert 		}
204*db0ac6deSCy Schubert 		os_free(txt);
205*db0ac6deSCy Schubert 	}
206*db0ac6deSCy Schubert 	BIO_free(out);
207*db0ac6deSCy Schubert 
208*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get1_EC_KEY(key);
209*db0ac6deSCy Schubert 	if (!eckey)
210*db0ac6deSCy Schubert 		return;
211*db0ac6deSCy Schubert 
212*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
213*db0ac6deSCy Schubert 	point = EC_KEY_get0_public_key(eckey);
214*db0ac6deSCy Schubert 	if (group && point)
215*db0ac6deSCy Schubert 		dpp_debug_print_point(title, group, point);
216*db0ac6deSCy Schubert 
217*db0ac6deSCy Schubert 	der_len = i2d_ECPrivateKey(eckey, &der);
218*db0ac6deSCy Schubert 	if (der_len > 0)
219*db0ac6deSCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
220*db0ac6deSCy Schubert 	OPENSSL_free(der);
221*db0ac6deSCy Schubert 	if (der_len <= 0) {
222*db0ac6deSCy Schubert 		der = NULL;
223*db0ac6deSCy Schubert 		der_len = i2d_EC_PUBKEY(eckey, &der);
224*db0ac6deSCy Schubert 		if (der_len > 0)
225*db0ac6deSCy Schubert 			wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
226*db0ac6deSCy Schubert 		OPENSSL_free(der);
227*db0ac6deSCy Schubert 	}
228*db0ac6deSCy Schubert 
229*db0ac6deSCy Schubert 	EC_KEY_free(eckey);
230c1d255d3SCy Schubert }
231c1d255d3SCy Schubert 
232c1d255d3SCy Schubert 
233c1d255d3SCy Schubert static int dpp_hash_vector(const struct dpp_curve_params *curve,
234c1d255d3SCy Schubert 			   size_t num_elem, const u8 *addr[], const size_t *len,
235c1d255d3SCy Schubert 			   u8 *mac)
236c1d255d3SCy Schubert {
237c1d255d3SCy Schubert 	if (curve->hash_len == 32)
238c1d255d3SCy Schubert 		return sha256_vector(num_elem, addr, len, mac);
239c1d255d3SCy Schubert 	if (curve->hash_len == 48)
240c1d255d3SCy Schubert 		return sha384_vector(num_elem, addr, len, mac);
241c1d255d3SCy Schubert 	if (curve->hash_len == 64)
242c1d255d3SCy Schubert 		return sha512_vector(num_elem, addr, len, mac);
243c1d255d3SCy Schubert 	return -1;
244c1d255d3SCy Schubert }
245c1d255d3SCy Schubert 
246c1d255d3SCy Schubert 
247c1d255d3SCy Schubert int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
248c1d255d3SCy Schubert 		    const char *label, u8 *out, size_t outlen)
249c1d255d3SCy Schubert {
250c1d255d3SCy Schubert 	if (hash_len == 32)
251c1d255d3SCy Schubert 		return hmac_sha256_kdf(secret, secret_len, NULL,
252c1d255d3SCy Schubert 				       (const u8 *) label, os_strlen(label),
253c1d255d3SCy Schubert 				       out, outlen);
254c1d255d3SCy Schubert 	if (hash_len == 48)
255c1d255d3SCy Schubert 		return hmac_sha384_kdf(secret, secret_len, NULL,
256c1d255d3SCy Schubert 				       (const u8 *) label, os_strlen(label),
257c1d255d3SCy Schubert 				       out, outlen);
258c1d255d3SCy Schubert 	if (hash_len == 64)
259c1d255d3SCy Schubert 		return hmac_sha512_kdf(secret, secret_len, NULL,
260c1d255d3SCy Schubert 				       (const u8 *) label, os_strlen(label),
261c1d255d3SCy Schubert 				       out, outlen);
262c1d255d3SCy Schubert 	return -1;
263c1d255d3SCy Schubert }
264c1d255d3SCy Schubert 
265c1d255d3SCy Schubert 
266c1d255d3SCy Schubert int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
267c1d255d3SCy Schubert 		    size_t num_elem, const u8 *addr[], const size_t *len,
268c1d255d3SCy Schubert 		    u8 *mac)
269c1d255d3SCy Schubert {
270c1d255d3SCy Schubert 	if (hash_len == 32)
271c1d255d3SCy Schubert 		return hmac_sha256_vector(key, key_len, num_elem, addr, len,
272c1d255d3SCy Schubert 					  mac);
273c1d255d3SCy Schubert 	if (hash_len == 48)
274c1d255d3SCy Schubert 		return hmac_sha384_vector(key, key_len, num_elem, addr, len,
275c1d255d3SCy Schubert 					  mac);
276c1d255d3SCy Schubert 	if (hash_len == 64)
277c1d255d3SCy Schubert 		return hmac_sha512_vector(key, key_len, num_elem, addr, len,
278c1d255d3SCy Schubert 					  mac);
279c1d255d3SCy Schubert 	return -1;
280c1d255d3SCy Schubert }
281c1d255d3SCy Schubert 
282c1d255d3SCy Schubert 
283c1d255d3SCy Schubert static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
284c1d255d3SCy Schubert 		    const u8 *data, size_t data_len, u8 *mac)
285c1d255d3SCy Schubert {
286c1d255d3SCy Schubert 	if (hash_len == 32)
287c1d255d3SCy Schubert 		return hmac_sha256(key, key_len, data, data_len, mac);
288c1d255d3SCy Schubert 	if (hash_len == 48)
289c1d255d3SCy Schubert 		return hmac_sha384(key, key_len, data, data_len, mac);
290c1d255d3SCy Schubert 	if (hash_len == 64)
291c1d255d3SCy Schubert 		return hmac_sha512(key, key_len, data, data_len, mac);
292c1d255d3SCy Schubert 	return -1;
293c1d255d3SCy Schubert }
294c1d255d3SCy Schubert 
295c1d255d3SCy Schubert 
296c1d255d3SCy Schubert #ifdef CONFIG_DPP2
297c1d255d3SCy Schubert 
298c1d255d3SCy Schubert static int dpp_pbkdf2_f(size_t hash_len,
299c1d255d3SCy Schubert 			const u8 *password, size_t password_len,
300c1d255d3SCy Schubert 			const u8 *salt, size_t salt_len,
301c1d255d3SCy Schubert 			unsigned int iterations, unsigned int count, u8 *digest)
302c1d255d3SCy Schubert {
303c1d255d3SCy Schubert 	unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
304c1d255d3SCy Schubert 	unsigned int i;
305c1d255d3SCy Schubert 	size_t j;
306c1d255d3SCy Schubert 	u8 count_buf[4];
307c1d255d3SCy Schubert 	const u8 *addr[2];
308c1d255d3SCy Schubert 	size_t len[2];
309c1d255d3SCy Schubert 
310c1d255d3SCy Schubert 	addr[0] = salt;
311c1d255d3SCy Schubert 	len[0] = salt_len;
312c1d255d3SCy Schubert 	addr[1] = count_buf;
313c1d255d3SCy Schubert 	len[1] = 4;
314c1d255d3SCy Schubert 
315c1d255d3SCy Schubert 	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
316c1d255d3SCy Schubert 	 * U1 = PRF(P, S || i)
317c1d255d3SCy Schubert 	 * U2 = PRF(P, U1)
318c1d255d3SCy Schubert 	 * Uc = PRF(P, Uc-1)
319c1d255d3SCy Schubert 	 */
320c1d255d3SCy Schubert 
321c1d255d3SCy Schubert 	WPA_PUT_BE32(count_buf, count);
322c1d255d3SCy Schubert 	if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
323c1d255d3SCy Schubert 			    tmp))
324c1d255d3SCy Schubert 		return -1;
325c1d255d3SCy Schubert 	os_memcpy(digest, tmp, hash_len);
326c1d255d3SCy Schubert 
327c1d255d3SCy Schubert 	for (i = 1; i < iterations; i++) {
328c1d255d3SCy Schubert 		if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
329c1d255d3SCy Schubert 			     tmp2))
330c1d255d3SCy Schubert 			return -1;
331c1d255d3SCy Schubert 		os_memcpy(tmp, tmp2, hash_len);
332c1d255d3SCy Schubert 		for (j = 0; j < hash_len; j++)
333c1d255d3SCy Schubert 			digest[j] ^= tmp2[j];
334c1d255d3SCy Schubert 	}
335c1d255d3SCy Schubert 
336c1d255d3SCy Schubert 	return 0;
337c1d255d3SCy Schubert }
338c1d255d3SCy Schubert 
339c1d255d3SCy Schubert 
340c1d255d3SCy Schubert int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
341c1d255d3SCy Schubert 	       const u8 *salt, size_t salt_len, unsigned int iterations,
342c1d255d3SCy Schubert 	       u8 *buf, size_t buflen)
343c1d255d3SCy Schubert {
344c1d255d3SCy Schubert 	unsigned int count = 0;
345c1d255d3SCy Schubert 	unsigned char *pos = buf;
346c1d255d3SCy Schubert 	size_t left = buflen, plen;
347c1d255d3SCy Schubert 	unsigned char digest[DPP_MAX_HASH_LEN];
348c1d255d3SCy Schubert 
349c1d255d3SCy Schubert 	while (left > 0) {
350c1d255d3SCy Schubert 		count++;
351c1d255d3SCy Schubert 		if (dpp_pbkdf2_f(hash_len, password, password_len,
352c1d255d3SCy Schubert 				 salt, salt_len, iterations, count, digest))
353c1d255d3SCy Schubert 			return -1;
354c1d255d3SCy Schubert 		plen = left > hash_len ? hash_len : left;
355c1d255d3SCy Schubert 		os_memcpy(pos, digest, plen);
356c1d255d3SCy Schubert 		pos += plen;
357c1d255d3SCy Schubert 		left -= plen;
358c1d255d3SCy Schubert 	}
359c1d255d3SCy Schubert 
360c1d255d3SCy Schubert 	return 0;
361c1d255d3SCy Schubert }
362c1d255d3SCy Schubert 
363c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
364c1d255d3SCy Schubert 
365c1d255d3SCy Schubert 
366*db0ac6deSCy Schubert int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
367c1d255d3SCy Schubert {
368*db0ac6deSCy Schubert 	int num_bytes, offset;
369*db0ac6deSCy Schubert 
370*db0ac6deSCy Schubert 	num_bytes = BN_num_bytes(bn);
371*db0ac6deSCy Schubert 	if ((size_t) num_bytes > len)
372*db0ac6deSCy Schubert 		return -1;
373*db0ac6deSCy Schubert 	offset = len - num_bytes;
374*db0ac6deSCy Schubert 	os_memset(pos, 0, offset);
375*db0ac6deSCy Schubert 	BN_bn2bin(bn, pos + offset);
376*db0ac6deSCy Schubert 	return 0;
377*db0ac6deSCy Schubert }
378*db0ac6deSCy Schubert 
379*db0ac6deSCy Schubert 
380*db0ac6deSCy Schubert struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
381*db0ac6deSCy Schubert {
382*db0ac6deSCy Schubert 	int len, res;
383*db0ac6deSCy Schubert 	EC_KEY *eckey;
384*db0ac6deSCy Schubert 	struct wpabuf *buf;
385*db0ac6deSCy Schubert 	unsigned char *pos;
386*db0ac6deSCy Schubert 
387*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get1_EC_KEY(pkey);
388*db0ac6deSCy Schubert 	if (!eckey)
389*db0ac6deSCy Schubert 		return NULL;
390*db0ac6deSCy Schubert 	EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
391*db0ac6deSCy Schubert 	len = i2o_ECPublicKey(eckey, NULL);
392*db0ac6deSCy Schubert 	if (len <= 0) {
393*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
394*db0ac6deSCy Schubert 			   "DDP: Failed to determine public key encoding length");
395*db0ac6deSCy Schubert 		EC_KEY_free(eckey);
396*db0ac6deSCy Schubert 		return NULL;
397*db0ac6deSCy Schubert 	}
398*db0ac6deSCy Schubert 
399*db0ac6deSCy Schubert 	buf = wpabuf_alloc(len);
400*db0ac6deSCy Schubert 	if (!buf) {
401*db0ac6deSCy Schubert 		EC_KEY_free(eckey);
402*db0ac6deSCy Schubert 		return NULL;
403*db0ac6deSCy Schubert 	}
404*db0ac6deSCy Schubert 
405*db0ac6deSCy Schubert 	pos = wpabuf_put(buf, len);
406*db0ac6deSCy Schubert 	res = i2o_ECPublicKey(eckey, &pos);
407*db0ac6deSCy Schubert 	EC_KEY_free(eckey);
408*db0ac6deSCy Schubert 	if (res != len) {
409*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
410*db0ac6deSCy Schubert 			   "DDP: Failed to encode public key (res=%d/%d)",
411*db0ac6deSCy Schubert 			   res, len);
412*db0ac6deSCy Schubert 		wpabuf_free(buf);
413*db0ac6deSCy Schubert 		return NULL;
414*db0ac6deSCy Schubert 	}
415*db0ac6deSCy Schubert 
416*db0ac6deSCy Schubert 	if (!prefix) {
417*db0ac6deSCy Schubert 		/* Remove 0x04 prefix to match DPP definition */
418*db0ac6deSCy Schubert 		pos = wpabuf_mhead(buf);
419*db0ac6deSCy Schubert 		os_memmove(pos, pos + 1, len - 1);
420*db0ac6deSCy Schubert 		buf->used--;
421*db0ac6deSCy Schubert 	}
422*db0ac6deSCy Schubert 
423*db0ac6deSCy Schubert 	return buf;
424*db0ac6deSCy Schubert }
425*db0ac6deSCy Schubert 
426*db0ac6deSCy Schubert 
427*db0ac6deSCy Schubert EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
428*db0ac6deSCy Schubert 				      const u8 *buf_x, const u8 *buf_y,
429*db0ac6deSCy Schubert 				      size_t len)
430*db0ac6deSCy Schubert {
431*db0ac6deSCy Schubert 	EC_KEY *eckey = NULL;
432*db0ac6deSCy Schubert 	BN_CTX *ctx;
433*db0ac6deSCy Schubert 	EC_POINT *point = NULL;
434*db0ac6deSCy Schubert 	BIGNUM *x = NULL, *y = NULL;
435*db0ac6deSCy Schubert 	EVP_PKEY *pkey = NULL;
436*db0ac6deSCy Schubert 
437*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
438*db0ac6deSCy Schubert 	if (!ctx) {
439*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Out of memory");
440*db0ac6deSCy Schubert 		return NULL;
441*db0ac6deSCy Schubert 	}
442*db0ac6deSCy Schubert 
443*db0ac6deSCy Schubert 	point = EC_POINT_new(group);
444*db0ac6deSCy Schubert 	x = BN_bin2bn(buf_x, len, NULL);
445*db0ac6deSCy Schubert 	y = BN_bin2bn(buf_y, len, NULL);
446*db0ac6deSCy Schubert 	if (!point || !x || !y) {
447*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Out of memory");
448*db0ac6deSCy Schubert 		goto fail;
449*db0ac6deSCy Schubert 	}
450*db0ac6deSCy Schubert 
451*db0ac6deSCy Schubert 	if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
452*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
453*db0ac6deSCy Schubert 			   "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
454*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
455*db0ac6deSCy Schubert 		goto fail;
456*db0ac6deSCy Schubert 	}
457*db0ac6deSCy Schubert 
458*db0ac6deSCy Schubert 	if (!EC_POINT_is_on_curve(group, point, ctx) ||
459*db0ac6deSCy Schubert 	    EC_POINT_is_at_infinity(group, point)) {
460*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Invalid point");
461*db0ac6deSCy Schubert 		goto fail;
462*db0ac6deSCy Schubert 	}
463*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
464*db0ac6deSCy Schubert 
465*db0ac6deSCy Schubert 	eckey = EC_KEY_new();
466*db0ac6deSCy Schubert 	if (!eckey ||
467*db0ac6deSCy Schubert 	    EC_KEY_set_group(eckey, group) != 1 ||
468*db0ac6deSCy Schubert 	    EC_KEY_set_public_key(eckey, point) != 1) {
469*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
470*db0ac6deSCy Schubert 			   "DPP: Failed to set EC_KEY: %s",
471*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
472*db0ac6deSCy Schubert 		goto fail;
473*db0ac6deSCy Schubert 	}
474*db0ac6deSCy Schubert 	EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
475*db0ac6deSCy Schubert 
476*db0ac6deSCy Schubert 	pkey = EVP_PKEY_new();
477*db0ac6deSCy Schubert 	if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
478*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
479*db0ac6deSCy Schubert 		goto fail;
480*db0ac6deSCy Schubert 	}
481*db0ac6deSCy Schubert 
482*db0ac6deSCy Schubert out:
483*db0ac6deSCy Schubert 	BN_free(x);
484*db0ac6deSCy Schubert 	BN_free(y);
485*db0ac6deSCy Schubert 	EC_KEY_free(eckey);
486*db0ac6deSCy Schubert 	EC_POINT_free(point);
487*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
488*db0ac6deSCy Schubert 	return pkey;
489*db0ac6deSCy Schubert fail:
490*db0ac6deSCy Schubert 	EVP_PKEY_free(pkey);
491*db0ac6deSCy Schubert 	pkey = NULL;
492*db0ac6deSCy Schubert 	goto out;
493*db0ac6deSCy Schubert }
494*db0ac6deSCy Schubert 
495*db0ac6deSCy Schubert 
496*db0ac6deSCy Schubert EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len)
497*db0ac6deSCy Schubert {
498*db0ac6deSCy Schubert 	const EC_KEY *eckey;
499*db0ac6deSCy Schubert 	const EC_GROUP *group;
500*db0ac6deSCy Schubert 	EVP_PKEY *pkey = NULL;
501c1d255d3SCy Schubert 
502c1d255d3SCy Schubert 	if (len & 1)
503c1d255d3SCy Schubert 		return NULL;
504c1d255d3SCy Schubert 
505*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get0_EC_KEY(group_key);
506*db0ac6deSCy Schubert 	if (!eckey) {
507*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
508*db0ac6deSCy Schubert 			   "DPP: Could not get EC_KEY from group_key");
509c1d255d3SCy Schubert 		return NULL;
510c1d255d3SCy Schubert 	}
511c1d255d3SCy Schubert 
512*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
513*db0ac6deSCy Schubert 	if (group)
514*db0ac6deSCy Schubert 		pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
515*db0ac6deSCy Schubert 						  len / 2);
516*db0ac6deSCy Schubert 	else
517*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
518*db0ac6deSCy Schubert 
519*db0ac6deSCy Schubert 	return pkey;
520c1d255d3SCy Schubert }
521c1d255d3SCy Schubert 
522c1d255d3SCy Schubert 
523*db0ac6deSCy Schubert EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
524c1d255d3SCy Schubert {
525*db0ac6deSCy Schubert 	EVP_PKEY_CTX *kctx = NULL;
526*db0ac6deSCy Schubert 	EC_KEY *ec_params = NULL;
527*db0ac6deSCy Schubert 	EVP_PKEY *params = NULL, *key = NULL;
528*db0ac6deSCy Schubert 	int nid;
529c1d255d3SCy Schubert 
530c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
531c1d255d3SCy Schubert 
532*db0ac6deSCy Schubert 	nid = OBJ_txt2nid(curve->name);
533*db0ac6deSCy Schubert 	if (nid == NID_undef) {
534*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
535*db0ac6deSCy Schubert 		return NULL;
536*db0ac6deSCy Schubert 	}
537*db0ac6deSCy Schubert 
538*db0ac6deSCy Schubert 	ec_params = EC_KEY_new_by_curve_name(nid);
539*db0ac6deSCy Schubert 	if (!ec_params) {
540*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
541*db0ac6deSCy Schubert 			   "DPP: Failed to generate EC_KEY parameters");
542*db0ac6deSCy Schubert 		goto fail;
543*db0ac6deSCy Schubert 	}
544*db0ac6deSCy Schubert 	EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
545*db0ac6deSCy Schubert 	params = EVP_PKEY_new();
546*db0ac6deSCy Schubert 	if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
547*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
548*db0ac6deSCy Schubert 			   "DPP: Failed to generate EVP_PKEY parameters");
549*db0ac6deSCy Schubert 		goto fail;
550*db0ac6deSCy Schubert 	}
551*db0ac6deSCy Schubert 
552*db0ac6deSCy Schubert 	kctx = EVP_PKEY_CTX_new(params, NULL);
553*db0ac6deSCy Schubert 	if (!kctx ||
554*db0ac6deSCy Schubert 	    EVP_PKEY_keygen_init(kctx) != 1 ||
555*db0ac6deSCy Schubert 	    EVP_PKEY_keygen(kctx, &key) != 1) {
556*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
557*db0ac6deSCy Schubert 		key = NULL;
558*db0ac6deSCy Schubert 		goto fail;
559*db0ac6deSCy Schubert 	}
560*db0ac6deSCy Schubert 
561*db0ac6deSCy Schubert 	if (wpa_debug_show_keys)
562c1d255d3SCy Schubert 		dpp_debug_print_key("Own generated key", key);
563c1d255d3SCy Schubert 
564*db0ac6deSCy Schubert fail:
565*db0ac6deSCy Schubert 	EC_KEY_free(ec_params);
566*db0ac6deSCy Schubert 	EVP_PKEY_free(params);
567*db0ac6deSCy Schubert 	EVP_PKEY_CTX_free(kctx);
568c1d255d3SCy Schubert 	return key;
569c1d255d3SCy Schubert }
570c1d255d3SCy Schubert 
571c1d255d3SCy Schubert 
572*db0ac6deSCy Schubert EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
573c1d255d3SCy Schubert 			   const u8 *privkey, size_t privkey_len)
574c1d255d3SCy Schubert {
575*db0ac6deSCy Schubert 	EVP_PKEY *pkey;
576*db0ac6deSCy Schubert 	EC_KEY *eckey;
577*db0ac6deSCy Schubert 	const EC_GROUP *group;
578*db0ac6deSCy Schubert 	int nid;
579c1d255d3SCy Schubert 
580*db0ac6deSCy Schubert 	pkey = EVP_PKEY_new();
581*db0ac6deSCy Schubert 	if (!pkey)
582*db0ac6deSCy Schubert 		return NULL;
583*db0ac6deSCy Schubert 	eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
584*db0ac6deSCy Schubert 	if (!eckey) {
585*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO,
586*db0ac6deSCy Schubert 			   "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
587*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
588*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
589c1d255d3SCy Schubert 		return NULL;
590c1d255d3SCy Schubert 	}
591*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
592*db0ac6deSCy Schubert 	if (!group) {
593*db0ac6deSCy Schubert 		EC_KEY_free(eckey);
594*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
595c1d255d3SCy Schubert 		return NULL;
596c1d255d3SCy Schubert 	}
597*db0ac6deSCy Schubert 	nid = EC_GROUP_get_curve_name(group);
598*db0ac6deSCy Schubert 	*curve = dpp_get_curve_nid(nid);
599c1d255d3SCy Schubert 	if (!*curve) {
600c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
601*db0ac6deSCy Schubert 			   "DPP: Unsupported curve (nid=%d) in pre-assigned key",
602*db0ac6deSCy Schubert 			   nid);
603*db0ac6deSCy Schubert 		EC_KEY_free(eckey);
604*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
605c1d255d3SCy Schubert 		return NULL;
606c1d255d3SCy Schubert 	}
607c1d255d3SCy Schubert 
608*db0ac6deSCy Schubert 	if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
609*db0ac6deSCy Schubert 		EC_KEY_free(eckey);
610*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
611*db0ac6deSCy Schubert 		return NULL;
612*db0ac6deSCy Schubert 	}
613*db0ac6deSCy Schubert 	return pkey;
614*db0ac6deSCy Schubert }
615*db0ac6deSCy Schubert 
616*db0ac6deSCy Schubert 
617*db0ac6deSCy Schubert typedef struct {
618*db0ac6deSCy Schubert 	/* AlgorithmIdentifier ecPublicKey with optional parameters present
619*db0ac6deSCy Schubert 	 * as an OID identifying the curve */
620*db0ac6deSCy Schubert 	X509_ALGOR *alg;
621*db0ac6deSCy Schubert 	/* Compressed format public key per ANSI X9.63 */
622*db0ac6deSCy Schubert 	ASN1_BIT_STRING *pub_key;
623*db0ac6deSCy Schubert } DPP_BOOTSTRAPPING_KEY;
624*db0ac6deSCy Schubert 
625*db0ac6deSCy Schubert ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
626*db0ac6deSCy Schubert 	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
627*db0ac6deSCy Schubert 	ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
628*db0ac6deSCy Schubert } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
629*db0ac6deSCy Schubert 
630*db0ac6deSCy Schubert IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
631*db0ac6deSCy Schubert 
632*db0ac6deSCy Schubert 
633*db0ac6deSCy Schubert static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
634*db0ac6deSCy Schubert {
635*db0ac6deSCy Schubert 	unsigned char *der = NULL;
636*db0ac6deSCy Schubert 	int der_len;
637*db0ac6deSCy Schubert 	const EC_KEY *eckey;
638*db0ac6deSCy Schubert 	struct wpabuf *ret = NULL;
639*db0ac6deSCy Schubert 	size_t len;
640*db0ac6deSCy Schubert 	const EC_GROUP *group;
641*db0ac6deSCy Schubert 	const EC_POINT *point;
642*db0ac6deSCy Schubert 	BN_CTX *ctx;
643*db0ac6deSCy Schubert 	DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
644*db0ac6deSCy Schubert 	int nid;
645*db0ac6deSCy Schubert 
646*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
647*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get0_EC_KEY(key);
648*db0ac6deSCy Schubert 	if (!ctx || !eckey)
649*db0ac6deSCy Schubert 		goto fail;
650*db0ac6deSCy Schubert 
651*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
652*db0ac6deSCy Schubert 	point = EC_KEY_get0_public_key(eckey);
653*db0ac6deSCy Schubert 	if (!group || !point)
654*db0ac6deSCy Schubert 		goto fail;
655*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: bootstrap public key", group, point);
656*db0ac6deSCy Schubert 	nid = EC_GROUP_get_curve_name(group);
657*db0ac6deSCy Schubert 
658*db0ac6deSCy Schubert 	bootstrap = DPP_BOOTSTRAPPING_KEY_new();
659*db0ac6deSCy Schubert 	if (!bootstrap ||
660*db0ac6deSCy Schubert 	    X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
661*db0ac6deSCy Schubert 			    V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
662*db0ac6deSCy Schubert 		goto fail;
663*db0ac6deSCy Schubert 
664*db0ac6deSCy Schubert 	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
665*db0ac6deSCy Schubert 				 NULL, 0, ctx);
666*db0ac6deSCy Schubert 	if (len == 0)
667*db0ac6deSCy Schubert 		goto fail;
668*db0ac6deSCy Schubert 
669*db0ac6deSCy Schubert 	der = OPENSSL_malloc(len);
670*db0ac6deSCy Schubert 	if (!der)
671*db0ac6deSCy Schubert 		goto fail;
672*db0ac6deSCy Schubert 	len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
673*db0ac6deSCy Schubert 				 der, len, ctx);
674*db0ac6deSCy Schubert 
675*db0ac6deSCy Schubert 	OPENSSL_free(bootstrap->pub_key->data);
676*db0ac6deSCy Schubert 	bootstrap->pub_key->data = der;
677*db0ac6deSCy Schubert 	der = NULL;
678*db0ac6deSCy Schubert 	bootstrap->pub_key->length = len;
679*db0ac6deSCy Schubert 	/* No unused bits */
680*db0ac6deSCy Schubert 	bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
681*db0ac6deSCy Schubert 	bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
682*db0ac6deSCy Schubert 
683*db0ac6deSCy Schubert 	der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
684*db0ac6deSCy Schubert 	if (der_len <= 0) {
685*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
686*db0ac6deSCy Schubert 			   "DDP: Failed to build DER encoded public key");
687*db0ac6deSCy Schubert 		goto fail;
688*db0ac6deSCy Schubert 	}
689*db0ac6deSCy Schubert 
690*db0ac6deSCy Schubert 	ret = wpabuf_alloc_copy(der, der_len);
691*db0ac6deSCy Schubert fail:
692*db0ac6deSCy Schubert 	DPP_BOOTSTRAPPING_KEY_free(bootstrap);
693*db0ac6deSCy Schubert 	OPENSSL_free(der);
694*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
695*db0ac6deSCy Schubert 	return ret;
696c1d255d3SCy Schubert }
697c1d255d3SCy Schubert 
698c1d255d3SCy Schubert 
699c1d255d3SCy Schubert int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
700c1d255d3SCy Schubert {
701c1d255d3SCy Schubert 	struct wpabuf *der;
702c1d255d3SCy Schubert 	int res;
703c1d255d3SCy Schubert 
704*db0ac6deSCy Schubert 	der = dpp_bootstrap_key_der(bi->pubkey);
705c1d255d3SCy Schubert 	if (!der)
706c1d255d3SCy Schubert 		return -1;
707c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
708c1d255d3SCy Schubert 			der);
709c1d255d3SCy Schubert 	res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
710c1d255d3SCy Schubert 	if (res < 0)
711c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
712c1d255d3SCy Schubert 	wpabuf_free(der);
713c1d255d3SCy Schubert 	return res;
714c1d255d3SCy Schubert }
715c1d255d3SCy Schubert 
716c1d255d3SCy Schubert 
717c1d255d3SCy Schubert int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
718c1d255d3SCy Schubert 	       const u8 *privkey, size_t privkey_len)
719c1d255d3SCy Schubert {
720c1d255d3SCy Schubert 	char *base64 = NULL;
721c1d255d3SCy Schubert 	char *pos, *end;
722c1d255d3SCy Schubert 	size_t len;
723c1d255d3SCy Schubert 	struct wpabuf *der = NULL;
724c1d255d3SCy Schubert 
725c1d255d3SCy Schubert 	bi->curve = dpp_get_curve_name(curve);
726c1d255d3SCy Schubert 	if (!bi->curve) {
727c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
728c1d255d3SCy Schubert 		return -1;
729c1d255d3SCy Schubert 	}
730c1d255d3SCy Schubert 
731c1d255d3SCy Schubert 	if (privkey)
732c1d255d3SCy Schubert 		bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
733c1d255d3SCy Schubert 	else
734c1d255d3SCy Schubert 		bi->pubkey = dpp_gen_keypair(bi->curve);
735c1d255d3SCy Schubert 	if (!bi->pubkey)
736c1d255d3SCy Schubert 		goto fail;
737c1d255d3SCy Schubert 	bi->own = 1;
738c1d255d3SCy Schubert 
739*db0ac6deSCy Schubert 	der = dpp_bootstrap_key_der(bi->pubkey);
740c1d255d3SCy Schubert 	if (!der)
741c1d255d3SCy Schubert 		goto fail;
742c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
743c1d255d3SCy Schubert 			der);
744c1d255d3SCy Schubert 
745c1d255d3SCy Schubert 	if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
746c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
747c1d255d3SCy Schubert 		goto fail;
748c1d255d3SCy Schubert 	}
749c1d255d3SCy Schubert 
750c1d255d3SCy Schubert 	base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
751c1d255d3SCy Schubert 	wpabuf_free(der);
752c1d255d3SCy Schubert 	der = NULL;
753c1d255d3SCy Schubert 	if (!base64)
754c1d255d3SCy Schubert 		goto fail;
755c1d255d3SCy Schubert 	pos = base64;
756c1d255d3SCy Schubert 	end = pos + len;
757c1d255d3SCy Schubert 	for (;;) {
758c1d255d3SCy Schubert 		pos = os_strchr(pos, '\n');
759c1d255d3SCy Schubert 		if (!pos)
760c1d255d3SCy Schubert 			break;
761c1d255d3SCy Schubert 		os_memmove(pos, pos + 1, end - pos);
762c1d255d3SCy Schubert 	}
763c1d255d3SCy Schubert 	os_free(bi->pk);
764c1d255d3SCy Schubert 	bi->pk = base64;
765c1d255d3SCy Schubert 	return 0;
766c1d255d3SCy Schubert fail:
767c1d255d3SCy Schubert 	os_free(base64);
768c1d255d3SCy Schubert 	wpabuf_free(der);
769c1d255d3SCy Schubert 	return -1;
770c1d255d3SCy Schubert }
771c1d255d3SCy Schubert 
772c1d255d3SCy Schubert 
773c1d255d3SCy Schubert int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len)
774c1d255d3SCy Schubert {
775c1d255d3SCy Schubert 	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
776c1d255d3SCy Schubert 	const char *info = "first intermediate key";
777c1d255d3SCy Schubert 	int res;
778c1d255d3SCy Schubert 
779c1d255d3SCy Schubert 	/* k1 = HKDF(<>, "first intermediate key", M.x) */
780c1d255d3SCy Schubert 
781c1d255d3SCy Schubert 	/* HKDF-Extract(<>, M.x) */
782c1d255d3SCy Schubert 	os_memset(salt, 0, hash_len);
783c1d255d3SCy Schubert 	if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
784c1d255d3SCy Schubert 		return -1;
785c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
786c1d255d3SCy Schubert 			prk, hash_len);
787c1d255d3SCy Schubert 
788c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, info, L) */
789c1d255d3SCy Schubert 	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
790c1d255d3SCy Schubert 	os_memset(prk, 0, hash_len);
791c1d255d3SCy Schubert 	if (res < 0)
792c1d255d3SCy Schubert 		return -1;
793c1d255d3SCy Schubert 
794c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
795c1d255d3SCy Schubert 			k1, hash_len);
796c1d255d3SCy Schubert 	return 0;
797c1d255d3SCy Schubert }
798c1d255d3SCy Schubert 
799c1d255d3SCy Schubert 
800c1d255d3SCy Schubert int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len)
801c1d255d3SCy Schubert {
802c1d255d3SCy Schubert 	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
803c1d255d3SCy Schubert 	const char *info = "second intermediate key";
804c1d255d3SCy Schubert 	int res;
805c1d255d3SCy Schubert 
806c1d255d3SCy Schubert 	/* k2 = HKDF(<>, "second intermediate key", N.x) */
807c1d255d3SCy Schubert 
808c1d255d3SCy Schubert 	/* HKDF-Extract(<>, N.x) */
809c1d255d3SCy Schubert 	os_memset(salt, 0, hash_len);
810c1d255d3SCy Schubert 	res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
811c1d255d3SCy Schubert 	if (res < 0)
812c1d255d3SCy Schubert 		return -1;
813c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
814c1d255d3SCy Schubert 			prk, hash_len);
815c1d255d3SCy Schubert 
816c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, info, L) */
817c1d255d3SCy Schubert 	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
818c1d255d3SCy Schubert 	os_memset(prk, 0, hash_len);
819c1d255d3SCy Schubert 	if (res < 0)
820c1d255d3SCy Schubert 		return -1;
821c1d255d3SCy Schubert 
822c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
823c1d255d3SCy Schubert 			k2, hash_len);
824c1d255d3SCy Schubert 	return 0;
825c1d255d3SCy Schubert }
826c1d255d3SCy Schubert 
827c1d255d3SCy Schubert 
828c1d255d3SCy Schubert int dpp_derive_bk_ke(struct dpp_authentication *auth)
829c1d255d3SCy Schubert {
830c1d255d3SCy Schubert 	unsigned int hash_len = auth->curve->hash_len;
831c1d255d3SCy Schubert 	size_t nonce_len = auth->curve->nonce_len;
832c1d255d3SCy Schubert 	u8 nonces[2 * DPP_MAX_NONCE_LEN];
833c1d255d3SCy Schubert 	const char *info_ke = "DPP Key";
834c1d255d3SCy Schubert 	int res;
835c1d255d3SCy Schubert 	const u8 *addr[3];
836c1d255d3SCy Schubert 	size_t len[3];
837c1d255d3SCy Schubert 	size_t num_elem = 0;
838c1d255d3SCy Schubert 
839c1d255d3SCy Schubert 	if (!auth->Mx_len || !auth->Nx_len) {
840c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
841c1d255d3SCy Schubert 			   "DPP: Mx/Nx not available - cannot derive ke");
842c1d255d3SCy Schubert 		return -1;
843c1d255d3SCy Schubert 	}
844c1d255d3SCy Schubert 
845c1d255d3SCy Schubert 	/* bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
846c1d255d3SCy Schubert 	os_memcpy(nonces, auth->i_nonce, nonce_len);
847c1d255d3SCy Schubert 	os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
848c1d255d3SCy Schubert 	addr[num_elem] = auth->Mx;
849c1d255d3SCy Schubert 	len[num_elem] = auth->Mx_len;
850c1d255d3SCy Schubert 	num_elem++;
851c1d255d3SCy Schubert 	addr[num_elem] = auth->Nx;
852c1d255d3SCy Schubert 	len[num_elem] = auth->Nx_len;
853c1d255d3SCy Schubert 	num_elem++;
854c1d255d3SCy Schubert 	if (auth->peer_bi && auth->own_bi) {
855c1d255d3SCy Schubert 		if (!auth->Lx_len) {
856c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
857c1d255d3SCy Schubert 				   "DPP: Lx not available - cannot derive ke");
858c1d255d3SCy Schubert 			return -1;
859c1d255d3SCy Schubert 		}
860c1d255d3SCy Schubert 		addr[num_elem] = auth->Lx;
861c1d255d3SCy Schubert 		len[num_elem] = auth->secret_len;
862c1d255d3SCy Schubert 		num_elem++;
863c1d255d3SCy Schubert 	}
864c1d255d3SCy Schubert 	res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
865c1d255d3SCy Schubert 			      num_elem, addr, len, auth->bk);
866c1d255d3SCy Schubert 	if (res < 0)
867c1d255d3SCy Schubert 		return -1;
868c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
869c1d255d3SCy Schubert 			"DPP: bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x])",
870c1d255d3SCy Schubert 			auth->bk, hash_len);
871c1d255d3SCy Schubert 
872c1d255d3SCy Schubert 	/* ke = HKDF-Expand(bk, "DPP Key", length) */
873c1d255d3SCy Schubert 	res = dpp_hkdf_expand(hash_len, auth->bk, hash_len, info_ke, auth->ke,
874c1d255d3SCy Schubert 			      hash_len);
875c1d255d3SCy Schubert 	if (res < 0)
876c1d255d3SCy Schubert 		return -1;
877c1d255d3SCy Schubert 
878c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
879c1d255d3SCy Schubert 			"DPP: ke = HKDF-Expand(bk, \"DPP Key\", length)",
880c1d255d3SCy Schubert 			auth->ke, hash_len);
881c1d255d3SCy Schubert 
882c1d255d3SCy Schubert 	return 0;
883c1d255d3SCy Schubert }
884c1d255d3SCy Schubert 
885c1d255d3SCy Schubert 
886*db0ac6deSCy Schubert int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len)
887c1d255d3SCy Schubert {
888*db0ac6deSCy Schubert 	EVP_PKEY_CTX *ctx;
889c1d255d3SCy Schubert 	int ret = -1;
890c1d255d3SCy Schubert 
891*db0ac6deSCy Schubert 	ERR_clear_error();
892c1d255d3SCy Schubert 	*secret_len = 0;
893c1d255d3SCy Schubert 
894*db0ac6deSCy Schubert 	ctx = EVP_PKEY_CTX_new(own, NULL);
895*db0ac6deSCy Schubert 	if (!ctx) {
896*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
897*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
898c1d255d3SCy Schubert 		return -1;
899c1d255d3SCy Schubert 	}
900c1d255d3SCy Schubert 
901*db0ac6deSCy Schubert 	if (EVP_PKEY_derive_init(ctx) != 1) {
902*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
903*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
904*db0ac6deSCy Schubert 		goto fail;
905*db0ac6deSCy Schubert 	}
906*db0ac6deSCy Schubert 
907*db0ac6deSCy Schubert 	if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
908c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR,
909*db0ac6deSCy Schubert 			   "DPP: EVP_PKEY_derive_set_peet failed: %s",
910*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
911c1d255d3SCy Schubert 		goto fail;
912c1d255d3SCy Schubert 	}
913c1d255d3SCy Schubert 
914*db0ac6deSCy Schubert 	if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
915*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
916*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
917c1d255d3SCy Schubert 		goto fail;
918c1d255d3SCy Schubert 	}
919c1d255d3SCy Schubert 
920*db0ac6deSCy Schubert 	if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
921*db0ac6deSCy Schubert 		u8 buf[200];
922*db0ac6deSCy Schubert 		int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
923*db0ac6deSCy Schubert 
924*db0ac6deSCy Schubert 		/* It looks like OpenSSL can return unexpectedly large buffer
925*db0ac6deSCy Schubert 		 * need for shared secret from EVP_PKEY_derive(NULL) in some
926*db0ac6deSCy Schubert 		 * cases. For example, group 19 has shown cases where secret_len
927*db0ac6deSCy Schubert 		 * is set to 72 even though the actual length ends up being
928*db0ac6deSCy Schubert 		 * updated to 32 when EVP_PKEY_derive() is called with a buffer
929*db0ac6deSCy Schubert 		 * for the value. Work around this by trying to fetch the value
930*db0ac6deSCy Schubert 		 * and continue if it is within supported range even when the
931*db0ac6deSCy Schubert 		 * initial buffer need is claimed to be larger. */
932*db0ac6deSCy Schubert 		wpa_printf(level,
933*db0ac6deSCy Schubert 			   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
934*db0ac6deSCy Schubert 			   (int) *secret_len);
935*db0ac6deSCy Schubert 		if (*secret_len > 200)
936*db0ac6deSCy Schubert 			goto fail;
937*db0ac6deSCy Schubert 		if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
938*db0ac6deSCy Schubert 			wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
939*db0ac6deSCy Schubert 				   ERR_error_string(ERR_get_error(), NULL));
940*db0ac6deSCy Schubert 			goto fail;
941*db0ac6deSCy Schubert 		}
942*db0ac6deSCy Schubert 		if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
943*db0ac6deSCy Schubert 			wpa_printf(MSG_ERROR,
944*db0ac6deSCy Schubert 				   "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
945*db0ac6deSCy Schubert 				   (int) *secret_len);
946*db0ac6deSCy Schubert 			goto fail;
947*db0ac6deSCy Schubert 		}
948*db0ac6deSCy Schubert 		wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
949*db0ac6deSCy Schubert 				buf, *secret_len);
950*db0ac6deSCy Schubert 		os_memcpy(secret, buf, *secret_len);
951*db0ac6deSCy Schubert 		forced_memzero(buf, sizeof(buf));
952*db0ac6deSCy Schubert 		goto done;
953*db0ac6deSCy Schubert 	}
954*db0ac6deSCy Schubert 
955*db0ac6deSCy Schubert 	if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
956*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
957*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
958c1d255d3SCy Schubert 		goto fail;
959c1d255d3SCy Schubert 	}
960c1d255d3SCy Schubert 
961*db0ac6deSCy Schubert done:
962c1d255d3SCy Schubert 	ret = 0;
963c1d255d3SCy Schubert 
964c1d255d3SCy Schubert fail:
965*db0ac6deSCy Schubert 	EVP_PKEY_CTX_free(ctx);
966c1d255d3SCy Schubert 	return ret;
967c1d255d3SCy Schubert }
968c1d255d3SCy Schubert 
969c1d255d3SCy Schubert 
970c1d255d3SCy Schubert int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
971c1d255d3SCy Schubert 		       const u8 *data, size_t data_len)
972c1d255d3SCy Schubert {
973c1d255d3SCy Schubert 	const u8 *addr[2];
974c1d255d3SCy Schubert 	size_t len[2];
975c1d255d3SCy Schubert 
976c1d255d3SCy Schubert 	addr[0] = data;
977c1d255d3SCy Schubert 	len[0] = data_len;
978c1d255d3SCy Schubert 	if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
979c1d255d3SCy Schubert 		return -1;
980c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
981c1d255d3SCy Schubert 		    bi->pubkey_hash, SHA256_MAC_LEN);
982c1d255d3SCy Schubert 
983c1d255d3SCy Schubert 	addr[0] = (const u8 *) "chirp";
984c1d255d3SCy Schubert 	len[0] = 5;
985c1d255d3SCy Schubert 	addr[1] = data;
986c1d255d3SCy Schubert 	len[1] = data_len;
987c1d255d3SCy Schubert 	if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
988c1d255d3SCy Schubert 		return -1;
989c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
990c1d255d3SCy Schubert 		    bi->pubkey_hash_chirp, SHA256_MAC_LEN);
991c1d255d3SCy Schubert 
992c1d255d3SCy Schubert 	return 0;
993c1d255d3SCy Schubert }
994c1d255d3SCy Schubert 
995c1d255d3SCy Schubert 
996c1d255d3SCy Schubert int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
997c1d255d3SCy Schubert 			       const u8 *data, size_t data_len)
998c1d255d3SCy Schubert {
999*db0ac6deSCy Schubert 	EVP_PKEY *pkey;
1000*db0ac6deSCy Schubert 	const unsigned char *p;
1001*db0ac6deSCy Schubert 	int res;
1002*db0ac6deSCy Schubert 	X509_PUBKEY *pub = NULL;
1003*db0ac6deSCy Schubert 	ASN1_OBJECT *ppkalg;
1004*db0ac6deSCy Schubert 	const unsigned char *pk;
1005*db0ac6deSCy Schubert 	int ppklen;
1006*db0ac6deSCy Schubert 	X509_ALGOR *pa;
1007*db0ac6deSCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1008*db0ac6deSCy Schubert 	(defined(LIBRESSL_VERSION_NUMBER) && \
1009*db0ac6deSCy Schubert 	 LIBRESSL_VERSION_NUMBER < 0x20800000L)
1010*db0ac6deSCy Schubert 	ASN1_OBJECT *pa_oid;
1011*db0ac6deSCy Schubert #else
1012*db0ac6deSCy Schubert 	const ASN1_OBJECT *pa_oid;
1013*db0ac6deSCy Schubert #endif
1014*db0ac6deSCy Schubert 	const void *pval;
1015*db0ac6deSCy Schubert 	int ptype;
1016*db0ac6deSCy Schubert 	const ASN1_OBJECT *poid;
1017*db0ac6deSCy Schubert 	char buf[100];
1018c1d255d3SCy Schubert 
1019c1d255d3SCy Schubert 	if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
1020c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
1021c1d255d3SCy Schubert 		return -1;
1022c1d255d3SCy Schubert 	}
1023c1d255d3SCy Schubert 
1024*db0ac6deSCy Schubert 	/* DER encoded ASN.1 SubjectPublicKeyInfo
1025*db0ac6deSCy Schubert 	 *
1026*db0ac6deSCy Schubert 	 * SubjectPublicKeyInfo  ::=  SEQUENCE  {
1027*db0ac6deSCy Schubert 	 *      algorithm            AlgorithmIdentifier,
1028*db0ac6deSCy Schubert 	 *      subjectPublicKey     BIT STRING  }
1029*db0ac6deSCy Schubert 	 *
1030*db0ac6deSCy Schubert 	 * AlgorithmIdentifier  ::=  SEQUENCE  {
1031*db0ac6deSCy Schubert 	 *      algorithm               OBJECT IDENTIFIER,
1032*db0ac6deSCy Schubert 	 *      parameters              ANY DEFINED BY algorithm OPTIONAL  }
1033*db0ac6deSCy Schubert 	 *
1034*db0ac6deSCy Schubert 	 * subjectPublicKey = compressed format public key per ANSI X9.63
1035*db0ac6deSCy Schubert 	 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1036*db0ac6deSCy Schubert 	 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1037*db0ac6deSCy Schubert 	 *       prime256v1 (1.2.840.10045.3.1.7)
1038*db0ac6deSCy Schubert 	 */
1039*db0ac6deSCy Schubert 
1040*db0ac6deSCy Schubert 	p = data;
1041*db0ac6deSCy Schubert 	pkey = d2i_PUBKEY(NULL, &p, data_len);
1042*db0ac6deSCy Schubert 
1043*db0ac6deSCy Schubert 	if (!pkey) {
1044c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1045c1d255d3SCy Schubert 			   "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1046c1d255d3SCy Schubert 		return -1;
1047c1d255d3SCy Schubert 	}
1048c1d255d3SCy Schubert 
1049*db0ac6deSCy Schubert 	if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
1050c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1051*db0ac6deSCy Schubert 			   "DPP: SubjectPublicKeyInfo does not describe an EC key");
1052*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
1053*db0ac6deSCy Schubert 		return -1;
1054*db0ac6deSCy Schubert 	}
1055*db0ac6deSCy Schubert 
1056*db0ac6deSCy Schubert 	res = X509_PUBKEY_set(&pub, pkey);
1057*db0ac6deSCy Schubert 	if (res != 1) {
1058*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
1059c1d255d3SCy Schubert 		goto fail;
1060c1d255d3SCy Schubert 	}
1061c1d255d3SCy Schubert 
1062*db0ac6deSCy Schubert 	res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
1063*db0ac6deSCy Schubert 	if (res != 1) {
1064*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1065*db0ac6deSCy Schubert 			   "DPP: Could not extract SubjectPublicKeyInfo parameters");
1066*db0ac6deSCy Schubert 		goto fail;
1067*db0ac6deSCy Schubert 	}
1068*db0ac6deSCy Schubert 	res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
1069*db0ac6deSCy Schubert 	if (res < 0 || (size_t) res >= sizeof(buf)) {
1070*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1071*db0ac6deSCy Schubert 			   "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1072*db0ac6deSCy Schubert 		goto fail;
1073*db0ac6deSCy Schubert 	}
1074*db0ac6deSCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
1075*db0ac6deSCy Schubert 	if (os_strcmp(buf, "id-ecPublicKey") != 0) {
1076*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1077*db0ac6deSCy Schubert 			   "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1078*db0ac6deSCy Schubert 		goto fail;
1079*db0ac6deSCy Schubert 	}
1080*db0ac6deSCy Schubert 
1081*db0ac6deSCy Schubert 	X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
1082*db0ac6deSCy Schubert 	if (ptype != V_ASN1_OBJECT) {
1083*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1084*db0ac6deSCy Schubert 			   "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1085*db0ac6deSCy Schubert 		goto fail;
1086*db0ac6deSCy Schubert 	}
1087*db0ac6deSCy Schubert 	poid = pval;
1088*db0ac6deSCy Schubert 	res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
1089*db0ac6deSCy Schubert 	if (res < 0 || (size_t) res >= sizeof(buf)) {
1090*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1091*db0ac6deSCy Schubert 			   "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1092*db0ac6deSCy Schubert 		goto fail;
1093*db0ac6deSCy Schubert 	}
1094*db0ac6deSCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
1095*db0ac6deSCy Schubert 	bi->curve = dpp_get_curve_oid(poid);
1096*db0ac6deSCy Schubert 	if (!bi->curve) {
1097*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
1098*db0ac6deSCy Schubert 			   "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1099*db0ac6deSCy Schubert 			   buf);
1100*db0ac6deSCy Schubert 		goto fail;
1101*db0ac6deSCy Schubert 	}
1102*db0ac6deSCy Schubert 
1103*db0ac6deSCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
1104*db0ac6deSCy Schubert 
1105*db0ac6deSCy Schubert 	X509_PUBKEY_free(pub);
1106*db0ac6deSCy Schubert 	bi->pubkey = pkey;
1107c1d255d3SCy Schubert 	return 0;
1108c1d255d3SCy Schubert fail:
1109*db0ac6deSCy Schubert 	X509_PUBKEY_free(pub);
1110*db0ac6deSCy Schubert 	EVP_PKEY_free(pkey);
1111c1d255d3SCy Schubert 	return -1;
1112c1d255d3SCy Schubert }
1113c1d255d3SCy Schubert 
1114c1d255d3SCy Schubert 
1115c1d255d3SCy Schubert static struct wpabuf *
1116c1d255d3SCy Schubert dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
1117c1d255d3SCy Schubert 		       const u8 *prot_hdr, u16 prot_hdr_len,
1118*db0ac6deSCy Schubert 		       const EVP_MD **ret_md)
1119c1d255d3SCy Schubert {
1120c1d255d3SCy Schubert 	struct json_token *root, *token;
1121c1d255d3SCy Schubert 	struct wpabuf *kid = NULL;
1122c1d255d3SCy Schubert 
1123c1d255d3SCy Schubert 	root = json_parse((const char *) prot_hdr, prot_hdr_len);
1124c1d255d3SCy Schubert 	if (!root) {
1125c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1126c1d255d3SCy Schubert 			   "DPP: JSON parsing failed for JWS Protected Header");
1127c1d255d3SCy Schubert 		goto fail;
1128c1d255d3SCy Schubert 	}
1129c1d255d3SCy Schubert 
1130c1d255d3SCy Schubert 	if (root->type != JSON_OBJECT) {
1131c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1132c1d255d3SCy Schubert 			   "DPP: JWS Protected Header root is not an object");
1133c1d255d3SCy Schubert 		goto fail;
1134c1d255d3SCy Schubert 	}
1135c1d255d3SCy Schubert 
1136c1d255d3SCy Schubert 	token = json_get_member(root, "typ");
1137c1d255d3SCy Schubert 	if (!token || token->type != JSON_STRING) {
1138c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
1139c1d255d3SCy Schubert 		goto fail;
1140c1d255d3SCy Schubert 	}
1141c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
1142c1d255d3SCy Schubert 		   token->string);
1143c1d255d3SCy Schubert 	if (os_strcmp(token->string, "dppCon") != 0) {
1144c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1145c1d255d3SCy Schubert 			   "DPP: Unsupported JWS Protected Header typ=%s",
1146c1d255d3SCy Schubert 			   token->string);
1147c1d255d3SCy Schubert 		goto fail;
1148c1d255d3SCy Schubert 	}
1149c1d255d3SCy Schubert 
1150c1d255d3SCy Schubert 	token = json_get_member(root, "alg");
1151c1d255d3SCy Schubert 	if (!token || token->type != JSON_STRING) {
1152c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
1153c1d255d3SCy Schubert 		goto fail;
1154c1d255d3SCy Schubert 	}
1155c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
1156c1d255d3SCy Schubert 		   token->string);
1157c1d255d3SCy Schubert 	if (os_strcmp(token->string, curve->jws_alg) != 0) {
1158c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1159c1d255d3SCy Schubert 			   "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
1160c1d255d3SCy Schubert 			   token->string, curve->jws_alg);
1161c1d255d3SCy Schubert 		goto fail;
1162c1d255d3SCy Schubert 	}
1163c1d255d3SCy Schubert 	if (os_strcmp(token->string, "ES256") == 0 ||
1164*db0ac6deSCy Schubert 	    os_strcmp(token->string, "BS256") == 0)
1165*db0ac6deSCy Schubert 		*ret_md = EVP_sha256();
1166*db0ac6deSCy Schubert 	else if (os_strcmp(token->string, "ES384") == 0 ||
1167*db0ac6deSCy Schubert 		 os_strcmp(token->string, "BS384") == 0)
1168*db0ac6deSCy Schubert 		*ret_md = EVP_sha384();
1169*db0ac6deSCy Schubert 	else if (os_strcmp(token->string, "ES512") == 0 ||
1170*db0ac6deSCy Schubert 		 os_strcmp(token->string, "BS512") == 0)
1171*db0ac6deSCy Schubert 		*ret_md = EVP_sha512();
1172*db0ac6deSCy Schubert 	else
1173*db0ac6deSCy Schubert 		*ret_md = NULL;
1174*db0ac6deSCy Schubert 	if (!*ret_md) {
1175c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1176c1d255d3SCy Schubert 			   "DPP: Unsupported JWS Protected Header alg=%s",
1177c1d255d3SCy Schubert 			   token->string);
1178c1d255d3SCy Schubert 		goto fail;
1179c1d255d3SCy Schubert 	}
1180c1d255d3SCy Schubert 
1181c1d255d3SCy Schubert 	kid = json_get_member_base64url(root, "kid");
1182c1d255d3SCy Schubert 	if (!kid) {
1183c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
1184c1d255d3SCy Schubert 		goto fail;
1185c1d255d3SCy Schubert 	}
1186c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
1187c1d255d3SCy Schubert 			kid);
1188c1d255d3SCy Schubert 
1189c1d255d3SCy Schubert fail:
1190c1d255d3SCy Schubert 	json_free(root);
1191c1d255d3SCy Schubert 	return kid;
1192c1d255d3SCy Schubert }
1193c1d255d3SCy Schubert 
1194c1d255d3SCy Schubert 
1195*db0ac6deSCy Schubert static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
1196c1d255d3SCy Schubert {
1197c1d255d3SCy Schubert 	struct wpabuf *uncomp;
1198c1d255d3SCy Schubert 	int res;
1199c1d255d3SCy Schubert 	u8 hash[SHA256_MAC_LEN];
1200c1d255d3SCy Schubert 	const u8 *addr[1];
1201c1d255d3SCy Schubert 	size_t len[1];
1202c1d255d3SCy Schubert 
1203c1d255d3SCy Schubert 	if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
1204c1d255d3SCy Schubert 		return -1;
1205*db0ac6deSCy Schubert 	uncomp = dpp_get_pubkey_point(pub, 1);
1206c1d255d3SCy Schubert 	if (!uncomp)
1207c1d255d3SCy Schubert 		return -1;
1208c1d255d3SCy Schubert 	addr[0] = wpabuf_head(uncomp);
1209c1d255d3SCy Schubert 	len[0] = wpabuf_len(uncomp);
1210c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
1211c1d255d3SCy Schubert 		    addr[0], len[0]);
1212c1d255d3SCy Schubert 	res = sha256_vector(1, addr, len, hash);
1213c1d255d3SCy Schubert 	wpabuf_free(uncomp);
1214c1d255d3SCy Schubert 	if (res < 0)
1215c1d255d3SCy Schubert 		return -1;
1216c1d255d3SCy Schubert 	if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
1217c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1218c1d255d3SCy Schubert 			   "DPP: Received hash value does not match calculated public key hash value");
1219c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
1220c1d255d3SCy Schubert 			    hash, SHA256_MAC_LEN);
1221c1d255d3SCy Schubert 		return -1;
1222c1d255d3SCy Schubert 	}
1223c1d255d3SCy Schubert 	return 0;
1224c1d255d3SCy Schubert }
1225c1d255d3SCy Schubert 
1226c1d255d3SCy Schubert 
1227c1d255d3SCy Schubert enum dpp_status_error
1228c1d255d3SCy Schubert dpp_process_signed_connector(struct dpp_signed_connector_info *info,
1229*db0ac6deSCy Schubert 			     EVP_PKEY *csign_pub, const char *connector)
1230c1d255d3SCy Schubert {
1231c1d255d3SCy Schubert 	enum dpp_status_error ret = 255;
1232c1d255d3SCy Schubert 	const char *pos, *end, *signed_start, *signed_end;
1233c1d255d3SCy Schubert 	struct wpabuf *kid = NULL;
1234c1d255d3SCy Schubert 	unsigned char *prot_hdr = NULL, *signature = NULL;
1235*db0ac6deSCy Schubert 	size_t prot_hdr_len = 0, signature_len = 0;
1236*db0ac6deSCy Schubert 	const EVP_MD *sign_md = NULL;
1237*db0ac6deSCy Schubert 	unsigned char *der = NULL;
1238*db0ac6deSCy Schubert 	int der_len;
1239*db0ac6deSCy Schubert 	int res;
1240*db0ac6deSCy Schubert 	EVP_MD_CTX *md_ctx = NULL;
1241*db0ac6deSCy Schubert 	ECDSA_SIG *sig = NULL;
1242*db0ac6deSCy Schubert 	BIGNUM *r = NULL, *s = NULL;
1243c1d255d3SCy Schubert 	const struct dpp_curve_params *curve;
1244*db0ac6deSCy Schubert 	const EC_KEY *eckey;
1245*db0ac6deSCy Schubert 	const EC_GROUP *group;
1246*db0ac6deSCy Schubert 	int nid;
1247c1d255d3SCy Schubert 
1248*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get0_EC_KEY(csign_pub);
1249*db0ac6deSCy Schubert 	if (!eckey)
1250*db0ac6deSCy Schubert 		goto fail;
1251*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
1252*db0ac6deSCy Schubert 	if (!group)
1253*db0ac6deSCy Schubert 		goto fail;
1254*db0ac6deSCy Schubert 	nid = EC_GROUP_get_curve_name(group);
1255*db0ac6deSCy Schubert 	curve = dpp_get_curve_nid(nid);
1256c1d255d3SCy Schubert 	if (!curve)
1257c1d255d3SCy Schubert 		goto fail;
1258c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
1259c1d255d3SCy Schubert 	os_memset(info, 0, sizeof(*info));
1260c1d255d3SCy Schubert 
1261c1d255d3SCy Schubert 	signed_start = pos = connector;
1262c1d255d3SCy Schubert 	end = os_strchr(pos, '.');
1263c1d255d3SCy Schubert 	if (!end) {
1264c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
1265c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1266c1d255d3SCy Schubert 		goto fail;
1267c1d255d3SCy Schubert 	}
1268c1d255d3SCy Schubert 	prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
1269c1d255d3SCy Schubert 	if (!prot_hdr) {
1270c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1271c1d255d3SCy Schubert 			   "DPP: Failed to base64url decode signedConnector JWS Protected Header");
1272c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1273c1d255d3SCy Schubert 		goto fail;
1274c1d255d3SCy Schubert 	}
1275c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG,
1276c1d255d3SCy Schubert 			  "DPP: signedConnector - JWS Protected Header",
1277c1d255d3SCy Schubert 			  prot_hdr, prot_hdr_len);
1278*db0ac6deSCy Schubert 	kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
1279c1d255d3SCy Schubert 	if (!kid) {
1280c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1281c1d255d3SCy Schubert 		goto fail;
1282c1d255d3SCy Schubert 	}
1283c1d255d3SCy Schubert 	if (wpabuf_len(kid) != SHA256_MAC_LEN) {
1284c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1285c1d255d3SCy Schubert 			   "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
1286c1d255d3SCy Schubert 			   (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
1287c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1288c1d255d3SCy Schubert 		goto fail;
1289c1d255d3SCy Schubert 	}
1290c1d255d3SCy Schubert 
1291c1d255d3SCy Schubert 	pos = end + 1;
1292c1d255d3SCy Schubert 	end = os_strchr(pos, '.');
1293c1d255d3SCy Schubert 	if (!end) {
1294c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1295c1d255d3SCy Schubert 			   "DPP: Missing dot(2) in signedConnector");
1296c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1297c1d255d3SCy Schubert 		goto fail;
1298c1d255d3SCy Schubert 	}
1299c1d255d3SCy Schubert 	signed_end = end - 1;
1300c1d255d3SCy Schubert 	info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
1301c1d255d3SCy Schubert 	if (!info->payload) {
1302c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1303c1d255d3SCy Schubert 			   "DPP: Failed to base64url decode signedConnector JWS Payload");
1304c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1305c1d255d3SCy Schubert 		goto fail;
1306c1d255d3SCy Schubert 	}
1307c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG,
1308c1d255d3SCy Schubert 			  "DPP: signedConnector - JWS Payload",
1309c1d255d3SCy Schubert 			  info->payload, info->payload_len);
1310c1d255d3SCy Schubert 	pos = end + 1;
1311c1d255d3SCy Schubert 	signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
1312c1d255d3SCy Schubert 	if (!signature) {
1313c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1314c1d255d3SCy Schubert 			   "DPP: Failed to base64url decode signedConnector signature");
1315c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1316c1d255d3SCy Schubert 		goto fail;
1317c1d255d3SCy Schubert 		}
1318c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
1319c1d255d3SCy Schubert 		    signature, signature_len);
1320c1d255d3SCy Schubert 
1321c1d255d3SCy Schubert 	if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
1322c1d255d3SCy Schubert 		ret = DPP_STATUS_NO_MATCH;
1323c1d255d3SCy Schubert 		goto fail;
1324c1d255d3SCy Schubert 	}
1325c1d255d3SCy Schubert 
1326c1d255d3SCy Schubert 	if (signature_len & 0x01) {
1327c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1328c1d255d3SCy Schubert 			   "DPP: Unexpected signedConnector signature length (%d)",
1329c1d255d3SCy Schubert 			   (int) signature_len);
1330c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1331c1d255d3SCy Schubert 		goto fail;
1332c1d255d3SCy Schubert 	}
1333c1d255d3SCy Schubert 
1334*db0ac6deSCy Schubert 	/* JWS Signature encodes the signature (r,s) as two octet strings. Need
1335*db0ac6deSCy Schubert 	 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
1336*db0ac6deSCy Schubert 	r = BN_bin2bn(signature, signature_len / 2, NULL);
1337*db0ac6deSCy Schubert 	s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
1338*db0ac6deSCy Schubert 	sig = ECDSA_SIG_new();
1339*db0ac6deSCy Schubert 	if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
1340*db0ac6deSCy Schubert 		goto fail;
1341*db0ac6deSCy Schubert 	r = NULL;
1342*db0ac6deSCy Schubert 	s = NULL;
1343*db0ac6deSCy Schubert 
1344*db0ac6deSCy Schubert 	der_len = i2d_ECDSA_SIG(sig, &der);
1345*db0ac6deSCy Schubert 	if (der_len <= 0) {
1346*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
1347*db0ac6deSCy Schubert 		goto fail;
1348*db0ac6deSCy Schubert 	}
1349*db0ac6deSCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
1350*db0ac6deSCy Schubert 	md_ctx = EVP_MD_CTX_create();
1351*db0ac6deSCy Schubert 	if (!md_ctx)
1352c1d255d3SCy Schubert 		goto fail;
1353c1d255d3SCy Schubert 
1354*db0ac6deSCy Schubert 	ERR_clear_error();
1355*db0ac6deSCy Schubert 	if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
1356*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
1357*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
1358c1d255d3SCy Schubert 		goto fail;
1359*db0ac6deSCy Schubert 	}
1360*db0ac6deSCy Schubert 	if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
1361*db0ac6deSCy Schubert 				   signed_end - signed_start + 1) != 1) {
1362*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
1363*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
1364c1d255d3SCy Schubert 		goto fail;
1365*db0ac6deSCy Schubert 	}
1366*db0ac6deSCy Schubert 	res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
1367c1d255d3SCy Schubert 	if (res != 1) {
1368c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1369*db0ac6deSCy Schubert 			   "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
1370*db0ac6deSCy Schubert 			   res, ERR_error_string(ERR_get_error(), NULL));
1371c1d255d3SCy Schubert 		ret = DPP_STATUS_INVALID_CONNECTOR;
1372c1d255d3SCy Schubert 		goto fail;
1373c1d255d3SCy Schubert 	}
1374c1d255d3SCy Schubert 
1375c1d255d3SCy Schubert 	ret = DPP_STATUS_OK;
1376c1d255d3SCy Schubert fail:
1377*db0ac6deSCy Schubert 	EVP_MD_CTX_destroy(md_ctx);
1378c1d255d3SCy Schubert 	os_free(prot_hdr);
1379c1d255d3SCy Schubert 	wpabuf_free(kid);
1380c1d255d3SCy Schubert 	os_free(signature);
1381*db0ac6deSCy Schubert 	ECDSA_SIG_free(sig);
1382*db0ac6deSCy Schubert 	BN_free(r);
1383*db0ac6deSCy Schubert 	BN_free(s);
1384*db0ac6deSCy Schubert 	OPENSSL_free(der);
1385c1d255d3SCy Schubert 	return ret;
1386c1d255d3SCy Schubert }
1387c1d255d3SCy Schubert 
1388c1d255d3SCy Schubert 
1389c1d255d3SCy Schubert enum dpp_status_error
1390c1d255d3SCy Schubert dpp_check_signed_connector(struct dpp_signed_connector_info *info,
1391c1d255d3SCy Schubert 			   const u8 *csign_key, size_t csign_key_len,
1392c1d255d3SCy Schubert 			   const u8 *peer_connector, size_t peer_connector_len)
1393c1d255d3SCy Schubert {
1394*db0ac6deSCy Schubert 	const unsigned char *p;
1395*db0ac6deSCy Schubert 	EVP_PKEY *csign = NULL;
1396c1d255d3SCy Schubert 	char *signed_connector = NULL;
1397c1d255d3SCy Schubert 	enum dpp_status_error res = DPP_STATUS_INVALID_CONNECTOR;
1398c1d255d3SCy Schubert 
1399*db0ac6deSCy Schubert 	p = csign_key;
1400*db0ac6deSCy Schubert 	csign = d2i_PUBKEY(NULL, &p, csign_key_len);
1401c1d255d3SCy Schubert 	if (!csign) {
1402c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR,
1403c1d255d3SCy Schubert 			   "DPP: Failed to parse local C-sign-key information");
1404c1d255d3SCy Schubert 		goto fail;
1405c1d255d3SCy Schubert 	}
1406c1d255d3SCy Schubert 
1407c1d255d3SCy Schubert 	wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
1408c1d255d3SCy Schubert 			  peer_connector, peer_connector_len);
1409c1d255d3SCy Schubert 	signed_connector = os_malloc(peer_connector_len + 1);
1410c1d255d3SCy Schubert 	if (!signed_connector)
1411c1d255d3SCy Schubert 		goto fail;
1412c1d255d3SCy Schubert 	os_memcpy(signed_connector, peer_connector, peer_connector_len);
1413c1d255d3SCy Schubert 	signed_connector[peer_connector_len] = '\0';
1414c1d255d3SCy Schubert 	res = dpp_process_signed_connector(info, csign, signed_connector);
1415c1d255d3SCy Schubert fail:
1416c1d255d3SCy Schubert 	os_free(signed_connector);
1417*db0ac6deSCy Schubert 	EVP_PKEY_free(csign);
1418c1d255d3SCy Schubert 	return res;
1419c1d255d3SCy Schubert }
1420c1d255d3SCy Schubert 
1421c1d255d3SCy Schubert 
1422c1d255d3SCy Schubert int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
1423c1d255d3SCy Schubert {
1424c1d255d3SCy Schubert 	struct wpabuf *pix, *prx, *bix, *brx;
1425c1d255d3SCy Schubert 	const u8 *addr[7];
1426c1d255d3SCy Schubert 	size_t len[7];
1427c1d255d3SCy Schubert 	size_t i, num_elem = 0;
1428c1d255d3SCy Schubert 	size_t nonce_len;
1429c1d255d3SCy Schubert 	u8 zero = 0;
1430c1d255d3SCy Schubert 	int res = -1;
1431c1d255d3SCy Schubert 
1432c1d255d3SCy Schubert 	/* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1433c1d255d3SCy Schubert 	nonce_len = auth->curve->nonce_len;
1434c1d255d3SCy Schubert 
1435c1d255d3SCy Schubert 	if (auth->initiator) {
1436*db0ac6deSCy Schubert 		pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1437*db0ac6deSCy Schubert 		prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1438c1d255d3SCy Schubert 		if (auth->own_bi)
1439*db0ac6deSCy Schubert 			bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1440c1d255d3SCy Schubert 		else
1441c1d255d3SCy Schubert 			bix = NULL;
1442*db0ac6deSCy Schubert 		brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1443c1d255d3SCy Schubert 	} else {
1444*db0ac6deSCy Schubert 		pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1445*db0ac6deSCy Schubert 		prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1446c1d255d3SCy Schubert 		if (auth->peer_bi)
1447*db0ac6deSCy Schubert 			bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1448c1d255d3SCy Schubert 		else
1449c1d255d3SCy Schubert 			bix = NULL;
1450*db0ac6deSCy Schubert 		brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1451c1d255d3SCy Schubert 	}
1452c1d255d3SCy Schubert 	if (!pix || !prx || !brx)
1453c1d255d3SCy Schubert 		goto fail;
1454c1d255d3SCy Schubert 
1455c1d255d3SCy Schubert 	addr[num_elem] = auth->i_nonce;
1456c1d255d3SCy Schubert 	len[num_elem] = nonce_len;
1457c1d255d3SCy Schubert 	num_elem++;
1458c1d255d3SCy Schubert 
1459c1d255d3SCy Schubert 	addr[num_elem] = auth->r_nonce;
1460c1d255d3SCy Schubert 	len[num_elem] = nonce_len;
1461c1d255d3SCy Schubert 	num_elem++;
1462c1d255d3SCy Schubert 
1463c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(pix);
1464c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(pix) / 2;
1465c1d255d3SCy Schubert 	num_elem++;
1466c1d255d3SCy Schubert 
1467c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(prx);
1468c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(prx) / 2;
1469c1d255d3SCy Schubert 	num_elem++;
1470c1d255d3SCy Schubert 
1471c1d255d3SCy Schubert 	if (bix) {
1472c1d255d3SCy Schubert 		addr[num_elem] = wpabuf_head(bix);
1473c1d255d3SCy Schubert 		len[num_elem] = wpabuf_len(bix) / 2;
1474c1d255d3SCy Schubert 		num_elem++;
1475c1d255d3SCy Schubert 	}
1476c1d255d3SCy Schubert 
1477c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(brx);
1478c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(brx) / 2;
1479c1d255d3SCy Schubert 	num_elem++;
1480c1d255d3SCy Schubert 
1481c1d255d3SCy Schubert 	addr[num_elem] = &zero;
1482c1d255d3SCy Schubert 	len[num_elem] = 1;
1483c1d255d3SCy Schubert 	num_elem++;
1484c1d255d3SCy Schubert 
1485c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
1486c1d255d3SCy Schubert 	for (i = 0; i < num_elem; i++)
1487c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1488c1d255d3SCy Schubert 	res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
1489c1d255d3SCy Schubert 	if (res == 0)
1490c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
1491c1d255d3SCy Schubert 			    auth->curve->hash_len);
1492c1d255d3SCy Schubert fail:
1493c1d255d3SCy Schubert 	wpabuf_free(pix);
1494c1d255d3SCy Schubert 	wpabuf_free(prx);
1495c1d255d3SCy Schubert 	wpabuf_free(bix);
1496c1d255d3SCy Schubert 	wpabuf_free(brx);
1497c1d255d3SCy Schubert 	return res;
1498c1d255d3SCy Schubert }
1499c1d255d3SCy Schubert 
1500c1d255d3SCy Schubert 
1501c1d255d3SCy Schubert int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
1502c1d255d3SCy Schubert {
1503c1d255d3SCy Schubert 	struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
1504c1d255d3SCy Schubert 	const u8 *addr[7];
1505c1d255d3SCy Schubert 	size_t len[7];
1506c1d255d3SCy Schubert 	size_t i, num_elem = 0;
1507c1d255d3SCy Schubert 	size_t nonce_len;
1508c1d255d3SCy Schubert 	u8 one = 1;
1509c1d255d3SCy Schubert 	int res = -1;
1510c1d255d3SCy Schubert 
1511c1d255d3SCy Schubert 	/* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
1512c1d255d3SCy Schubert 	nonce_len = auth->curve->nonce_len;
1513c1d255d3SCy Schubert 
1514c1d255d3SCy Schubert 	if (auth->initiator) {
1515*db0ac6deSCy Schubert 		pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1516*db0ac6deSCy Schubert 		prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1517c1d255d3SCy Schubert 		if (auth->own_bi)
1518*db0ac6deSCy Schubert 			bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1519c1d255d3SCy Schubert 		else
1520c1d255d3SCy Schubert 			bix = NULL;
1521c1d255d3SCy Schubert 		if (!auth->peer_bi)
1522c1d255d3SCy Schubert 			goto fail;
1523*db0ac6deSCy Schubert 		brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1524c1d255d3SCy Schubert 	} else {
1525*db0ac6deSCy Schubert 		pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1526*db0ac6deSCy Schubert 		prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1527c1d255d3SCy Schubert 		if (auth->peer_bi)
1528*db0ac6deSCy Schubert 			bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1529c1d255d3SCy Schubert 		else
1530c1d255d3SCy Schubert 			bix = NULL;
1531c1d255d3SCy Schubert 		if (!auth->own_bi)
1532c1d255d3SCy Schubert 			goto fail;
1533*db0ac6deSCy Schubert 		brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1534c1d255d3SCy Schubert 	}
1535c1d255d3SCy Schubert 	if (!pix || !prx || !brx)
1536c1d255d3SCy Schubert 		goto fail;
1537c1d255d3SCy Schubert 
1538c1d255d3SCy Schubert 	addr[num_elem] = auth->r_nonce;
1539c1d255d3SCy Schubert 	len[num_elem] = nonce_len;
1540c1d255d3SCy Schubert 	num_elem++;
1541c1d255d3SCy Schubert 
1542c1d255d3SCy Schubert 	addr[num_elem] = auth->i_nonce;
1543c1d255d3SCy Schubert 	len[num_elem] = nonce_len;
1544c1d255d3SCy Schubert 	num_elem++;
1545c1d255d3SCy Schubert 
1546c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(prx);
1547c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(prx) / 2;
1548c1d255d3SCy Schubert 	num_elem++;
1549c1d255d3SCy Schubert 
1550c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(pix);
1551c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(pix) / 2;
1552c1d255d3SCy Schubert 	num_elem++;
1553c1d255d3SCy Schubert 
1554c1d255d3SCy Schubert 	addr[num_elem] = wpabuf_head(brx);
1555c1d255d3SCy Schubert 	len[num_elem] = wpabuf_len(brx) / 2;
1556c1d255d3SCy Schubert 	num_elem++;
1557c1d255d3SCy Schubert 
1558c1d255d3SCy Schubert 	if (bix) {
1559c1d255d3SCy Schubert 		addr[num_elem] = wpabuf_head(bix);
1560c1d255d3SCy Schubert 		len[num_elem] = wpabuf_len(bix) / 2;
1561c1d255d3SCy Schubert 		num_elem++;
1562c1d255d3SCy Schubert 	}
1563c1d255d3SCy Schubert 
1564c1d255d3SCy Schubert 	addr[num_elem] = &one;
1565c1d255d3SCy Schubert 	len[num_elem] = 1;
1566c1d255d3SCy Schubert 	num_elem++;
1567c1d255d3SCy Schubert 
1568c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
1569c1d255d3SCy Schubert 	for (i = 0; i < num_elem; i++)
1570c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1571c1d255d3SCy Schubert 	res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
1572c1d255d3SCy Schubert 	if (res == 0)
1573c1d255d3SCy Schubert 		wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
1574c1d255d3SCy Schubert 			    auth->curve->hash_len);
1575c1d255d3SCy Schubert fail:
1576c1d255d3SCy Schubert 	wpabuf_free(pix);
1577c1d255d3SCy Schubert 	wpabuf_free(prx);
1578c1d255d3SCy Schubert 	wpabuf_free(bix);
1579c1d255d3SCy Schubert 	wpabuf_free(brx);
1580c1d255d3SCy Schubert 	return res;
1581c1d255d3SCy Schubert }
1582c1d255d3SCy Schubert 
1583c1d255d3SCy Schubert 
1584c1d255d3SCy Schubert int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
1585c1d255d3SCy Schubert {
1586*db0ac6deSCy Schubert 	const EC_GROUP *group;
1587*db0ac6deSCy Schubert 	EC_POINT *l = NULL;
1588*db0ac6deSCy Schubert 	const EC_KEY *BI, *bR, *pR;
1589*db0ac6deSCy Schubert 	const EC_POINT *BI_point;
1590*db0ac6deSCy Schubert 	BN_CTX *bnctx;
1591*db0ac6deSCy Schubert 	BIGNUM *lx, *sum, *q;
1592*db0ac6deSCy Schubert 	const BIGNUM *bR_bn, *pR_bn;
1593c1d255d3SCy Schubert 	int ret = -1;
1594c1d255d3SCy Schubert 
1595c1d255d3SCy Schubert 	/* L = ((bR + pR) modulo q) * BI */
1596c1d255d3SCy Schubert 
1597*db0ac6deSCy Schubert 	bnctx = BN_CTX_new();
1598*db0ac6deSCy Schubert 	sum = BN_new();
1599*db0ac6deSCy Schubert 	q = BN_new();
1600*db0ac6deSCy Schubert 	lx = BN_new();
1601*db0ac6deSCy Schubert 	if (!bnctx || !sum || !q || !lx)
1602*db0ac6deSCy Schubert 		goto fail;
1603*db0ac6deSCy Schubert 	BI = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
1604*db0ac6deSCy Schubert 	if (!BI)
1605*db0ac6deSCy Schubert 		goto fail;
1606*db0ac6deSCy Schubert 	BI_point = EC_KEY_get0_public_key(BI);
1607*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(BI);
1608*db0ac6deSCy Schubert 	if (!group)
1609c1d255d3SCy Schubert 		goto fail;
1610c1d255d3SCy Schubert 
1611*db0ac6deSCy Schubert 	bR = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
1612*db0ac6deSCy Schubert 	pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
1613*db0ac6deSCy Schubert 	if (!bR || !pR)
1614c1d255d3SCy Schubert 		goto fail;
1615*db0ac6deSCy Schubert 	bR_bn = EC_KEY_get0_private_key(bR);
1616*db0ac6deSCy Schubert 	pR_bn = EC_KEY_get0_private_key(pR);
1617*db0ac6deSCy Schubert 	if (!bR_bn || !pR_bn)
1618*db0ac6deSCy Schubert 		goto fail;
1619*db0ac6deSCy Schubert 	if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
1620*db0ac6deSCy Schubert 	    BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
1621*db0ac6deSCy Schubert 		goto fail;
1622*db0ac6deSCy Schubert 	l = EC_POINT_new(group);
1623*db0ac6deSCy Schubert 	if (!l ||
1624*db0ac6deSCy Schubert 	    EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
1625*db0ac6deSCy Schubert 	    EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
1626*db0ac6deSCy Schubert 						bnctx) != 1) {
1627*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
1628*db0ac6deSCy Schubert 			   "OpenSSL: failed: %s",
1629*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
1630*db0ac6deSCy Schubert 		goto fail;
1631*db0ac6deSCy Schubert 	}
1632c1d255d3SCy Schubert 
1633*db0ac6deSCy Schubert 	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
1634*db0ac6deSCy Schubert 		goto fail;
1635c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1636c1d255d3SCy Schubert 	auth->Lx_len = auth->secret_len;
1637c1d255d3SCy Schubert 	ret = 0;
1638c1d255d3SCy Schubert fail:
1639*db0ac6deSCy Schubert 	EC_POINT_clear_free(l);
1640*db0ac6deSCy Schubert 	BN_clear_free(lx);
1641*db0ac6deSCy Schubert 	BN_clear_free(sum);
1642*db0ac6deSCy Schubert 	BN_free(q);
1643*db0ac6deSCy Schubert 	BN_CTX_free(bnctx);
1644c1d255d3SCy Schubert 	return ret;
1645c1d255d3SCy Schubert }
1646c1d255d3SCy Schubert 
1647c1d255d3SCy Schubert 
1648c1d255d3SCy Schubert int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
1649c1d255d3SCy Schubert {
1650*db0ac6deSCy Schubert 	const EC_GROUP *group;
1651*db0ac6deSCy Schubert 	EC_POINT *l = NULL, *sum = NULL;
1652*db0ac6deSCy Schubert 	const EC_KEY *bI, *BR, *PR;
1653*db0ac6deSCy Schubert 	const EC_POINT *BR_point, *PR_point;
1654*db0ac6deSCy Schubert 	BN_CTX *bnctx;
1655*db0ac6deSCy Schubert 	BIGNUM *lx;
1656*db0ac6deSCy Schubert 	const BIGNUM *bI_bn;
1657c1d255d3SCy Schubert 	int ret = -1;
1658c1d255d3SCy Schubert 
1659c1d255d3SCy Schubert 	/* L = bI * (BR + PR) */
1660c1d255d3SCy Schubert 
1661*db0ac6deSCy Schubert 	bnctx = BN_CTX_new();
1662*db0ac6deSCy Schubert 	lx = BN_new();
1663*db0ac6deSCy Schubert 	if (!bnctx || !lx)
1664c1d255d3SCy Schubert 		goto fail;
1665*db0ac6deSCy Schubert 	BR = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
1666*db0ac6deSCy Schubert 	PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
1667*db0ac6deSCy Schubert 	if (!BR || !PR)
1668c1d255d3SCy Schubert 		goto fail;
1669*db0ac6deSCy Schubert 	BR_point = EC_KEY_get0_public_key(BR);
1670*db0ac6deSCy Schubert 	PR_point = EC_KEY_get0_public_key(PR);
1671c1d255d3SCy Schubert 
1672*db0ac6deSCy Schubert 	bI = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
1673*db0ac6deSCy Schubert 	if (!bI)
1674*db0ac6deSCy Schubert 		goto fail;
1675*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(bI);
1676*db0ac6deSCy Schubert 	bI_bn = EC_KEY_get0_private_key(bI);
1677*db0ac6deSCy Schubert 	if (!group || !bI_bn)
1678*db0ac6deSCy Schubert 		goto fail;
1679*db0ac6deSCy Schubert 	sum = EC_POINT_new(group);
1680*db0ac6deSCy Schubert 	l = EC_POINT_new(group);
1681*db0ac6deSCy Schubert 	if (!sum || !l ||
1682*db0ac6deSCy Schubert 	    EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
1683*db0ac6deSCy Schubert 	    EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
1684*db0ac6deSCy Schubert 	    EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
1685*db0ac6deSCy Schubert 						bnctx) != 1) {
1686*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
1687*db0ac6deSCy Schubert 			   "OpenSSL: failed: %s",
1688*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
1689*db0ac6deSCy Schubert 		goto fail;
1690*db0ac6deSCy Schubert 	}
1691*db0ac6deSCy Schubert 
1692*db0ac6deSCy Schubert 	if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
1693*db0ac6deSCy Schubert 		goto fail;
1694c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1695c1d255d3SCy Schubert 	auth->Lx_len = auth->secret_len;
1696c1d255d3SCy Schubert 	ret = 0;
1697c1d255d3SCy Schubert fail:
1698*db0ac6deSCy Schubert 	EC_POINT_clear_free(l);
1699*db0ac6deSCy Schubert 	EC_POINT_clear_free(sum);
1700*db0ac6deSCy Schubert 	BN_clear_free(lx);
1701*db0ac6deSCy Schubert 	BN_CTX_free(bnctx);
1702c1d255d3SCy Schubert 	return ret;
1703c1d255d3SCy Schubert }
1704c1d255d3SCy Schubert 
1705c1d255d3SCy Schubert 
1706c1d255d3SCy Schubert int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len)
1707c1d255d3SCy Schubert {
1708c1d255d3SCy Schubert 	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1709c1d255d3SCy Schubert 	const char *info = "DPP PMK";
1710c1d255d3SCy Schubert 	int res;
1711c1d255d3SCy Schubert 
1712c1d255d3SCy Schubert 	/* PMK = HKDF(<>, "DPP PMK", N.x) */
1713c1d255d3SCy Schubert 
1714c1d255d3SCy Schubert 	/* HKDF-Extract(<>, N.x) */
1715c1d255d3SCy Schubert 	os_memset(salt, 0, hash_len);
1716c1d255d3SCy Schubert 	if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
1717c1d255d3SCy Schubert 		return -1;
1718c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1719c1d255d3SCy Schubert 			prk, hash_len);
1720c1d255d3SCy Schubert 
1721c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, info, L) */
1722c1d255d3SCy Schubert 	res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
1723c1d255d3SCy Schubert 	os_memset(prk, 0, hash_len);
1724c1d255d3SCy Schubert 	if (res < 0)
1725c1d255d3SCy Schubert 		return -1;
1726c1d255d3SCy Schubert 
1727c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
1728c1d255d3SCy Schubert 			pmk, hash_len);
1729c1d255d3SCy Schubert 	return 0;
1730c1d255d3SCy Schubert }
1731c1d255d3SCy Schubert 
1732c1d255d3SCy Schubert 
1733c1d255d3SCy Schubert int dpp_derive_pmkid(const struct dpp_curve_params *curve,
1734*db0ac6deSCy Schubert 		     EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
1735c1d255d3SCy Schubert {
1736c1d255d3SCy Schubert 	struct wpabuf *nkx, *pkx;
1737c1d255d3SCy Schubert 	int ret = -1, res;
1738c1d255d3SCy Schubert 	const u8 *addr[2];
1739c1d255d3SCy Schubert 	size_t len[2];
1740c1d255d3SCy Schubert 	u8 hash[SHA256_MAC_LEN];
1741c1d255d3SCy Schubert 
1742c1d255d3SCy Schubert 	/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
1743*db0ac6deSCy Schubert 	nkx = dpp_get_pubkey_point(own_key, 0);
1744*db0ac6deSCy Schubert 	pkx = dpp_get_pubkey_point(peer_key, 0);
1745c1d255d3SCy Schubert 	if (!nkx || !pkx)
1746c1d255d3SCy Schubert 		goto fail;
1747c1d255d3SCy Schubert 	addr[0] = wpabuf_head(nkx);
1748c1d255d3SCy Schubert 	len[0] = wpabuf_len(nkx) / 2;
1749c1d255d3SCy Schubert 	addr[1] = wpabuf_head(pkx);
1750c1d255d3SCy Schubert 	len[1] = wpabuf_len(pkx) / 2;
1751c1d255d3SCy Schubert 	if (len[0] != len[1])
1752c1d255d3SCy Schubert 		goto fail;
1753c1d255d3SCy Schubert 	if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
1754c1d255d3SCy Schubert 		addr[0] = wpabuf_head(pkx);
1755c1d255d3SCy Schubert 		addr[1] = wpabuf_head(nkx);
1756c1d255d3SCy Schubert 	}
1757c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
1758c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
1759c1d255d3SCy Schubert 	res = sha256_vector(2, addr, len, hash);
1760c1d255d3SCy Schubert 	if (res < 0)
1761c1d255d3SCy Schubert 		goto fail;
1762c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
1763c1d255d3SCy Schubert 	os_memcpy(pmkid, hash, PMKID_LEN);
1764c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
1765c1d255d3SCy Schubert 	ret = 0;
1766c1d255d3SCy Schubert fail:
1767c1d255d3SCy Schubert 	wpabuf_free(nkx);
1768c1d255d3SCy Schubert 	wpabuf_free(pkx);
1769c1d255d3SCy Schubert 	return ret;
1770c1d255d3SCy Schubert }
1771c1d255d3SCy Schubert 
1772c1d255d3SCy Schubert 
1773c1d255d3SCy Schubert /* Role-specific elements for PKEX */
1774c1d255d3SCy Schubert 
1775c1d255d3SCy Schubert /* NIST P-256 */
1776c1d255d3SCy Schubert static const u8 pkex_init_x_p256[32] = {
1777c1d255d3SCy Schubert 	0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
1778c1d255d3SCy Schubert 	0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
1779c1d255d3SCy Schubert 	0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
1780c1d255d3SCy Schubert 	0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
1781c1d255d3SCy Schubert  };
1782c1d255d3SCy Schubert static const u8 pkex_init_y_p256[32] = {
1783c1d255d3SCy Schubert 	0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
1784c1d255d3SCy Schubert 	0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
1785c1d255d3SCy Schubert 	0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
1786c1d255d3SCy Schubert 	0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
1787c1d255d3SCy Schubert  };
1788c1d255d3SCy Schubert static const u8 pkex_resp_x_p256[32] = {
1789c1d255d3SCy Schubert 	0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
1790c1d255d3SCy Schubert 	0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
1791c1d255d3SCy Schubert 	0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
1792c1d255d3SCy Schubert 	0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
1793c1d255d3SCy Schubert };
1794c1d255d3SCy Schubert static const u8 pkex_resp_y_p256[32] = {
1795c1d255d3SCy Schubert 	0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
1796c1d255d3SCy Schubert 	0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
1797c1d255d3SCy Schubert 	0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
1798c1d255d3SCy Schubert 	0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
1799c1d255d3SCy Schubert };
1800c1d255d3SCy Schubert 
1801c1d255d3SCy Schubert /* NIST P-384 */
1802c1d255d3SCy Schubert static const u8 pkex_init_x_p384[48] = {
1803c1d255d3SCy Schubert 	0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
1804c1d255d3SCy Schubert 	0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
1805c1d255d3SCy Schubert 	0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
1806c1d255d3SCy Schubert 	0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
1807c1d255d3SCy Schubert 	0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
1808c1d255d3SCy Schubert 	0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
1809c1d255d3SCy Schubert };
1810c1d255d3SCy Schubert static const u8 pkex_init_y_p384[48] = {
1811c1d255d3SCy Schubert 	0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
1812c1d255d3SCy Schubert 	0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
1813c1d255d3SCy Schubert 	0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
1814c1d255d3SCy Schubert 	0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
1815c1d255d3SCy Schubert 	0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
1816c1d255d3SCy Schubert 	0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
1817c1d255d3SCy Schubert };
1818c1d255d3SCy Schubert static const u8 pkex_resp_x_p384[48] = {
1819c1d255d3SCy Schubert 	0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
1820c1d255d3SCy Schubert 	0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
1821c1d255d3SCy Schubert 	0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
1822c1d255d3SCy Schubert 	0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
1823c1d255d3SCy Schubert 	0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
1824c1d255d3SCy Schubert 	0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
1825c1d255d3SCy Schubert };
1826c1d255d3SCy Schubert static const u8 pkex_resp_y_p384[48] = {
1827c1d255d3SCy Schubert 	0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
1828c1d255d3SCy Schubert 	0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
1829c1d255d3SCy Schubert 	0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
1830c1d255d3SCy Schubert 	0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
1831c1d255d3SCy Schubert 	0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
1832c1d255d3SCy Schubert 	0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
1833c1d255d3SCy Schubert };
1834c1d255d3SCy Schubert 
1835c1d255d3SCy Schubert /* NIST P-521 */
1836c1d255d3SCy Schubert static const u8 pkex_init_x_p521[66] = {
1837c1d255d3SCy Schubert 	0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
1838c1d255d3SCy Schubert 	0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
1839c1d255d3SCy Schubert 	0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
1840c1d255d3SCy Schubert 	0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
1841c1d255d3SCy Schubert 	0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
1842c1d255d3SCy Schubert 	0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
1843c1d255d3SCy Schubert 	0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
1844c1d255d3SCy Schubert 	0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
1845c1d255d3SCy Schubert 	0x97, 0x76
1846c1d255d3SCy Schubert };
1847c1d255d3SCy Schubert static const u8 pkex_init_y_p521[66] = {
1848c1d255d3SCy Schubert 	0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
1849c1d255d3SCy Schubert 	0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
1850c1d255d3SCy Schubert 	0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
1851c1d255d3SCy Schubert 	0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
1852c1d255d3SCy Schubert 	0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
1853c1d255d3SCy Schubert 	0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
1854c1d255d3SCy Schubert 	0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
1855c1d255d3SCy Schubert 	0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
1856c1d255d3SCy Schubert 	0x03, 0xa8
1857c1d255d3SCy Schubert };
1858c1d255d3SCy Schubert static const u8 pkex_resp_x_p521[66] = {
1859c1d255d3SCy Schubert 	0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
1860c1d255d3SCy Schubert 	0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
1861c1d255d3SCy Schubert 	0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
1862c1d255d3SCy Schubert 	0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
1863c1d255d3SCy Schubert 	0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
1864c1d255d3SCy Schubert 	0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
1865c1d255d3SCy Schubert 	0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
1866c1d255d3SCy Schubert 	0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
1867c1d255d3SCy Schubert 	0x84, 0xb4
1868c1d255d3SCy Schubert };
1869c1d255d3SCy Schubert static const u8 pkex_resp_y_p521[66] = {
1870c1d255d3SCy Schubert 	0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
1871c1d255d3SCy Schubert 	0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
1872c1d255d3SCy Schubert 	0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
1873c1d255d3SCy Schubert 	0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
1874c1d255d3SCy Schubert 	0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
1875c1d255d3SCy Schubert 	0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
1876c1d255d3SCy Schubert 	0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
1877c1d255d3SCy Schubert 	0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
1878c1d255d3SCy Schubert 	0xce, 0xe1
1879c1d255d3SCy Schubert };
1880c1d255d3SCy Schubert 
1881c1d255d3SCy Schubert /* Brainpool P-256r1 */
1882c1d255d3SCy Schubert static const u8 pkex_init_x_bp_p256r1[32] = {
1883c1d255d3SCy Schubert 	0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
1884c1d255d3SCy Schubert 	0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
1885c1d255d3SCy Schubert 	0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
1886c1d255d3SCy Schubert 	0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
1887c1d255d3SCy Schubert };
1888c1d255d3SCy Schubert static const u8 pkex_init_y_bp_p256r1[32] = {
1889c1d255d3SCy Schubert 	0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
1890c1d255d3SCy Schubert 	0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
1891c1d255d3SCy Schubert 	0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
1892c1d255d3SCy Schubert 	0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
1893c1d255d3SCy Schubert };
1894c1d255d3SCy Schubert static const u8 pkex_resp_x_bp_p256r1[32] = {
1895c1d255d3SCy Schubert 	0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
1896c1d255d3SCy Schubert 	0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
1897c1d255d3SCy Schubert 	0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
1898c1d255d3SCy Schubert 	0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
1899c1d255d3SCy Schubert };
1900c1d255d3SCy Schubert static const u8 pkex_resp_y_bp_p256r1[32] = {
1901c1d255d3SCy Schubert 	0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
1902c1d255d3SCy Schubert 	0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
1903c1d255d3SCy Schubert 	0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
1904c1d255d3SCy Schubert 	0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
1905c1d255d3SCy Schubert };
1906c1d255d3SCy Schubert 
1907c1d255d3SCy Schubert /* Brainpool P-384r1 */
1908c1d255d3SCy Schubert static const u8 pkex_init_x_bp_p384r1[48] = {
1909c1d255d3SCy Schubert 	0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
1910c1d255d3SCy Schubert 	0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
1911c1d255d3SCy Schubert 	0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
1912c1d255d3SCy Schubert 	0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
1913c1d255d3SCy Schubert 	0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
1914c1d255d3SCy Schubert 	0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
1915c1d255d3SCy Schubert };
1916c1d255d3SCy Schubert static const u8 pkex_init_y_bp_p384r1[48] = {
1917c1d255d3SCy Schubert 	0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
1918c1d255d3SCy Schubert 	0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
1919c1d255d3SCy Schubert 	0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
1920c1d255d3SCy Schubert 	0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
1921c1d255d3SCy Schubert 	0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
1922c1d255d3SCy Schubert 	0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
1923c1d255d3SCy Schubert };
1924c1d255d3SCy Schubert static const u8 pkex_resp_x_bp_p384r1[48] = {
1925c1d255d3SCy Schubert 	0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
1926c1d255d3SCy Schubert 	0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
1927c1d255d3SCy Schubert 	0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
1928c1d255d3SCy Schubert 	0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
1929c1d255d3SCy Schubert 	0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
1930c1d255d3SCy Schubert 	0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
1931c1d255d3SCy Schubert };
1932c1d255d3SCy Schubert static const u8 pkex_resp_y_bp_p384r1[48] = {
1933c1d255d3SCy Schubert 	0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
1934c1d255d3SCy Schubert 	0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
1935c1d255d3SCy Schubert 	0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
1936c1d255d3SCy Schubert 	0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
1937c1d255d3SCy Schubert 	0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
1938c1d255d3SCy Schubert 	0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
1939c1d255d3SCy Schubert };
1940c1d255d3SCy Schubert 
1941c1d255d3SCy Schubert /* Brainpool P-512r1 */
1942c1d255d3SCy Schubert static const u8 pkex_init_x_bp_p512r1[64] = {
1943c1d255d3SCy Schubert 	0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
1944c1d255d3SCy Schubert 	0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
1945c1d255d3SCy Schubert 	0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
1946c1d255d3SCy Schubert 	0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
1947c1d255d3SCy Schubert 	0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
1948c1d255d3SCy Schubert 	0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
1949c1d255d3SCy Schubert 	0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
1950c1d255d3SCy Schubert 	0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
1951c1d255d3SCy Schubert };
1952c1d255d3SCy Schubert static const u8 pkex_init_y_bp_p512r1[64] = {
1953c1d255d3SCy Schubert 	0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
1954c1d255d3SCy Schubert 	0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
1955c1d255d3SCy Schubert 	0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
1956c1d255d3SCy Schubert 	0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
1957c1d255d3SCy Schubert 	0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
1958c1d255d3SCy Schubert 	0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
1959c1d255d3SCy Schubert 	0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
1960c1d255d3SCy Schubert 	0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
1961c1d255d3SCy Schubert };
1962c1d255d3SCy Schubert static const u8 pkex_resp_x_bp_p512r1[64] = {
1963c1d255d3SCy Schubert 	0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
1964c1d255d3SCy Schubert 	0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
1965c1d255d3SCy Schubert 	0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
1966c1d255d3SCy Schubert 	0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
1967c1d255d3SCy Schubert 	0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
1968c1d255d3SCy Schubert 	0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
1969c1d255d3SCy Schubert 	0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
1970c1d255d3SCy Schubert 	0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
1971c1d255d3SCy Schubert };
1972c1d255d3SCy Schubert static const u8 pkex_resp_y_bp_p512r1[64] = {
1973c1d255d3SCy Schubert 	0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
1974c1d255d3SCy Schubert 	0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
1975c1d255d3SCy Schubert 	0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
1976c1d255d3SCy Schubert 	0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
1977c1d255d3SCy Schubert 	0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
1978c1d255d3SCy Schubert 	0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
1979c1d255d3SCy Schubert 	0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
1980c1d255d3SCy Schubert 	0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
1981c1d255d3SCy Schubert };
1982c1d255d3SCy Schubert 
1983c1d255d3SCy Schubert 
1984*db0ac6deSCy Schubert static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
1985*db0ac6deSCy Schubert 					 int init)
1986c1d255d3SCy Schubert {
1987*db0ac6deSCy Schubert 	EC_GROUP *group;
1988*db0ac6deSCy Schubert 	size_t len = curve->prime_len;
1989c1d255d3SCy Schubert 	const u8 *x, *y;
1990*db0ac6deSCy Schubert 	EVP_PKEY *res;
1991c1d255d3SCy Schubert 
1992c1d255d3SCy Schubert 	switch (curve->ike_group) {
1993c1d255d3SCy Schubert 	case 19:
1994c1d255d3SCy Schubert 		x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
1995c1d255d3SCy Schubert 		y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
1996c1d255d3SCy Schubert 		break;
1997c1d255d3SCy Schubert 	case 20:
1998c1d255d3SCy Schubert 		x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
1999c1d255d3SCy Schubert 		y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
2000c1d255d3SCy Schubert 		break;
2001c1d255d3SCy Schubert 	case 21:
2002c1d255d3SCy Schubert 		x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
2003c1d255d3SCy Schubert 		y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
2004c1d255d3SCy Schubert 		break;
2005c1d255d3SCy Schubert 	case 28:
2006c1d255d3SCy Schubert 		x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
2007c1d255d3SCy Schubert 		y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
2008c1d255d3SCy Schubert 		break;
2009c1d255d3SCy Schubert 	case 29:
2010c1d255d3SCy Schubert 		x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
2011c1d255d3SCy Schubert 		y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
2012c1d255d3SCy Schubert 		break;
2013c1d255d3SCy Schubert 	case 30:
2014c1d255d3SCy Schubert 		x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
2015c1d255d3SCy Schubert 		y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
2016c1d255d3SCy Schubert 		break;
2017c1d255d3SCy Schubert 	default:
2018c1d255d3SCy Schubert 		return NULL;
2019c1d255d3SCy Schubert 	}
2020c1d255d3SCy Schubert 
2021*db0ac6deSCy Schubert 	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
2022*db0ac6deSCy Schubert 	if (!group)
2023*db0ac6deSCy Schubert 		return NULL;
2024*db0ac6deSCy Schubert 	res = dpp_set_pubkey_point_group(group, x, y, len);
2025*db0ac6deSCy Schubert 	EC_GROUP_free(group);
2026*db0ac6deSCy Schubert 	return res;
2027c1d255d3SCy Schubert }
2028c1d255d3SCy Schubert 
2029c1d255d3SCy Schubert 
2030*db0ac6deSCy Schubert EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
2031*db0ac6deSCy Schubert 			      const u8 *mac_init, const char *code,
2032*db0ac6deSCy Schubert 			      const char *identifier, BN_CTX *bnctx,
2033*db0ac6deSCy Schubert 			      EC_GROUP **ret_group)
2034c1d255d3SCy Schubert {
2035c1d255d3SCy Schubert 	u8 hash[DPP_MAX_HASH_LEN];
2036c1d255d3SCy Schubert 	const u8 *addr[3];
2037c1d255d3SCy Schubert 	size_t len[3];
2038c1d255d3SCy Schubert 	unsigned int num_elem = 0;
2039*db0ac6deSCy Schubert 	EC_POINT *Qi = NULL;
2040*db0ac6deSCy Schubert 	EVP_PKEY *Pi = NULL;
2041*db0ac6deSCy Schubert 	const EC_KEY *Pi_ec;
2042*db0ac6deSCy Schubert 	const EC_POINT *Pi_point;
2043*db0ac6deSCy Schubert 	BIGNUM *hash_bn = NULL;
2044*db0ac6deSCy Schubert 	const EC_GROUP *group = NULL;
2045*db0ac6deSCy Schubert 	EC_GROUP *group2 = NULL;
2046c1d255d3SCy Schubert 
2047c1d255d3SCy Schubert 	/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
2048c1d255d3SCy Schubert 
2049c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
2050c1d255d3SCy Schubert 	addr[num_elem] = mac_init;
2051c1d255d3SCy Schubert 	len[num_elem] = ETH_ALEN;
2052c1d255d3SCy Schubert 	num_elem++;
2053c1d255d3SCy Schubert 	if (identifier) {
2054c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
2055c1d255d3SCy Schubert 			   identifier);
2056c1d255d3SCy Schubert 		addr[num_elem] = (const u8 *) identifier;
2057c1d255d3SCy Schubert 		len[num_elem] = os_strlen(identifier);
2058c1d255d3SCy Schubert 		num_elem++;
2059c1d255d3SCy Schubert 	}
2060c1d255d3SCy Schubert 	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
2061c1d255d3SCy Schubert 	addr[num_elem] = (const u8 *) code;
2062c1d255d3SCy Schubert 	len[num_elem] = os_strlen(code);
2063c1d255d3SCy Schubert 	num_elem++;
2064c1d255d3SCy Schubert 	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
2065c1d255d3SCy Schubert 		goto fail;
2066c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2067c1d255d3SCy Schubert 			"DPP: H(MAC-Initiator | [identifier |] code)",
2068c1d255d3SCy Schubert 			hash, curve->hash_len);
2069*db0ac6deSCy Schubert 	Pi = dpp_pkex_get_role_elem(curve, 1);
2070*db0ac6deSCy Schubert 	if (!Pi)
2071c1d255d3SCy Schubert 		goto fail;
2072*db0ac6deSCy Schubert 	dpp_debug_print_key("DPP: Pi", Pi);
2073*db0ac6deSCy Schubert 	Pi_ec = EVP_PKEY_get0_EC_KEY(Pi);
2074*db0ac6deSCy Schubert 	if (!Pi_ec)
2075c1d255d3SCy Schubert 		goto fail;
2076*db0ac6deSCy Schubert 	Pi_point = EC_KEY_get0_public_key(Pi_ec);
2077266f97b5SCy Schubert 
2078*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(Pi_ec);
2079*db0ac6deSCy Schubert 	if (!group)
2080c1d255d3SCy Schubert 		goto fail;
2081*db0ac6deSCy Schubert 	group2 = EC_GROUP_dup(group);
2082*db0ac6deSCy Schubert 	if (!group2)
2083*db0ac6deSCy Schubert 		goto fail;
2084*db0ac6deSCy Schubert 	Qi = EC_POINT_new(group2);
2085*db0ac6deSCy Schubert 	if (!Qi) {
2086*db0ac6deSCy Schubert 		EC_GROUP_free(group2);
2087*db0ac6deSCy Schubert 		goto fail;
2088*db0ac6deSCy Schubert 	}
2089*db0ac6deSCy Schubert 	hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
2090*db0ac6deSCy Schubert 	if (!hash_bn ||
2091*db0ac6deSCy Schubert 	    EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
2092*db0ac6deSCy Schubert 		goto fail;
2093*db0ac6deSCy Schubert 	if (EC_POINT_is_at_infinity(group, Qi)) {
2094c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
2095c1d255d3SCy Schubert 		goto fail;
2096c1d255d3SCy Schubert 	}
2097*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Qi", group, Qi);
2098c1d255d3SCy Schubert out:
2099*db0ac6deSCy Schubert 	EVP_PKEY_free(Pi);
2100*db0ac6deSCy Schubert 	BN_clear_free(hash_bn);
2101*db0ac6deSCy Schubert 	if (ret_group && Qi)
2102*db0ac6deSCy Schubert 		*ret_group = group2;
2103c1d255d3SCy Schubert 	else
2104*db0ac6deSCy Schubert 		EC_GROUP_free(group2);
2105c1d255d3SCy Schubert 	return Qi;
2106c1d255d3SCy Schubert fail:
2107*db0ac6deSCy Schubert 	EC_POINT_free(Qi);
2108c1d255d3SCy Schubert 	Qi = NULL;
2109c1d255d3SCy Schubert 	goto out;
2110c1d255d3SCy Schubert }
2111c1d255d3SCy Schubert 
2112c1d255d3SCy Schubert 
2113*db0ac6deSCy Schubert EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
2114*db0ac6deSCy Schubert 			      const u8 *mac_resp, const char *code,
2115*db0ac6deSCy Schubert 			      const char *identifier, BN_CTX *bnctx,
2116*db0ac6deSCy Schubert 			      EC_GROUP **ret_group)
2117c1d255d3SCy Schubert {
2118c1d255d3SCy Schubert 	u8 hash[DPP_MAX_HASH_LEN];
2119c1d255d3SCy Schubert 	const u8 *addr[3];
2120c1d255d3SCy Schubert 	size_t len[3];
2121c1d255d3SCy Schubert 	unsigned int num_elem = 0;
2122*db0ac6deSCy Schubert 	EC_POINT *Qr = NULL;
2123*db0ac6deSCy Schubert 	EVP_PKEY *Pr = NULL;
2124*db0ac6deSCy Schubert 	const EC_KEY *Pr_ec;
2125*db0ac6deSCy Schubert 	const EC_POINT *Pr_point;
2126*db0ac6deSCy Schubert 	BIGNUM *hash_bn = NULL;
2127*db0ac6deSCy Schubert 	const EC_GROUP *group = NULL;
2128*db0ac6deSCy Schubert 	EC_GROUP *group2 = NULL;
2129c1d255d3SCy Schubert 
2130c1d255d3SCy Schubert 	/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
2131c1d255d3SCy Schubert 
2132c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
2133c1d255d3SCy Schubert 	addr[num_elem] = mac_resp;
2134c1d255d3SCy Schubert 	len[num_elem] = ETH_ALEN;
2135c1d255d3SCy Schubert 	num_elem++;
2136c1d255d3SCy Schubert 	if (identifier) {
2137c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
2138c1d255d3SCy Schubert 			   identifier);
2139c1d255d3SCy Schubert 		addr[num_elem] = (const u8 *) identifier;
2140c1d255d3SCy Schubert 		len[num_elem] = os_strlen(identifier);
2141c1d255d3SCy Schubert 		num_elem++;
2142c1d255d3SCy Schubert 	}
2143c1d255d3SCy Schubert 	wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
2144c1d255d3SCy Schubert 	addr[num_elem] = (const u8 *) code;
2145c1d255d3SCy Schubert 	len[num_elem] = os_strlen(code);
2146c1d255d3SCy Schubert 	num_elem++;
2147c1d255d3SCy Schubert 	if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
2148c1d255d3SCy Schubert 		goto fail;
2149c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2150c1d255d3SCy Schubert 			"DPP: H(MAC-Responder | [identifier |] code)",
2151c1d255d3SCy Schubert 			hash, curve->hash_len);
2152*db0ac6deSCy Schubert 	Pr = dpp_pkex_get_role_elem(curve, 0);
2153*db0ac6deSCy Schubert 	if (!Pr)
2154c1d255d3SCy Schubert 		goto fail;
2155*db0ac6deSCy Schubert 	dpp_debug_print_key("DPP: Pr", Pr);
2156*db0ac6deSCy Schubert 	Pr_ec = EVP_PKEY_get0_EC_KEY(Pr);
2157*db0ac6deSCy Schubert 	if (!Pr_ec)
2158c1d255d3SCy Schubert 		goto fail;
2159*db0ac6deSCy Schubert 	Pr_point = EC_KEY_get0_public_key(Pr_ec);
2160266f97b5SCy Schubert 
2161*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(Pr_ec);
2162*db0ac6deSCy Schubert 	if (!group)
2163c1d255d3SCy Schubert 		goto fail;
2164*db0ac6deSCy Schubert 	group2 = EC_GROUP_dup(group);
2165*db0ac6deSCy Schubert 	if (!group2)
2166*db0ac6deSCy Schubert 		goto fail;
2167*db0ac6deSCy Schubert 	Qr = EC_POINT_new(group2);
2168*db0ac6deSCy Schubert 	if (!Qr) {
2169*db0ac6deSCy Schubert 		EC_GROUP_free(group2);
2170*db0ac6deSCy Schubert 		goto fail;
2171*db0ac6deSCy Schubert 	}
2172*db0ac6deSCy Schubert 	hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
2173*db0ac6deSCy Schubert 	if (!hash_bn ||
2174*db0ac6deSCy Schubert 	    EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
2175*db0ac6deSCy Schubert 		goto fail;
2176*db0ac6deSCy Schubert 	if (EC_POINT_is_at_infinity(group, Qr)) {
2177c1d255d3SCy Schubert 		wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
2178c1d255d3SCy Schubert 		goto fail;
2179c1d255d3SCy Schubert 	}
2180*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Qr", group, Qr);
2181c1d255d3SCy Schubert out:
2182*db0ac6deSCy Schubert 	EVP_PKEY_free(Pr);
2183*db0ac6deSCy Schubert 	BN_clear_free(hash_bn);
2184*db0ac6deSCy Schubert 	if (ret_group && Qr)
2185*db0ac6deSCy Schubert 		*ret_group = group2;
2186c1d255d3SCy Schubert 	else
2187*db0ac6deSCy Schubert 		EC_GROUP_free(group2);
2188c1d255d3SCy Schubert 	return Qr;
2189c1d255d3SCy Schubert fail:
2190*db0ac6deSCy Schubert 	EC_POINT_free(Qr);
2191c1d255d3SCy Schubert 	Qr = NULL;
2192c1d255d3SCy Schubert 	goto out;
2193c1d255d3SCy Schubert }
2194c1d255d3SCy Schubert 
2195c1d255d3SCy Schubert 
2196c1d255d3SCy Schubert int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
2197c1d255d3SCy Schubert 		      const u8 *Mx, size_t Mx_len,
2198c1d255d3SCy Schubert 		      const u8 *Nx, size_t Nx_len,
2199c1d255d3SCy Schubert 		      const char *code,
2200c1d255d3SCy Schubert 		      const u8 *Kx, size_t Kx_len,
2201c1d255d3SCy Schubert 		      u8 *z, unsigned int hash_len)
2202c1d255d3SCy Schubert {
2203c1d255d3SCy Schubert 	u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
2204c1d255d3SCy Schubert 	int res;
2205c1d255d3SCy Schubert 	u8 *info, *pos;
2206c1d255d3SCy Schubert 	size_t info_len;
2207c1d255d3SCy Schubert 
2208c1d255d3SCy Schubert 	/* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
2209c1d255d3SCy Schubert 	 */
2210c1d255d3SCy Schubert 
2211c1d255d3SCy Schubert 	/* HKDF-Extract(<>, IKM=K.x) */
2212c1d255d3SCy Schubert 	os_memset(salt, 0, hash_len);
2213c1d255d3SCy Schubert 	if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
2214c1d255d3SCy Schubert 		return -1;
2215c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
2216c1d255d3SCy Schubert 			prk, hash_len);
2217c1d255d3SCy Schubert 	info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
2218c1d255d3SCy Schubert 	info = os_malloc(info_len);
2219c1d255d3SCy Schubert 	if (!info)
2220c1d255d3SCy Schubert 		return -1;
2221c1d255d3SCy Schubert 	pos = info;
2222c1d255d3SCy Schubert 	os_memcpy(pos, mac_init, ETH_ALEN);
2223c1d255d3SCy Schubert 	pos += ETH_ALEN;
2224c1d255d3SCy Schubert 	os_memcpy(pos, mac_resp, ETH_ALEN);
2225c1d255d3SCy Schubert 	pos += ETH_ALEN;
2226c1d255d3SCy Schubert 	os_memcpy(pos, Mx, Mx_len);
2227c1d255d3SCy Schubert 	pos += Mx_len;
2228c1d255d3SCy Schubert 	os_memcpy(pos, Nx, Nx_len);
2229c1d255d3SCy Schubert 	pos += Nx_len;
2230c1d255d3SCy Schubert 	os_memcpy(pos, code, os_strlen(code));
2231c1d255d3SCy Schubert 
2232c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, info, L) */
2233c1d255d3SCy Schubert 	if (hash_len == 32)
2234c1d255d3SCy Schubert 		res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
2235c1d255d3SCy Schubert 				      z, hash_len);
2236c1d255d3SCy Schubert 	else if (hash_len == 48)
2237c1d255d3SCy Schubert 		res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
2238c1d255d3SCy Schubert 				      z, hash_len);
2239c1d255d3SCy Schubert 	else if (hash_len == 64)
2240c1d255d3SCy Schubert 		res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
2241c1d255d3SCy Schubert 				      z, hash_len);
2242c1d255d3SCy Schubert 	else
2243c1d255d3SCy Schubert 		res = -1;
2244c1d255d3SCy Schubert 	os_free(info);
2245c1d255d3SCy Schubert 	os_memset(prk, 0, hash_len);
2246c1d255d3SCy Schubert 	if (res < 0)
2247c1d255d3SCy Schubert 		return -1;
2248c1d255d3SCy Schubert 
2249c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
2250c1d255d3SCy Schubert 			z, hash_len);
2251c1d255d3SCy Schubert 	return 0;
2252c1d255d3SCy Schubert }
2253c1d255d3SCy Schubert 
2254c1d255d3SCy Schubert 
2255c1d255d3SCy Schubert int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
2256c1d255d3SCy Schubert 				     const u8 *net_access_key,
2257c1d255d3SCy Schubert 				     size_t net_access_key_len,
2258c1d255d3SCy Schubert 				     struct json_token *peer_net_access_key)
2259c1d255d3SCy Schubert {
2260*db0ac6deSCy Schubert 	BN_CTX *bnctx = NULL;
2261*db0ac6deSCy Schubert 	EVP_PKEY *own_key = NULL, *peer_key = NULL;
2262*db0ac6deSCy Schubert 	BIGNUM *sum = NULL, *q = NULL, *mx = NULL;
2263*db0ac6deSCy Schubert 	EC_POINT *m = NULL;
2264*db0ac6deSCy Schubert 	const EC_KEY *cR, *pR;
2265*db0ac6deSCy Schubert 	const EC_GROUP *group;
2266*db0ac6deSCy Schubert 	const BIGNUM *cR_bn, *pR_bn;
2267*db0ac6deSCy Schubert 	const EC_POINT *CI_point;
2268*db0ac6deSCy Schubert 	const EC_KEY *CI;
2269c1d255d3SCy Schubert 	u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
2270c1d255d3SCy Schubert 	u8 prk[DPP_MAX_HASH_LEN];
2271c1d255d3SCy Schubert 	const struct dpp_curve_params *curve;
2272c1d255d3SCy Schubert 	int res = -1;
2273c1d255d3SCy Schubert 	u8 nonces[2 * DPP_MAX_NONCE_LEN];
2274c1d255d3SCy Schubert 
2275c1d255d3SCy Schubert 	own_key = dpp_set_keypair(&auth->curve, net_access_key,
2276c1d255d3SCy Schubert 				  net_access_key_len);
2277c1d255d3SCy Schubert 	if (!own_key) {
2278c1d255d3SCy Schubert 		dpp_auth_fail(auth, "Failed to parse own netAccessKey");
2279c1d255d3SCy Schubert 		goto fail;
2280c1d255d3SCy Schubert 	}
2281c1d255d3SCy Schubert 
2282c1d255d3SCy Schubert 	peer_key = dpp_parse_jwk(peer_net_access_key, &curve);
2283c1d255d3SCy Schubert 	if (!peer_key)
2284c1d255d3SCy Schubert 		goto fail;
2285c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
2286c1d255d3SCy Schubert 
2287c1d255d3SCy Schubert 	if (auth->curve != curve) {
2288c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2289c1d255d3SCy Schubert 			   "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
2290c1d255d3SCy Schubert 			   auth->curve->name, curve->name);
2291c1d255d3SCy Schubert 		goto fail;
2292c1d255d3SCy Schubert 	}
2293c1d255d3SCy Schubert 
2294c1d255d3SCy Schubert 	auth->own_protocol_key = dpp_gen_keypair(curve);
2295c1d255d3SCy Schubert 	if (!auth->own_protocol_key)
2296c1d255d3SCy Schubert 		goto fail;
2297c1d255d3SCy Schubert 
2298c1d255d3SCy Schubert 	if (random_get_bytes(auth->e_nonce, auth->curve->nonce_len)) {
2299c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2300c1d255d3SCy Schubert 		goto fail;
2301c1d255d3SCy Schubert 	}
2302c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: E-nonce",
2303c1d255d3SCy Schubert 			auth->e_nonce, auth->curve->nonce_len);
2304c1d255d3SCy Schubert 
2305c1d255d3SCy Schubert 	/* M = { cR + pR } * CI */
2306*db0ac6deSCy Schubert 	cR = EVP_PKEY_get0_EC_KEY(own_key);
2307*db0ac6deSCy Schubert 	pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
2308*db0ac6deSCy Schubert 	if (!pR)
2309c1d255d3SCy Schubert 		goto fail;
2310*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(pR);
2311*db0ac6deSCy Schubert 	bnctx = BN_CTX_new();
2312*db0ac6deSCy Schubert 	sum = BN_new();
2313*db0ac6deSCy Schubert 	mx = BN_new();
2314*db0ac6deSCy Schubert 	q = BN_new();
2315*db0ac6deSCy Schubert 	m = EC_POINT_new(group);
2316*db0ac6deSCy Schubert 	if (!cR || !bnctx || !sum || !mx || !q || !m)
2317*db0ac6deSCy Schubert 		goto fail;
2318*db0ac6deSCy Schubert 	cR_bn = EC_KEY_get0_private_key(cR);
2319*db0ac6deSCy Schubert 	pR_bn = EC_KEY_get0_private_key(pR);
2320*db0ac6deSCy Schubert 	if (!cR_bn || !pR_bn)
2321*db0ac6deSCy Schubert 		goto fail;
2322*db0ac6deSCy Schubert 	CI = EVP_PKEY_get0_EC_KEY(peer_key);
2323*db0ac6deSCy Schubert 	CI_point = EC_KEY_get0_public_key(CI);
2324*db0ac6deSCy Schubert 	if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2325*db0ac6deSCy Schubert 	    BN_mod_add(sum, cR_bn, pR_bn, q, bnctx) != 1 ||
2326*db0ac6deSCy Schubert 	    EC_POINT_mul(group, m, NULL, CI_point, sum, bnctx) != 1 ||
2327*db0ac6deSCy Schubert 	    EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
2328*db0ac6deSCy Schubert 						bnctx) != 1) {
2329*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
2330*db0ac6deSCy Schubert 			   "OpenSSL: failed: %s",
2331*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2332c1d255d3SCy Schubert 		goto fail;
2333c1d255d3SCy Schubert 	}
2334*db0ac6deSCy Schubert 
2335*db0ac6deSCy Schubert 	if (dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
2336*db0ac6deSCy Schubert 		goto fail;
2337c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
2338c1d255d3SCy Schubert 
2339c1d255d3SCy Schubert 	/* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
2340c1d255d3SCy Schubert 
2341c1d255d3SCy Schubert 	/* HKDF-Extract(C-nonce | E-nonce, M.x) */
2342c1d255d3SCy Schubert 	os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
2343c1d255d3SCy Schubert 	os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
2344c1d255d3SCy Schubert 	if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
2345c1d255d3SCy Schubert 		     Mx, curve->prime_len, prk) < 0)
2346c1d255d3SCy Schubert 		goto fail;
2347c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
2348c1d255d3SCy Schubert 
2349c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, "dpp reconfig key", L) */
2350c1d255d3SCy Schubert 	if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
2351c1d255d3SCy Schubert 			    "dpp reconfig key", auth->ke, curve->hash_len) < 0)
2352c1d255d3SCy Schubert 		goto fail;
2353c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2354c1d255d3SCy Schubert 			"DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
2355c1d255d3SCy Schubert 			auth->ke, curve->hash_len);
2356c1d255d3SCy Schubert 
2357c1d255d3SCy Schubert 	res = 0;
2358*db0ac6deSCy Schubert 	EVP_PKEY_free(auth->reconfig_old_protocol_key);
2359c1d255d3SCy Schubert 	auth->reconfig_old_protocol_key = own_key;
2360c1d255d3SCy Schubert 	own_key = NULL;
2361c1d255d3SCy Schubert fail:
2362c1d255d3SCy Schubert 	forced_memzero(prk, sizeof(prk));
2363c1d255d3SCy Schubert 	forced_memzero(Mx, sizeof(Mx));
2364*db0ac6deSCy Schubert 	EC_POINT_clear_free(m);
2365*db0ac6deSCy Schubert 	BN_free(q);
2366*db0ac6deSCy Schubert 	BN_clear_free(mx);
2367*db0ac6deSCy Schubert 	BN_clear_free(sum);
2368*db0ac6deSCy Schubert 	EVP_PKEY_free(own_key);
2369*db0ac6deSCy Schubert 	EVP_PKEY_free(peer_key);
2370*db0ac6deSCy Schubert 	BN_CTX_free(bnctx);
2371c1d255d3SCy Schubert 	return res;
2372c1d255d3SCy Schubert }
2373c1d255d3SCy Schubert 
2374c1d255d3SCy Schubert 
2375c1d255d3SCy Schubert int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
2376c1d255d3SCy Schubert 				     const u8 *r_proto, u16 r_proto_len,
2377c1d255d3SCy Schubert 				     struct json_token *net_access_key)
2378c1d255d3SCy Schubert {
2379*db0ac6deSCy Schubert 	BN_CTX *bnctx = NULL;
2380*db0ac6deSCy Schubert 	EVP_PKEY *pr = NULL, *peer_key = NULL;
2381*db0ac6deSCy Schubert 	EC_POINT *sum = NULL, *m = NULL;
2382*db0ac6deSCy Schubert 	BIGNUM *mx = NULL;
2383*db0ac6deSCy Schubert 	const EC_KEY *cI, *CR, *PR;
2384*db0ac6deSCy Schubert 	const EC_GROUP *group;
2385*db0ac6deSCy Schubert 	const EC_POINT *CR_point, *PR_point;
2386*db0ac6deSCy Schubert 	const BIGNUM *cI_bn;
2387c1d255d3SCy Schubert 	u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
2388c1d255d3SCy Schubert 	u8 prk[DPP_MAX_HASH_LEN];
2389c1d255d3SCy Schubert 	int res = -1;
2390c1d255d3SCy Schubert 	const struct dpp_curve_params *curve;
2391c1d255d3SCy Schubert 	u8 nonces[2 * DPP_MAX_NONCE_LEN];
2392c1d255d3SCy Schubert 
2393c1d255d3SCy Schubert 	pr = dpp_set_pubkey_point(auth->conf->connector_key,
2394c1d255d3SCy Schubert 				  r_proto, r_proto_len);
2395c1d255d3SCy Schubert 	if (!pr) {
2396c1d255d3SCy Schubert 		dpp_auth_fail(auth, "Invalid Responder Protocol Key");
2397c1d255d3SCy Schubert 		goto fail;
2398c1d255d3SCy Schubert 	}
2399c1d255d3SCy Schubert 	dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
2400*db0ac6deSCy Schubert 	EVP_PKEY_free(auth->peer_protocol_key);
2401c1d255d3SCy Schubert 	auth->peer_protocol_key = pr;
2402c1d255d3SCy Schubert 	pr = NULL;
2403c1d255d3SCy Schubert 
2404c1d255d3SCy Schubert 	peer_key = dpp_parse_jwk(net_access_key, &curve);
2405c1d255d3SCy Schubert 	if (!peer_key)
2406c1d255d3SCy Schubert 		goto fail;
2407c1d255d3SCy Schubert 	dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
2408c1d255d3SCy Schubert 	if (auth->curve != curve) {
2409c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2410c1d255d3SCy Schubert 			   "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
2411c1d255d3SCy Schubert 			   auth->curve->name, curve->name);
2412c1d255d3SCy Schubert 		goto fail;
2413c1d255d3SCy Schubert 	}
2414c1d255d3SCy Schubert 
2415c1d255d3SCy Schubert 	/* M = cI * { CR + PR } */
2416*db0ac6deSCy Schubert 	cI = EVP_PKEY_get0_EC_KEY(auth->conf->connector_key);
2417*db0ac6deSCy Schubert 	cI_bn = EC_KEY_get0_private_key(cI);
2418*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(cI);
2419*db0ac6deSCy Schubert 	bnctx = BN_CTX_new();
2420*db0ac6deSCy Schubert 	sum = EC_POINT_new(group);
2421*db0ac6deSCy Schubert 	m = EC_POINT_new(group);
2422*db0ac6deSCy Schubert 	mx = BN_new();
2423*db0ac6deSCy Schubert 	CR = EVP_PKEY_get0_EC_KEY(peer_key);
2424*db0ac6deSCy Schubert 	PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
2425*db0ac6deSCy Schubert 	CR_point = EC_KEY_get0_public_key(CR);
2426*db0ac6deSCy Schubert 	PR_point = EC_KEY_get0_public_key(PR);
2427*db0ac6deSCy Schubert 	if (!bnctx || !sum || !m || !mx ||
2428*db0ac6deSCy Schubert 	    EC_POINT_add(group, sum, CR_point, PR_point, bnctx) != 1 ||
2429*db0ac6deSCy Schubert 	    EC_POINT_mul(group, m, NULL, sum, cI_bn, bnctx) != 1 ||
2430*db0ac6deSCy Schubert 	    EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
2431*db0ac6deSCy Schubert 						bnctx) != 1 ||
2432*db0ac6deSCy Schubert 	    dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
2433c1d255d3SCy Schubert 		goto fail;
2434c1d255d3SCy Schubert 
2435c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
2436c1d255d3SCy Schubert 
2437c1d255d3SCy Schubert 	/* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
2438c1d255d3SCy Schubert 
2439c1d255d3SCy Schubert 	/* HKDF-Extract(C-nonce | E-nonce, M.x) */
2440c1d255d3SCy Schubert 	os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
2441c1d255d3SCy Schubert 	os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
2442c1d255d3SCy Schubert 	if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
2443c1d255d3SCy Schubert 		     Mx, curve->prime_len, prk) < 0)
2444c1d255d3SCy Schubert 		goto fail;
2445c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
2446c1d255d3SCy Schubert 
2447c1d255d3SCy Schubert 	/* HKDF-Expand(PRK, "dpp reconfig key", L) */
2448c1d255d3SCy Schubert 	if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
2449c1d255d3SCy Schubert 			    "dpp reconfig key", auth->ke, curve->hash_len) < 0)
2450c1d255d3SCy Schubert 		goto fail;
2451c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2452c1d255d3SCy Schubert 			"DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
2453c1d255d3SCy Schubert 			auth->ke, curve->hash_len);
2454c1d255d3SCy Schubert 
2455c1d255d3SCy Schubert 	res = 0;
2456c1d255d3SCy Schubert fail:
2457c1d255d3SCy Schubert 	forced_memzero(prk, sizeof(prk));
2458c1d255d3SCy Schubert 	forced_memzero(Mx, sizeof(Mx));
2459*db0ac6deSCy Schubert 	EVP_PKEY_free(pr);
2460*db0ac6deSCy Schubert 	EVP_PKEY_free(peer_key);
2461*db0ac6deSCy Schubert 	EC_POINT_clear_free(sum);
2462*db0ac6deSCy Schubert 	EC_POINT_clear_free(m);
2463*db0ac6deSCy Schubert 	BN_clear_free(mx);
2464*db0ac6deSCy Schubert 	BN_CTX_free(bnctx);
2465c1d255d3SCy Schubert 	return res;
2466c1d255d3SCy Schubert }
2467c1d255d3SCy Schubert 
2468c1d255d3SCy Schubert 
2469c1d255d3SCy Schubert static char *
2470c1d255d3SCy Schubert dpp_build_jws_prot_hdr(struct dpp_configurator *conf, size_t *signed1_len)
2471c1d255d3SCy Schubert {
2472c1d255d3SCy Schubert 	struct wpabuf *jws_prot_hdr;
2473c1d255d3SCy Schubert 	char *signed1;
2474c1d255d3SCy Schubert 
2475c1d255d3SCy Schubert 	jws_prot_hdr = wpabuf_alloc(100);
2476c1d255d3SCy Schubert 	if (!jws_prot_hdr)
2477c1d255d3SCy Schubert 		return NULL;
2478c1d255d3SCy Schubert 	json_start_object(jws_prot_hdr, NULL);
2479c1d255d3SCy Schubert 	json_add_string(jws_prot_hdr, "typ", "dppCon");
2480c1d255d3SCy Schubert 	json_value_sep(jws_prot_hdr);
2481c1d255d3SCy Schubert 	json_add_string(jws_prot_hdr, "kid", conf->kid);
2482c1d255d3SCy Schubert 	json_value_sep(jws_prot_hdr);
2483c1d255d3SCy Schubert 	json_add_string(jws_prot_hdr, "alg", conf->curve->jws_alg);
2484c1d255d3SCy Schubert 	json_end_object(jws_prot_hdr);
2485c1d255d3SCy Schubert 	signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
2486c1d255d3SCy Schubert 				    wpabuf_len(jws_prot_hdr),
2487c1d255d3SCy Schubert 				    signed1_len);
2488c1d255d3SCy Schubert 	wpabuf_free(jws_prot_hdr);
2489c1d255d3SCy Schubert 	return signed1;
2490c1d255d3SCy Schubert }
2491c1d255d3SCy Schubert 
2492c1d255d3SCy Schubert 
2493c1d255d3SCy Schubert static char *
2494c1d255d3SCy Schubert dpp_build_conn_signature(struct dpp_configurator *conf,
2495c1d255d3SCy Schubert 			 const char *signed1, size_t signed1_len,
2496c1d255d3SCy Schubert 			 const char *signed2, size_t signed2_len,
2497c1d255d3SCy Schubert 			 size_t *signed3_len)
2498c1d255d3SCy Schubert {
2499c1d255d3SCy Schubert 	const struct dpp_curve_params *curve;
2500c1d255d3SCy Schubert 	char *signed3 = NULL;
2501*db0ac6deSCy Schubert 	unsigned char *signature = NULL;
2502*db0ac6deSCy Schubert 	const unsigned char *p;
2503*db0ac6deSCy Schubert 	size_t signature_len;
2504*db0ac6deSCy Schubert 	EVP_MD_CTX *md_ctx = NULL;
2505*db0ac6deSCy Schubert 	ECDSA_SIG *sig = NULL;
2506c1d255d3SCy Schubert 	char *dot = ".";
2507*db0ac6deSCy Schubert 	const EVP_MD *sign_md;
2508*db0ac6deSCy Schubert 	const BIGNUM *r, *s;
2509c1d255d3SCy Schubert 
2510c1d255d3SCy Schubert 	curve = conf->curve;
2511c1d255d3SCy Schubert 	if (curve->hash_len == SHA256_MAC_LEN) {
2512*db0ac6deSCy Schubert 		sign_md = EVP_sha256();
2513c1d255d3SCy Schubert 	} else if (curve->hash_len == SHA384_MAC_LEN) {
2514*db0ac6deSCy Schubert 		sign_md = EVP_sha384();
2515c1d255d3SCy Schubert 	} else if (curve->hash_len == SHA512_MAC_LEN) {
2516*db0ac6deSCy Schubert 		sign_md = EVP_sha512();
2517c1d255d3SCy Schubert 	} else {
2518c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
2519c1d255d3SCy Schubert 		goto fail;
2520c1d255d3SCy Schubert 	}
2521*db0ac6deSCy Schubert 
2522*db0ac6deSCy Schubert 	md_ctx = EVP_MD_CTX_create();
2523*db0ac6deSCy Schubert 	if (!md_ctx)
2524*db0ac6deSCy Schubert 		goto fail;
2525*db0ac6deSCy Schubert 
2526*db0ac6deSCy Schubert 	ERR_clear_error();
2527*db0ac6deSCy Schubert 	if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, conf->csign) != 1) {
2528*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
2529*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2530266f97b5SCy Schubert 		goto fail;
2531266f97b5SCy Schubert 	}
2532*db0ac6deSCy Schubert 	if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
2533*db0ac6deSCy Schubert 	    EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
2534*db0ac6deSCy Schubert 	    EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
2535*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
2536*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2537c1d255d3SCy Schubert 		goto fail;
2538266f97b5SCy Schubert 	}
2539*db0ac6deSCy Schubert 	if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
2540*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
2541*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2542*db0ac6deSCy Schubert 		goto fail;
2543*db0ac6deSCy Schubert 	}
2544*db0ac6deSCy Schubert 	signature = os_malloc(signature_len);
2545*db0ac6deSCy Schubert 	if (!signature)
2546*db0ac6deSCy Schubert 		goto fail;
2547*db0ac6deSCy Schubert 	if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
2548*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
2549*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2550*db0ac6deSCy Schubert 		goto fail;
2551*db0ac6deSCy Schubert 	}
2552*db0ac6deSCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
2553*db0ac6deSCy Schubert 		    signature, signature_len);
2554*db0ac6deSCy Schubert 	/* Convert to raw coordinates r,s */
2555*db0ac6deSCy Schubert 	p = signature;
2556*db0ac6deSCy Schubert 	sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
2557*db0ac6deSCy Schubert 	if (!sig)
2558*db0ac6deSCy Schubert 		goto fail;
2559*db0ac6deSCy Schubert 	ECDSA_SIG_get0(sig, &r, &s);
2560*db0ac6deSCy Schubert 	if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
2561*db0ac6deSCy Schubert 	    dpp_bn2bin_pad(s, signature + curve->prime_len,
2562*db0ac6deSCy Schubert 			   curve->prime_len) < 0)
2563*db0ac6deSCy Schubert 		goto fail;
2564*db0ac6deSCy Schubert 	signature_len = 2 * curve->prime_len;
2565c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
2566*db0ac6deSCy Schubert 		    signature, signature_len);
2567*db0ac6deSCy Schubert 	signed3 = base64_url_encode(signature, signature_len, signed3_len);
2568c1d255d3SCy Schubert fail:
2569*db0ac6deSCy Schubert 	EVP_MD_CTX_destroy(md_ctx);
2570*db0ac6deSCy Schubert 	ECDSA_SIG_free(sig);
2571*db0ac6deSCy Schubert 	os_free(signature);
2572c1d255d3SCy Schubert 	return signed3;
2573c1d255d3SCy Schubert }
2574c1d255d3SCy Schubert 
2575c1d255d3SCy Schubert char * dpp_sign_connector(struct dpp_configurator *conf,
2576c1d255d3SCy Schubert 			  const struct wpabuf *dppcon)
2577c1d255d3SCy Schubert {
2578c1d255d3SCy Schubert 	char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
2579c1d255d3SCy Schubert 	char *signed_conn = NULL, *pos;
2580c1d255d3SCy Schubert 	size_t signed1_len, signed2_len, signed3_len;
2581c1d255d3SCy Schubert 
2582c1d255d3SCy Schubert 	signed1 = dpp_build_jws_prot_hdr(conf, &signed1_len);
2583c1d255d3SCy Schubert 	signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
2584c1d255d3SCy Schubert 				    &signed2_len);
2585c1d255d3SCy Schubert 	if (!signed1 || !signed2)
2586c1d255d3SCy Schubert 		goto fail;
2587c1d255d3SCy Schubert 
2588c1d255d3SCy Schubert 	signed3 = dpp_build_conn_signature(conf, signed1, signed1_len,
2589c1d255d3SCy Schubert 					   signed2, signed2_len, &signed3_len);
2590c1d255d3SCy Schubert 	if (!signed3)
2591c1d255d3SCy Schubert 		goto fail;
2592c1d255d3SCy Schubert 
2593c1d255d3SCy Schubert 	signed_conn = os_malloc(signed1_len + signed2_len + signed3_len + 3);
2594c1d255d3SCy Schubert 	if (!signed_conn)
2595c1d255d3SCy Schubert 		goto fail;
2596c1d255d3SCy Schubert 	pos = signed_conn;
2597c1d255d3SCy Schubert 	os_memcpy(pos, signed1, signed1_len);
2598c1d255d3SCy Schubert 	pos += signed1_len;
2599c1d255d3SCy Schubert 	*pos++ = '.';
2600c1d255d3SCy Schubert 	os_memcpy(pos, signed2, signed2_len);
2601c1d255d3SCy Schubert 	pos += signed2_len;
2602c1d255d3SCy Schubert 	*pos++ = '.';
2603c1d255d3SCy Schubert 	os_memcpy(pos, signed3, signed3_len);
2604c1d255d3SCy Schubert 	pos += signed3_len;
2605c1d255d3SCy Schubert 	*pos = '\0';
2606c1d255d3SCy Schubert 
2607c1d255d3SCy Schubert fail:
2608c1d255d3SCy Schubert 	os_free(signed1);
2609c1d255d3SCy Schubert 	os_free(signed2);
2610c1d255d3SCy Schubert 	os_free(signed3);
2611c1d255d3SCy Schubert 	return signed_conn;
2612c1d255d3SCy Schubert }
2613c1d255d3SCy Schubert 
2614c1d255d3SCy Schubert 
2615c1d255d3SCy Schubert #ifdef CONFIG_DPP2
2616c1d255d3SCy Schubert 
2617c1d255d3SCy Schubert struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
2618c1d255d3SCy Schubert 			      size_t net_access_key_len)
2619c1d255d3SCy Schubert {
2620c1d255d3SCy Schubert 	struct wpabuf *pub = NULL;
2621*db0ac6deSCy Schubert 	EVP_PKEY *own_key;
2622c1d255d3SCy Schubert 	struct dpp_pfs *pfs;
2623c1d255d3SCy Schubert 
2624c1d255d3SCy Schubert 	pfs = os_zalloc(sizeof(*pfs));
2625c1d255d3SCy Schubert 	if (!pfs)
2626c1d255d3SCy Schubert 		return NULL;
2627c1d255d3SCy Schubert 
2628c1d255d3SCy Schubert 	own_key = dpp_set_keypair(&pfs->curve, net_access_key,
2629c1d255d3SCy Schubert 				  net_access_key_len);
2630c1d255d3SCy Schubert 	if (!own_key) {
2631c1d255d3SCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
2632c1d255d3SCy Schubert 		goto fail;
2633c1d255d3SCy Schubert 	}
2634*db0ac6deSCy Schubert 	EVP_PKEY_free(own_key);
2635c1d255d3SCy Schubert 
2636c1d255d3SCy Schubert 	pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
2637c1d255d3SCy Schubert 	if (!pfs->ecdh)
2638c1d255d3SCy Schubert 		goto fail;
2639c1d255d3SCy Schubert 
2640c1d255d3SCy Schubert 	pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
2641c1d255d3SCy Schubert 	pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
2642c1d255d3SCy Schubert 	if (!pub)
2643c1d255d3SCy Schubert 		goto fail;
2644c1d255d3SCy Schubert 
2645c1d255d3SCy Schubert 	pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
2646c1d255d3SCy Schubert 	if (!pfs->ie)
2647c1d255d3SCy Schubert 		goto fail;
2648c1d255d3SCy Schubert 	wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
2649c1d255d3SCy Schubert 	wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
2650c1d255d3SCy Schubert 	wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
2651c1d255d3SCy Schubert 	wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
2652c1d255d3SCy Schubert 	wpabuf_put_buf(pfs->ie, pub);
2653c1d255d3SCy Schubert 	wpabuf_free(pub);
2654c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
2655c1d255d3SCy Schubert 			pfs->ie);
2656c1d255d3SCy Schubert 
2657c1d255d3SCy Schubert 	return pfs;
2658c1d255d3SCy Schubert fail:
2659c1d255d3SCy Schubert 	wpabuf_free(pub);
2660c1d255d3SCy Schubert 	dpp_pfs_free(pfs);
2661c1d255d3SCy Schubert 	return NULL;
2662c1d255d3SCy Schubert }
2663c1d255d3SCy Schubert 
2664c1d255d3SCy Schubert 
2665c1d255d3SCy Schubert int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
2666c1d255d3SCy Schubert {
2667c1d255d3SCy Schubert 	if (peer_ie_len < 2)
2668c1d255d3SCy Schubert 		return -1;
2669c1d255d3SCy Schubert 	if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
2670c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
2671c1d255d3SCy Schubert 		return -1;
2672c1d255d3SCy Schubert 	}
2673c1d255d3SCy Schubert 
2674c1d255d3SCy Schubert 	pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
2675c1d255d3SCy Schubert 					      peer_ie_len - 2);
2676c1d255d3SCy Schubert 	pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
2677c1d255d3SCy Schubert 	if (!pfs->secret) {
2678c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
2679c1d255d3SCy Schubert 		return -1;
2680c1d255d3SCy Schubert 	}
2681c1d255d3SCy Schubert 	wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
2682c1d255d3SCy Schubert 	return 0;
2683c1d255d3SCy Schubert }
2684c1d255d3SCy Schubert 
2685c1d255d3SCy Schubert 
2686c1d255d3SCy Schubert void dpp_pfs_free(struct dpp_pfs *pfs)
2687c1d255d3SCy Schubert {
2688c1d255d3SCy Schubert 	if (!pfs)
2689c1d255d3SCy Schubert 		return;
2690c1d255d3SCy Schubert 	crypto_ecdh_deinit(pfs->ecdh);
2691c1d255d3SCy Schubert 	wpabuf_free(pfs->ie);
2692c1d255d3SCy Schubert 	wpabuf_clear_free(pfs->secret);
2693c1d255d3SCy Schubert 	os_free(pfs);
2694c1d255d3SCy Schubert }
2695c1d255d3SCy Schubert 
2696c1d255d3SCy Schubert 
2697c1d255d3SCy Schubert struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
2698c1d255d3SCy Schubert {
2699*db0ac6deSCy Schubert 	X509_REQ *req = NULL;
2700c1d255d3SCy Schubert 	struct wpabuf *buf = NULL;
2701*db0ac6deSCy Schubert 	unsigned char *der;
2702*db0ac6deSCy Schubert 	int der_len;
2703*db0ac6deSCy Schubert 	EVP_PKEY *key;
2704*db0ac6deSCy Schubert 	const EVP_MD *sign_md;
2705c1d255d3SCy Schubert 	unsigned int hash_len = auth->curve->hash_len;
2706*db0ac6deSCy Schubert 	EC_KEY *eckey;
2707*db0ac6deSCy Schubert 	BIO *out = NULL;
2708c1d255d3SCy Schubert 	u8 cp[DPP_CP_LEN];
2709*db0ac6deSCy Schubert 	char *password;
2710c1d255d3SCy Schubert 	size_t password_len;
2711*db0ac6deSCy Schubert 	int res;
2712c1d255d3SCy Schubert 
2713c1d255d3SCy Schubert 	/* TODO: use auth->csrattrs */
2714c1d255d3SCy Schubert 
2715c1d255d3SCy Schubert 	/* TODO: support generation of a new private key if csrAttrs requests
2716c1d255d3SCy Schubert 	 * a specific group to be used */
2717c1d255d3SCy Schubert 	key = auth->own_protocol_key;
2718c1d255d3SCy Schubert 
2719*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get1_EC_KEY(key);
2720*db0ac6deSCy Schubert 	if (!eckey)
2721*db0ac6deSCy Schubert 		goto fail;
2722*db0ac6deSCy Schubert 	der = NULL;
2723*db0ac6deSCy Schubert 	der_len = i2d_ECPrivateKey(eckey, &der);
2724*db0ac6deSCy Schubert 	if (der_len <= 0)
2725c1d255d3SCy Schubert 		goto fail;
2726c1d255d3SCy Schubert 	wpabuf_free(auth->priv_key);
2727*db0ac6deSCy Schubert 	auth->priv_key = wpabuf_alloc_copy(der, der_len);
2728*db0ac6deSCy Schubert 	OPENSSL_free(der);
2729*db0ac6deSCy Schubert 	if (!auth->priv_key)
2730c1d255d3SCy Schubert 		goto fail;
2731c1d255d3SCy Schubert 
2732*db0ac6deSCy Schubert 	req = X509_REQ_new();
2733*db0ac6deSCy Schubert 	if (!req || !X509_REQ_set_pubkey(req, key))
2734c1d255d3SCy Schubert 		goto fail;
2735c1d255d3SCy Schubert 
2736*db0ac6deSCy Schubert 	if (name) {
2737*db0ac6deSCy Schubert 		X509_NAME *n;
2738*db0ac6deSCy Schubert 
2739*db0ac6deSCy Schubert 		n = X509_REQ_get_subject_name(req);
2740*db0ac6deSCy Schubert 		if (!n)
2741*db0ac6deSCy Schubert 			goto fail;
2742*db0ac6deSCy Schubert 
2743*db0ac6deSCy Schubert 		if (X509_NAME_add_entry_by_txt(
2744*db0ac6deSCy Schubert 			    n, "CN", MBSTRING_UTF8,
2745*db0ac6deSCy Schubert 			    (const unsigned char *) name, -1, -1, 0) != 1)
2746*db0ac6deSCy Schubert 			goto fail;
2747*db0ac6deSCy Schubert 	}
2748*db0ac6deSCy Schubert 
2749c1d255d3SCy Schubert 	/* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
2750c1d255d3SCy Schubert 	if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
2751c1d255d3SCy Schubert 			    "CSR challengePassword", cp, DPP_CP_LEN) < 0)
2752c1d255d3SCy Schubert 		goto fail;
2753c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2754c1d255d3SCy Schubert 			"DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
2755c1d255d3SCy Schubert 			cp, DPP_CP_LEN);
2756c1d255d3SCy Schubert 	password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
2757c1d255d3SCy Schubert 	forced_memzero(cp, DPP_CP_LEN);
2758*db0ac6deSCy Schubert 	if (!password)
2759c1d255d3SCy Schubert 		goto fail;
2760c1d255d3SCy Schubert 
2761*db0ac6deSCy Schubert 	res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
2762*db0ac6deSCy Schubert 					V_ASN1_UTF8STRING,
2763*db0ac6deSCy Schubert 					(const unsigned char *) password,
2764*db0ac6deSCy Schubert 					password_len);
2765*db0ac6deSCy Schubert 	bin_clear_free(password, password_len);
2766*db0ac6deSCy Schubert 	if (!res)
2767*db0ac6deSCy Schubert 		goto fail;
2768*db0ac6deSCy Schubert 
2769*db0ac6deSCy Schubert 	/* TODO */
2770*db0ac6deSCy Schubert 
2771c1d255d3SCy Schubert 	/* TODO: hash func selection based on csrAttrs */
2772c1d255d3SCy Schubert 	if (hash_len == SHA256_MAC_LEN) {
2773*db0ac6deSCy Schubert 		sign_md = EVP_sha256();
2774c1d255d3SCy Schubert 	} else if (hash_len == SHA384_MAC_LEN) {
2775*db0ac6deSCy Schubert 		sign_md = EVP_sha384();
2776c1d255d3SCy Schubert 	} else if (hash_len == SHA512_MAC_LEN) {
2777*db0ac6deSCy Schubert 		sign_md = EVP_sha512();
2778c1d255d3SCy Schubert 	} else {
2779c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
2780c1d255d3SCy Schubert 		goto fail;
2781c1d255d3SCy Schubert 	}
2782c1d255d3SCy Schubert 
2783*db0ac6deSCy Schubert 	if (!X509_REQ_sign(req, key, sign_md))
2784c1d255d3SCy Schubert 		goto fail;
2785*db0ac6deSCy Schubert 
2786*db0ac6deSCy Schubert 	der = NULL;
2787*db0ac6deSCy Schubert 	der_len = i2d_X509_REQ(req, &der);
2788*db0ac6deSCy Schubert 	if (der_len < 0)
2789*db0ac6deSCy Schubert 		goto fail;
2790*db0ac6deSCy Schubert 	buf = wpabuf_alloc_copy(der, der_len);
2791*db0ac6deSCy Schubert 	OPENSSL_free(der);
2792*db0ac6deSCy Schubert 
2793c1d255d3SCy Schubert 	wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
2794c1d255d3SCy Schubert 
2795c1d255d3SCy Schubert fail:
2796*db0ac6deSCy Schubert 	BIO_free_all(out);
2797*db0ac6deSCy Schubert 	X509_REQ_free(req);
2798c1d255d3SCy Schubert 	return buf;
2799c1d255d3SCy Schubert }
2800c1d255d3SCy Schubert 
2801c1d255d3SCy Schubert 
2802*db0ac6deSCy Schubert struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7)
2803c1d255d3SCy Schubert {
2804*db0ac6deSCy Schubert #ifdef OPENSSL_IS_BORINGSSL
2805*db0ac6deSCy Schubert 	CBS pkcs7_cbs;
2806*db0ac6deSCy Schubert #else /* OPENSSL_IS_BORINGSSL */
2807*db0ac6deSCy Schubert 	PKCS7 *p7 = NULL;
2808*db0ac6deSCy Schubert 	const unsigned char *p = wpabuf_head(pkcs7);
2809*db0ac6deSCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
2810*db0ac6deSCy Schubert 	STACK_OF(X509) *certs;
2811*db0ac6deSCy Schubert 	int i, num;
2812*db0ac6deSCy Schubert 	BIO *out = NULL;
2813*db0ac6deSCy Schubert 	size_t rlen;
2814*db0ac6deSCy Schubert 	struct wpabuf *pem = NULL;
2815*db0ac6deSCy Schubert 	int res;
2816*db0ac6deSCy Schubert 
2817*db0ac6deSCy Schubert #ifdef OPENSSL_IS_BORINGSSL
2818*db0ac6deSCy Schubert 	certs = sk_X509_new_null();
2819*db0ac6deSCy Schubert 	if (!certs)
2820*db0ac6deSCy Schubert 		goto fail;
2821*db0ac6deSCy Schubert 	CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
2822*db0ac6deSCy Schubert 	if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
2823*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
2824*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2825*db0ac6deSCy Schubert 		goto fail;
2826*db0ac6deSCy Schubert 	}
2827*db0ac6deSCy Schubert #else /* OPENSSL_IS_BORINGSSL */
2828*db0ac6deSCy Schubert 	p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
2829*db0ac6deSCy Schubert 	if (!p7) {
2830*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
2831*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
2832*db0ac6deSCy Schubert 		goto fail;
2833*db0ac6deSCy Schubert 	}
2834*db0ac6deSCy Schubert 
2835*db0ac6deSCy Schubert 	switch (OBJ_obj2nid(p7->type)) {
2836*db0ac6deSCy Schubert 	case NID_pkcs7_signed:
2837*db0ac6deSCy Schubert 		certs = p7->d.sign->cert;
2838*db0ac6deSCy Schubert 		break;
2839*db0ac6deSCy Schubert 	case NID_pkcs7_signedAndEnveloped:
2840*db0ac6deSCy Schubert 		certs = p7->d.signed_and_enveloped->cert;
2841*db0ac6deSCy Schubert 		break;
2842*db0ac6deSCy Schubert 	default:
2843*db0ac6deSCy Schubert 		certs = NULL;
2844*db0ac6deSCy Schubert 		break;
2845*db0ac6deSCy Schubert 	}
2846*db0ac6deSCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
2847*db0ac6deSCy Schubert 
2848*db0ac6deSCy Schubert 	if (!certs || ((num = sk_X509_num(certs)) == 0)) {
2849*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO,
2850*db0ac6deSCy Schubert 			   "DPP: No certificates found in PKCS#7 object");
2851*db0ac6deSCy Schubert 		goto fail;
2852*db0ac6deSCy Schubert 	}
2853*db0ac6deSCy Schubert 
2854*db0ac6deSCy Schubert 	out = BIO_new(BIO_s_mem());
2855*db0ac6deSCy Schubert 	if (!out)
2856*db0ac6deSCy Schubert 		goto fail;
2857*db0ac6deSCy Schubert 
2858*db0ac6deSCy Schubert 	for (i = 0; i < num; i++) {
2859*db0ac6deSCy Schubert 		X509 *cert = sk_X509_value(certs, i);
2860*db0ac6deSCy Schubert 
2861*db0ac6deSCy Schubert 		PEM_write_bio_X509(out, cert);
2862*db0ac6deSCy Schubert 	}
2863*db0ac6deSCy Schubert 
2864*db0ac6deSCy Schubert 	rlen = BIO_ctrl_pending(out);
2865*db0ac6deSCy Schubert 	pem = wpabuf_alloc(rlen);
2866*db0ac6deSCy Schubert 	if (!pem)
2867*db0ac6deSCy Schubert 		goto fail;
2868*db0ac6deSCy Schubert 	res = BIO_read(out, wpabuf_put(pem, 0), rlen);
2869*db0ac6deSCy Schubert 	if (res <= 0) {
2870*db0ac6deSCy Schubert 		wpabuf_free(pem);
2871*db0ac6deSCy Schubert 		pem = NULL;
2872*db0ac6deSCy Schubert 		goto fail;
2873*db0ac6deSCy Schubert 	}
2874*db0ac6deSCy Schubert 	wpabuf_put(pem, res);
2875*db0ac6deSCy Schubert 
2876*db0ac6deSCy Schubert fail:
2877*db0ac6deSCy Schubert #ifdef OPENSSL_IS_BORINGSSL
2878*db0ac6deSCy Schubert 	if (certs)
2879*db0ac6deSCy Schubert 		sk_X509_pop_free(certs, X509_free);
2880*db0ac6deSCy Schubert #else /* OPENSSL_IS_BORINGSSL */
2881*db0ac6deSCy Schubert 	PKCS7_free(p7);
2882*db0ac6deSCy Schubert #endif /* OPENSSL_IS_BORINGSSL */
2883*db0ac6deSCy Schubert 	if (out)
2884*db0ac6deSCy Schubert 		BIO_free_all(out);
2885*db0ac6deSCy Schubert 
2886*db0ac6deSCy Schubert 	return pem;
2887*db0ac6deSCy Schubert }
2888*db0ac6deSCy Schubert 
2889*db0ac6deSCy Schubert 
2890*db0ac6deSCy Schubert int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
2891*db0ac6deSCy Schubert {
2892*db0ac6deSCy Schubert 	X509_REQ *req;
2893*db0ac6deSCy Schubert 	const unsigned char *pos;
2894*db0ac6deSCy Schubert 	EVP_PKEY *pkey;
2895*db0ac6deSCy Schubert 	int res, loc, ret = -1;
2896*db0ac6deSCy Schubert 	X509_ATTRIBUTE *attr;
2897*db0ac6deSCy Schubert 	ASN1_TYPE *type;
2898*db0ac6deSCy Schubert 	ASN1_STRING *str;
2899*db0ac6deSCy Schubert 	unsigned char *utf8 = NULL;
2900c1d255d3SCy Schubert 	unsigned char *cp = NULL;
2901c1d255d3SCy Schubert 	size_t cp_len;
2902c1d255d3SCy Schubert 	u8 exp_cp[DPP_CP_LEN];
2903c1d255d3SCy Schubert 	unsigned int hash_len = auth->curve->hash_len;
2904c1d255d3SCy Schubert 
2905*db0ac6deSCy Schubert 	pos = wpabuf_head(csr);
2906*db0ac6deSCy Schubert 	req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
2907*db0ac6deSCy Schubert 	if (!req) {
2908*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
2909*db0ac6deSCy Schubert 		return -1;
2910*db0ac6deSCy Schubert 	}
2911*db0ac6deSCy Schubert 
2912*db0ac6deSCy Schubert 	pkey = X509_REQ_get_pubkey(req);
2913*db0ac6deSCy Schubert 	if (!pkey) {
2914*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
2915c1d255d3SCy Schubert 		goto fail;
2916c1d255d3SCy Schubert 	}
2917c1d255d3SCy Schubert 
2918*db0ac6deSCy Schubert 	res = X509_REQ_verify(req, pkey);
2919*db0ac6deSCy Schubert 	EVP_PKEY_free(pkey);
2920*db0ac6deSCy Schubert 	if (res != 1) {
2921*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
2922*db0ac6deSCy Schubert 			   "DPP: CSR does not have a valid signature");
2923*db0ac6deSCy Schubert 		goto fail;
2924*db0ac6deSCy Schubert 	}
2925*db0ac6deSCy Schubert 
2926*db0ac6deSCy Schubert 	loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
2927*db0ac6deSCy Schubert 	if (loc < 0) {
2928c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2929c1d255d3SCy Schubert 			   "DPP: CSR does not include challengePassword");
2930c1d255d3SCy Schubert 		goto fail;
2931c1d255d3SCy Schubert 	}
2932*db0ac6deSCy Schubert 
2933*db0ac6deSCy Schubert 	attr = X509_REQ_get_attr(req, loc);
2934*db0ac6deSCy Schubert 	if (!attr) {
2935c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2936*db0ac6deSCy Schubert 			   "DPP: Could not get challengePassword attribute");
2937c1d255d3SCy Schubert 		goto fail;
2938c1d255d3SCy Schubert 	}
2939c1d255d3SCy Schubert 
2940*db0ac6deSCy Schubert 	type = X509_ATTRIBUTE_get0_type(attr, 0);
2941*db0ac6deSCy Schubert 	if (!type) {
2942*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
2943*db0ac6deSCy Schubert 			   "DPP: Could not get challengePassword attribute type");
2944*db0ac6deSCy Schubert 		goto fail;
2945*db0ac6deSCy Schubert 	}
2946*db0ac6deSCy Schubert 
2947*db0ac6deSCy Schubert 	res = ASN1_TYPE_get(type);
2948*db0ac6deSCy Schubert 	/* This is supposed to be UTF8String, but allow other strings as well
2949*db0ac6deSCy Schubert 	 * since challengePassword is using ASCII (base64 encoded). */
2950*db0ac6deSCy Schubert 	if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
2951*db0ac6deSCy Schubert 	    res != V_ASN1_IA5STRING) {
2952*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
2953*db0ac6deSCy Schubert 			   "DPP: Unexpected challengePassword attribute type %d",
2954*db0ac6deSCy Schubert 			   res);
2955*db0ac6deSCy Schubert 		goto fail;
2956*db0ac6deSCy Schubert 	}
2957*db0ac6deSCy Schubert 
2958*db0ac6deSCy Schubert 	str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
2959*db0ac6deSCy Schubert 	if (!str) {
2960*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
2961*db0ac6deSCy Schubert 			   "DPP: Could not get ASN.1 string for challengePassword");
2962*db0ac6deSCy Schubert 		goto fail;
2963*db0ac6deSCy Schubert 	}
2964*db0ac6deSCy Schubert 
2965*db0ac6deSCy Schubert 	res = ASN1_STRING_to_UTF8(&utf8, str);
2966*db0ac6deSCy Schubert 	if (res < 0) {
2967*db0ac6deSCy Schubert 		wpa_printf(MSG_DEBUG,
2968*db0ac6deSCy Schubert 			   "DPP: Could not get UTF8 version of challengePassword");
2969*db0ac6deSCy Schubert 		goto fail;
2970*db0ac6deSCy Schubert 	}
2971*db0ac6deSCy Schubert 
2972*db0ac6deSCy Schubert 	cp = base64_decode((const char *) utf8, res, &cp_len);
2973*db0ac6deSCy Schubert 	OPENSSL_free(utf8);
2974c1d255d3SCy Schubert 	if (!cp) {
2975c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2976c1d255d3SCy Schubert 			   "DPP: Could not base64 decode challengePassword");
2977c1d255d3SCy Schubert 		goto fail;
2978c1d255d3SCy Schubert 	}
2979c1d255d3SCy Schubert 	if (cp_len != DPP_CP_LEN) {
2980c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2981c1d255d3SCy Schubert 			   "DPP: Unexpected cp length (%zu) in CSR challengePassword",
2982c1d255d3SCy Schubert 			   cp_len);
2983c1d255d3SCy Schubert 		goto fail;
2984c1d255d3SCy Schubert 	}
2985c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG, "DPP: cp from CSR challengePassword",
2986c1d255d3SCy Schubert 			cp, cp_len);
2987c1d255d3SCy Schubert 
2988c1d255d3SCy Schubert 	/* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
2989c1d255d3SCy Schubert 	if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
2990c1d255d3SCy Schubert 			    "CSR challengePassword", exp_cp, DPP_CP_LEN) < 0)
2991c1d255d3SCy Schubert 		goto fail;
2992c1d255d3SCy Schubert 	wpa_hexdump_key(MSG_DEBUG,
2993c1d255d3SCy Schubert 			"DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
2994c1d255d3SCy Schubert 			exp_cp, DPP_CP_LEN);
2995c1d255d3SCy Schubert 	if (os_memcmp_const(cp, exp_cp, DPP_CP_LEN) != 0) {
2996c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
2997c1d255d3SCy Schubert 			   "DPP: CSR challengePassword does not match calculated cp");
2998c1d255d3SCy Schubert 		goto fail;
2999c1d255d3SCy Schubert 	}
3000c1d255d3SCy Schubert 
3001c1d255d3SCy Schubert 	ret = 0;
3002c1d255d3SCy Schubert fail:
3003c1d255d3SCy Schubert 	os_free(cp);
3004*db0ac6deSCy Schubert 	X509_REQ_free(req);
3005c1d255d3SCy Schubert 	return ret;
3006c1d255d3SCy Schubert }
3007c1d255d3SCy Schubert 
3008c1d255d3SCy Schubert 
3009c1d255d3SCy Schubert struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
3010c1d255d3SCy Schubert 					     size_t csign_key_len,
3011c1d255d3SCy Schubert 					     const u8 *pp_key,
3012c1d255d3SCy Schubert 					     size_t pp_key_len)
3013c1d255d3SCy Schubert {
3014*db0ac6deSCy Schubert 	const unsigned char *p;
3015*db0ac6deSCy Schubert 	EVP_PKEY *csign = NULL, *ppkey = NULL;
3016c1d255d3SCy Schubert 	struct dpp_reconfig_id *id = NULL;
3017*db0ac6deSCy Schubert 	BN_CTX *ctx = NULL;
3018*db0ac6deSCy Schubert 	BIGNUM *bn = NULL, *q = NULL;
3019*db0ac6deSCy Schubert 	const EC_KEY *eckey;
3020*db0ac6deSCy Schubert 	const EC_GROUP *group;
3021*db0ac6deSCy Schubert 	EC_POINT *e_id = NULL;
3022c1d255d3SCy Schubert 
3023*db0ac6deSCy Schubert 	p = csign_key;
3024*db0ac6deSCy Schubert 	csign = d2i_PUBKEY(NULL, &p, csign_key_len);
3025c1d255d3SCy Schubert 	if (!csign)
3026c1d255d3SCy Schubert 		goto fail;
3027c1d255d3SCy Schubert 
3028c1d255d3SCy Schubert 	if (!pp_key)
3029c1d255d3SCy Schubert 		goto fail;
3030*db0ac6deSCy Schubert 	p = pp_key;
3031*db0ac6deSCy Schubert 	ppkey = d2i_PUBKEY(NULL, &p, pp_key_len);
3032c1d255d3SCy Schubert 	if (!ppkey)
3033c1d255d3SCy Schubert 		goto fail;
3034c1d255d3SCy Schubert 
3035*db0ac6deSCy Schubert 	eckey = EVP_PKEY_get0_EC_KEY(csign);
3036*db0ac6deSCy Schubert 	if (!eckey)
3037*db0ac6deSCy Schubert 		goto fail;
3038*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(eckey);
3039*db0ac6deSCy Schubert 	if (!group)
3040c1d255d3SCy Schubert 		goto fail;
3041c1d255d3SCy Schubert 
3042*db0ac6deSCy Schubert 	e_id = EC_POINT_new(group);
3043*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
3044*db0ac6deSCy Schubert 	bn = BN_new();
3045*db0ac6deSCy Schubert 	q = BN_new();
3046*db0ac6deSCy Schubert 	if (!e_id || !ctx || !bn || !q ||
3047*db0ac6deSCy Schubert 	    !EC_GROUP_get_order(group, q, ctx) ||
3048*db0ac6deSCy Schubert 	    !BN_rand_range(bn, q) ||
3049*db0ac6deSCy Schubert 	    !EC_POINT_mul(group, e_id, bn, NULL, NULL, ctx))
3050c1d255d3SCy Schubert 		goto fail;
3051c1d255d3SCy Schubert 
3052*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Generated random point E-id", group, e_id);
3053c1d255d3SCy Schubert 
3054c1d255d3SCy Schubert 	id = os_zalloc(sizeof(*id));
3055c1d255d3SCy Schubert 	if (!id)
3056c1d255d3SCy Schubert 		goto fail;
3057*db0ac6deSCy Schubert 	id->group = group;
3058c1d255d3SCy Schubert 	id->e_id = e_id;
3059c1d255d3SCy Schubert 	e_id = NULL;
3060c1d255d3SCy Schubert 	id->csign = csign;
3061c1d255d3SCy Schubert 	csign = NULL;
3062c1d255d3SCy Schubert 	id->pp_key = ppkey;
3063c1d255d3SCy Schubert 	ppkey = NULL;
3064c1d255d3SCy Schubert fail:
3065*db0ac6deSCy Schubert 	EC_POINT_free(e_id);
3066*db0ac6deSCy Schubert 	EVP_PKEY_free(csign);
3067*db0ac6deSCy Schubert 	EVP_PKEY_free(ppkey);
3068*db0ac6deSCy Schubert 	BN_clear_free(bn);
3069*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
3070c1d255d3SCy Schubert 	return id;
3071c1d255d3SCy Schubert }
3072c1d255d3SCy Schubert 
3073c1d255d3SCy Schubert 
3074*db0ac6deSCy Schubert static EVP_PKEY * dpp_pkey_from_point(const EC_GROUP *group,
3075*db0ac6deSCy Schubert 				      const EC_POINT *point)
3076*db0ac6deSCy Schubert {
3077*db0ac6deSCy Schubert 	EC_KEY *eckey;
3078*db0ac6deSCy Schubert 	EVP_PKEY *pkey = NULL;
3079*db0ac6deSCy Schubert 
3080*db0ac6deSCy Schubert 	eckey = EC_KEY_new();
3081*db0ac6deSCy Schubert 	if (!eckey ||
3082*db0ac6deSCy Schubert 	    EC_KEY_set_group(eckey, group) != 1 ||
3083*db0ac6deSCy Schubert 	    EC_KEY_set_public_key(eckey, point) != 1) {
3084*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR,
3085*db0ac6deSCy Schubert 			   "DPP: Failed to set EC_KEY: %s",
3086*db0ac6deSCy Schubert 			   ERR_error_string(ERR_get_error(), NULL));
3087*db0ac6deSCy Schubert 		goto fail;
3088*db0ac6deSCy Schubert 	}
3089*db0ac6deSCy Schubert 	EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
3090*db0ac6deSCy Schubert 
3091*db0ac6deSCy Schubert 	pkey = EVP_PKEY_new();
3092*db0ac6deSCy Schubert 	if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
3093*db0ac6deSCy Schubert 		wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
3094*db0ac6deSCy Schubert 		EVP_PKEY_free(pkey);
3095*db0ac6deSCy Schubert 		pkey = NULL;
3096*db0ac6deSCy Schubert 		goto fail;
3097*db0ac6deSCy Schubert 	}
3098*db0ac6deSCy Schubert 
3099*db0ac6deSCy Schubert fail:
3100*db0ac6deSCy Schubert 	EC_KEY_free(eckey);
3101*db0ac6deSCy Schubert 	return pkey;
3102*db0ac6deSCy Schubert }
3103*db0ac6deSCy Schubert 
3104*db0ac6deSCy Schubert 
3105c1d255d3SCy Schubert int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
3106c1d255d3SCy Schubert {
3107*db0ac6deSCy Schubert 	BN_CTX *ctx = NULL;
3108*db0ac6deSCy Schubert 	BIGNUM *bn = NULL, *q = NULL;
3109*db0ac6deSCy Schubert 	EC_POINT *e_prime_id = NULL, *a_nonce = NULL;
3110c1d255d3SCy Schubert 	int ret = -1;
3111*db0ac6deSCy Schubert 	const EC_KEY *pp;
3112*db0ac6deSCy Schubert 	const EC_POINT *pp_point;
3113c1d255d3SCy Schubert 
3114*db0ac6deSCy Schubert 	pp = EVP_PKEY_get0_EC_KEY(id->pp_key);
3115*db0ac6deSCy Schubert 	if (!pp)
3116*db0ac6deSCy Schubert 		goto fail;
3117*db0ac6deSCy Schubert 	pp_point = EC_KEY_get0_public_key(pp);
3118*db0ac6deSCy Schubert 	e_prime_id = EC_POINT_new(id->group);
3119*db0ac6deSCy Schubert 	a_nonce = EC_POINT_new(id->group);
3120*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
3121*db0ac6deSCy Schubert 	bn = BN_new();
3122*db0ac6deSCy Schubert 	q = BN_new();
3123c1d255d3SCy Schubert 	/* Generate random 0 <= a-nonce < q
3124c1d255d3SCy Schubert 	 * A-NONCE = a-nonce * G
3125c1d255d3SCy Schubert 	 * E'-id = E-id + a-nonce * P_pk */
3126*db0ac6deSCy Schubert 	if (!pp_point || !e_prime_id || !a_nonce || !ctx || !bn || !q ||
3127*db0ac6deSCy Schubert 	    !EC_GROUP_get_order(id->group, q, ctx) ||
3128*db0ac6deSCy Schubert 	    !BN_rand_range(bn, q) || /* bn = a-nonce */
3129*db0ac6deSCy Schubert 	    !EC_POINT_mul(id->group, a_nonce, bn, NULL, NULL, ctx) ||
3130*db0ac6deSCy Schubert 	    !EC_POINT_mul(id->group, e_prime_id, NULL, pp_point, bn, ctx) ||
3131*db0ac6deSCy Schubert 	    !EC_POINT_add(id->group, e_prime_id, id->e_id, e_prime_id, ctx))
3132c1d255d3SCy Schubert 		goto fail;
3133c1d255d3SCy Schubert 
3134*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Generated A-NONCE", id->group, a_nonce);
3135*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Encrypted E-id to E'-id",
3136*db0ac6deSCy Schubert 			      id->group, e_prime_id);
3137c1d255d3SCy Schubert 
3138*db0ac6deSCy Schubert 	EVP_PKEY_free(id->a_nonce);
3139*db0ac6deSCy Schubert 	EVP_PKEY_free(id->e_prime_id);
3140*db0ac6deSCy Schubert 	id->a_nonce = dpp_pkey_from_point(id->group, a_nonce);
3141*db0ac6deSCy Schubert 	id->e_prime_id = dpp_pkey_from_point(id->group, e_prime_id);
3142c1d255d3SCy Schubert 	if (!id->a_nonce || !id->e_prime_id)
3143c1d255d3SCy Schubert 		goto fail;
3144c1d255d3SCy Schubert 
3145c1d255d3SCy Schubert 	ret = 0;
3146c1d255d3SCy Schubert 
3147c1d255d3SCy Schubert fail:
3148*db0ac6deSCy Schubert 	EC_POINT_free(e_prime_id);
3149*db0ac6deSCy Schubert 	EC_POINT_free(a_nonce);
3150*db0ac6deSCy Schubert 	BN_clear_free(bn);
3151*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
3152c1d255d3SCy Schubert 	return ret;
3153c1d255d3SCy Schubert }
3154c1d255d3SCy Schubert 
3155c1d255d3SCy Schubert 
3156c1d255d3SCy Schubert void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
3157c1d255d3SCy Schubert {
3158c1d255d3SCy Schubert 	if (id) {
3159*db0ac6deSCy Schubert 		EC_POINT_clear_free(id->e_id);
3160*db0ac6deSCy Schubert 		EVP_PKEY_free(id->csign);
3161*db0ac6deSCy Schubert 		EVP_PKEY_free(id->a_nonce);
3162*db0ac6deSCy Schubert 		EVP_PKEY_free(id->e_prime_id);
3163*db0ac6deSCy Schubert 		EVP_PKEY_free(id->pp_key);
3164c1d255d3SCy Schubert 		os_free(id);
3165c1d255d3SCy Schubert 	}
3166c1d255d3SCy Schubert }
3167c1d255d3SCy Schubert 
3168c1d255d3SCy Schubert 
3169*db0ac6deSCy Schubert EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
3170*db0ac6deSCy Schubert 			    EVP_PKEY *e_prime_id)
3171c1d255d3SCy Schubert {
3172*db0ac6deSCy Schubert 	const EC_KEY *pp_ec, *a_nonce_ec, *e_prime_id_ec;
3173*db0ac6deSCy Schubert 	const BIGNUM *pp_bn;
3174*db0ac6deSCy Schubert 	const EC_GROUP *group;
3175*db0ac6deSCy Schubert 	EC_POINT *e_id = NULL;
3176*db0ac6deSCy Schubert 	const EC_POINT *a_nonce_point, *e_prime_id_point;
3177*db0ac6deSCy Schubert 	BN_CTX *ctx = NULL;
3178c1d255d3SCy Schubert 
3179c1d255d3SCy Schubert 	if (!ppkey)
3180c1d255d3SCy Schubert 		return NULL;
3181c1d255d3SCy Schubert 
3182c1d255d3SCy Schubert 	/* E-id = E'-id - s_C * A-NONCE */
3183*db0ac6deSCy Schubert 	pp_ec = EVP_PKEY_get0_EC_KEY(ppkey);
3184*db0ac6deSCy Schubert 	a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
3185*db0ac6deSCy Schubert 	e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
3186*db0ac6deSCy Schubert 	if (!pp_ec || !a_nonce_ec || !e_prime_id_ec)
3187c1d255d3SCy Schubert 		return NULL;
3188*db0ac6deSCy Schubert 	pp_bn = EC_KEY_get0_private_key(pp_ec);
3189*db0ac6deSCy Schubert 	group = EC_KEY_get0_group(pp_ec);
3190*db0ac6deSCy Schubert 	a_nonce_point = EC_KEY_get0_public_key(a_nonce_ec);
3191*db0ac6deSCy Schubert 	e_prime_id_point = EC_KEY_get0_public_key(e_prime_id_ec);
3192*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
3193*db0ac6deSCy Schubert 	if (!pp_bn || !group || !a_nonce_point || !e_prime_id_point || !ctx)
3194*db0ac6deSCy Schubert 		goto fail;
3195*db0ac6deSCy Schubert 	e_id = EC_POINT_new(group);
3196*db0ac6deSCy Schubert 	if (!e_id ||
3197*db0ac6deSCy Schubert 	    !EC_POINT_mul(group, e_id, NULL, a_nonce_point, pp_bn, ctx) ||
3198*db0ac6deSCy Schubert 	    !EC_POINT_invert(group, e_id, ctx) ||
3199*db0ac6deSCy Schubert 	    !EC_POINT_add(group, e_id, e_prime_id_point, e_id, ctx)) {
3200*db0ac6deSCy Schubert 		EC_POINT_clear_free(e_id);
3201c1d255d3SCy Schubert 		goto fail;
3202c1d255d3SCy Schubert 	}
3203c1d255d3SCy Schubert 
3204*db0ac6deSCy Schubert 	dpp_debug_print_point("DPP: Decrypted E-id", group, e_id);
3205c1d255d3SCy Schubert 
3206c1d255d3SCy Schubert fail:
3207*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
3208c1d255d3SCy Schubert 	return e_id;
3209c1d255d3SCy Schubert }
3210c1d255d3SCy Schubert 
3211c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
3212c1d255d3SCy Schubert 
3213c1d255d3SCy Schubert 
3214c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
3215c1d255d3SCy Schubert 
3216c1d255d3SCy Schubert int dpp_test_gen_invalid_key(struct wpabuf *msg,
3217c1d255d3SCy Schubert 			     const struct dpp_curve_params *curve)
3218c1d255d3SCy Schubert {
3219*db0ac6deSCy Schubert 	BN_CTX *ctx;
3220*db0ac6deSCy Schubert 	BIGNUM *x, *y;
3221c1d255d3SCy Schubert 	int ret = -1;
3222*db0ac6deSCy Schubert 	EC_GROUP *group;
3223*db0ac6deSCy Schubert 	EC_POINT *point;
3224c1d255d3SCy Schubert 
3225*db0ac6deSCy Schubert 	group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
3226*db0ac6deSCy Schubert 	if (!group)
3227*db0ac6deSCy Schubert 		return -1;
3228*db0ac6deSCy Schubert 
3229*db0ac6deSCy Schubert 	ctx = BN_CTX_new();
3230*db0ac6deSCy Schubert 	point = EC_POINT_new(group);
3231*db0ac6deSCy Schubert 	x = BN_new();
3232*db0ac6deSCy Schubert 	y = BN_new();
3233*db0ac6deSCy Schubert 	if (!ctx || !point || !x || !y)
3234c1d255d3SCy Schubert 		goto fail;
3235c1d255d3SCy Schubert 
3236*db0ac6deSCy Schubert 	if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
3237c1d255d3SCy Schubert 		goto fail;
3238c1d255d3SCy Schubert 
3239*db0ac6deSCy Schubert 	/* Generate a random y coordinate that results in a point that is not
3240*db0ac6deSCy Schubert 	 * on the curve. */
3241*db0ac6deSCy Schubert 	for (;;) {
3242*db0ac6deSCy Schubert 		if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
3243c1d255d3SCy Schubert 			goto fail;
3244c1d255d3SCy Schubert 
3245*db0ac6deSCy Schubert 		if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
3246*db0ac6deSCy Schubert 							ctx) != 1) {
3247*db0ac6deSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
3248*db0ac6deSCy Schubert 		/* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
3249*db0ac6deSCy Schubert 		 * return an error from EC_POINT_set_affine_coordinates_GFp()
3250*db0ac6deSCy Schubert 		 * when the point is not on the curve. */
3251*db0ac6deSCy Schubert 			break;
3252*db0ac6deSCy Schubert #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
3253*db0ac6deSCy Schubert 			goto fail;
3254*db0ac6deSCy Schubert #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
3255c1d255d3SCy Schubert 		}
3256c1d255d3SCy Schubert 
3257*db0ac6deSCy Schubert 		if (!EC_POINT_is_on_curve(group, point, ctx))
3258*db0ac6deSCy Schubert 			break;
3259*db0ac6deSCy Schubert 	}
3260*db0ac6deSCy Schubert 
3261*db0ac6deSCy Schubert 	if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
3262*db0ac6deSCy Schubert 			   curve->prime_len) < 0 ||
3263*db0ac6deSCy Schubert 	    dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
3264*db0ac6deSCy Schubert 			   curve->prime_len) < 0)
3265*db0ac6deSCy Schubert 		goto fail;
3266*db0ac6deSCy Schubert 
3267c1d255d3SCy Schubert 	ret = 0;
3268c1d255d3SCy Schubert fail:
3269*db0ac6deSCy Schubert 	if (ret < 0)
3270*db0ac6deSCy Schubert 		wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
3271*db0ac6deSCy Schubert 	BN_free(x);
3272*db0ac6deSCy Schubert 	BN_free(y);
3273*db0ac6deSCy Schubert 	EC_POINT_free(point);
3274*db0ac6deSCy Schubert 	BN_CTX_free(ctx);
3275*db0ac6deSCy Schubert 	EC_GROUP_free(group);
3276*db0ac6deSCy Schubert 
3277c1d255d3SCy Schubert 	return ret;
3278c1d255d3SCy Schubert }
3279c1d255d3SCy Schubert 
3280c1d255d3SCy Schubert 
3281c1d255d3SCy Schubert char * dpp_corrupt_connector_signature(const char *connector)
3282c1d255d3SCy Schubert {
3283c1d255d3SCy Schubert 	char *tmp, *pos, *signed3 = NULL;
3284c1d255d3SCy Schubert 	unsigned char *signature = NULL;
3285c1d255d3SCy Schubert 	size_t signature_len = 0, signed3_len;
3286c1d255d3SCy Schubert 
3287c1d255d3SCy Schubert 	tmp = os_zalloc(os_strlen(connector) + 5);
3288c1d255d3SCy Schubert 	if (!tmp)
3289c1d255d3SCy Schubert 		goto fail;
3290c1d255d3SCy Schubert 	os_memcpy(tmp, connector, os_strlen(connector));
3291c1d255d3SCy Schubert 
3292c1d255d3SCy Schubert 	pos = os_strchr(tmp, '.');
3293c1d255d3SCy Schubert 	if (!pos)
3294c1d255d3SCy Schubert 		goto fail;
3295c1d255d3SCy Schubert 
3296c1d255d3SCy Schubert 	pos = os_strchr(pos + 1, '.');
3297c1d255d3SCy Schubert 	if (!pos)
3298c1d255d3SCy Schubert 		goto fail;
3299c1d255d3SCy Schubert 	pos++;
3300c1d255d3SCy Schubert 
3301c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
3302c1d255d3SCy Schubert 		   pos);
3303c1d255d3SCy Schubert 	signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
3304c1d255d3SCy Schubert 	if (!signature || signature_len == 0)
3305c1d255d3SCy Schubert 		goto fail;
3306c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
3307c1d255d3SCy Schubert 		    signature, signature_len);
3308c1d255d3SCy Schubert 	signature[signature_len - 1] ^= 0x01;
3309c1d255d3SCy Schubert 	wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
3310c1d255d3SCy Schubert 		    signature, signature_len);
3311c1d255d3SCy Schubert 	signed3 = base64_url_encode(signature, signature_len, &signed3_len);
3312c1d255d3SCy Schubert 	if (!signed3)
3313c1d255d3SCy Schubert 		goto fail;
3314c1d255d3SCy Schubert 	os_memcpy(pos, signed3, signed3_len);
3315c1d255d3SCy Schubert 	pos[signed3_len] = '\0';
3316c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
3317c1d255d3SCy Schubert 		   pos);
3318c1d255d3SCy Schubert 
3319c1d255d3SCy Schubert out:
3320c1d255d3SCy Schubert 	os_free(signature);
3321c1d255d3SCy Schubert 	os_free(signed3);
3322c1d255d3SCy Schubert 	return tmp;
3323c1d255d3SCy Schubert fail:
3324c1d255d3SCy Schubert 	os_free(tmp);
3325c1d255d3SCy Schubert 	tmp = NULL;
3326c1d255d3SCy Schubert 	goto out;
3327c1d255d3SCy Schubert }
3328c1d255d3SCy Schubert 
3329c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
3330