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