blob: f17f95a2ca34c4b38d782a693b2cb12e8b7664c4 [file] [log] [blame]
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001/*
2 * DPP crypto functionality
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2020, The Linux Foundation
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070011
12#include "utils/common.h"
13#include "utils/base64.h"
14#include "utils/json.h"
15#include "common/ieee802_11_defs.h"
16#include "crypto/crypto.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070017#include "crypto/random.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070018#include "crypto/sha384.h"
19#include "crypto/sha512.h"
Hai Shaloma20dcd72022-02-04 13:43:00 -080020#include "tls/asn1.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070021#include "dpp.h"
22#include "dpp_i.h"
23
24
Hai Shalom4fbc08f2020-05-18 12:37:00 -070025static const struct dpp_curve_params dpp_curves[] = {
26 /* The mandatory to support and the default NIST P-256 curve needs to
27 * be the first entry on this list. */
28 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
29 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
30 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
31 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
32 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
33 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
34 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
35};
36
37
38const struct dpp_curve_params * dpp_get_curve_name(const char *name)
39{
40 int i;
41
42 if (!name)
43 return &dpp_curves[0];
44
45 for (i = 0; dpp_curves[i].name; i++) {
46 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
47 (dpp_curves[i].jwk_crv &&
48 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
49 return &dpp_curves[i];
50 }
51 return NULL;
52}
53
54
55const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name)
56{
57 int i;
58
59 for (i = 0; dpp_curves[i].name; i++) {
60 if (dpp_curves[i].jwk_crv &&
61 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
62 return &dpp_curves[i];
63 }
64 return NULL;
65}
66
67
Hai Shalom899fcc72020-10-19 14:38:18 -070068const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
69{
70 int i;
71
72 for (i = 0; dpp_curves[i].name; i++) {
73 if (dpp_curves[i].ike_group == group)
74 return &dpp_curves[i];
75 }
76 return NULL;
77}
78
79
Hai Shaloma20dcd72022-02-04 13:43:00 -080080void dpp_debug_print_key(const char *title, struct crypto_ec_key *key)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070081{
Hai Shaloma20dcd72022-02-04 13:43:00 -080082 struct wpabuf *der = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -070083
Hai Shaloma20dcd72022-02-04 13:43:00 -080084 crypto_ec_key_debug_print(key, title);
Hai Shalom4fbc08f2020-05-18 12:37:00 -070085
Hai Shaloma20dcd72022-02-04 13:43:00 -080086 der = crypto_ec_key_get_ecprivate_key(key, true);
87 if (der) {
88 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: ECPrivateKey", der);
89 } else {
90 der = crypto_ec_key_get_subject_public_key(key);
91 if (der)
92 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: EC_PUBKEY", der);
Hai Shalom4fbc08f2020-05-18 12:37:00 -070093 }
94
Hai Shaloma20dcd72022-02-04 13:43:00 -080095 wpabuf_clear_free(der);
Hai Shalom4fbc08f2020-05-18 12:37:00 -070096}
97
98
99static int dpp_hash_vector(const struct dpp_curve_params *curve,
100 size_t num_elem, const u8 *addr[], const size_t *len,
101 u8 *mac)
102{
103 if (curve->hash_len == 32)
104 return sha256_vector(num_elem, addr, len, mac);
105 if (curve->hash_len == 48)
106 return sha384_vector(num_elem, addr, len, mac);
107 if (curve->hash_len == 64)
108 return sha512_vector(num_elem, addr, len, mac);
109 return -1;
110}
111
112
113int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
114 const char *label, u8 *out, size_t outlen)
115{
116 if (hash_len == 32)
117 return hmac_sha256_kdf(secret, secret_len, NULL,
118 (const u8 *) label, os_strlen(label),
119 out, outlen);
120 if (hash_len == 48)
121 return hmac_sha384_kdf(secret, secret_len, NULL,
122 (const u8 *) label, os_strlen(label),
123 out, outlen);
124 if (hash_len == 64)
125 return hmac_sha512_kdf(secret, secret_len, NULL,
126 (const u8 *) label, os_strlen(label),
127 out, outlen);
128 return -1;
129}
130
131
132int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
133 size_t num_elem, const u8 *addr[], const size_t *len,
134 u8 *mac)
135{
136 if (hash_len == 32)
137 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
138 mac);
139 if (hash_len == 48)
140 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
141 mac);
142 if (hash_len == 64)
143 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
144 mac);
145 return -1;
146}
147
148
149static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
150 const u8 *data, size_t data_len, u8 *mac)
151{
152 if (hash_len == 32)
153 return hmac_sha256(key, key_len, data, data_len, mac);
154 if (hash_len == 48)
155 return hmac_sha384(key, key_len, data, data_len, mac);
156 if (hash_len == 64)
157 return hmac_sha512(key, key_len, data, data_len, mac);
158 return -1;
159}
160
161
162#ifdef CONFIG_DPP2
163
164static int dpp_pbkdf2_f(size_t hash_len,
165 const u8 *password, size_t password_len,
166 const u8 *salt, size_t salt_len,
167 unsigned int iterations, unsigned int count, u8 *digest)
168{
169 unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
170 unsigned int i;
171 size_t j;
172 u8 count_buf[4];
173 const u8 *addr[2];
174 size_t len[2];
175
176 addr[0] = salt;
177 len[0] = salt_len;
178 addr[1] = count_buf;
179 len[1] = 4;
180
181 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
182 * U1 = PRF(P, S || i)
183 * U2 = PRF(P, U1)
184 * Uc = PRF(P, Uc-1)
185 */
186
187 WPA_PUT_BE32(count_buf, count);
188 if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
189 tmp))
190 return -1;
191 os_memcpy(digest, tmp, hash_len);
192
193 for (i = 1; i < iterations; i++) {
194 if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
195 tmp2))
196 return -1;
197 os_memcpy(tmp, tmp2, hash_len);
198 for (j = 0; j < hash_len; j++)
199 digest[j] ^= tmp2[j];
200 }
201
202 return 0;
203}
204
205
206int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
207 const u8 *salt, size_t salt_len, unsigned int iterations,
208 u8 *buf, size_t buflen)
209{
210 unsigned int count = 0;
211 unsigned char *pos = buf;
212 size_t left = buflen, plen;
213 unsigned char digest[DPP_MAX_HASH_LEN];
214
215 while (left > 0) {
216 count++;
217 if (dpp_pbkdf2_f(hash_len, password, password_len,
218 salt, salt_len, iterations, count, digest))
219 return -1;
220 plen = left > hash_len ? hash_len : left;
221 os_memcpy(pos, digest, plen);
222 pos += plen;
223 left -= plen;
224 }
225
226 return 0;
227}
228
229#endif /* CONFIG_DPP2 */
230
231
Hai Shaloma20dcd72022-02-04 13:43:00 -0800232struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key,
233 const u8 *buf, size_t len)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700234{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800235 int ike_group = crypto_ec_key_group(group_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700236
237 if (len & 1)
238 return NULL;
239
Hai Shaloma20dcd72022-02-04 13:43:00 -0800240 if (ike_group < 0) {
241 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700242 return NULL;
243 }
244
Hai Shaloma20dcd72022-02-04 13:43:00 -0800245 return crypto_ec_key_set_pub(ike_group, buf, buf + len / 2, len / 2);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700246}
247
248
Sunil Ravi38ad1ed2023-01-17 23:58:31 +0000249int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash)
250{
251 struct wpabuf *uncomp;
252 const u8 *addr[1];
253 size_t len[1];
254 int res;
255
256 if (!key)
257 return -1;
258
259 uncomp = crypto_ec_key_get_pubkey_point(key, 1);
260 if (!uncomp)
261 return -1;
262 addr[0] = wpabuf_head(uncomp);
263 len[0] = wpabuf_len(uncomp);
264 res = sha256_vector(1, addr, len, hash);
265 wpabuf_free(uncomp);
266 return res;
267}
268
269
Hai Shaloma20dcd72022-02-04 13:43:00 -0800270struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700271{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800272 struct crypto_ec_key *key;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700273
274 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
275
Hai Shaloma20dcd72022-02-04 13:43:00 -0800276 key = crypto_ec_key_gen(curve->ike_group);
277 if (key && wpa_debug_show_keys)
278 dpp_debug_print_key("Own generated key", key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700279
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700280 return key;
281}
282
283
Hai Shaloma20dcd72022-02-04 13:43:00 -0800284struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
285 const u8 *privkey, size_t privkey_len)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700286{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800287 struct crypto_ec_key *key;
288 int group;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700289
Hai Shaloma20dcd72022-02-04 13:43:00 -0800290 key = crypto_ec_key_parse_priv(privkey, privkey_len);
291 if (!key) {
292 wpa_printf(MSG_INFO, "DPP: Failed to parse private key");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700293 return NULL;
294 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800295
296 group = crypto_ec_key_group(key);
297 if (group < 0) {
298 crypto_ec_key_deinit(key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700299 return NULL;
300 }
Hai Shaloma20dcd72022-02-04 13:43:00 -0800301
302 *curve = dpp_get_curve_ike_group(group);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700303 if (!*curve) {
304 wpa_printf(MSG_INFO,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800305 "DPP: Unsupported curve (group=%d) in pre-assigned key",
306 group);
307 crypto_ec_key_deinit(key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700308 return NULL;
309 }
310
Hai Shaloma20dcd72022-02-04 13:43:00 -0800311 return key;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700312}
313
314
315int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
316{
317 struct wpabuf *der;
318 int res;
319
Hai Shaloma20dcd72022-02-04 13:43:00 -0800320 der = crypto_ec_key_get_subject_public_key(bi->pubkey);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700321 if (!der)
322 return -1;
323 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
324 der);
325 res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der));
326 if (res < 0)
327 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
328 wpabuf_free(der);
329 return res;
330}
331
332
333int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
334 const u8 *privkey, size_t privkey_len)
335{
336 char *base64 = NULL;
337 char *pos, *end;
338 size_t len;
339 struct wpabuf *der = NULL;
340
341 bi->curve = dpp_get_curve_name(curve);
342 if (!bi->curve) {
343 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
344 return -1;
345 }
346
347 if (privkey)
348 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
349 else
350 bi->pubkey = dpp_gen_keypair(bi->curve);
351 if (!bi->pubkey)
352 goto fail;
353 bi->own = 1;
354
Hai Shaloma20dcd72022-02-04 13:43:00 -0800355 der = crypto_ec_key_get_subject_public_key(bi->pubkey);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700356 if (!der)
357 goto fail;
358 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
359 der);
360
361 if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) {
362 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
363 goto fail;
364 }
365
366 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
367 wpabuf_free(der);
368 der = NULL;
369 if (!base64)
370 goto fail;
371 pos = base64;
372 end = pos + len;
373 for (;;) {
374 pos = os_strchr(pos, '\n');
375 if (!pos)
376 break;
377 os_memmove(pos, pos + 1, end - pos);
378 }
379 os_free(bi->pk);
380 bi->pk = base64;
381 return 0;
382fail:
383 os_free(base64);
384 wpabuf_free(der);
385 return -1;
386}
387
388
389int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len)
390{
391 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
392 const char *info = "first intermediate key";
393 int res;
394
395 /* k1 = HKDF(<>, "first intermediate key", M.x) */
396
397 /* HKDF-Extract(<>, M.x) */
398 os_memset(salt, 0, hash_len);
399 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
400 return -1;
401 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
402 prk, hash_len);
403
404 /* HKDF-Expand(PRK, info, L) */
405 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
406 os_memset(prk, 0, hash_len);
407 if (res < 0)
408 return -1;
409
410 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
411 k1, hash_len);
412 return 0;
413}
414
415
416int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len)
417{
418 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
419 const char *info = "second intermediate key";
420 int res;
421
422 /* k2 = HKDF(<>, "second intermediate key", N.x) */
423
424 /* HKDF-Extract(<>, N.x) */
425 os_memset(salt, 0, hash_len);
426 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
427 if (res < 0)
428 return -1;
429 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
430 prk, hash_len);
431
432 /* HKDF-Expand(PRK, info, L) */
433 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
434 os_memset(prk, 0, hash_len);
435 if (res < 0)
436 return -1;
437
438 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
439 k2, hash_len);
440 return 0;
441}
442
443
444int dpp_derive_bk_ke(struct dpp_authentication *auth)
445{
446 unsigned int hash_len = auth->curve->hash_len;
447 size_t nonce_len = auth->curve->nonce_len;
448 u8 nonces[2 * DPP_MAX_NONCE_LEN];
449 const char *info_ke = "DPP Key";
450 int res;
451 const u8 *addr[3];
452 size_t len[3];
453 size_t num_elem = 0;
454
455 if (!auth->Mx_len || !auth->Nx_len) {
456 wpa_printf(MSG_DEBUG,
457 "DPP: Mx/Nx not available - cannot derive ke");
458 return -1;
459 }
460
461 /* bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
462 os_memcpy(nonces, auth->i_nonce, nonce_len);
463 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
464 addr[num_elem] = auth->Mx;
465 len[num_elem] = auth->Mx_len;
466 num_elem++;
467 addr[num_elem] = auth->Nx;
468 len[num_elem] = auth->Nx_len;
469 num_elem++;
470 if (auth->peer_bi && auth->own_bi) {
471 if (!auth->Lx_len) {
472 wpa_printf(MSG_DEBUG,
473 "DPP: Lx not available - cannot derive ke");
474 return -1;
475 }
476 addr[num_elem] = auth->Lx;
477 len[num_elem] = auth->secret_len;
478 num_elem++;
479 }
480 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
481 num_elem, addr, len, auth->bk);
482 if (res < 0)
483 return -1;
484 wpa_hexdump_key(MSG_DEBUG,
485 "DPP: bk = HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x])",
486 auth->bk, hash_len);
487
Hai Shalom899fcc72020-10-19 14:38:18 -0700488 /* ke = HKDF-Expand(bk, "DPP Key", length) */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700489 res = dpp_hkdf_expand(hash_len, auth->bk, hash_len, info_ke, auth->ke,
490 hash_len);
491 if (res < 0)
492 return -1;
493
494 wpa_hexdump_key(MSG_DEBUG,
495 "DPP: ke = HKDF-Expand(bk, \"DPP Key\", length)",
496 auth->ke, hash_len);
497
498 return 0;
499}
500
501
Hai Shaloma20dcd72022-02-04 13:43:00 -0800502int dpp_ecdh(struct crypto_ec_key *own, struct crypto_ec_key *peer,
503 u8 *secret, size_t *secret_len)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700504{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800505 struct crypto_ecdh *ecdh;
506 struct wpabuf *peer_pub, *secret_buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700507 int ret = -1;
508
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700509 *secret_len = 0;
510
Hai Shaloma20dcd72022-02-04 13:43:00 -0800511 ecdh = crypto_ecdh_init2(crypto_ec_key_group(own), own);
512 if (!ecdh) {
513 wpa_printf(MSG_ERROR, "DPP: crypto_ecdh_init2() failed");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700514 return -1;
515 }
516
Hai Shaloma20dcd72022-02-04 13:43:00 -0800517 peer_pub = crypto_ec_key_get_pubkey_point(peer, 0);
518 if (!peer_pub) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700519 wpa_printf(MSG_ERROR,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800520 "DPP: crypto_ec_key_get_pubkey_point() failed");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700521 goto fail;
522 }
523
Hai Shaloma20dcd72022-02-04 13:43:00 -0800524 secret_buf = crypto_ecdh_set_peerkey(ecdh, 1, wpabuf_head(peer_pub),
525 wpabuf_len(peer_pub));
526 if (!secret_buf) {
527 wpa_printf(MSG_ERROR, "DPP: crypto_ecdh_set_peerkey() failed");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700528 goto fail;
529 }
530
Hai Shaloma20dcd72022-02-04 13:43:00 -0800531 if (wpabuf_len(secret_buf) > DPP_MAX_SHARED_SECRET_LEN) {
532 wpa_printf(MSG_ERROR, "DPP: ECDH secret longer than expected");
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700533 goto fail;
534 }
535
Hai Shaloma20dcd72022-02-04 13:43:00 -0800536 *secret_len = wpabuf_len(secret_buf);
537 os_memcpy(secret, wpabuf_head(secret_buf), wpabuf_len(secret_buf));
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700538 ret = 0;
539
540fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -0800541 wpabuf_clear_free(secret_buf);
542 wpabuf_free(peer_pub);
543 crypto_ecdh_deinit(ecdh);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700544 return ret;
545}
546
547
548int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
549 const u8 *data, size_t data_len)
550{
551 const u8 *addr[2];
552 size_t len[2];
553
554 addr[0] = data;
555 len[0] = data_len;
556 if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0)
557 return -1;
558 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
559 bi->pubkey_hash, SHA256_MAC_LEN);
560
561 addr[0] = (const u8 *) "chirp";
562 len[0] = 5;
563 addr[1] = data;
564 len[1] = data_len;
565 if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0)
566 return -1;
567 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)",
568 bi->pubkey_hash_chirp, SHA256_MAC_LEN);
569
570 return 0;
571}
572
573
574int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
575 const u8 *data, size_t data_len)
576{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800577 struct crypto_ec_key *key;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700578
579 if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
580 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
581 return -1;
582 }
583
Hai Shaloma20dcd72022-02-04 13:43:00 -0800584 key = crypto_ec_key_parse_pub(data, data_len);
585 if (!key) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700586 wpa_printf(MSG_DEBUG,
587 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
588 return -1;
589 }
590
Hai Shaloma20dcd72022-02-04 13:43:00 -0800591 bi->curve = dpp_get_curve_ike_group(crypto_ec_key_group(key));
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700592 if (!bi->curve) {
593 wpa_printf(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800594 "DPP: Unsupported SubjectPublicKeyInfo curve: group %d",
595 crypto_ec_key_group(key));
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700596 goto fail;
597 }
598
Hai Shaloma20dcd72022-02-04 13:43:00 -0800599 bi->pubkey = key;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700600 return 0;
601fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -0800602 crypto_ec_key_deinit(key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700603 return -1;
604}
605
606
607static struct wpabuf *
608dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
609 const u8 *prot_hdr, u16 prot_hdr_len,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800610 int *hash_func)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700611{
612 struct json_token *root, *token;
613 struct wpabuf *kid = NULL;
614
615 root = json_parse((const char *) prot_hdr, prot_hdr_len);
616 if (!root) {
617 wpa_printf(MSG_DEBUG,
618 "DPP: JSON parsing failed for JWS Protected Header");
619 goto fail;
620 }
621
622 if (root->type != JSON_OBJECT) {
623 wpa_printf(MSG_DEBUG,
624 "DPP: JWS Protected Header root is not an object");
625 goto fail;
626 }
627
628 token = json_get_member(root, "typ");
629 if (!token || token->type != JSON_STRING) {
630 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
631 goto fail;
632 }
633 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
634 token->string);
635 if (os_strcmp(token->string, "dppCon") != 0) {
636 wpa_printf(MSG_DEBUG,
637 "DPP: Unsupported JWS Protected Header typ=%s",
638 token->string);
639 goto fail;
640 }
641
642 token = json_get_member(root, "alg");
643 if (!token || token->type != JSON_STRING) {
644 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
645 goto fail;
646 }
647 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
648 token->string);
649 if (os_strcmp(token->string, curve->jws_alg) != 0) {
650 wpa_printf(MSG_DEBUG,
651 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
652 token->string, curve->jws_alg);
653 goto fail;
654 }
655 if (os_strcmp(token->string, "ES256") == 0 ||
Hai Shaloma20dcd72022-02-04 13:43:00 -0800656 os_strcmp(token->string, "BS256") == 0) {
657 *hash_func = CRYPTO_HASH_ALG_SHA256;
658 } else if (os_strcmp(token->string, "ES384") == 0 ||
659 os_strcmp(token->string, "BS384") == 0) {
660 *hash_func = CRYPTO_HASH_ALG_SHA384;
661 } else if (os_strcmp(token->string, "ES512") == 0 ||
662 os_strcmp(token->string, "BS512") == 0) {
663 *hash_func = CRYPTO_HASH_ALG_SHA512;
664 } else {
665 *hash_func = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700666 wpa_printf(MSG_DEBUG,
667 "DPP: Unsupported JWS Protected Header alg=%s",
668 token->string);
669 goto fail;
670 }
671
672 kid = json_get_member_base64url(root, "kid");
673 if (!kid) {
674 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
675 goto fail;
676 }
677 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
678 kid);
679
680fail:
681 json_free(root);
682 return kid;
683}
684
685
Hai Shaloma20dcd72022-02-04 13:43:00 -0800686static int dpp_check_pubkey_match(struct crypto_ec_key *pub,
687 struct wpabuf *r_hash)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700688{
689 struct wpabuf *uncomp;
690 int res;
691 u8 hash[SHA256_MAC_LEN];
692 const u8 *addr[1];
693 size_t len[1];
694
695 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
696 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800697 uncomp = crypto_ec_key_get_pubkey_point(pub, 1);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700698 if (!uncomp)
699 return -1;
700 addr[0] = wpabuf_head(uncomp);
701 len[0] = wpabuf_len(uncomp);
702 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
703 addr[0], len[0]);
704 res = sha256_vector(1, addr, len, hash);
705 wpabuf_free(uncomp);
706 if (res < 0)
707 return -1;
708 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
709 wpa_printf(MSG_DEBUG,
710 "DPP: Received hash value does not match calculated public key hash value");
711 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
712 hash, SHA256_MAC_LEN);
713 return -1;
714 }
715 return 0;
716}
717
718
719enum dpp_status_error
720dpp_process_signed_connector(struct dpp_signed_connector_info *info,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800721 struct crypto_ec_key *csign_pub,
722 const char *connector)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700723{
724 enum dpp_status_error ret = 255;
725 const char *pos, *end, *signed_start, *signed_end;
726 struct wpabuf *kid = NULL;
727 unsigned char *prot_hdr = NULL, *signature = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800728 size_t prot_hdr_len = 0, signature_len = 0, signed_len;
729 int res, hash_func = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700730 const struct dpp_curve_params *curve;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800731 u8 *hash = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700732
Hai Shaloma20dcd72022-02-04 13:43:00 -0800733 curve = dpp_get_curve_ike_group(crypto_ec_key_group(csign_pub));
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700734 if (!curve)
735 goto fail;
736 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
737 os_memset(info, 0, sizeof(*info));
738
739 signed_start = pos = connector;
740 end = os_strchr(pos, '.');
741 if (!end) {
742 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
743 ret = DPP_STATUS_INVALID_CONNECTOR;
744 goto fail;
745 }
746 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
747 if (!prot_hdr) {
748 wpa_printf(MSG_DEBUG,
749 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
750 ret = DPP_STATUS_INVALID_CONNECTOR;
751 goto fail;
752 }
753 wpa_hexdump_ascii(MSG_DEBUG,
754 "DPP: signedConnector - JWS Protected Header",
755 prot_hdr, prot_hdr_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800756 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &hash_func);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700757 if (!kid) {
758 ret = DPP_STATUS_INVALID_CONNECTOR;
759 goto fail;
760 }
761 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
762 wpa_printf(MSG_DEBUG,
763 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
764 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
765 ret = DPP_STATUS_INVALID_CONNECTOR;
766 goto fail;
767 }
768
769 pos = end + 1;
770 end = os_strchr(pos, '.');
771 if (!end) {
772 wpa_printf(MSG_DEBUG,
773 "DPP: Missing dot(2) in signedConnector");
774 ret = DPP_STATUS_INVALID_CONNECTOR;
775 goto fail;
776 }
777 signed_end = end - 1;
778 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
779 if (!info->payload) {
780 wpa_printf(MSG_DEBUG,
781 "DPP: Failed to base64url decode signedConnector JWS Payload");
782 ret = DPP_STATUS_INVALID_CONNECTOR;
783 goto fail;
784 }
785 wpa_hexdump_ascii(MSG_DEBUG,
786 "DPP: signedConnector - JWS Payload",
787 info->payload, info->payload_len);
788 pos = end + 1;
789 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
790 if (!signature) {
791 wpa_printf(MSG_DEBUG,
792 "DPP: Failed to base64url decode signedConnector signature");
793 ret = DPP_STATUS_INVALID_CONNECTOR;
794 goto fail;
795 }
796 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
797 signature, signature_len);
798
799 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
800 ret = DPP_STATUS_NO_MATCH;
801 goto fail;
802 }
803
804 if (signature_len & 0x01) {
805 wpa_printf(MSG_DEBUG,
806 "DPP: Unexpected signedConnector signature length (%d)",
807 (int) signature_len);
808 ret = DPP_STATUS_INVALID_CONNECTOR;
809 goto fail;
810 }
811
Hai Shaloma20dcd72022-02-04 13:43:00 -0800812 hash = os_malloc(curve->hash_len);
813 if (!hash)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700814 goto fail;
815
Hai Shaloma20dcd72022-02-04 13:43:00 -0800816 signed_len = signed_end - signed_start + 1;
817 if (hash_func == CRYPTO_HASH_ALG_SHA256)
818 res = sha256_vector(1, (const u8 **) &signed_start, &signed_len,
819 hash);
820 else if (hash_func == CRYPTO_HASH_ALG_SHA384)
821 res = sha384_vector(1, (const u8 **) &signed_start, &signed_len,
822 hash);
823 else if (hash_func == CRYPTO_HASH_ALG_SHA512)
824 res = sha512_vector(1, (const u8 **) &signed_start, &signed_len,
825 hash);
826 else
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700827 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800828
829 if (res)
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700830 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800831
832 res = crypto_ec_key_verify_signature_r_s(csign_pub,
833 hash, curve->hash_len,
834 signature, signature_len / 2,
835 signature + signature_len / 2,
836 signature_len / 2);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700837 if (res != 1) {
838 wpa_printf(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -0800839 "DPP: signedConnector signature check failed (res=%d)",
840 res);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700841 ret = DPP_STATUS_INVALID_CONNECTOR;
842 goto fail;
843 }
844
845 ret = DPP_STATUS_OK;
846fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -0800847 os_free(hash);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700848 os_free(prot_hdr);
849 wpabuf_free(kid);
850 os_free(signature);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700851 return ret;
852}
853
854
855enum dpp_status_error
856dpp_check_signed_connector(struct dpp_signed_connector_info *info,
857 const u8 *csign_key, size_t csign_key_len,
858 const u8 *peer_connector, size_t peer_connector_len)
859{
Hai Shaloma20dcd72022-02-04 13:43:00 -0800860 struct crypto_ec_key *csign;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700861 char *signed_connector = NULL;
862 enum dpp_status_error res = DPP_STATUS_INVALID_CONNECTOR;
863
Hai Shaloma20dcd72022-02-04 13:43:00 -0800864 csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700865 if (!csign) {
866 wpa_printf(MSG_ERROR,
867 "DPP: Failed to parse local C-sign-key information");
868 goto fail;
869 }
870
871 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
872 peer_connector, peer_connector_len);
873 signed_connector = os_malloc(peer_connector_len + 1);
874 if (!signed_connector)
875 goto fail;
876 os_memcpy(signed_connector, peer_connector, peer_connector_len);
877 signed_connector[peer_connector_len] = '\0';
878 res = dpp_process_signed_connector(info, csign, signed_connector);
879fail:
880 os_free(signed_connector);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800881 crypto_ec_key_deinit(csign);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700882 return res;
883}
884
885
886int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
887{
888 struct wpabuf *pix, *prx, *bix, *brx;
889 const u8 *addr[7];
890 size_t len[7];
891 size_t i, num_elem = 0;
892 size_t nonce_len;
893 u8 zero = 0;
894 int res = -1;
895
896 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
897 nonce_len = auth->curve->nonce_len;
898
899 if (auth->initiator) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800900 pix = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
901 prx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
902 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700903 if (auth->own_bi)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800904 bix = crypto_ec_key_get_pubkey_point(
905 auth->own_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700906 else
907 bix = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800908 brx = crypto_ec_key_get_pubkey_point(auth->peer_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700909 } else {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800910 pix = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
911 0);
912 prx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700913 if (auth->peer_bi)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800914 bix = crypto_ec_key_get_pubkey_point(
915 auth->peer_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700916 else
917 bix = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800918 brx = crypto_ec_key_get_pubkey_point(auth->own_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700919 }
920 if (!pix || !prx || !brx)
921 goto fail;
922
923 addr[num_elem] = auth->i_nonce;
924 len[num_elem] = nonce_len;
925 num_elem++;
926
927 addr[num_elem] = auth->r_nonce;
928 len[num_elem] = nonce_len;
929 num_elem++;
930
931 addr[num_elem] = wpabuf_head(pix);
932 len[num_elem] = wpabuf_len(pix) / 2;
933 num_elem++;
934
935 addr[num_elem] = wpabuf_head(prx);
936 len[num_elem] = wpabuf_len(prx) / 2;
937 num_elem++;
938
939 if (bix) {
940 addr[num_elem] = wpabuf_head(bix);
941 len[num_elem] = wpabuf_len(bix) / 2;
942 num_elem++;
943 }
944
945 addr[num_elem] = wpabuf_head(brx);
946 len[num_elem] = wpabuf_len(brx) / 2;
947 num_elem++;
948
949 addr[num_elem] = &zero;
950 len[num_elem] = 1;
951 num_elem++;
952
953 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
954 for (i = 0; i < num_elem; i++)
955 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
956 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
957 if (res == 0)
958 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
959 auth->curve->hash_len);
960fail:
961 wpabuf_free(pix);
962 wpabuf_free(prx);
963 wpabuf_free(bix);
964 wpabuf_free(brx);
965 return res;
966}
967
968
969int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
970{
971 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
972 const u8 *addr[7];
973 size_t len[7];
974 size_t i, num_elem = 0;
975 size_t nonce_len;
976 u8 one = 1;
977 int res = -1;
978
979 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
980 nonce_len = auth->curve->nonce_len;
981
982 if (auth->initiator) {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800983 pix = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
984 prx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
985 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700986 if (auth->own_bi)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800987 bix = crypto_ec_key_get_pubkey_point(
988 auth->own_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700989 else
990 bix = NULL;
991 if (!auth->peer_bi)
992 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800993 brx = crypto_ec_key_get_pubkey_point(auth->peer_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700994 } else {
Hai Shaloma20dcd72022-02-04 13:43:00 -0800995 pix = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
996 0);
997 prx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700998 if (auth->peer_bi)
Hai Shaloma20dcd72022-02-04 13:43:00 -0800999 bix = crypto_ec_key_get_pubkey_point(
1000 auth->peer_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001001 else
1002 bix = NULL;
1003 if (!auth->own_bi)
1004 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001005 brx = crypto_ec_key_get_pubkey_point(auth->own_bi->pubkey, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001006 }
1007 if (!pix || !prx || !brx)
1008 goto fail;
1009
1010 addr[num_elem] = auth->r_nonce;
1011 len[num_elem] = nonce_len;
1012 num_elem++;
1013
1014 addr[num_elem] = auth->i_nonce;
1015 len[num_elem] = nonce_len;
1016 num_elem++;
1017
1018 addr[num_elem] = wpabuf_head(prx);
1019 len[num_elem] = wpabuf_len(prx) / 2;
1020 num_elem++;
1021
1022 addr[num_elem] = wpabuf_head(pix);
1023 len[num_elem] = wpabuf_len(pix) / 2;
1024 num_elem++;
1025
1026 addr[num_elem] = wpabuf_head(brx);
1027 len[num_elem] = wpabuf_len(brx) / 2;
1028 num_elem++;
1029
1030 if (bix) {
1031 addr[num_elem] = wpabuf_head(bix);
1032 len[num_elem] = wpabuf_len(bix) / 2;
1033 num_elem++;
1034 }
1035
1036 addr[num_elem] = &one;
1037 len[num_elem] = 1;
1038 num_elem++;
1039
1040 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
1041 for (i = 0; i < num_elem; i++)
1042 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1043 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
1044 if (res == 0)
1045 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
1046 auth->curve->hash_len);
1047fail:
1048 wpabuf_free(pix);
1049 wpabuf_free(prx);
1050 wpabuf_free(bix);
1051 wpabuf_free(brx);
1052 return res;
1053}
1054
1055
1056int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
1057{
Hai Shaloma20dcd72022-02-04 13:43:00 -08001058 struct crypto_ec *ec;
Sunil8cd6f4d2022-06-28 18:40:46 +00001059 struct crypto_ec_point *L = NULL, *BI = NULL;
1060 const struct crypto_bignum *q;
1061 struct crypto_bignum *sum = NULL, *lx = NULL, *bR = NULL, *pR = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001062 int ret = -1;
1063
1064 /* L = ((bR + pR) modulo q) * BI */
1065
Hai Shaloma20dcd72022-02-04 13:43:00 -08001066 ec = crypto_ec_init(crypto_ec_key_group(auth->peer_bi->pubkey));
1067 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001068 goto fail;
1069
Hai Shaloma20dcd72022-02-04 13:43:00 -08001070 q = crypto_ec_get_order(ec);
1071 BI = crypto_ec_key_get_public_key(auth->peer_bi->pubkey);
1072 bR = crypto_ec_key_get_private_key(auth->own_bi->pubkey);
1073 pR = crypto_ec_key_get_private_key(auth->own_protocol_key);
1074 sum = crypto_bignum_init();
1075 L = crypto_ec_point_init(ec);
1076 lx = crypto_bignum_init();
1077 if (!q || !BI || !bR || !pR || !sum || !L || !lx ||
1078 crypto_bignum_addmod(bR, pR, q, sum) ||
1079 crypto_ec_point_mul(ec, BI, sum, L) ||
1080 crypto_ec_point_x(ec, L, lx) ||
1081 crypto_bignum_to_bin(lx, auth->Lx, sizeof(auth->Lx),
1082 auth->secret_len) < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001083 goto fail;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001084
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001085 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1086 auth->Lx_len = auth->secret_len;
1087 ret = 0;
1088fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001089 crypto_bignum_deinit(lx, 1);
1090 crypto_bignum_deinit(sum, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001091 crypto_bignum_deinit(bR, 1);
1092 crypto_bignum_deinit(pR, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001093 crypto_ec_point_deinit(L, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001094 crypto_ec_point_deinit(BI, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001095 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001096 return ret;
1097}
1098
1099
1100int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
1101{
Hai Shaloma20dcd72022-02-04 13:43:00 -08001102 struct crypto_ec *ec;
Sunil8cd6f4d2022-06-28 18:40:46 +00001103 struct crypto_ec_point *L = NULL, *sum = NULL, *BR = NULL, *PR = NULL;
1104 struct crypto_bignum *lx = NULL, *bI = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001105 int ret = -1;
1106
1107 /* L = bI * (BR + PR) */
1108
Hai Shaloma20dcd72022-02-04 13:43:00 -08001109 ec = crypto_ec_init(crypto_ec_key_group(auth->peer_bi->pubkey));
1110 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001111 goto fail;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001112
Hai Shaloma20dcd72022-02-04 13:43:00 -08001113 BR = crypto_ec_key_get_public_key(auth->peer_bi->pubkey);
1114 PR = crypto_ec_key_get_public_key(auth->peer_protocol_key);
1115 bI = crypto_ec_key_get_private_key(auth->own_bi->pubkey);
1116 sum = crypto_ec_point_init(ec);
1117 L = crypto_ec_point_init(ec);
1118 lx = crypto_bignum_init();
1119 if (!BR || !PR || !bI || !sum || !L || !lx ||
1120 crypto_ec_point_add(ec, BR, PR, sum) ||
1121 crypto_ec_point_mul(ec, sum, bI, L) ||
1122 crypto_ec_point_x(ec, L, lx) ||
1123 crypto_bignum_to_bin(lx, auth->Lx, sizeof(auth->Lx),
1124 auth->secret_len) < 0)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001125 goto fail;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001126
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001127 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1128 auth->Lx_len = auth->secret_len;
1129 ret = 0;
1130fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001131 crypto_bignum_deinit(lx, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001132 crypto_bignum_deinit(bI, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001133 crypto_ec_point_deinit(sum, 1);
1134 crypto_ec_point_deinit(L, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001135 crypto_ec_point_deinit(BR, 1);
1136 crypto_ec_point_deinit(PR, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001137 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001138 return ret;
1139}
1140
1141
1142int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len)
1143{
1144 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1145 const char *info = "DPP PMK";
1146 int res;
1147
1148 /* PMK = HKDF(<>, "DPP PMK", N.x) */
1149
1150 /* HKDF-Extract(<>, N.x) */
1151 os_memset(salt, 0, hash_len);
1152 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
1153 return -1;
1154 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1155 prk, hash_len);
1156
1157 /* HKDF-Expand(PRK, info, L) */
1158 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
1159 os_memset(prk, 0, hash_len);
1160 if (res < 0)
1161 return -1;
1162
1163 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
1164 pmk, hash_len);
1165 return 0;
1166}
1167
1168
1169int dpp_derive_pmkid(const struct dpp_curve_params *curve,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001170 struct crypto_ec_key *own_key,
1171 struct crypto_ec_key *peer_key, u8 *pmkid)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001172{
1173 struct wpabuf *nkx, *pkx;
1174 int ret = -1, res;
1175 const u8 *addr[2];
1176 size_t len[2];
1177 u8 hash[SHA256_MAC_LEN];
1178
1179 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
Hai Shaloma20dcd72022-02-04 13:43:00 -08001180 nkx = crypto_ec_key_get_pubkey_point(own_key, 0);
1181 pkx = crypto_ec_key_get_pubkey_point(peer_key, 0);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001182 if (!nkx || !pkx)
1183 goto fail;
1184 addr[0] = wpabuf_head(nkx);
1185 len[0] = wpabuf_len(nkx) / 2;
1186 addr[1] = wpabuf_head(pkx);
1187 len[1] = wpabuf_len(pkx) / 2;
1188 if (len[0] != len[1])
1189 goto fail;
1190 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
1191 addr[0] = wpabuf_head(pkx);
1192 addr[1] = wpabuf_head(nkx);
1193 }
1194 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
1195 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
1196 res = sha256_vector(2, addr, len, hash);
1197 if (res < 0)
1198 goto fail;
1199 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
1200 os_memcpy(pmkid, hash, PMKID_LEN);
1201 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
1202 ret = 0;
1203fail:
1204 wpabuf_free(nkx);
1205 wpabuf_free(pkx);
1206 return ret;
1207}
1208
1209
1210/* Role-specific elements for PKEX */
1211
1212/* NIST P-256 */
1213static const u8 pkex_init_x_p256[32] = {
1214 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
1215 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
1216 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
1217 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
1218 };
1219static const u8 pkex_init_y_p256[32] = {
1220 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
1221 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
1222 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
1223 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
1224 };
1225static const u8 pkex_resp_x_p256[32] = {
1226 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
1227 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
1228 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
1229 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
1230};
1231static const u8 pkex_resp_y_p256[32] = {
1232 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
1233 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
1234 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
1235 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
1236};
1237
1238/* NIST P-384 */
1239static const u8 pkex_init_x_p384[48] = {
1240 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
1241 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
1242 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
1243 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
1244 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
1245 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
1246};
1247static const u8 pkex_init_y_p384[48] = {
1248 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
1249 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
1250 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
1251 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
1252 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
1253 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
1254};
1255static const u8 pkex_resp_x_p384[48] = {
1256 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
1257 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
1258 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
1259 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
1260 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
1261 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
1262};
1263static const u8 pkex_resp_y_p384[48] = {
1264 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
1265 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
1266 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
1267 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
1268 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
1269 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
1270};
1271
1272/* NIST P-521 */
1273static const u8 pkex_init_x_p521[66] = {
1274 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
1275 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
1276 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
1277 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
1278 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
1279 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
1280 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
1281 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
1282 0x97, 0x76
1283};
1284static const u8 pkex_init_y_p521[66] = {
1285 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
1286 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
1287 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
1288 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
1289 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
1290 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
1291 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
1292 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
1293 0x03, 0xa8
1294};
1295static const u8 pkex_resp_x_p521[66] = {
1296 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
1297 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
1298 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
1299 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
1300 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
1301 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
1302 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
1303 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
1304 0x84, 0xb4
1305};
1306static const u8 pkex_resp_y_p521[66] = {
1307 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
1308 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
1309 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
1310 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
1311 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
1312 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
1313 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
1314 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
1315 0xce, 0xe1
1316};
1317
1318/* Brainpool P-256r1 */
1319static const u8 pkex_init_x_bp_p256r1[32] = {
1320 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
1321 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
1322 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
1323 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
1324};
1325static const u8 pkex_init_y_bp_p256r1[32] = {
1326 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
1327 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
1328 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
1329 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
1330};
1331static const u8 pkex_resp_x_bp_p256r1[32] = {
1332 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
1333 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
1334 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
1335 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
1336};
1337static const u8 pkex_resp_y_bp_p256r1[32] = {
1338 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
1339 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
1340 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
1341 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
1342};
1343
1344/* Brainpool P-384r1 */
1345static const u8 pkex_init_x_bp_p384r1[48] = {
1346 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
1347 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
1348 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
1349 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
1350 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
1351 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
1352};
1353static const u8 pkex_init_y_bp_p384r1[48] = {
1354 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
1355 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
1356 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
1357 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
1358 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
1359 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
1360};
1361static const u8 pkex_resp_x_bp_p384r1[48] = {
1362 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
1363 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
1364 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
1365 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
1366 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
1367 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
1368};
1369static const u8 pkex_resp_y_bp_p384r1[48] = {
1370 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
1371 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
1372 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
1373 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
1374 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
1375 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
1376};
1377
1378/* Brainpool P-512r1 */
1379static const u8 pkex_init_x_bp_p512r1[64] = {
1380 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
1381 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
1382 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
1383 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
1384 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
1385 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
1386 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
1387 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
1388};
1389static const u8 pkex_init_y_bp_p512r1[64] = {
1390 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
1391 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
1392 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
1393 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
1394 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
1395 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
1396 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
1397 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
1398};
1399static const u8 pkex_resp_x_bp_p512r1[64] = {
1400 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
1401 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
1402 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
1403 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
1404 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
1405 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
1406 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
1407 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
1408};
1409static const u8 pkex_resp_y_bp_p512r1[64] = {
1410 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
1411 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
1412 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
1413 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
1414 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
1415 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
1416 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
1417 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
1418};
1419
1420
Hai Shaloma20dcd72022-02-04 13:43:00 -08001421static struct crypto_ec_key *
1422dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, int init)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001423{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001424 const u8 *x, *y;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001425
1426 switch (curve->ike_group) {
1427 case 19:
1428 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
1429 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
1430 break;
1431 case 20:
1432 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
1433 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
1434 break;
1435 case 21:
1436 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
1437 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
1438 break;
1439 case 28:
1440 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
1441 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
1442 break;
1443 case 29:
1444 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
1445 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
1446 break;
1447 case 30:
1448 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
1449 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
1450 break;
1451 default:
1452 return NULL;
1453 }
1454
Hai Shaloma20dcd72022-02-04 13:43:00 -08001455 return crypto_ec_key_set_pub(curve->ike_group, x, y, curve->prime_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001456}
1457
1458
Hai Shaloma20dcd72022-02-04 13:43:00 -08001459struct crypto_ec_point *
1460dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
Sunil Ravi89eba102022-09-13 21:04:37 -07001461 const char *code, size_t code_len, const char *identifier,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001462 struct crypto_ec **ret_ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001463{
1464 u8 hash[DPP_MAX_HASH_LEN];
1465 const u8 *addr[3];
1466 size_t len[3];
1467 unsigned int num_elem = 0;
Sunil8cd6f4d2022-06-28 18:40:46 +00001468 struct crypto_ec_point *Qi = NULL, *Pi = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001469 struct crypto_ec_key *Pi_key = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001470 struct crypto_bignum *hash_bn = NULL;
1471 struct crypto_ec *ec = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001472
Hai Shaloma20dcd72022-02-04 13:43:00 -08001473 /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001474
Hai Shaloma20dcd72022-02-04 13:43:00 -08001475 if (mac_init) {
1476 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR,
1477 MAC2STR(mac_init));
1478 addr[num_elem] = mac_init;
1479 len[num_elem] = ETH_ALEN;
1480 num_elem++;
1481 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001482 if (identifier) {
1483 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
1484 identifier);
1485 addr[num_elem] = (const u8 *) identifier;
1486 len[num_elem] = os_strlen(identifier);
1487 num_elem++;
1488 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001489 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001490 addr[num_elem] = (const u8 *) code;
Sunil Ravi89eba102022-09-13 21:04:37 -07001491 len[num_elem] = code_len;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001492 num_elem++;
1493 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
1494 goto fail;
1495 wpa_hexdump_key(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001496 "DPP: H([MAC-Initiator |] [identifier |] code)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001497 hash, curve->hash_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001498 Pi_key = dpp_pkex_get_role_elem(curve, 1);
1499 if (!Pi_key)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001500 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001501 dpp_debug_print_key("DPP: Pi", Pi_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001502
Hai Shaloma20dcd72022-02-04 13:43:00 -08001503 ec = crypto_ec_init(curve->ike_group);
1504 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001505 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001506
1507 Pi = crypto_ec_key_get_public_key(Pi_key);
1508 Qi = crypto_ec_point_init(ec);
1509 hash_bn = crypto_bignum_init_set(hash, curve->hash_len);
1510 if (!Pi || !Qi || !hash_bn || crypto_ec_point_mul(ec, Pi, hash_bn, Qi))
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001511 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001512
1513 if (crypto_ec_point_is_at_infinity(ec, Qi)) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001514 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
1515 goto fail;
1516 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001517 crypto_ec_point_debug_print(ec, Qi, "DPP: Qi");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001518out:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001519 crypto_ec_key_deinit(Pi_key);
Sunil8cd6f4d2022-06-28 18:40:46 +00001520 crypto_ec_point_deinit(Pi, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001521 crypto_bignum_deinit(hash_bn, 1);
1522 if (ret_ec && Qi)
1523 *ret_ec = ec;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001524 else
Hai Shaloma20dcd72022-02-04 13:43:00 -08001525 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001526 return Qi;
1527fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001528 crypto_ec_point_deinit(Qi, 1);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001529 Qi = NULL;
1530 goto out;
1531}
1532
1533
Hai Shaloma20dcd72022-02-04 13:43:00 -08001534struct crypto_ec_point *
1535dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
Sunil Ravi89eba102022-09-13 21:04:37 -07001536 const char *code, size_t code_len, const char *identifier,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001537 struct crypto_ec **ret_ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001538{
1539 u8 hash[DPP_MAX_HASH_LEN];
1540 const u8 *addr[3];
1541 size_t len[3];
1542 unsigned int num_elem = 0;
Sunil8cd6f4d2022-06-28 18:40:46 +00001543 struct crypto_ec_point *Qr = NULL, *Pr = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001544 struct crypto_ec_key *Pr_key = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001545 struct crypto_bignum *hash_bn = NULL;
1546 struct crypto_ec *ec = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001547
Hai Shaloma20dcd72022-02-04 13:43:00 -08001548 /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001549
Hai Shaloma20dcd72022-02-04 13:43:00 -08001550 if (mac_resp) {
1551 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR,
1552 MAC2STR(mac_resp));
1553 addr[num_elem] = mac_resp;
1554 len[num_elem] = ETH_ALEN;
1555 num_elem++;
1556 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001557 if (identifier) {
1558 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
1559 identifier);
1560 addr[num_elem] = (const u8 *) identifier;
1561 len[num_elem] = os_strlen(identifier);
1562 num_elem++;
1563 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001564 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001565 addr[num_elem] = (const u8 *) code;
Sunil Ravi89eba102022-09-13 21:04:37 -07001566 len[num_elem] = code_len;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001567 num_elem++;
1568 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
1569 goto fail;
1570 wpa_hexdump_key(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001571 "DPP: H([MAC-Responder |] [identifier |] code)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001572 hash, curve->hash_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001573 Pr_key = dpp_pkex_get_role_elem(curve, 0);
1574 if (!Pr_key)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001575 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001576 dpp_debug_print_key("DPP: Pr", Pr_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001577
Hai Shaloma20dcd72022-02-04 13:43:00 -08001578 ec = crypto_ec_init(curve->ike_group);
1579 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001580 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001581
1582 Pr = crypto_ec_key_get_public_key(Pr_key);
1583 Qr = crypto_ec_point_init(ec);
1584 hash_bn = crypto_bignum_init_set(hash, curve->hash_len);
1585 if (!Pr || !Qr || !hash_bn || crypto_ec_point_mul(ec, Pr, hash_bn, Qr))
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001586 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001587
1588 if (crypto_ec_point_is_at_infinity(ec, Qr)) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001589 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
1590 goto fail;
1591 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001592 crypto_ec_point_debug_print(ec, Qr, "DPP: Qr");
1593
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001594out:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001595 crypto_ec_key_deinit(Pr_key);
Sunil8cd6f4d2022-06-28 18:40:46 +00001596 crypto_ec_point_deinit(Pr, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001597 crypto_bignum_deinit(hash_bn, 1);
1598 if (ret_ec && Qr)
1599 *ret_ec = ec;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001600 else
Hai Shaloma20dcd72022-02-04 13:43:00 -08001601 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001602 return Qr;
1603fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001604 crypto_ec_point_deinit(Qr, 1);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001605 Qr = NULL;
1606 goto out;
1607}
1608
1609
1610int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
Hai Shaloma20dcd72022-02-04 13:43:00 -08001611 u8 ver_init, u8 ver_resp,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001612 const u8 *Mx, size_t Mx_len,
1613 const u8 *Nx, size_t Nx_len,
Sunil Ravi89eba102022-09-13 21:04:37 -07001614 const char *code, size_t code_len,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001615 const u8 *Kx, size_t Kx_len,
1616 u8 *z, unsigned int hash_len)
1617{
1618 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1619 int res;
1620 u8 *info, *pos;
1621 size_t info_len;
1622
Hai Shaloma20dcd72022-02-04 13:43:00 -08001623 /*
1624 * v1: info = MAC-Initiator | MAC-Responder
1625 * v2: info = Protocol Version-Initiator | Protocol Version-Responder
1626 * z = HKDF(<>, info | M.x | N.x | code, K.x)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001627 */
1628
1629 /* HKDF-Extract(<>, IKM=K.x) */
1630 os_memset(salt, 0, hash_len);
1631 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
1632 return -1;
1633 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1634 prk, hash_len);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001635 if (mac_init && mac_resp)
1636 info_len = 2 * ETH_ALEN;
1637 else
1638 info_len = 2;
Sunil Ravi89eba102022-09-13 21:04:37 -07001639 info_len += Mx_len + Nx_len + code_len;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001640 info = os_malloc(info_len);
1641 if (!info)
1642 return -1;
1643 pos = info;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001644 if (mac_init && mac_resp) {
1645 os_memcpy(pos, mac_init, ETH_ALEN);
1646 pos += ETH_ALEN;
1647 os_memcpy(pos, mac_resp, ETH_ALEN);
1648 pos += ETH_ALEN;
1649 } else {
1650 *pos++ = ver_init;
1651 *pos++ = ver_resp;
1652 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001653 os_memcpy(pos, Mx, Mx_len);
1654 pos += Mx_len;
1655 os_memcpy(pos, Nx, Nx_len);
1656 pos += Nx_len;
Sunil Ravi89eba102022-09-13 21:04:37 -07001657 os_memcpy(pos, code, code_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001658
1659 /* HKDF-Expand(PRK, info, L) */
1660 if (hash_len == 32)
1661 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
1662 z, hash_len);
1663 else if (hash_len == 48)
1664 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
1665 z, hash_len);
1666 else if (hash_len == 64)
1667 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
1668 z, hash_len);
1669 else
1670 res = -1;
1671 os_free(info);
1672 os_memset(prk, 0, hash_len);
1673 if (res < 0)
1674 return -1;
1675
1676 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
1677 z, hash_len);
1678 return 0;
1679}
1680
1681
1682int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
1683 const u8 *net_access_key,
1684 size_t net_access_key_len,
1685 struct json_token *peer_net_access_key)
1686{
Hai Shaloma20dcd72022-02-04 13:43:00 -08001687 struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00001688 struct crypto_bignum *sum = NULL, *cR = NULL, *pR = NULL;
1689 const struct crypto_bignum *q;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001690 struct crypto_ec *ec = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00001691 struct crypto_ec_point *M = NULL, *CI = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001692 u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
1693 u8 prk[DPP_MAX_HASH_LEN];
1694 const struct dpp_curve_params *curve;
1695 int res = -1;
Hai Shalom899fcc72020-10-19 14:38:18 -07001696 u8 nonces[2 * DPP_MAX_NONCE_LEN];
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001697
1698 own_key = dpp_set_keypair(&auth->curve, net_access_key,
1699 net_access_key_len);
1700 if (!own_key) {
1701 dpp_auth_fail(auth, "Failed to parse own netAccessKey");
1702 goto fail;
1703 }
1704
1705 peer_key = dpp_parse_jwk(peer_net_access_key, &curve);
1706 if (!peer_key)
1707 goto fail;
1708 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
1709
1710 if (auth->curve != curve) {
1711 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07001712 "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001713 auth->curve->name, curve->name);
1714 goto fail;
1715 }
1716
1717 auth->own_protocol_key = dpp_gen_keypair(curve);
1718 if (!auth->own_protocol_key)
1719 goto fail;
1720
Hai Shalom899fcc72020-10-19 14:38:18 -07001721 if (random_get_bytes(auth->e_nonce, auth->curve->nonce_len)) {
1722 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
1723 goto fail;
1724 }
1725 wpa_hexdump_key(MSG_DEBUG, "DPP: E-nonce",
1726 auth->e_nonce, auth->curve->nonce_len);
1727
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001728 /* M = { cR + pR } * CI */
Hai Shaloma20dcd72022-02-04 13:43:00 -08001729 ec = crypto_ec_init(curve->ike_group);
1730 if (!ec)
Hai Shalom60840252021-02-19 19:02:11 -08001731 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001732
1733 sum = crypto_bignum_init();
1734 q = crypto_ec_get_order(ec);
1735 M = crypto_ec_point_init(ec);
1736 cR = crypto_ec_key_get_private_key(own_key);
1737 pR = crypto_ec_key_get_private_key(auth->own_protocol_key);
1738 CI = crypto_ec_key_get_public_key(peer_key);
1739 if (!sum || !q || !M || !cR || !pR || !CI ||
1740 crypto_bignum_addmod(cR, pR, q, sum) ||
1741 crypto_ec_point_mul(ec, CI, sum, M) ||
1742 crypto_ec_point_to_bin(ec, M, Mx, NULL)) {
1743 wpa_printf(MSG_ERROR, "DPP: Error during M computation");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001744 goto fail;
1745 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001746 wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
1747
Hai Shalom899fcc72020-10-19 14:38:18 -07001748 /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001749
Hai Shalom899fcc72020-10-19 14:38:18 -07001750 /* HKDF-Extract(C-nonce | E-nonce, M.x) */
1751 os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
1752 os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
1753 if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001754 Mx, curve->prime_len, prk) < 0)
1755 goto fail;
1756 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
1757
1758 /* HKDF-Expand(PRK, "dpp reconfig key", L) */
1759 if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
1760 "dpp reconfig key", auth->ke, curve->hash_len) < 0)
1761 goto fail;
1762 wpa_hexdump_key(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07001763 "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001764 auth->ke, curve->hash_len);
1765
1766 res = 0;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001767 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001768 auth->reconfig_old_protocol_key = own_key;
1769 own_key = NULL;
1770fail:
1771 forced_memzero(prk, sizeof(prk));
1772 forced_memzero(Mx, sizeof(Mx));
Hai Shaloma20dcd72022-02-04 13:43:00 -08001773 crypto_ec_point_deinit(M, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001774 crypto_ec_point_deinit(CI, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001775 crypto_bignum_deinit(sum, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001776 crypto_bignum_deinit(cR, 1);
1777 crypto_bignum_deinit(pR, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001778 crypto_ec_key_deinit(own_key);
1779 crypto_ec_key_deinit(peer_key);
1780 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001781 return res;
1782}
1783
1784
1785int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
1786 const u8 *r_proto, u16 r_proto_len,
1787 struct json_token *net_access_key)
1788{
Hai Shaloma20dcd72022-02-04 13:43:00 -08001789 struct crypto_ec_key *pr = NULL, *peer_key = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00001790 struct crypto_bignum *cI = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001791 struct crypto_ec *ec = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00001792 struct crypto_ec_point *sum = NULL, *M = NULL, *CR = NULL, *PR = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001793 u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
1794 u8 prk[DPP_MAX_HASH_LEN];
1795 int res = -1;
1796 const struct dpp_curve_params *curve;
Hai Shalom899fcc72020-10-19 14:38:18 -07001797 u8 nonces[2 * DPP_MAX_NONCE_LEN];
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001798
1799 pr = dpp_set_pubkey_point(auth->conf->connector_key,
1800 r_proto, r_proto_len);
1801 if (!pr) {
1802 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
1803 goto fail;
1804 }
1805 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001806 crypto_ec_key_deinit(auth->peer_protocol_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001807 auth->peer_protocol_key = pr;
1808 pr = NULL;
1809
1810 peer_key = dpp_parse_jwk(net_access_key, &curve);
1811 if (!peer_key)
1812 goto fail;
1813 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
1814 if (auth->curve != curve) {
1815 wpa_printf(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07001816 "DPP: Mismatching netAccessKey curves (own=%s != peer=%s)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001817 auth->curve->name, curve->name);
1818 goto fail;
1819 }
1820
1821 /* M = cI * { CR + PR } */
Hai Shaloma20dcd72022-02-04 13:43:00 -08001822 ec = crypto_ec_init(curve->ike_group);
1823 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001824 goto fail;
1825
Hai Shaloma20dcd72022-02-04 13:43:00 -08001826 cI = crypto_ec_key_get_private_key(auth->conf->connector_key);
1827 sum = crypto_ec_point_init(ec);
1828 M = crypto_ec_point_init(ec);
1829 CR = crypto_ec_key_get_public_key(peer_key);
1830 PR = crypto_ec_key_get_public_key(auth->peer_protocol_key);
1831 if (!cI || !sum || !M || !CR || !PR ||
1832 crypto_ec_point_add(ec, CR, PR, sum) ||
1833 crypto_ec_point_mul(ec, sum, cI, M) ||
1834 crypto_ec_point_to_bin(ec, M, Mx, NULL)) {
1835 wpa_printf(MSG_ERROR, "DPP: Error during M computation");
1836 goto fail;
1837 }
1838
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001839 wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
1840
Hai Shalom899fcc72020-10-19 14:38:18 -07001841 /* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001842
Hai Shalom899fcc72020-10-19 14:38:18 -07001843 /* HKDF-Extract(C-nonce | E-nonce, M.x) */
1844 os_memcpy(nonces, auth->c_nonce, curve->nonce_len);
1845 os_memcpy(&nonces[curve->nonce_len], auth->e_nonce, curve->nonce_len);
1846 if (dpp_hmac(curve->hash_len, nonces, 2 * curve->nonce_len,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001847 Mx, curve->prime_len, prk) < 0)
1848 goto fail;
1849 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK", prk, curve->hash_len);
1850
1851 /* HKDF-Expand(PRK, "dpp reconfig key", L) */
1852 if (dpp_hkdf_expand(curve->hash_len, prk, curve->hash_len,
1853 "dpp reconfig key", auth->ke, curve->hash_len) < 0)
1854 goto fail;
1855 wpa_hexdump_key(MSG_DEBUG,
Hai Shalom899fcc72020-10-19 14:38:18 -07001856 "DPP: ke = HKDF(C-nonce | E-nonce, \"dpp reconfig key\", M.x)",
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001857 auth->ke, curve->hash_len);
1858
1859 res = 0;
1860fail:
1861 forced_memzero(prk, sizeof(prk));
1862 forced_memzero(Mx, sizeof(Mx));
Sunil8cd6f4d2022-06-28 18:40:46 +00001863 crypto_bignum_deinit(cI, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001864 crypto_ec_key_deinit(pr);
1865 crypto_ec_key_deinit(peer_key);
1866 crypto_ec_point_deinit(sum, 1);
1867 crypto_ec_point_deinit(M, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00001868 crypto_ec_point_deinit(CR, 1);
1869 crypto_ec_point_deinit(PR, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001870 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001871 return res;
1872}
1873
1874
1875static char *
1876dpp_build_jws_prot_hdr(struct dpp_configurator *conf, size_t *signed1_len)
1877{
1878 struct wpabuf *jws_prot_hdr;
1879 char *signed1;
1880
1881 jws_prot_hdr = wpabuf_alloc(100);
1882 if (!jws_prot_hdr)
1883 return NULL;
1884 json_start_object(jws_prot_hdr, NULL);
1885 json_add_string(jws_prot_hdr, "typ", "dppCon");
1886 json_value_sep(jws_prot_hdr);
1887 json_add_string(jws_prot_hdr, "kid", conf->kid);
1888 json_value_sep(jws_prot_hdr);
1889 json_add_string(jws_prot_hdr, "alg", conf->curve->jws_alg);
1890 json_end_object(jws_prot_hdr);
1891 signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
1892 wpabuf_len(jws_prot_hdr),
1893 signed1_len);
1894 wpabuf_free(jws_prot_hdr);
1895 return signed1;
1896}
1897
1898
1899static char *
1900dpp_build_conn_signature(struct dpp_configurator *conf,
1901 const char *signed1, size_t signed1_len,
1902 const char *signed2, size_t signed2_len,
1903 size_t *signed3_len)
1904{
1905 const struct dpp_curve_params *curve;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001906 struct wpabuf *sig = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001907 char *signed3 = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001908 char *dot = ".";
Hai Shaloma20dcd72022-02-04 13:43:00 -08001909 const u8 *vector[3];
1910 size_t vector_len[3];
1911 u8 *hash;
1912 int ret;
1913
1914 vector[0] = (const u8 *) signed1;
1915 vector[1] = (const u8 *) dot;
1916 vector[2] = (const u8 *) signed2;
1917 vector_len[0] = signed1_len;
1918 vector_len[1] = 1;
1919 vector_len[2] = signed2_len;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001920
1921 curve = conf->curve;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001922 hash = os_malloc(curve->hash_len);
1923 if (!hash)
1924 goto fail;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001925 if (curve->hash_len == SHA256_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001926 ret = sha256_vector(3, vector, vector_len, hash);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001927 } else if (curve->hash_len == SHA384_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001928 ret = sha384_vector(3, vector, vector_len, hash);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001929 } else if (curve->hash_len == SHA512_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001930 ret = sha512_vector(3, vector, vector_len, hash);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001931 } else {
1932 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
1933 goto fail;
1934 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001935 if (ret) {
1936 wpa_printf(MSG_DEBUG, "DPP: Hash computation failed");
1937 goto fail;
1938 }
1939 wpa_hexdump(MSG_DEBUG, "DPP: Hash value for Connector signature",
1940 hash, curve->hash_len);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001941
Hai Shaloma20dcd72022-02-04 13:43:00 -08001942 sig = crypto_ec_key_sign_r_s(conf->csign, hash, curve->hash_len);
1943 if (!sig) {
1944 wpa_printf(MSG_ERROR, "DPP: Signature computation failed");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001945 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08001946 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001947
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001948 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
Hai Shaloma20dcd72022-02-04 13:43:00 -08001949 wpabuf_head(sig), wpabuf_len(sig));
1950 signed3 = base64_url_encode(wpabuf_head(sig), wpabuf_len(sig),
1951 signed3_len);
1952
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001953fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08001954 os_free(hash);
1955 wpabuf_free(sig);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001956 return signed3;
1957}
1958
1959char * dpp_sign_connector(struct dpp_configurator *conf,
1960 const struct wpabuf *dppcon)
1961{
1962 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
1963 char *signed_conn = NULL, *pos;
1964 size_t signed1_len, signed2_len, signed3_len;
1965
1966 signed1 = dpp_build_jws_prot_hdr(conf, &signed1_len);
1967 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
1968 &signed2_len);
1969 if (!signed1 || !signed2)
1970 goto fail;
1971
1972 signed3 = dpp_build_conn_signature(conf, signed1, signed1_len,
1973 signed2, signed2_len, &signed3_len);
1974 if (!signed3)
1975 goto fail;
1976
1977 signed_conn = os_malloc(signed1_len + signed2_len + signed3_len + 3);
1978 if (!signed_conn)
1979 goto fail;
1980 pos = signed_conn;
1981 os_memcpy(pos, signed1, signed1_len);
1982 pos += signed1_len;
1983 *pos++ = '.';
1984 os_memcpy(pos, signed2, signed2_len);
1985 pos += signed2_len;
1986 *pos++ = '.';
1987 os_memcpy(pos, signed3, signed3_len);
1988 pos += signed3_len;
1989 *pos = '\0';
1990
1991fail:
1992 os_free(signed1);
1993 os_free(signed2);
1994 os_free(signed3);
1995 return signed_conn;
1996}
1997
1998
1999#ifdef CONFIG_DPP2
2000
2001struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
2002 size_t net_access_key_len)
2003{
2004 struct wpabuf *pub = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002005 struct crypto_ec_key *own_key;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002006 struct dpp_pfs *pfs;
2007
2008 pfs = os_zalloc(sizeof(*pfs));
2009 if (!pfs)
2010 return NULL;
2011
2012 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
2013 net_access_key_len);
2014 if (!own_key) {
2015 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
2016 goto fail;
2017 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002018 crypto_ec_key_deinit(own_key);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002019
2020 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
2021 if (!pfs->ecdh)
2022 goto fail;
2023
2024 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
2025 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
2026 if (!pub)
2027 goto fail;
2028
2029 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
2030 if (!pfs->ie)
2031 goto fail;
2032 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
2033 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
2034 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
2035 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
2036 wpabuf_put_buf(pfs->ie, pub);
2037 wpabuf_free(pub);
2038 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
2039 pfs->ie);
2040
2041 return pfs;
2042fail:
2043 wpabuf_free(pub);
2044 dpp_pfs_free(pfs);
2045 return NULL;
2046}
2047
2048
2049int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
2050{
2051 if (peer_ie_len < 2)
2052 return -1;
2053 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
2054 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
2055 return -1;
2056 }
2057
2058 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
2059 peer_ie_len - 2);
2060 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
2061 if (!pfs->secret) {
2062 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
2063 return -1;
2064 }
2065 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
2066 return 0;
2067}
2068
2069
2070void dpp_pfs_free(struct dpp_pfs *pfs)
2071{
2072 if (!pfs)
2073 return;
2074 crypto_ecdh_deinit(pfs->ecdh);
2075 wpabuf_free(pfs->ie);
2076 wpabuf_clear_free(pfs->secret);
2077 os_free(pfs);
2078}
2079
Hai Shalom899fcc72020-10-19 14:38:18 -07002080
2081struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
2082{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002083 struct crypto_csr *csr = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002084 struct wpabuf *buf = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002085 struct crypto_ec_key *key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002086 unsigned int hash_len = auth->curve->hash_len;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002087 struct wpabuf *priv_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002088 u8 cp[DPP_CP_LEN];
Hai Shaloma20dcd72022-02-04 13:43:00 -08002089 char *password = NULL;
2090 size_t password_len = 0;
2091 int hash_sign_algo;
Hai Shalom899fcc72020-10-19 14:38:18 -07002092
2093 /* TODO: use auth->csrattrs */
2094
2095 /* TODO: support generation of a new private key if csrAttrs requests
2096 * a specific group to be used */
2097 key = auth->own_protocol_key;
2098
Hai Shaloma20dcd72022-02-04 13:43:00 -08002099 priv_key = crypto_ec_key_get_ecprivate_key(key, true);
2100 if (!priv_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002101 goto fail;
2102 wpabuf_free(auth->priv_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002103 auth->priv_key = priv_key;
2104
2105 csr = crypto_csr_init();
2106 if (!csr || crypto_csr_set_ec_public_key(csr, key))
Hai Shalom899fcc72020-10-19 14:38:18 -07002107 goto fail;
2108
Hai Shaloma20dcd72022-02-04 13:43:00 -08002109 if (name && crypto_csr_set_name(csr, CSR_NAME_CN, name))
Hai Shalom899fcc72020-10-19 14:38:18 -07002110 goto fail;
2111
Hai Shalom899fcc72020-10-19 14:38:18 -07002112 /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
2113 if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
2114 "CSR challengePassword", cp, DPP_CP_LEN) < 0)
2115 goto fail;
2116 wpa_hexdump_key(MSG_DEBUG,
2117 "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
2118 cp, DPP_CP_LEN);
2119 password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
2120 forced_memzero(cp, DPP_CP_LEN);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002121 if (!password ||
2122 crypto_csr_set_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
2123 ASN1_TAG_UTF8STRING, (const u8 *) password,
2124 password_len))
Hai Shalom899fcc72020-10-19 14:38:18 -07002125 goto fail;
2126
Hai Shalom899fcc72020-10-19 14:38:18 -07002127 /* TODO: hash func selection based on csrAttrs */
2128 if (hash_len == SHA256_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002129 hash_sign_algo = CRYPTO_HASH_ALG_SHA256;
Hai Shalom899fcc72020-10-19 14:38:18 -07002130 } else if (hash_len == SHA384_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002131 hash_sign_algo = CRYPTO_HASH_ALG_SHA384;
Hai Shalom899fcc72020-10-19 14:38:18 -07002132 } else if (hash_len == SHA512_MAC_LEN) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002133 hash_sign_algo = CRYPTO_HASH_ALG_SHA512;
Hai Shalom899fcc72020-10-19 14:38:18 -07002134 } else {
2135 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
2136 goto fail;
2137 }
2138
Hai Shaloma20dcd72022-02-04 13:43:00 -08002139 buf = crypto_csr_sign(csr, key, hash_sign_algo);
2140 if (!buf)
Hai Shalom899fcc72020-10-19 14:38:18 -07002141 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002142 wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
2143
2144fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002145 bin_clear_free(password, password_len);
2146 crypto_csr_deinit(csr);
Hai Shalom899fcc72020-10-19 14:38:18 -07002147 return buf;
2148}
2149
2150
Hai Shaloma20dcd72022-02-04 13:43:00 -08002151int dpp_validate_csr(struct dpp_authentication *auth,
2152 const struct wpabuf *csrbuf)
Hai Shalom899fcc72020-10-19 14:38:18 -07002153{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002154 struct crypto_csr *csr;
2155 const u8 *attr;
2156 size_t attr_len;
2157 int attr_type;
Hai Shalom899fcc72020-10-19 14:38:18 -07002158 unsigned char *cp = NULL;
2159 size_t cp_len;
2160 u8 exp_cp[DPP_CP_LEN];
2161 unsigned int hash_len = auth->curve->hash_len;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002162 int ret = -1;
Hai Shalom899fcc72020-10-19 14:38:18 -07002163
Hai Shaloma20dcd72022-02-04 13:43:00 -08002164 csr = crypto_csr_verify(csrbuf);
2165 if (!csr) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002166 wpa_printf(MSG_DEBUG,
Hai Shaloma20dcd72022-02-04 13:43:00 -08002167 "DPP: CSR invalid or invalid signature");
Hai Shalom899fcc72020-10-19 14:38:18 -07002168 goto fail;
2169 }
2170
Hai Shaloma20dcd72022-02-04 13:43:00 -08002171 attr = crypto_csr_get_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
2172 &attr_len, &attr_type);
2173 if (!attr) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002174 wpa_printf(MSG_DEBUG,
2175 "DPP: CSR does not include challengePassword");
2176 goto fail;
2177 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002178 /* This is supposed to be UTF8String, but allow other strings as well
2179 * since challengePassword is using ASCII (base64 encoded). */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002180 if (attr_type != ASN1_TAG_UTF8STRING &&
2181 attr_type != ASN1_TAG_PRINTABLESTRING &&
2182 attr_type != ASN1_TAG_IA5STRING) {
Hai Shalom899fcc72020-10-19 14:38:18 -07002183 wpa_printf(MSG_DEBUG,
2184 "DPP: Unexpected challengePassword attribute type %d",
Hai Shaloma20dcd72022-02-04 13:43:00 -08002185 attr_type);
Hai Shalom899fcc72020-10-19 14:38:18 -07002186 goto fail;
2187 }
2188
Hai Shaloma20dcd72022-02-04 13:43:00 -08002189 cp = base64_decode((const char *) attr, attr_len, &cp_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07002190 if (!cp) {
2191 wpa_printf(MSG_DEBUG,
2192 "DPP: Could not base64 decode challengePassword");
2193 goto fail;
2194 }
2195 if (cp_len != DPP_CP_LEN) {
2196 wpa_printf(MSG_DEBUG,
2197 "DPP: Unexpected cp length (%zu) in CSR challengePassword",
2198 cp_len);
2199 goto fail;
2200 }
2201 wpa_hexdump_key(MSG_DEBUG, "DPP: cp from CSR challengePassword",
2202 cp, cp_len);
2203
2204 /* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
2205 if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
2206 "CSR challengePassword", exp_cp, DPP_CP_LEN) < 0)
2207 goto fail;
2208 wpa_hexdump_key(MSG_DEBUG,
2209 "DPP: cp = HKDF-Expand(bk, \"CSR challengePassword\", 64)",
2210 exp_cp, DPP_CP_LEN);
2211 if (os_memcmp_const(cp, exp_cp, DPP_CP_LEN) != 0) {
2212 wpa_printf(MSG_DEBUG,
2213 "DPP: CSR challengePassword does not match calculated cp");
2214 goto fail;
2215 }
2216
2217 ret = 0;
2218fail:
2219 os_free(cp);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002220 crypto_csr_deinit(csr);
Hai Shalom899fcc72020-10-19 14:38:18 -07002221 return ret;
2222}
2223
2224
2225struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
2226 size_t csign_key_len,
2227 const u8 *pp_key,
2228 size_t pp_key_len)
2229{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002230 struct crypto_ec_key *csign = NULL, *ppkey = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002231 struct dpp_reconfig_id *id = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002232 struct crypto_ec *ec = NULL;
2233 const struct crypto_bignum *q;
2234 struct crypto_bignum *bn = NULL;
2235 struct crypto_ec_point *e_id = NULL;
2236 const struct crypto_ec_point *generator;
Hai Shalom899fcc72020-10-19 14:38:18 -07002237
Hai Shaloma20dcd72022-02-04 13:43:00 -08002238 csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07002239 if (!csign)
2240 goto fail;
2241
2242 if (!pp_key)
2243 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002244 ppkey = crypto_ec_key_parse_pub(pp_key, pp_key_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07002245 if (!ppkey)
2246 goto fail;
2247
Hai Shaloma20dcd72022-02-04 13:43:00 -08002248 ec = crypto_ec_init(crypto_ec_key_group(csign));
2249 if (!ec)
Hai Shalom899fcc72020-10-19 14:38:18 -07002250 goto fail;
2251
Hai Shaloma20dcd72022-02-04 13:43:00 -08002252 e_id = crypto_ec_point_init(ec);
2253 bn = crypto_bignum_init();
2254 q = crypto_ec_get_order(ec);
2255 generator = crypto_ec_get_generator(ec);
2256 if (!e_id || !bn || !q || !generator ||
2257 crypto_bignum_rand(bn, q) ||
2258 crypto_ec_point_mul(ec, generator, bn, e_id))
Hai Shalom899fcc72020-10-19 14:38:18 -07002259 goto fail;
2260
Hai Shaloma20dcd72022-02-04 13:43:00 -08002261 crypto_ec_point_debug_print(ec, e_id,
2262 "DPP: Generated random point E-id");
Hai Shalom899fcc72020-10-19 14:38:18 -07002263
2264 id = os_zalloc(sizeof(*id));
2265 if (!id)
2266 goto fail;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002267
2268 id->ec = ec;
2269 ec = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002270 id->e_id = e_id;
2271 e_id = NULL;
2272 id->csign = csign;
2273 csign = NULL;
2274 id->pp_key = ppkey;
2275 ppkey = NULL;
2276fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002277 crypto_ec_point_deinit(e_id, 1);
2278 crypto_ec_key_deinit(csign);
2279 crypto_ec_key_deinit(ppkey);
2280 crypto_bignum_deinit(bn, 1);
2281 crypto_ec_deinit(ec);
Hai Shalom899fcc72020-10-19 14:38:18 -07002282 return id;
2283}
2284
2285
Hai Shalom899fcc72020-10-19 14:38:18 -07002286int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
2287{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002288 const struct crypto_bignum *q;
2289 struct crypto_bignum *bn;
Sunil8cd6f4d2022-06-28 18:40:46 +00002290 const struct crypto_ec_point *generator;
2291 struct crypto_ec_point *e_prime_id, *a_nonce, *pp;
Hai Shalom899fcc72020-10-19 14:38:18 -07002292 int ret = -1;
Hai Shalom899fcc72020-10-19 14:38:18 -07002293
Hai Shaloma20dcd72022-02-04 13:43:00 -08002294 pp = crypto_ec_key_get_public_key(id->pp_key);
2295 e_prime_id = crypto_ec_point_init(id->ec);
2296 a_nonce = crypto_ec_point_init(id->ec);
2297 bn = crypto_bignum_init();
2298 q = crypto_ec_get_order(id->ec);
2299 generator = crypto_ec_get_generator(id->ec);
2300
Hai Shalom899fcc72020-10-19 14:38:18 -07002301 /* Generate random 0 <= a-nonce < q
2302 * A-NONCE = a-nonce * G
2303 * E'-id = E-id + a-nonce * P_pk */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002304 if (!pp || !e_prime_id || !a_nonce || !bn || !q || !generator ||
2305 crypto_bignum_rand(bn, q) || /* bn = a-nonce */
2306 crypto_ec_point_mul(id->ec, generator, bn, a_nonce) ||
2307 crypto_ec_point_mul(id->ec, pp, bn, e_prime_id) ||
2308 crypto_ec_point_add(id->ec, id->e_id, e_prime_id, e_prime_id))
Hai Shalom899fcc72020-10-19 14:38:18 -07002309 goto fail;
2310
Hai Shaloma20dcd72022-02-04 13:43:00 -08002311 crypto_ec_point_debug_print(id->ec, a_nonce,
2312 "DPP: Generated A-NONCE");
2313 crypto_ec_point_debug_print(id->ec, e_prime_id,
2314 "DPP: Encrypted E-id to E'-id");
Hai Shalom899fcc72020-10-19 14:38:18 -07002315
Hai Shaloma20dcd72022-02-04 13:43:00 -08002316 crypto_ec_key_deinit(id->a_nonce);
2317 crypto_ec_key_deinit(id->e_prime_id);
2318 id->a_nonce = crypto_ec_key_set_pub_point(id->ec, a_nonce);
2319 id->e_prime_id = crypto_ec_key_set_pub_point(id->ec, e_prime_id);
Hai Shalom899fcc72020-10-19 14:38:18 -07002320 if (!id->a_nonce || !id->e_prime_id)
2321 goto fail;
2322
2323 ret = 0;
2324
2325fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002326 crypto_ec_point_deinit(e_prime_id, 1);
2327 crypto_ec_point_deinit(a_nonce, 1);
Sunil8cd6f4d2022-06-28 18:40:46 +00002328 crypto_ec_point_deinit(pp, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002329 crypto_bignum_deinit(bn, 1);
Hai Shalom899fcc72020-10-19 14:38:18 -07002330 return ret;
2331}
2332
2333
2334void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
2335{
2336 if (id) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002337 crypto_ec_point_deinit(id->e_id, 1);
2338 crypto_ec_key_deinit(id->csign);
2339 crypto_ec_key_deinit(id->a_nonce);
2340 crypto_ec_key_deinit(id->e_prime_id);
2341 crypto_ec_key_deinit(id->pp_key);
2342 crypto_ec_deinit(id->ec);
Hai Shalom899fcc72020-10-19 14:38:18 -07002343 os_free(id);
2344 }
2345}
2346
2347
Hai Shaloma20dcd72022-02-04 13:43:00 -08002348struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
2349 struct crypto_ec_key *a_nonce,
2350 struct crypto_ec_key *e_prime_id)
Hai Shalom899fcc72020-10-19 14:38:18 -07002351{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002352 struct crypto_ec *ec;
Sunil8cd6f4d2022-06-28 18:40:46 +00002353 struct crypto_bignum *pp = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002354 struct crypto_ec_point *e_id = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00002355 struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
Hai Shalom899fcc72020-10-19 14:38:18 -07002356
2357 if (!ppkey)
2358 return NULL;
2359
2360 /* E-id = E'-id - s_C * A-NONCE */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002361 ec = crypto_ec_init(crypto_ec_key_group(ppkey));
2362 if (!ec)
Hai Shalom899fcc72020-10-19 14:38:18 -07002363 return NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002364
2365 pp = crypto_ec_key_get_private_key(ppkey);
2366 a_nonce_point = crypto_ec_key_get_public_key(a_nonce);
2367 e_prime_id_point = crypto_ec_key_get_public_key(e_prime_id);
2368 e_id = crypto_ec_point_init(ec);
2369 if (!pp || !a_nonce_point || !e_prime_id_point || !e_id ||
2370 crypto_ec_point_mul(ec, a_nonce_point, pp, e_id) ||
2371 crypto_ec_point_invert(ec, e_id) ||
2372 crypto_ec_point_add(ec, e_id, e_prime_id_point, e_id)) {
2373 crypto_ec_point_deinit(e_id, 1);
Hai Shalom899fcc72020-10-19 14:38:18 -07002374 goto fail;
2375 }
2376
Hai Shaloma20dcd72022-02-04 13:43:00 -08002377 crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id");
Hai Shalom899fcc72020-10-19 14:38:18 -07002378
2379fail:
Sunil8cd6f4d2022-06-28 18:40:46 +00002380 crypto_ec_point_deinit(a_nonce_point, 1);
2381 crypto_ec_point_deinit(e_prime_id_point, 1);
2382 crypto_bignum_deinit(pp, 1);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002383 crypto_ec_deinit(ec);
Hai Shalom899fcc72020-10-19 14:38:18 -07002384 return e_id;
2385}
2386
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002387#endif /* CONFIG_DPP2 */
2388
2389
Sunil Ravia04bd252022-05-02 22:54:18 -07002390#ifdef CONFIG_DPP3
Sunil Ravi89eba102022-09-13 21:04:37 -07002391
Sunil Ravia04bd252022-05-02 22:54:18 -07002392int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
2393{
2394 int ret = -1, res;
2395 u8 Sx[DPP_MAX_SHARED_SECRET_LEN];
2396 size_t Sx_len;
2397 unsigned int hash_len;
2398 const char *info = "New DPP Protocol Key";
2399 const u8 *addr[3];
2400 size_t len[3];
2401 u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN];
2402 struct wpabuf *pcx = NULL, *pex = NULL;
2403
2404 hash_len = auth->curve->hash_len;
2405
2406 /*
2407 * Configurator: S = pc * Pe
2408 * Enrollee: S = pe * Pc
2409 * k = HKDF(bk, "New DPP Protocol Key", S.x)
2410 * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key",
2411 * len(new-curve-hash-out))
2412 * Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)
2413 *
2414 * auth->own_protocol_key and auth->peer_protocol_key have already been
2415 * updated to use the new keys. The new curve determines the size of
2416 * the (new) protocol keys and S.x. The other parameters (bk, hash
2417 * algorithm, k) are determined based on the initially determined curve
2418 * during the (re)authentication exchange.
2419 */
2420
2421 if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
2422 Sx, &Sx_len) < 0)
2423 goto fail;
2424
2425 wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len);
2426
2427 /* tmp = HKDF-Extract(bk, S.x) */
2428 addr[0] = Sx;
2429 len[0] = Sx_len;
2430 res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp);
2431 if (res < 0)
2432 goto fail;
2433 wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)",
2434 tmp, hash_len);
2435 /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output))
2436 */
2437 res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len);
2438 if (res < 0)
2439 return -1;
2440
2441 wpa_hexdump_key(MSG_DEBUG,
2442 "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")",
2443 k, hash_len);
2444
2445 /* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */
2446 addr[0] = auth->e_nonce;
2447 len[0] = auth->curve->nonce_len;
2448
2449 if (auth->configurator) {
2450 pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
2451 pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
2452 0);
2453 } else {
2454 pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
2455 0);
2456 pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
2457 }
2458 if (!pcx || !pex)
2459 goto fail;
2460 addr[1] = wpabuf_head(pcx);
2461 len[1] = wpabuf_len(pcx) / 2;
2462 addr[2] = wpabuf_head(pex);
2463 len[2] = wpabuf_len(pex) / 2;
2464
2465 if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0)
2466 goto fail;
2467 wpa_hexdump_key(MSG_DEBUG,
2468 "DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)",
2469 auth_i, hash_len);
2470 ret = 0;
2471fail:
2472 forced_memzero(Sx, sizeof(Sx));
2473 forced_memzero(tmp, sizeof(tmp));
2474 forced_memzero(k, sizeof(k));
2475 wpabuf_free(pcx);
2476 wpabuf_free(pex);
2477 return ret;
2478}
Sunil Ravi89eba102022-09-13 21:04:37 -07002479
2480
2481int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
2482 enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id)
2483{
2484 switch (iana_group) {
2485 case 19:
2486 *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
2487 *kdf_id = HPKE_KDF_HKDF_SHA256;
2488 *aead_id = HPKE_AEAD_AES_128_GCM;
2489 return 0;
2490 case 20:
2491 *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
2492 *kdf_id = HPKE_KDF_HKDF_SHA384;
2493 *aead_id = HPKE_AEAD_AES_256_GCM;
2494 return 0;
2495 case 21:
2496 *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
2497 *kdf_id = HPKE_KDF_HKDF_SHA512;
2498 *aead_id = HPKE_AEAD_AES_256_GCM;
2499 return 0;
2500 case 28:
2501 *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
2502 *kdf_id = HPKE_KDF_HKDF_SHA256;
2503 *aead_id = HPKE_AEAD_AES_128_GCM;
2504 return 0;
2505 case 29:
2506 *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
2507 *kdf_id = HPKE_KDF_HKDF_SHA384;
2508 *aead_id = HPKE_AEAD_AES_256_GCM;
2509 return 0;
2510 case 30:
2511 *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
2512 *kdf_id = HPKE_KDF_HKDF_SHA512;
2513 *aead_id = HPKE_AEAD_AES_256_GCM;
2514 return 0;
2515 }
2516
2517 return -1;
2518}
2519
Sunil Ravia04bd252022-05-02 22:54:18 -07002520#endif /* CONFIG_DPP3 */
2521
2522
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002523#ifdef CONFIG_TESTING_OPTIONS
2524
2525int dpp_test_gen_invalid_key(struct wpabuf *msg,
2526 const struct dpp_curve_params *curve)
2527{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002528 struct crypto_ec *ec;
2529 struct crypto_ec_key *key = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00002530 struct crypto_ec_point *p = NULL, *pub_key = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002531 u8 *x, *y;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002532 int ret = -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002533
Hai Shaloma20dcd72022-02-04 13:43:00 -08002534 ec = crypto_ec_init(curve->ike_group);
2535 x = wpabuf_put(msg, curve->prime_len);
2536 y = wpabuf_put(msg, curve->prime_len);
2537 if (!ec)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002538 goto fail;
2539
Hai Shaloma20dcd72022-02-04 13:43:00 -08002540retry:
2541 /* Generate valid key pair */
2542 key = crypto_ec_key_gen(curve->ike_group);
2543 if (!key)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002544 goto fail;
2545
Hai Shaloma20dcd72022-02-04 13:43:00 -08002546 /* Retrieve public key coordinates */
2547 pub_key = crypto_ec_key_get_public_key(key);
Sunil8cd6f4d2022-06-28 18:40:46 +00002548 if (!pub_key || crypto_ec_point_to_bin(ec, pub_key, x, y))
Hai Shaloma20dcd72022-02-04 13:43:00 -08002549 goto fail;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002550
Hai Shaloma20dcd72022-02-04 13:43:00 -08002551 /* And corrupt them */
2552 y[curve->prime_len - 1] ^= 0x01;
2553 p = crypto_ec_point_from_bin(ec, x);
2554 if (p && crypto_ec_point_is_on_curve(ec, p)) {
2555 crypto_ec_point_deinit(p, 0);
2556 p = NULL;
2557 goto retry;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002558 }
2559
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002560 ret = 0;
2561fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002562 crypto_ec_point_deinit(p, 0);
Sunil8cd6f4d2022-06-28 18:40:46 +00002563 crypto_ec_point_deinit(pub_key, 0);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002564 crypto_ec_key_deinit(key);
2565 crypto_ec_deinit(ec);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002566 return ret;
2567}
2568
2569
2570char * dpp_corrupt_connector_signature(const char *connector)
2571{
2572 char *tmp, *pos, *signed3 = NULL;
2573 unsigned char *signature = NULL;
2574 size_t signature_len = 0, signed3_len;
2575
2576 tmp = os_zalloc(os_strlen(connector) + 5);
2577 if (!tmp)
2578 goto fail;
2579 os_memcpy(tmp, connector, os_strlen(connector));
2580
2581 pos = os_strchr(tmp, '.');
2582 if (!pos)
2583 goto fail;
2584
2585 pos = os_strchr(pos + 1, '.');
2586 if (!pos)
2587 goto fail;
2588 pos++;
2589
2590 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
2591 pos);
2592 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
2593 if (!signature || signature_len == 0)
2594 goto fail;
2595 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
2596 signature, signature_len);
2597 signature[signature_len - 1] ^= 0x01;
2598 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
2599 signature, signature_len);
2600 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
2601 if (!signed3)
2602 goto fail;
2603 os_memcpy(pos, signed3, signed3_len);
2604 pos[signed3_len] = '\0';
2605 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
2606 pos);
2607
2608out:
2609 os_free(signature);
2610 os_free(signed3);
2611 return tmp;
2612fail:
2613 os_free(tmp);
2614 tmp = NULL;
2615 goto out;
2616}
2617
2618#endif /* CONFIG_TESTING_OPTIONS */