]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/dpp.c
DPP: AP parameters for DPP AKM
[thirdparty/hostap.git] / src / common / dpp.c
CommitLineData
be27e185
JM
1/*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
461d39af 10#include <openssl/opensslv.h>
be27e185
JM
11#include <openssl/err.h>
12
13#include "utils/common.h"
14#include "utils/base64.h"
461d39af 15#include "utils/json.h"
be27e185 16#include "common/ieee802_11_common.h"
30d27b04
JM
17#include "common/ieee802_11_defs.h"
18#include "common/wpa_ctrl.h"
be27e185 19#include "crypto/crypto.h"
30d27b04
JM
20#include "crypto/random.h"
21#include "crypto/aes.h"
22#include "crypto/aes_siv.h"
23#include "crypto/sha384.h"
24#include "crypto/sha512.h"
be27e185
JM
25#include "dpp.h"
26
27
461d39af
JM
28#if OPENSSL_VERSION_NUMBER < 0x10100000L
29/* Compatibility wrappers for older versions. */
30
31static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
32{
33 sig->r = r;
34 sig->s = s;
35 return 1;
36}
37
38
39static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
40 const BIGNUM **ps)
41{
42 if (pr)
43 *pr = sig->r;
44 if (ps)
45 *ps = sig->s;
46}
47
48#endif
49
50
be27e185
JM
51static const struct dpp_curve_params dpp_curves[] = {
52 /* The mandatory to support and the default NIST P-256 curve needs to
53 * be the first entry on this list. */
54 { "prime256v1", 32, 32, 16, 32, "P-256" },
55 { "secp384r1", 48, 48, 24, 48, "P-384" },
56 { "secp521r1", 64, 64, 32, 66, "P-521" },
57 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256R1" },
58 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384R1" },
59 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512R1" },
60 { NULL, 0, 0, 0, 0, NULL }
61};
62
63
30d27b04
JM
64static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
65{
66 int len, res;
67 EC_KEY *eckey;
68 struct wpabuf *buf;
69 unsigned char *pos;
70
71 eckey = EVP_PKEY_get1_EC_KEY(pkey);
72 if (!eckey)
73 return NULL;
74 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
75 len = i2o_ECPublicKey(eckey, NULL);
76 if (len <= 0) {
77 wpa_printf(MSG_ERROR,
78 "DDP: Failed to determine public key encoding length");
79 EC_KEY_free(eckey);
80 return NULL;
81 }
82
83 buf = wpabuf_alloc(len);
84 if (!buf) {
85 EC_KEY_free(eckey);
86 return NULL;
87 }
88
89 pos = wpabuf_put(buf, len);
90 res = i2o_ECPublicKey(eckey, &pos);
91 EC_KEY_free(eckey);
92 if (res != len) {
93 wpa_printf(MSG_ERROR,
94 "DDP: Failed to encode public key (res=%d/%d)",
95 res, len);
96 wpabuf_free(buf);
97 return NULL;
98 }
99
100 if (!prefix) {
101 /* Remove 0x04 prefix to match DPP definition */
102 pos = wpabuf_mhead(buf);
103 os_memmove(pos, pos + 1, len - 1);
104 buf->used--;
105 }
106
107 return buf;
108}
109
110
111static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
112 const u8 *buf_x, const u8 *buf_y,
113 size_t len)
114{
115 EC_KEY *eckey = NULL;
116 BN_CTX *ctx;
117 EC_POINT *point = NULL;
118 BIGNUM *x = NULL, *y = NULL;
119 EVP_PKEY *pkey = NULL;
120
121 ctx = BN_CTX_new();
122 if (!ctx) {
123 wpa_printf(MSG_ERROR, "DPP: Out of memory");
124 return NULL;
125 }
126
127 point = EC_POINT_new(group);
128 x = BN_bin2bn(buf_x, len, NULL);
129 y = BN_bin2bn(buf_y, len, NULL);
130 if (!point || !x || !y) {
131 wpa_printf(MSG_ERROR, "DPP: Out of memory");
132 goto fail;
133 }
134
135 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
136 wpa_printf(MSG_ERROR,
137 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
138 ERR_error_string(ERR_get_error(), NULL));
139 goto fail;
140 }
141
142 if (!EC_POINT_is_on_curve(group, point, ctx) ||
143 EC_POINT_is_at_infinity(group, point)) {
144 wpa_printf(MSG_ERROR, "DPP: Invalid point");
145 goto fail;
146 }
147
148 eckey = EC_KEY_new();
149 if (!eckey ||
150 EC_KEY_set_group(eckey, group) != 1 ||
151 EC_KEY_set_public_key(eckey, point) != 1) {
152 wpa_printf(MSG_ERROR,
153 "DPP: Failed to set EC_KEY: %s",
154 ERR_error_string(ERR_get_error(), NULL));
155 goto fail;
156 }
157 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
158
159 pkey = EVP_PKEY_new();
160 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
161 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
162 goto fail;
163 }
164
165out:
166 BN_free(x);
167 BN_free(y);
168 EC_KEY_free(eckey);
169 EC_POINT_free(point);
170 BN_CTX_free(ctx);
171 return pkey;
172fail:
173 EVP_PKEY_free(pkey);
174 pkey = NULL;
175 goto out;
176}
177
178
179static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
180 const u8 *buf, size_t len)
181{
182 EC_KEY *eckey;
183 const EC_GROUP *group;
184 EVP_PKEY *pkey = NULL;
185
186 if (len & 1)
187 return NULL;
188
189 eckey = EVP_PKEY_get1_EC_KEY(group_key);
190 if (!eckey) {
191 wpa_printf(MSG_ERROR,
192 "DPP: Could not get EC_KEY from group_key");
193 return NULL;
194 }
195
196 group = EC_KEY_get0_group(eckey);
197 if (group)
198 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
199 len / 2);
200 else
201 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
202
203 EC_KEY_free(eckey);
204 return pkey;
205}
206
207
208struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
209 size_t len)
210{
211 struct wpabuf *msg;
212
213 msg = wpabuf_alloc(7 + len);
214 if (!msg)
215 return NULL;
216 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
217 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
218 wpabuf_put_be24(msg, OUI_WFA);
219 wpabuf_put_u8(msg, DPP_OUI_TYPE);
220 wpabuf_put_u8(msg, type);
221 return msg;
222}
223
224
225const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
226{
227 u16 id, alen;
228 const u8 *pos = buf, *end = buf + len;
229
230 while (end - pos >= 4) {
231 id = WPA_GET_LE16(pos);
232 pos += 2;
233 alen = WPA_GET_LE16(pos);
234 pos += 2;
235 if (alen > end - pos)
236 return NULL;
237 if (id == req_id) {
238 *ret_len = alen;
239 return pos;
240 }
241 pos += alen;
242 }
243
244 return NULL;
245}
246
247
248int dpp_check_attrs(const u8 *buf, size_t len)
249{
250 const u8 *pos, *end;
251
252 pos = buf;
253 end = buf + len;
254 while (end - pos >= 4) {
255 u16 id, alen;
256
257 id = WPA_GET_LE16(pos);
258 pos += 2;
259 alen = WPA_GET_LE16(pos);
260 pos += 2;
261 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
262 id, alen);
263 if (alen > end - pos) {
264 wpa_printf(MSG_DEBUG,
265 "DPP: Truncated message - not enough room for the attribute - dropped");
266 return -1;
267 }
268 pos += alen;
269 }
270
271 if (end != pos) {
272 wpa_printf(MSG_DEBUG,
273 "DPP: Unexpected octets (%d) after the last attribute",
274 (int) (end - pos));
275 return -1;
276 }
277
278 return 0;
279}
280
281
be27e185
JM
282void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
283{
284 if (!info)
285 return;
286 os_free(info->uri);
287 os_free(info->info);
288 EVP_PKEY_free(info->pubkey);
289 os_free(info);
290}
291
292
293static int dpp_uri_valid_info(const char *info)
294{
295 while (*info) {
296 unsigned char val = *info++;
297
298 if (val < 0x20 || val > 0x7e || val == 0x3b)
299 return 0;
300 }
301
302 return 1;
303}
304
305
306static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
307{
308 bi->uri = os_strdup(uri);
309 return bi->uri ? 0 : -1;
310}
311
312
313int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
314 const char *chan_list)
315{
316 const char *pos = chan_list;
317 int opclass, channel, freq;
318
319 while (pos && *pos && *pos != ';') {
320 opclass = atoi(pos);
321 if (opclass <= 0)
322 goto fail;
323 pos = os_strchr(pos, '/');
324 if (!pos)
325 goto fail;
326 pos++;
327 channel = atoi(pos);
328 if (channel <= 0)
329 goto fail;
330 while (*pos >= '0' && *pos <= '9')
331 pos++;
332 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
333 wpa_printf(MSG_DEBUG,
334 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
335 opclass, channel, freq);
336 if (freq < 0) {
337 wpa_printf(MSG_DEBUG,
338 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
339 opclass, channel);
340 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
341 wpa_printf(MSG_DEBUG,
342 "DPP: Too many channels in URI channel-list - ignore list");
343 bi->num_freq = 0;
344 break;
345 } else {
346 bi->freq[bi->num_freq++] = freq;
347 }
348
349 if (*pos == ';' || *pos == '\0')
350 break;
351 if (*pos != ',')
352 goto fail;
353 pos++;
354 }
355
356 return 0;
357fail:
358 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
359 return -1;
360}
361
362
363int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
364{
365 if (!mac)
366 return 0;
367
368 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
369 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
370 return -1;
371 }
372
373 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
374
375 return 0;
376}
377
378
379int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
380{
381 const char *end;
382
383 if (!info)
384 return 0;
385
386 end = os_strchr(info, ';');
387 if (!end)
388 end = info + os_strlen(info);
389 bi->info = os_malloc(end - info + 1);
390 if (!bi->info)
391 return -1;
392 os_memcpy(bi->info, info, end - info);
393 bi->info[end - info] = '\0';
394 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
395 if (!dpp_uri_valid_info(bi->info)) {
396 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
397 return -1;
398 }
399
400 return 0;
401}
402
403
404static const struct dpp_curve_params *
405dpp_get_curve_oid(const ASN1_OBJECT *poid)
406{
407 ASN1_OBJECT *oid;
408 int i;
409
410 for (i = 0; dpp_curves[i].name; i++) {
411 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
412 if (oid && OBJ_cmp(poid, oid) == 0)
413 return &dpp_curves[i];
414 }
415 return NULL;
416}
417
418
419static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
420{
421 int i, tmp;
422
423 if (!nid)
424 return NULL;
425 for (i = 0; dpp_curves[i].name; i++) {
426 tmp = OBJ_txt2nid(dpp_curves[i].name);
427 if (tmp == nid)
428 return &dpp_curves[i];
429 }
430 return NULL;
431}
432
433
434static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
435{
436 const char *end;
437 u8 *data;
438 size_t data_len;
439 EVP_PKEY *pkey;
440 const unsigned char *p;
441 int res;
442 X509_PUBKEY *pub = NULL;
443 ASN1_OBJECT *ppkalg;
444 const unsigned char *pk;
445 int ppklen;
446 X509_ALGOR *pa;
447 ASN1_OBJECT *pa_oid;
448 const void *pval;
449 int ptype;
450 const ASN1_OBJECT *poid;
451 char buf[100];
452
453 end = os_strchr(info, ';');
454 if (!end)
455 return -1;
456
457 data = base64_decode((const unsigned char *) info, end - info,
458 &data_len);
459 if (!data) {
460 wpa_printf(MSG_DEBUG,
461 "DPP: Invalid base64 encoding on URI public-key");
462 return -1;
463 }
464 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
465 data, data_len);
466
467 if (sha256_vector(1, (const u8 **) &data, &data_len,
468 bi->pubkey_hash) < 0) {
469 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
470 return -1;
471 }
30d27b04
JM
472 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
473 bi->pubkey_hash, SHA256_MAC_LEN);
be27e185
JM
474
475 /* DER encoded ASN.1 SubjectPublicKeyInfo
476 *
477 * SubjectPublicKeyInfo ::= SEQUENCE {
478 * algorithm AlgorithmIdentifier,
479 * subjectPublicKey BIT STRING }
480 *
481 * AlgorithmIdentifier ::= SEQUENCE {
482 * algorithm OBJECT IDENTIFIER,
483 * parameters ANY DEFINED BY algorithm OPTIONAL }
484 *
485 * subjectPublicKey = compressed format public key per ANSI X9.63
486 * algorithm = ecPublicKey (1.2.840.10045.2.1)
487 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
488 * prime256v1 (1.2.840.10045.3.1.7)
489 */
490
491 p = data;
492 pkey = d2i_PUBKEY(NULL, &p, data_len);
493 os_free(data);
494
495 if (!pkey) {
496 wpa_printf(MSG_DEBUG,
497 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
498 return -1;
499 }
500
501 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
502 wpa_printf(MSG_DEBUG,
503 "DPP: SubjectPublicKeyInfo does not describe an EC key");
504 EVP_PKEY_free(pkey);
505 return -1;
506 }
507
508 res = X509_PUBKEY_set(&pub, pkey);
509 if (res != 1) {
510 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
511 goto fail;
512 }
513
514 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
515 if (res != 1) {
516 wpa_printf(MSG_DEBUG,
517 "DPP: Could not extract SubjectPublicKeyInfo parameters");
518 goto fail;
519 }
520 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
521 if (res < 0 || (size_t) res >= sizeof(buf)) {
522 wpa_printf(MSG_DEBUG,
523 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
524 goto fail;
525 }
526 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
527 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
528 wpa_printf(MSG_DEBUG,
529 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
530 goto fail;
531 }
532
533 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
534 if (ptype != V_ASN1_OBJECT) {
535 wpa_printf(MSG_DEBUG,
536 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
537 goto fail;
538 }
539 poid = pval;
540 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
541 if (res < 0 || (size_t) res >= sizeof(buf)) {
542 wpa_printf(MSG_DEBUG,
543 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
544 goto fail;
545 }
546 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
547 bi->curve = dpp_get_curve_oid(poid);
548 if (!bi->curve) {
549 wpa_printf(MSG_DEBUG,
550 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
551 buf);
552 goto fail;
553 }
554
555 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
556
557 X509_PUBKEY_free(pub);
558 bi->pubkey = pkey;
559 return 0;
560fail:
561 X509_PUBKEY_free(pub);
562 EVP_PKEY_free(pkey);
563 return -1;
564}
565
566
567static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
568{
569 const char *pos = uri;
570 const char *end;
571 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
572 struct dpp_bootstrap_info *bi;
573
574 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
575
576 if (os_strncmp(pos, "DPP:", 4) != 0) {
577 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
578 return NULL;
579 }
580 pos += 4;
581
582 for (;;) {
583 end = os_strchr(pos, ';');
584 if (!end)
585 break;
586
587 if (end == pos) {
588 /* Handle terminating ";;" and ignore unexpected ";"
589 * for parsing robustness. */
590 pos++;
591 continue;
592 }
593
594 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
595 chan_list = pos + 2;
596 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
597 mac = pos + 2;
598 else if (pos[0] == 'I' && pos[1] == ':' && !info)
599 info = pos + 2;
600 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
601 pk = pos + 2;
602 else
603 wpa_hexdump_ascii(MSG_DEBUG,
604 "DPP: Ignore unrecognized URI parameter",
605 pos, end - pos);
606 pos = end + 1;
607 }
608
609 if (!pk) {
610 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
611 return NULL;
612 }
613
614 bi = os_zalloc(sizeof(*bi));
615 if (!bi)
616 return NULL;
617
618 if (dpp_clone_uri(bi, uri) < 0 ||
619 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
620 dpp_parse_uri_mac(bi, mac) < 0 ||
621 dpp_parse_uri_info(bi, info) < 0 ||
622 dpp_parse_uri_pk(bi, pk) < 0) {
623 dpp_bootstrap_info_free(bi);
624 bi = NULL;
625 }
626
627 return bi;
628}
629
630
631struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri)
632{
633 struct dpp_bootstrap_info *bi;
634
635 bi = dpp_parse_uri(uri);
636 if (bi)
637 bi->type = DPP_BOOTSTRAP_QR_CODE;
638 return bi;
639}
640
641
642static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
643{
644 EC_KEY *eckey;
645 BIO *out;
646 size_t rlen;
647 char *txt;
648 int res;
649 unsigned char *der = NULL;
650 int der_len;
651
652 out = BIO_new(BIO_s_mem());
653 if (!out)
654 return;
655
656 EVP_PKEY_print_private(out, key, 0, NULL);
657 rlen = BIO_ctrl_pending(out);
658 txt = os_malloc(rlen + 1);
659 if (txt) {
660 res = BIO_read(out, txt, rlen);
661 if (res > 0) {
662 txt[res] = '\0';
663 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
664 }
665 os_free(txt);
666 }
667 BIO_free(out);
668
669 eckey = EVP_PKEY_get1_EC_KEY(key);
670 if (!eckey)
671 return;
672
673 der_len = i2d_ECPrivateKey(eckey, &der);
674 if (der_len > 0)
675 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
676 OPENSSL_free(der);
677 if (der_len <= 0) {
678 der = NULL;
679 der_len = i2d_EC_PUBKEY(eckey, &der);
680 if (der_len > 0)
681 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
682 OPENSSL_free(der);
683 }
684
685 EC_KEY_free(eckey);
686}
687
688
689static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
690{
691#ifdef OPENSSL_IS_BORINGSSL
692 EVP_PKEY_CTX *kctx = NULL;
693 const EC_GROUP *group;
694 EC_KEY *ec_params;
695#else
696 EVP_PKEY_CTX *pctx, *kctx = NULL;
697#endif
698 EVP_PKEY *params = NULL, *key = NULL;
699 int nid;
700
701 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
702
703 nid = OBJ_txt2nid(curve->name);
704 if (nid == NID_undef) {
705 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
706 return NULL;
707 }
708#ifdef OPENSSL_IS_BORINGSSL
709 group = EC_GROUP_new_by_curve_name(nid);
710 ec_params = EC_KEY_new();
711 if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) {
712 wpa_printf(MSG_ERROR,
713 "DPP: Failed to generate EC_KEY parameters");
714 goto fail;
715 }
716 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
717 params = EVP_PKEY_new();
718 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
719 wpa_printf(MSG_ERROR,
720 "DPP: Failed to generate EVP_PKEY parameters");
721 goto fail;
722 }
723#else
724 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
725 if (!pctx ||
726 EVP_PKEY_paramgen_init(pctx) != 1 ||
727 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 ||
728 EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 ||
729 EVP_PKEY_paramgen(pctx, &params) != 1) {
730 wpa_printf(MSG_ERROR,
731 "DPP: Failed to generate EVP_PKEY parameters");
732 EVP_PKEY_CTX_free(pctx);
733 goto fail;
734 }
735 EVP_PKEY_CTX_free(pctx);
736#endif
737
738 kctx = EVP_PKEY_CTX_new(params, NULL);
739 if (!kctx ||
740 EVP_PKEY_keygen_init(kctx) != 1 ||
741 EVP_PKEY_keygen(kctx, &key) != 1) {
742 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
743 goto fail;
744 }
745
746 if (wpa_debug_show_keys)
747 dpp_debug_print_key("Own generated key", key);
748
749 EVP_PKEY_free(params);
750 EVP_PKEY_CTX_free(kctx);
751 return key;
752fail:
753 EVP_PKEY_CTX_free(kctx);
754 EVP_PKEY_free(params);
755 return NULL;
756}
757
758
759static const struct dpp_curve_params *
760dpp_get_curve_name(const char *name)
761{
762 int i;
763
764 for (i = 0; dpp_curves[i].name; i++) {
765 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
766 (dpp_curves[i].jwk_crv &&
767 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
768 return &dpp_curves[i];
769 }
770 return NULL;
771}
772
773
461d39af
JM
774static const struct dpp_curve_params *
775dpp_get_curve_jwk_crv(const char *name)
776{
777 int i;
778
779 for (i = 0; dpp_curves[i].name; i++) {
780 if (dpp_curves[i].jwk_crv &&
781 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
782 return &dpp_curves[i];
783 }
784 return NULL;
785}
786
787
be27e185
JM
788static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
789 const u8 *privkey, size_t privkey_len)
790{
791 EVP_PKEY *pkey;
792 EC_KEY *eckey;
793 const EC_GROUP *group;
794 int nid;
795
796 pkey = EVP_PKEY_new();
797 if (!pkey)
798 return NULL;
799 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
800 if (!eckey) {
801 wpa_printf(MSG_INFO,
802 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
803 ERR_error_string(ERR_get_error(), NULL));
804 EVP_PKEY_free(pkey);
805 return NULL;
806 }
807 group = EC_KEY_get0_group(eckey);
808 if (!group) {
809 EC_KEY_free(eckey);
810 EVP_PKEY_free(pkey);
811 return NULL;
812 }
813 nid = EC_GROUP_get_curve_name(group);
814 *curve = dpp_get_curve_nid(nid);
815 if (!*curve) {
816 wpa_printf(MSG_INFO,
817 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
818 nid);
819 EC_KEY_free(eckey);
820 EVP_PKEY_free(pkey);
821 return NULL;
822 }
823
824 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
825 EC_KEY_free(eckey);
826 EVP_PKEY_free(pkey);
827 return NULL;
828 }
829 return pkey;
830}
831
832
833char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
834 const u8 *privkey, size_t privkey_len)
835{
836 unsigned char *base64 = NULL;
837 char *pos, *end;
838 size_t len;
839 unsigned char *der = NULL;
840 int der_len;
841 EC_KEY *eckey;
842
843 if (!curve) {
844 bi->curve = &dpp_curves[0];
845 } else {
846 bi->curve = dpp_get_curve_name(curve);
847 if (!bi->curve) {
848 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
849 curve);
850 return NULL;
851 }
852 }
853 if (privkey)
854 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
855 else
856 bi->pubkey = dpp_gen_keypair(bi->curve);
857 if (!bi->pubkey)
858 goto fail;
859 bi->own = 1;
860
861 /* Need to get the compressed form of the public key through EC_KEY, so
862 * cannot use the simpler i2d_PUBKEY() here. */
863 eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey);
864 if (!eckey)
865 goto fail;
866 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
867 der_len = i2d_EC_PUBKEY(eckey, &der);
868 EC_KEY_free(eckey);
869 if (der_len <= 0) {
870 wpa_printf(MSG_ERROR,
871 "DDP: Failed to build DER encoded public key");
872 goto fail;
873 }
874
875 len = der_len;
876 if (sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash) < 0) {
877 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
878 goto fail;
879 }
880
881 base64 = base64_encode(der, der_len, &len);
882 OPENSSL_free(der);
883 if (!base64)
884 goto fail;
885 pos = (char *) base64;
886 end = pos + len;
887 for (;;) {
888 pos = os_strchr(pos, '\n');
889 if (!pos)
890 break;
891 os_memmove(pos, pos + 1, end - pos);
892 }
893 return (char *) base64;
894fail:
895 os_free(base64);
896 OPENSSL_free(der);
897 return NULL;
898}
30d27b04
JM
899
900
901static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
902 unsigned int hash_len)
903{
904 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
905 const char *info = "first intermediate key";
906 int res = -1;
907
908 /* k1 = HKDF(<>, "first intermediate key", M.x) */
909
910 /* HKDF-Extract(<>, M.x) */
911 os_memset(salt, 0, hash_len);
912 if (hash_len == 32) {
913 if (hmac_sha256(salt, SHA256_MAC_LEN, Mx, Mx_len, prk) < 0)
914 return -1;
915 } else if (hash_len == 48) {
916 if (hmac_sha384(salt, SHA384_MAC_LEN, Mx, Mx_len, prk) < 0)
917 return -1;
918 } else if (hash_len == 64) {
919 if (hmac_sha512(salt, SHA512_MAC_LEN, Mx, Mx_len, prk) < 0)
920 return -1;
921 } else {
922 return -1;
923 }
924 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
925 prk, hash_len);
926
927 /* HKDF-Expand(PRK, info, L) */
928 if (hash_len == 32)
929 res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL,
930 (const u8 *) info, os_strlen(info),
931 k1, SHA256_MAC_LEN);
932 else if (hash_len == 48)
933 res = hmac_sha384_kdf(prk, SHA384_MAC_LEN, NULL,
934 (const u8 *) info, os_strlen(info),
935 k1, SHA384_MAC_LEN);
936 else if (hash_len == 64)
937 res = hmac_sha512_kdf(prk, SHA512_MAC_LEN, NULL,
938 (const u8 *) info, os_strlen(info),
939 k1, SHA512_MAC_LEN);
940 os_memset(prk, 0, hash_len);
941 if (res < 0)
942 return -1;
943
944 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
945 k1, hash_len);
946 return 0;
947}
948
949
950static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
951 unsigned int hash_len)
952{
953 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
954 const char *info = "second intermediate key";
955 int res;
956
957 /* k2 = HKDF(<>, "second intermediate key", N.x) */
958
959 /* HKDF-Extract(<>, N.x) */
960 os_memset(salt, 0, hash_len);
961 if (hash_len == 32)
962 res = hmac_sha256(salt, SHA256_MAC_LEN, Nx, Nx_len, prk);
963 else if (hash_len == 48)
964 res = hmac_sha384(salt, SHA384_MAC_LEN, Nx, Nx_len, prk);
965 else if (hash_len == 64)
966 res = hmac_sha512(salt, SHA512_MAC_LEN, Nx, Nx_len, prk);
967 else
968 res = -1;
969 if (res < 0)
970 return -1;
971 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
972 prk, hash_len);
973
974 /* HKDF-Expand(PRK, info, L) */
975 if (hash_len == 32)
976 res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL,
977 (const u8 *) info, os_strlen(info),
978 k2, SHA256_MAC_LEN);
979 else if (hash_len == 48)
980 res = hmac_sha384_kdf(prk, SHA384_MAC_LEN, NULL,
981 (const u8 *) info, os_strlen(info),
982 k2, SHA384_MAC_LEN);
983 else if (hash_len == 64)
984 res = hmac_sha512_kdf(prk, SHA512_MAC_LEN, NULL,
985 (const u8 *) info, os_strlen(info),
986 k2, SHA512_MAC_LEN);
987 os_memset(prk, 0, hash_len);
988 if (res < 0)
989 return -1;
990
991 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
992 k2, hash_len);
993 return 0;
994}
995
996
997static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
998 unsigned int hash_len)
999{
1000 size_t nonce_len;
1001 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1002 const char *info_ke = "DPP Key";
1003 u8 prk[DPP_MAX_HASH_LEN];
1004 int res;
1005 const u8 *addr[3];
1006 size_t len[3];
1007 size_t num_elem = 0;
1008
1009 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1010
1011 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1012 nonce_len = auth->curve->nonce_len;
1013 os_memcpy(nonces, auth->i_nonce, nonce_len);
1014 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1015 addr[num_elem] = auth->Mx;
1016 len[num_elem] = auth->secret_len;
1017 num_elem++;
1018 addr[num_elem] = auth->Nx;
1019 len[num_elem] = auth->secret_len;
1020 num_elem++;
1021 if (auth->peer_bi && auth->own_bi) {
1022 addr[num_elem] = auth->Lx;
1023 len[num_elem] = auth->secret_len;
1024 num_elem++;
1025 }
1026 if (hash_len == 32)
1027 res = hmac_sha256_vector(nonces, 2 * nonce_len,
1028 num_elem, addr, len, prk);
1029 else if (hash_len == 48)
1030 res = hmac_sha384_vector(nonces, 2 * nonce_len,
1031 num_elem, addr, len, prk);
1032 else if (hash_len == 64)
1033 res = hmac_sha512_vector(nonces, 2 * nonce_len,
1034 num_elem, addr, len, prk);
1035 else
1036 res = -1;
1037 if (res < 0)
1038 return -1;
1039 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1040 prk, hash_len);
1041
1042 /* HKDF-Expand(PRK, info, L) */
1043 if (hash_len == 32)
1044 res = hmac_sha256_kdf(prk, SHA256_MAC_LEN, NULL,
1045 (const u8 *) info_ke, os_strlen(info_ke),
1046 ke, SHA256_MAC_LEN);
1047 else if (hash_len == 48)
1048 res = hmac_sha384_kdf(prk, SHA384_MAC_LEN, NULL,
1049 (const u8 *) info_ke, os_strlen(info_ke),
1050 ke, SHA384_MAC_LEN);
1051 else if (hash_len == 64)
1052 res = hmac_sha512_kdf(prk, SHA512_MAC_LEN, NULL,
1053 (const u8 *) info_ke, os_strlen(info_ke),
1054 ke, SHA512_MAC_LEN);
1055 os_memset(prk, 0, hash_len);
1056 if (res < 0)
1057 return -1;
1058
1059 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1060 ke, hash_len);
1061 return 0;
1062}
1063
1064
1065struct dpp_authentication * dpp_auth_init(void *msg_ctx,
1066 struct dpp_bootstrap_info *peer_bi,
1067 struct dpp_bootstrap_info *own_bi,
1068 int configurator)
1069{
1070 struct dpp_authentication *auth;
1071 size_t nonce_len;
1072 EVP_PKEY_CTX *ctx = NULL;
1073 size_t secret_len;
1074 struct wpabuf *msg, *pi = NULL;
1075 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1076 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1077 u8 *pos;
1078 const u8 *addr[1];
1079 size_t len[1], siv_len;
1080
1081 auth = os_zalloc(sizeof(*auth));
1082 if (!auth)
1083 return NULL;
1084 auth->msg_ctx = msg_ctx;
1085 auth->initiator = 1;
1086 auth->configurator = configurator;
1087 auth->peer_bi = peer_bi;
1088 auth->own_bi = own_bi;
1089 auth->curve = peer_bi->curve;
1090
1091 nonce_len = auth->curve->nonce_len;
1092 if (random_get_bytes(auth->i_nonce, nonce_len)) {
1093 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
1094 goto fail;
1095 }
1096 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
1097
1098 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1099 if (!auth->own_protocol_key)
1100 goto fail;
1101
1102 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1103 if (!pi)
1104 goto fail;
1105
1106 /* ECDH: M = pI * BR */
1107 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
1108 if (!ctx ||
1109 EVP_PKEY_derive_init(ctx) != 1 ||
1110 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 ||
1111 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
1112 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
1113 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
1114 wpa_printf(MSG_ERROR,
1115 "DPP: Failed to derive ECDH shared secret: %s",
1116 ERR_error_string(ERR_get_error(), NULL));
1117 goto fail;
1118 }
1119 auth->secret_len = secret_len;
1120 EVP_PKEY_CTX_free(ctx);
1121 ctx = NULL;
1122
1123 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
1124 auth->Mx, auth->secret_len);
1125
1126 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
1127 auth->curve->hash_len) < 0)
1128 goto fail;
1129
1130 /* Build DPP Authentication Request frame attributes */
1131 msg = wpabuf_alloc(2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pi) +
1132 4 + sizeof(wrapped_data));
1133 if (!msg)
1134 goto fail;
1135 auth->req_attr = msg;
1136
1137 /* Responder Bootstrapping Key Hash */
1138 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1139 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1140 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
1141
1142 /* Initiator Bootstrapping Key Hash */
1143 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1144 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1145 if (auth->own_bi)
1146 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
1147 else
1148 os_memset(wpabuf_put(msg, SHA256_MAC_LEN), 0, SHA256_MAC_LEN);
1149
1150 /* Initiator Protocol Key */
1151 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1152 wpabuf_put_le16(msg, wpabuf_len(pi));
1153 wpabuf_put_buf(msg, pi);
1154 wpabuf_free(pi);
1155 pi = NULL;
1156
1157 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1158 pos = clear;
1159 /* I-nonce */
1160 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1161 pos += 2;
1162 WPA_PUT_LE16(pos, nonce_len);
1163 pos += 2;
1164 os_memcpy(pos, auth->i_nonce, nonce_len);
1165 pos += nonce_len;
1166 /* I-capabilities */
1167 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1168 pos += 2;
1169 WPA_PUT_LE16(pos, 1);
1170 pos += 2;
1171 auth->i_capab = configurator ? DPP_CAPAB_CONFIGURATOR :
1172 DPP_CAPAB_ENROLLEE;
1173 *pos++ = auth->i_capab;
1174
1175 addr[0] = wpabuf_head(msg);
1176 len[0] = wpabuf_len(msg);
1177 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
1178 siv_len = pos - clear;
1179 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1180 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1181 1, addr, len, wrapped_data) < 0)
1182 goto fail;
1183 siv_len += AES_BLOCK_SIZE;
1184 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1185 wrapped_data, siv_len);
1186
1187 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1188 wpabuf_put_le16(msg, siv_len);
1189 wpabuf_put_data(msg, wrapped_data, siv_len);
1190
1191 wpa_hexdump_buf(MSG_DEBUG,
1192 "DPP: Authentication Request frame attributes", msg);
1193
1194 return auth;
1195fail:
1196 wpabuf_free(pi);
1197 EVP_PKEY_CTX_free(ctx);
1198 dpp_auth_deinit(auth);
1199 return NULL;
1200}
1201
1202
461d39af
JM
1203struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
1204 const char *json)
1205{
1206 size_t nonce_len;
1207 size_t json_len, clear_len;
1208 struct wpabuf *clear = NULL, *msg = NULL;
1209 u8 *wrapped;
1210
1211 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
1212
1213 nonce_len = auth->curve->nonce_len;
1214 if (random_get_bytes(auth->e_nonce, nonce_len)) {
1215 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
1216 goto fail;
1217 }
1218 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
1219 json_len = os_strlen(json);
1220 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len);
1221
1222 /* { E-nonce, configAttrib }ke */
1223 clear_len = 4 + nonce_len + 4 + json_len;
1224 clear = wpabuf_alloc(clear_len);
1225 msg = wpabuf_alloc(4 + clear_len + AES_BLOCK_SIZE);
1226 if (!clear || !msg)
1227 goto fail;
1228
1229 /* E-nonce */
1230 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
1231 wpabuf_put_le16(clear, nonce_len);
1232 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
1233
1234 /* configAttrib */
1235 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
1236 wpabuf_put_le16(clear, json_len);
1237 wpabuf_put_data(clear, json, json_len);
1238
1239 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1240 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1241 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1242
1243 /* No AES-SIV AD */
1244 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
1245 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
1246 wpabuf_head(clear), wpabuf_len(clear),
1247 0, NULL, NULL, wrapped) < 0)
1248 goto fail;
1249 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1250 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
1251
1252 wpa_hexdump_buf(MSG_DEBUG,
1253 "DPP: Configuration Request frame attributes", msg);
1254 wpabuf_free(clear);
1255 return msg;
1256
1257fail:
1258 wpabuf_free(clear);
1259 wpabuf_free(msg);
1260 return NULL;
1261}
1262
1263
30d27b04
JM
1264static void dpp_auth_success(struct dpp_authentication *auth)
1265{
1266 wpa_printf(MSG_DEBUG,
1267 "DPP: Authentication success - clear temporary keys");
1268 os_memset(auth->Mx, 0, sizeof(auth->Mx));
1269 os_memset(auth->Nx, 0, sizeof(auth->Nx));
1270 os_memset(auth->Lx, 0, sizeof(auth->Lx));
1271 os_memset(auth->k1, 0, sizeof(auth->k1));
1272 os_memset(auth->k2, 0, sizeof(auth->k2));
1273
1274 auth->auth_success = 1;
1275}
1276
1277
1278static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
1279{
1280 struct wpabuf *pix, *prx, *bix, *brx;
1281 const u8 *addr[7];
1282 size_t len[7];
1283 size_t i, num_elem = 0;
1284 size_t nonce_len;
1285 u8 zero = 0;
1286 int res = -1;
1287
1288 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1289 nonce_len = auth->curve->nonce_len;
1290
1291 if (auth->initiator) {
1292 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1293 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1294 if (auth->own_bi)
1295 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1296 else
1297 bix = NULL;
1298 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1299 } else {
1300 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1301 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1302 if (auth->peer_bi)
1303 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1304 else
1305 bix = NULL;
1306 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1307 }
1308 if (!pix || !prx || !brx)
1309 goto fail;
1310
1311 addr[num_elem] = auth->i_nonce;
1312 len[num_elem] = nonce_len;
1313 num_elem++;
1314
1315 addr[num_elem] = auth->r_nonce;
1316 len[num_elem] = nonce_len;
1317 num_elem++;
1318
1319 addr[num_elem] = wpabuf_head(pix);
1320 len[num_elem] = wpabuf_len(pix) / 2;
1321 num_elem++;
1322
1323 addr[num_elem] = wpabuf_head(prx);
1324 len[num_elem] = wpabuf_len(prx) / 2;
1325 num_elem++;
1326
1327 if (bix) {
1328 addr[num_elem] = wpabuf_head(bix);
1329 len[num_elem] = wpabuf_len(bix) / 2;
1330 num_elem++;
1331 }
1332
1333 addr[num_elem] = wpabuf_head(brx);
1334 len[num_elem] = wpabuf_len(brx) / 2;
1335 num_elem++;
1336
1337 addr[num_elem] = &zero;
1338 len[num_elem] = 1;
1339 num_elem++;
1340
1341 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
1342 for (i = 0; i < num_elem; i++)
1343 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1344 if (auth->curve->hash_len == 32)
1345 res = sha256_vector(num_elem, addr, len, r_auth);
1346 else if (auth->curve->hash_len == 48)
1347 res = sha384_vector(num_elem, addr, len, r_auth);
1348 else if (auth->curve->hash_len == 64)
1349 res = sha512_vector(num_elem, addr, len, r_auth);
1350 else
1351 res = -1;
1352 if (res == 0)
1353 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
1354 auth->curve->hash_len);
1355fail:
1356 wpabuf_free(pix);
1357 wpabuf_free(prx);
1358 wpabuf_free(bix);
1359 wpabuf_free(brx);
1360 return res;
1361}
1362
1363
1364static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
1365{
1366 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
1367 const u8 *addr[7];
1368 size_t len[7];
1369 size_t i, num_elem = 0;
1370 size_t nonce_len;
1371 u8 one = 1;
1372 int res = -1;
1373
1374 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
1375 nonce_len = auth->curve->nonce_len;
1376
1377 if (auth->initiator) {
1378 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1379 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1380 if (auth->own_bi)
1381 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1382 else
1383 bix = NULL;
1384 if (!auth->peer_bi)
1385 goto fail;
1386 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1387 } else {
1388 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1389 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1390 if (auth->peer_bi)
1391 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1392 else
1393 bix = NULL;
1394 if (!auth->own_bi)
1395 goto fail;
1396 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1397 }
1398 if (!pix || !prx || !brx)
1399 goto fail;
1400
1401 addr[num_elem] = auth->r_nonce;
1402 len[num_elem] = nonce_len;
1403 num_elem++;
1404
1405 addr[num_elem] = auth->i_nonce;
1406 len[num_elem] = nonce_len;
1407 num_elem++;
1408
1409 addr[num_elem] = wpabuf_head(prx);
1410 len[num_elem] = wpabuf_len(prx) / 2;
1411 num_elem++;
1412
1413 addr[num_elem] = wpabuf_head(pix);
1414 len[num_elem] = wpabuf_len(pix) / 2;
1415 num_elem++;
1416
1417 addr[num_elem] = wpabuf_head(brx);
1418 len[num_elem] = wpabuf_len(brx) / 2;
1419 num_elem++;
1420
1421 if (bix) {
1422 addr[num_elem] = wpabuf_head(bix);
1423 len[num_elem] = wpabuf_len(bix) / 2;
1424 num_elem++;
1425 }
1426
1427 addr[num_elem] = &one;
1428 len[num_elem] = 1;
1429 num_elem++;
1430
1431 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
1432 for (i = 0; i < num_elem; i++)
1433 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1434 if (auth->curve->hash_len == 32)
1435 res = sha256_vector(num_elem, addr, len, i_auth);
1436 else if (auth->curve->hash_len == 48)
1437 res = sha384_vector(num_elem, addr, len, i_auth);
1438 else if (auth->curve->hash_len == 64)
1439 res = sha512_vector(num_elem, addr, len, i_auth);
1440 else
1441 res = -1;
1442 if (res == 0)
1443 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
1444 auth->curve->hash_len);
1445fail:
1446 wpabuf_free(pix);
1447 wpabuf_free(prx);
1448 wpabuf_free(bix);
1449 wpabuf_free(brx);
1450 return res;
1451}
1452
1453
1454static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
1455{
1456 const EC_GROUP *group;
1457 EC_POINT *l = NULL;
1458 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
1459 const EC_POINT *BI_point;
1460 BN_CTX *bnctx;
1461 BIGNUM *lx, *sum, *q;
1462 const BIGNUM *bR_bn, *pR_bn;
1463 int ret = -1;
1464 int num_bytes, offset;
1465
1466 /* L = ((bR + pR) modulo q) * BI */
1467
1468 bnctx = BN_CTX_new();
1469 sum = BN_new();
1470 q = BN_new();
1471 lx = BN_new();
1472 if (!bnctx || !sum || !q || !lx)
1473 goto fail;
1474 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
1475 if (!BI)
1476 goto fail;
1477 BI_point = EC_KEY_get0_public_key(BI);
1478 group = EC_KEY_get0_group(BI);
1479 if (!group)
1480 goto fail;
1481
1482 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
1483 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
1484 if (!bR || !pR)
1485 goto fail;
1486 bR_bn = EC_KEY_get0_private_key(bR);
1487 pR_bn = EC_KEY_get0_private_key(pR);
1488 if (!bR_bn || !pR_bn)
1489 goto fail;
1490 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
1491 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
1492 goto fail;
1493 l = EC_POINT_new(group);
1494 if (!l ||
1495 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
1496 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
1497 bnctx) != 1) {
1498 wpa_printf(MSG_ERROR,
1499 "OpenSSL: failed: %s",
1500 ERR_error_string(ERR_get_error(), NULL));
1501 goto fail;
1502 }
1503
1504 num_bytes = BN_num_bytes(lx);
1505 if ((size_t) num_bytes > auth->secret_len)
1506 goto fail;
1507 if (auth->secret_len > (size_t) num_bytes)
1508 offset = auth->secret_len - num_bytes;
1509 else
1510 offset = 0;
1511
1512 os_memset(auth->Lx, 0, offset);
1513 BN_bn2bin(lx, auth->Lx + offset);
1514 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1515 ret = 0;
1516fail:
1517 EC_POINT_clear_free(l);
1518 EC_KEY_free(BI);
1519 EC_KEY_free(bR);
1520 EC_KEY_free(pR);
1521 BN_clear_free(lx);
1522 BN_clear_free(sum);
1523 BN_free(q);
1524 BN_CTX_free(bnctx);
1525 return ret;
1526}
1527
1528
1529static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
1530{
1531 const EC_GROUP *group;
1532 EC_POINT *l = NULL, *sum = NULL;
1533 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
1534 const EC_POINT *BR_point, *PR_point;
1535 BN_CTX *bnctx;
1536 BIGNUM *lx;
1537 const BIGNUM *bI_bn;
1538 int ret = -1;
1539 int num_bytes, offset;
1540
1541 /* L = bI * (BR + PR) */
1542
1543 bnctx = BN_CTX_new();
1544 lx = BN_new();
1545 if (!bnctx || !lx)
1546 goto fail;
1547 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
1548 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
1549 if (!BR || !PR)
1550 goto fail;
1551 BR_point = EC_KEY_get0_public_key(BR);
1552 PR_point = EC_KEY_get0_public_key(PR);
1553
1554 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
1555 if (!bI)
1556 goto fail;
1557 group = EC_KEY_get0_group(bI);
1558 bI_bn = EC_KEY_get0_private_key(bI);
1559 if (!group || !bI_bn)
1560 goto fail;
1561 sum = EC_POINT_new(group);
1562 l = EC_POINT_new(group);
1563 if (!sum || !l ||
1564 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
1565 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
1566 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
1567 bnctx) != 1) {
1568 wpa_printf(MSG_ERROR,
1569 "OpenSSL: failed: %s",
1570 ERR_error_string(ERR_get_error(), NULL));
1571 goto fail;
1572 }
1573
1574 num_bytes = BN_num_bytes(lx);
1575 if ((size_t) num_bytes > auth->secret_len)
1576 goto fail;
1577 if (auth->secret_len > (size_t) num_bytes)
1578 offset = auth->secret_len - num_bytes;
1579 else
1580 offset = 0;
1581
1582 os_memset(auth->Lx, 0, offset);
1583 BN_bn2bin(lx, auth->Lx + offset);
1584 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
1585 ret = 0;
1586fail:
1587 EC_POINT_clear_free(l);
1588 EC_KEY_free(bI);
1589 EC_KEY_free(BR);
1590 EC_KEY_free(PR);
1591 BN_clear_free(lx);
1592 BN_CTX_free(bnctx);
1593 return ret;
1594}
1595
1596
1597static int dpp_auth_build_resp(struct dpp_authentication *auth)
1598{
1599 size_t nonce_len;
1600 EVP_PKEY_CTX *ctx = NULL;
1601 size_t secret_len;
1602 struct wpabuf *msg, *pr = NULL;
1603 u8 r_auth[4 + DPP_MAX_HASH_LEN];
1604 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE];
1605#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1606 4 + sizeof(wrapped_r_auth)
1607 size_t wrapped_r_auth_len;
1608 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1609 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1610 u8 *pos;
1611 const u8 *addr[1];
1612 size_t len[1], siv_len;
1613
1614 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
1615
1616 nonce_len = auth->curve->nonce_len;
1617 if (random_get_bytes(auth->r_nonce, nonce_len)) {
1618 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
1619 goto fail;
1620 }
1621 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
1622
1623 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1624 if (!auth->own_protocol_key)
1625 goto fail;
1626
1627 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1628 if (!pr)
1629 goto fail;
1630
1631 /* ECDH: N = pR * PI */
1632 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
1633 if (!ctx ||
1634 EVP_PKEY_derive_init(ctx) != 1 ||
1635 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 ||
1636 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
1637 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
1638 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
1639 wpa_printf(MSG_ERROR,
1640 "DPP: Failed to derive ECDH shared secret: %s",
1641 ERR_error_string(ERR_get_error(), NULL));
1642 goto fail;
1643 }
1644 EVP_PKEY_CTX_free(ctx);
1645 ctx = NULL;
1646
1647 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
1648 auth->Nx, auth->secret_len);
1649
1650 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
1651 auth->curve->hash_len) < 0)
1652 goto fail;
1653
1654 if (auth->own_bi && auth->peer_bi) {
1655 /* Mutual authentication */
1656 if (dpp_auth_derive_l_responder(auth) < 0)
1657 goto fail;
1658 }
1659
1660 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
1661 goto fail;
1662
1663 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1664 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
1665 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
1666 if (dpp_gen_r_auth(auth, r_auth + 4) < 0 ||
1667 aes_siv_encrypt(auth->ke, auth->curve->hash_len,
1668 r_auth, 4 + auth->curve->hash_len,
1669 0, NULL, NULL, wrapped_r_auth) < 0)
1670 goto fail;
1671 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
1672 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
1673 wrapped_r_auth, wrapped_r_auth_len);
1674
1675 /* Build DPP Authentication Response frame attributes */
1676 msg = wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1677 4 + wpabuf_len(pr) + 4 + sizeof(wrapped_data));
1678 if (!msg)
1679 goto fail;
1680 wpabuf_free(auth->resp_attr);
1681 auth->resp_attr = msg;
1682
1683 /* DPP Status */
1684 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1685 wpabuf_put_le16(msg, 1);
1686 wpabuf_put_u8(msg, DPP_STATUS_OK);
1687
1688 /* Responder Bootstrapping Key Hash */
1689 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1690 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1691 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
1692
1693 if (auth->peer_bi) {
1694 /* Mutual authentication */
1695 /* Initiator Bootstrapping Key Hash */
1696 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1697 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1698 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
1699 SHA256_MAC_LEN);
1700 }
1701
1702 /* Responder Protocol Key */
1703 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1704 wpabuf_put_le16(msg, wpabuf_len(pr));
1705 wpabuf_put_buf(msg, pr);
1706 wpabuf_free(pr);
1707 pr = NULL;
1708
1709 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1710 pos = clear;
1711 /* R-nonce */
1712 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1713 pos += 2;
1714 WPA_PUT_LE16(pos, nonce_len);
1715 pos += 2;
1716 os_memcpy(pos, auth->r_nonce, nonce_len);
1717 pos += nonce_len;
1718 /* I-nonce */
1719 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1720 pos += 2;
1721 WPA_PUT_LE16(pos, nonce_len);
1722 pos += 2;
1723 os_memcpy(pos, auth->i_nonce, nonce_len);
1724 pos += nonce_len;
1725 /* R-capabilities */
1726 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1727 pos += 2;
1728 WPA_PUT_LE16(pos, 1);
1729 pos += 2;
1730 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1731 DPP_CAPAB_ENROLLEE;
1732 *pos++ = auth->r_capab;
1733 /* {R-auth}ke */
1734 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1735 pos += 2;
1736 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1737 pos += 2;
1738 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1739 pos += wrapped_r_auth_len;
1740
1741 addr[0] = wpabuf_head(msg);
1742 len[0] = wpabuf_len(msg);
1743 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
1744 siv_len = pos - clear;
1745 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1746 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len, clear, siv_len,
1747 1, addr, len, wrapped_data) < 0)
1748 goto fail;
1749 siv_len += AES_BLOCK_SIZE;
1750 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1751 wrapped_data, siv_len);
1752
1753 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1754 wpabuf_put_le16(msg, siv_len);
1755 wpabuf_put_data(msg, wrapped_data, siv_len);
1756
1757 wpa_hexdump_buf(MSG_DEBUG,
1758 "DPP: Authentication Response frame attributes", msg);
1759
1760 return 0;
1761
1762fail:
1763 wpabuf_free(pr);
1764 return -1;
1765}
1766
1767
1768static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
1769 enum dpp_status_error status)
1770{
1771 size_t nonce_len;
1772 struct wpabuf *msg;
1773#define DPP_AUTH_RESP_CLEAR_LEN2 4 + DPP_MAX_NONCE_LEN + 4 + 1
1774 u8 clear[DPP_AUTH_RESP_CLEAR_LEN2];
1775 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN2 + AES_BLOCK_SIZE];
1776 u8 *pos;
1777 const u8 *addr[1];
1778 size_t len[1], siv_len;
1779
1780 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
1781
1782 /* Build DPP Authentication Response frame attributes */
1783 msg = wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1784 4 + sizeof(wrapped_data));
1785 if (!msg)
1786 goto fail;
1787 wpabuf_free(auth->resp_attr);
1788 auth->resp_attr = msg;
1789
1790 /* DPP Status */
1791 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1792 wpabuf_put_le16(msg, 1);
1793 wpabuf_put_u8(msg, status);
1794
1795 /* Responder Bootstrapping Key Hash */
1796 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1797 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1798 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
1799
1800 if (auth->peer_bi) {
1801 /* Mutual authentication */
1802 /* Initiator Bootstrapping Key Hash */
1803 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1804 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1805 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash,
1806 SHA256_MAC_LEN);
1807 }
1808
1809 /* Wrapped data ({I-nonce, R-capabilities}k1) */
1810 pos = clear;
1811 /* I-nonce */
1812 nonce_len = auth->curve->nonce_len;
1813 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1814 pos += 2;
1815 WPA_PUT_LE16(pos, nonce_len);
1816 pos += 2;
1817 os_memcpy(pos, auth->i_nonce, nonce_len);
1818 pos += nonce_len;
1819 /* R-capabilities */
1820 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1821 pos += 2;
1822 WPA_PUT_LE16(pos, 1);
1823 pos += 2;
1824 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1825 DPP_CAPAB_ENROLLEE;
1826 *pos++ = auth->r_capab;
1827
1828 addr[0] = wpabuf_head(msg);
1829 len[0] = wpabuf_len(msg);
1830 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
1831 siv_len = pos - clear;
1832 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1833 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1834 1, addr, len, wrapped_data) < 0)
1835 goto fail;
1836 siv_len += AES_BLOCK_SIZE;
1837 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1838 wrapped_data, siv_len);
1839
1840 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1841 wpabuf_put_le16(msg, siv_len);
1842 wpabuf_put_data(msg, wrapped_data, siv_len);
1843
1844 wpa_hexdump_buf(MSG_DEBUG,
1845 "DPP: Authentication Response frame attributes", msg);
1846
1847 return 0;
1848
1849fail:
1850 return -1;
1851}
1852
1853
1854struct dpp_authentication *
1855dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
1856 struct dpp_bootstrap_info *peer_bi,
1857 struct dpp_bootstrap_info *own_bi,
1858 unsigned int freq, const u8 *attr_start,
1859 const u8 *wrapped_data, u16 wrapped_data_len)
1860{
1861 EVP_PKEY *pi = NULL;
1862 EVP_PKEY_CTX *ctx = NULL;
1863 size_t secret_len;
1864 const u8 *addr[1];
1865 size_t len[1];
1866 u8 *unwrapped = NULL;
1867 size_t unwrapped_len = 0;
1868 const u8 *i_proto, *i_nonce, *i_capab, *i_bootstrap;
1869 u16 i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len;
1870 struct dpp_authentication *auth = NULL;
1871 size_t attr_len;
1872
1873 if (wrapped_data_len < AES_BLOCK_SIZE)
1874 return NULL;
1875
1876 attr_len = wrapped_data - 4 - attr_start;
1877
1878 auth = os_zalloc(sizeof(*auth));
1879 if (!auth)
1880 goto fail;
1881 auth->msg_ctx = msg_ctx;
1882 auth->peer_bi = peer_bi;
1883 auth->own_bi = own_bi;
1884 auth->curve = own_bi->curve;
1885 auth->curr_freq = freq;
1886
1887 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
1888 &i_proto_len);
1889 if (!i_proto) {
1890 wpa_printf(MSG_DEBUG,
1891 "DPP: Missing required Initiator Protocol Key attribute");
1892 goto fail;
1893 }
1894 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
1895 i_proto, i_proto_len);
1896
1897 /* M = bR * PI */
1898 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
1899 if (!pi) {
1900 wpa_printf(MSG_DEBUG, "DPP: Invalid Initiator Protocol Key");
1901 goto fail;
1902 }
1903 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
1904
1905 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL);
1906 if (!ctx ||
1907 EVP_PKEY_derive_init(ctx) != 1 ||
1908 EVP_PKEY_derive_set_peer(ctx, pi) != 1 ||
1909 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
1910 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
1911 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) {
1912 wpa_printf(MSG_ERROR,
1913 "DPP: Failed to derive ECDH shared secret: %s",
1914 ERR_error_string(ERR_get_error(), NULL));
1915 goto fail;
1916 }
1917 auth->secret_len = secret_len;
1918 EVP_PKEY_CTX_free(ctx);
1919 ctx = NULL;
1920
1921 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
1922 auth->Mx, auth->secret_len);
1923
1924 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
1925 auth->curve->hash_len) < 0)
1926 goto fail;
1927
1928 addr[0] = attr_start;
1929 len[0] = attr_len;
1930 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
1931 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1932 wrapped_data, wrapped_data_len);
1933 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1934 unwrapped = os_malloc(unwrapped_len);
1935 if (!unwrapped)
1936 goto fail;
1937 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
1938 wrapped_data, wrapped_data_len,
1939 1, addr, len, unwrapped) < 0) {
1940 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
1941 goto fail;
1942 }
1943 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1944 unwrapped, unwrapped_len);
1945
1946 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1947 wpa_printf(MSG_DEBUG,
1948 "DPP: Invalid attribute in unwrapped data");
1949 goto fail;
1950 }
1951
1952 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
1953 &i_nonce_len);
1954 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
1955 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
1956 goto fail;
1957 }
1958 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
1959 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
1960
1961 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
1962 DPP_ATTR_I_CAPABILITIES,
1963 &i_capab_len);
1964 if (!i_capab || i_capab_len < 1) {
1965 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-capabilities");
1966 goto fail;
1967 }
1968 auth->i_capab = i_capab[0];
1969 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
1970
1971 bin_clear_free(unwrapped, unwrapped_len);
1972 unwrapped = NULL;
1973
1974 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
1975 case DPP_CAPAB_ENROLLEE:
1976 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
1977 wpa_printf(MSG_DEBUG,
1978 "DPP: Local policy does not allow Configurator role");
1979 goto not_compatible;
1980 }
1981 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
1982 auth->configurator = 1;
1983 break;
1984 case DPP_CAPAB_CONFIGURATOR:
1985 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
1986 wpa_printf(MSG_DEBUG,
1987 "DPP: Local policy does not allow Enrollee role");
1988 goto not_compatible;
1989 }
1990 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
1991 auth->configurator = 0;
1992 break;
1993 default:
1994 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
1995 goto not_compatible;
1996 }
1997
1998 auth->peer_protocol_key = pi;
1999 pi = NULL;
2000 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
2001 char hex[SHA256_MAC_LEN * 2 + 1];
2002
2003 wpa_printf(MSG_DEBUG,
2004 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2005 if (dpp_auth_build_resp_status(auth,
2006 DPP_STATUS_RESPONSE_PENDING) < 0)
2007 goto fail;
2008 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2009 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2010 &i_bootstrap_len);
2011 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
2012 auth->response_pending = 1;
2013 os_memcpy(auth->waiting_pubkey_hash,
2014 i_bootstrap, i_bootstrap_len);
2015 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
2016 i_bootstrap_len);
2017 } else {
2018 hex[0] = '\0';
2019 }
2020
2021 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
2022 "%s", hex);
2023 return auth;
2024 }
2025 if (dpp_auth_build_resp(auth) < 0)
2026 goto fail;
2027
2028 return auth;
2029
2030not_compatible:
2031 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2032 "i-capab=0x%02x", auth->i_capab);
2033 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
2034 auth->configurator = 1;
2035 else
2036 auth->configurator = 0;
2037 auth->peer_protocol_key = pi;
2038 pi = NULL;
2039 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
2040 goto fail;
2041
2042 auth->remove_on_tx_status = 1;
2043 return auth;
2044fail:
2045 bin_clear_free(unwrapped, unwrapped_len);
2046 EVP_PKEY_free(pi);
2047 EVP_PKEY_CTX_free(ctx);
2048 dpp_auth_deinit(auth);
2049 return NULL;
2050}
2051
2052
2053int dpp_notify_new_qr_code(struct dpp_authentication *auth,
2054 struct dpp_bootstrap_info *peer_bi)
2055{
2056 if (!auth || !auth->response_pending ||
2057 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
2058 SHA256_MAC_LEN) != 0)
2059 return 0;
2060
2061 wpa_printf(MSG_DEBUG,
2062 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2063 MACSTR, MAC2STR(auth->peer_mac_addr));
2064 auth->peer_bi = peer_bi;
2065
2066 if (dpp_auth_build_resp(auth) < 0)
2067 return -1;
2068
2069 return 1;
2070}
2071
2072
2073static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth)
2074{
2075 struct wpabuf *msg;
2076 u8 i_auth[4 + DPP_MAX_HASH_LEN];
2077 size_t i_auth_len;
2078 const u8 *addr[1];
2079 size_t len[1];
2080 u8 *wrapped_i_auth;
2081
2082 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
2083
2084 i_auth_len = 4 + auth->curve->hash_len;
2085 /* Build DPP Authentication Confirmation frame attributes */
2086 msg = wpabuf_alloc(4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
2087 4 + i_auth_len + AES_BLOCK_SIZE);
2088 if (!msg)
2089 goto fail;
2090
2091 /* DPP Status */
2092 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
2093 wpabuf_put_le16(msg, 1);
2094 wpabuf_put_u8(msg, DPP_STATUS_OK);
2095
2096 /* Responder Bootstrapping Key Hash */
2097 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
2098 wpabuf_put_le16(msg, SHA256_MAC_LEN);
2099 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
2100
2101 if (auth->own_bi) {
2102 /* Mutual authentication */
2103 /* Initiator Bootstrapping Key Hash */
2104 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
2105 wpabuf_put_le16(msg, SHA256_MAC_LEN);
2106 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN);
2107 }
2108
2109 addr[0] = wpabuf_head(msg);
2110 len[0] = wpabuf_len(msg);
2111 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2112 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
2113 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
2114 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2115 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
2116 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
2117 if (dpp_gen_i_auth(auth, i_auth + 4) < 0 ||
2118 aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2119 i_auth, i_auth_len,
2120 1, addr, len, wrapped_i_auth) < 0)
2121 goto fail;
2122 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
2123 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
2124
2125 wpa_hexdump_buf(MSG_DEBUG,
2126 "DPP: Authentication Confirmation frame attributes",
2127 msg);
2128 dpp_auth_success(auth);
2129
2130 return msg;
2131
2132fail:
2133 return NULL;
2134}
2135
2136
2137static void
2138dpp_auth_resp_rx_status(struct dpp_authentication *auth,
2139 const u8 *attr_start, size_t attr_len,
2140 const u8 *wrapped_data, u16 wrapped_data_len,
2141 enum dpp_status_error status)
2142{
2143 const u8 *addr[1];
2144 size_t len[1];
2145 u8 *unwrapped = NULL;
2146 size_t unwrapped_len = 0;
2147 const u8 *i_nonce, *r_capab;
2148 u16 i_nonce_len, r_capab_len;
2149
2150 if (status == DPP_STATUS_NOT_COMPATIBLE) {
2151 wpa_printf(MSG_DEBUG,
2152 "DPP: Responder reported incompatible roles");
2153 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
2154 wpa_printf(MSG_DEBUG,
2155 "DPP: Responder reported more time needed");
2156 } else {
2157 wpa_printf(MSG_DEBUG,
2158 "DPP: Responder reported failure (status %d)",
2159 status);
2160 return;
2161 }
2162
2163 addr[0] = attr_start;
2164 len[0] = attr_len;
2165 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2166 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2167 wrapped_data, wrapped_data_len);
2168 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2169 unwrapped = os_malloc(unwrapped_len);
2170 if (!unwrapped)
2171 goto fail;
2172 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
2173 wrapped_data, wrapped_data_len,
2174 1, addr, len, unwrapped) < 0) {
2175 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
2176 goto fail;
2177 }
2178 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2179 unwrapped, unwrapped_len);
2180
2181 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2182 wpa_printf(MSG_DEBUG,
2183 "DPP: Invalid attribute in unwrapped data");
2184 goto fail;
2185 }
2186
2187 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2188 &i_nonce_len);
2189 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
2190 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
2191 goto fail;
2192 }
2193 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2194 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
2195 wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
2196 goto fail;
2197 }
2198
2199 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
2200 DPP_ATTR_R_CAPABILITIES,
2201 &r_capab_len);
2202 if (!r_capab || r_capab_len < 1) {
2203 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
2204 goto fail;
2205 }
2206 auth->r_capab = r_capab[0];
2207 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
2208 if (status == DPP_STATUS_NOT_COMPATIBLE) {
2209 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2210 "r-capab=0x%02x", auth->r_capab);
2211 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
2212 wpa_printf(MSG_DEBUG,
2213 "DPP: Continue waiting for full DPP Authentication Response");
2214 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING);
2215 }
2216fail:
2217 bin_clear_free(unwrapped, unwrapped_len);
2218}
2219
2220
2221struct wpabuf *
2222dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *attr_start,
2223 size_t attr_len)
2224{
2225 EVP_PKEY *pr;
2226 EVP_PKEY_CTX *ctx = NULL;
2227 size_t secret_len;
2228 const u8 *addr[1];
2229 size_t len[1];
2230 u8 *unwrapped = NULL, *unwrapped2 = NULL;
2231 size_t unwrapped_len = 0, unwrapped2_len = 0;
2232 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
2233 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
2234 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
2235 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
2236 wrapped2_len, r_auth_len;
2237 u8 r_auth2[DPP_MAX_HASH_LEN];
2238
2239 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2240 &wrapped_data_len);
2241 if (!wrapped_data) {
2242 wpa_printf(MSG_DEBUG,
2243 "DPP: Missing required Wrapped data attribute");
2244 return NULL;
2245 }
2246 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
2247 wrapped_data, wrapped_data_len);
2248
2249 if (wrapped_data_len < AES_BLOCK_SIZE)
2250 return NULL;
2251
2252 attr_len = wrapped_data - 4 - attr_start;
2253
2254 r_bootstrap = dpp_get_attr(attr_start, attr_len,
2255 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
2256 &r_bootstrap_len);
2257 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
2258 wpa_printf(MSG_DEBUG,
2259 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
2260 return NULL;
2261 }
2262 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
2263 r_bootstrap, r_bootstrap_len);
2264 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
2265 SHA256_MAC_LEN) != 0) {
2266 wpa_hexdump(MSG_DEBUG,
2267 "DPP: Expected Responder Bootstrapping Key Hash",
2268 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
2269 return NULL;
2270 }
2271
2272 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2273 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2274 &i_bootstrap_len);
2275 if (i_bootstrap) {
2276 if (i_bootstrap_len != SHA256_MAC_LEN) {
2277 wpa_printf(MSG_DEBUG,
2278 "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
2279 return NULL;
2280 }
2281 wpa_hexdump(MSG_MSGDUMP,
2282 "DPP: Initiator Bootstrapping Key Hash",
2283 i_bootstrap, i_bootstrap_len);
2284 if (!auth->own_bi ||
2285 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
2286 SHA256_MAC_LEN) != 0) {
2287 wpa_printf(MSG_DEBUG,
2288 "DPP: Initiator Bootstrapping Key Hash attribute did not match");
2289 return NULL;
2290 }
2291 }
2292
2293 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
2294 &status_len);
2295 if (!status || status_len < 1) {
2296 wpa_printf(MSG_DEBUG,
2297 "DPP: Missing or invalid required DPP Status attribute");
2298 return NULL;
2299 }
2300 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
2301 auth->auth_resp_status = status[0];
2302 if (status[0] != DPP_STATUS_OK) {
2303 dpp_auth_resp_rx_status(auth, attr_start,
2304 attr_len, wrapped_data,
2305 wrapped_data_len, status[0]);
2306 return NULL;
2307 }
2308
2309 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
2310 &r_proto_len);
2311 if (!r_proto) {
2312 wpa_printf(MSG_DEBUG,
2313 "DPP: Missing required Responder Protocol Key attribute");
2314 return NULL;
2315 }
2316 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
2317 r_proto, r_proto_len);
2318
2319 /* N = pI * PR */
2320 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
2321 if (!pr) {
2322 wpa_printf(MSG_DEBUG, "DPP: Invalid Responder Protocol Key");
2323 return NULL;
2324 }
2325 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
2326
2327 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL);
2328 if (!ctx ||
2329 EVP_PKEY_derive_init(ctx) != 1 ||
2330 EVP_PKEY_derive_set_peer(ctx, pr) != 1 ||
2331 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 ||
2332 secret_len > DPP_MAX_SHARED_SECRET_LEN ||
2333 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) {
2334 wpa_printf(MSG_ERROR,
2335 "DPP: Failed to derive ECDH shared secret: %s",
2336 ERR_error_string(ERR_get_error(), NULL));
2337 goto fail;
2338 }
2339 EVP_PKEY_CTX_free(ctx);
2340 ctx = NULL;
2341 auth->peer_protocol_key = pr;
2342 pr = NULL;
2343
2344 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2345 auth->Nx, auth->secret_len);
2346
2347 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2348 auth->curve->hash_len) < 0)
2349 goto fail;
2350
2351 addr[0] = attr_start;
2352 len[0] = attr_len;
2353 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2354 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2355 wrapped_data, wrapped_data_len);
2356 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2357 unwrapped = os_malloc(unwrapped_len);
2358 if (!unwrapped)
2359 goto fail;
2360 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
2361 wrapped_data, wrapped_data_len,
2362 1, addr, len, unwrapped) < 0) {
2363 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
2364 goto fail;
2365 }
2366 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2367 unwrapped, unwrapped_len);
2368
2369 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2370 wpa_printf(MSG_DEBUG,
2371 "DPP: Invalid attribute in unwrapped data");
2372 goto fail;
2373 }
2374
2375 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
2376 &r_nonce_len);
2377 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
2378 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-nonce");
2379 goto fail;
2380 }
2381 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
2382 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
2383
2384 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2385 &i_nonce_len);
2386 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
2387 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce");
2388 goto fail;
2389 }
2390 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2391 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
2392 wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch");
2393 goto fail;
2394 }
2395
2396 if (auth->own_bi && auth->peer_bi) {
2397 /* Mutual authentication */
2398 if (dpp_auth_derive_l_initiator(auth) < 0)
2399 goto fail;
2400 }
2401
2402 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2403 goto fail;
2404
2405 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
2406 DPP_ATTR_R_CAPABILITIES,
2407 &r_capab_len);
2408 if (!r_capab || r_capab_len < 1) {
2409 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities");
2410 goto fail;
2411 }
2412 auth->r_capab = r_capab[0];
2413 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
2414 if ((auth->configurator && (auth->r_capab & DPP_CAPAB_CONFIGURATOR)) ||
2415 (!auth->configurator && (auth->r_capab & DPP_CAPAB_ENROLLEE))) {
2416 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
2417 goto fail;
2418 }
2419
2420 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
2421 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
2422 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
2423 wpa_printf(MSG_DEBUG,
2424 "DPP: Missing or invalid Secondary Wrapped Data");
2425 goto fail;
2426 }
2427
2428 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2429 wrapped2, wrapped2_len);
2430 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
2431 unwrapped2 = os_malloc(unwrapped2_len);
2432 if (!unwrapped2)
2433 goto fail;
2434 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2435 wrapped2, wrapped2_len,
2436 0, NULL, NULL, unwrapped2) < 0) {
2437 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
2438 goto fail;
2439 }
2440 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2441 unwrapped2, unwrapped2_len);
2442
2443 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
2444 wpa_printf(MSG_DEBUG,
2445 "DPP: Invalid attribute in secondary unwrapped data");
2446 goto fail;
2447 }
2448
2449 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
2450 &r_auth_len);
2451 if (!r_auth || r_auth_len != auth->curve->hash_len) {
2452 wpa_printf(MSG_DEBUG,
2453 "DPP: Missing or invalid Responder Authenticating Tag");
2454 goto fail;
2455 }
2456 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
2457 r_auth, r_auth_len);
2458 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2459 if (dpp_gen_r_auth(auth, r_auth2) < 0)
2460 goto fail;
2461 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
2462 r_auth2, r_auth_len);
2463 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
2464 wpa_printf(MSG_DEBUG,
2465 "DPP: Mismatching Responder Authenticating Tag");
2466 goto fail;
2467 }
2468
2469 bin_clear_free(unwrapped, unwrapped_len);
2470 bin_clear_free(unwrapped2, unwrapped2_len);
2471
2472 return dpp_auth_build_conf(auth);
2473
2474fail:
2475 bin_clear_free(unwrapped, unwrapped_len);
2476 bin_clear_free(unwrapped2, unwrapped2_len);
2477 EVP_PKEY_free(pr);
2478 EVP_PKEY_CTX_free(ctx);
2479 return NULL;
2480}
2481
2482
2483int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *attr_start,
2484 size_t attr_len)
2485{
2486 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
2487 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
2488 i_auth_len;
2489 const u8 *addr[1];
2490 size_t len[1];
2491 u8 *unwrapped = NULL;
2492 size_t unwrapped_len = 0;
2493 u8 i_auth2[DPP_MAX_HASH_LEN];
2494
2495 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2496 &wrapped_data_len);
2497 if (!wrapped_data) {
2498 wpa_printf(MSG_DEBUG,
2499 "DPP: Missing required Wrapped data attribute");
2500 return -1;
2501 }
2502 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
2503 wrapped_data, wrapped_data_len);
2504
2505 if (wrapped_data_len < AES_BLOCK_SIZE)
2506 return -1;
2507
2508 attr_len = wrapped_data - 4 - attr_start;
2509
2510 r_bootstrap = dpp_get_attr(attr_start, attr_len,
2511 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
2512 &r_bootstrap_len);
2513 if (!r_bootstrap || r_bootstrap > wrapped_data ||
2514 r_bootstrap_len != SHA256_MAC_LEN) {
2515 wpa_printf(MSG_DEBUG,
2516 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute");
2517 return -1;
2518 }
2519 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
2520 r_bootstrap, r_bootstrap_len);
2521 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
2522 SHA256_MAC_LEN) != 0) {
2523 wpa_hexdump(MSG_DEBUG,
2524 "DPP: Expected Responder Bootstrapping Key Hash",
2525 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
2526 return -1;
2527 }
2528
2529 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2530 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2531 &i_bootstrap_len);
2532 if (i_bootstrap) {
2533 if (i_bootstrap > wrapped_data ||
2534 i_bootstrap_len != SHA256_MAC_LEN) {
2535 wpa_printf(MSG_DEBUG,
2536 "DPP: Invalid Initiator Bootstrapping Key Hash attribute");
2537 return -1;
2538 }
2539 wpa_hexdump(MSG_MSGDUMP,
2540 "DPP: Initiator Bootstrapping Key Hash",
2541 i_bootstrap, i_bootstrap_len);
2542 if (!auth->peer_bi ||
2543 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
2544 SHA256_MAC_LEN) != 0) {
2545 wpa_printf(MSG_DEBUG,
2546 "DPP: Initiator Bootstrapping Key Hash attribute did not match");
2547 return -1;
2548 }
2549 }
2550
2551 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
2552 &status_len);
2553 if (!status || status_len < 1) {
2554 wpa_printf(MSG_DEBUG,
2555 "DPP: Missing or invalid required DPP Status attribute");
2556 return -1;
2557 }
2558 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
2559 if (status[0] != DPP_STATUS_OK) {
2560 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
2561 return -1;
2562 }
2563
2564 addr[0] = attr_start;
2565 len[0] = attr_len;
2566 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2567 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2568 wrapped_data, wrapped_data_len);
2569 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2570 unwrapped = os_malloc(unwrapped_len);
2571 if (!unwrapped)
2572 return -1;
2573 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2574 wrapped_data, wrapped_data_len,
2575 1, addr, len, unwrapped) < 0) {
2576 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
2577 goto fail;
2578 }
2579 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2580 unwrapped, unwrapped_len);
2581
2582 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2583 wpa_printf(MSG_DEBUG,
2584 "DPP: Invalid attribute in unwrapped data");
2585 goto fail;
2586 }
2587
2588 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
2589 &i_auth_len);
2590 if (!i_auth || i_auth_len != auth->curve->hash_len) {
2591 wpa_printf(MSG_DEBUG,
2592 "DPP: Missing or invalid Initiator Authenticating Tag");
2593 goto fail;
2594 }
2595 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
2596 i_auth, i_auth_len);
2597 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2598 if (dpp_gen_i_auth(auth, i_auth2) < 0)
2599 goto fail;
2600 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
2601 i_auth2, i_auth_len);
2602 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
2603 wpa_printf(MSG_DEBUG,
2604 "DPP: Mismatching Initiator Authenticating Tag");
2605 goto fail;
2606 }
2607
2608 bin_clear_free(unwrapped, unwrapped_len);
2609 dpp_auth_success(auth);
2610 return 0;
2611fail:
2612 bin_clear_free(unwrapped, unwrapped_len);
2613 return -1;
2614}
2615
2616
461d39af
JM
2617void dpp_configuration_free(struct dpp_configuration *conf)
2618{
2619 if (!conf)
2620 return;
2621 str_clear_free(conf->passphrase);
2622 bin_clear_free(conf, sizeof(*conf));
2623}
2624
2625
30d27b04
JM
2626void dpp_auth_deinit(struct dpp_authentication *auth)
2627{
2628 if (!auth)
2629 return;
461d39af
JM
2630 dpp_configuration_free(auth->conf_ap);
2631 dpp_configuration_free(auth->conf_sta);
30d27b04
JM
2632 EVP_PKEY_free(auth->own_protocol_key);
2633 EVP_PKEY_free(auth->peer_protocol_key);
2634 wpabuf_free(auth->req_attr);
2635 wpabuf_free(auth->resp_attr);
461d39af
JM
2636 wpabuf_free(auth->conf_req);
2637 os_free(auth->connector);
2638 wpabuf_free(auth->net_access_key);
2639 wpabuf_free(auth->c_sign_key);
2640#ifdef CONFIG_TESTING_OPTIONS
2641 os_free(auth->config_obj_override);
2642 os_free(auth->discovery_override);
2643 os_free(auth->groups_override);
2644 os_free(auth->devices_override);
2645#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
2646 bin_clear_free(auth, sizeof(*auth));
2647}
461d39af
JM
2648
2649
2650static struct wpabuf *
2651dpp_build_conf_start(struct dpp_authentication *auth,
2652 struct dpp_configuration *conf, size_t tailroom)
2653{
2654 struct wpabuf *buf;
2655 char ssid[6 * sizeof(conf->ssid) + 1];
2656
2657#ifdef CONFIG_TESTING_OPTIONS
2658 if (auth->discovery_override)
2659 tailroom += os_strlen(auth->discovery_override);
2660#endif /* CONFIG_TESTING_OPTIONS */
2661
2662 buf = wpabuf_alloc(200 + tailroom);
2663 if (!buf)
2664 return NULL;
2665 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
2666#ifdef CONFIG_TESTING_OPTIONS
2667 if (auth->discovery_override) {
2668 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
2669 auth->discovery_override);
2670 wpabuf_put_str(buf, auth->discovery_override);
2671 wpabuf_put_u8(buf, ',');
2672 return buf;
2673 }
2674#endif /* CONFIG_TESTING_OPTIONS */
2675 wpabuf_put_str(buf, "{\"ssid\":\"");
2676 json_escape_string(ssid, sizeof(ssid),
2677 (const char *) conf->ssid, conf->ssid_len);
2678 wpabuf_put_str(buf, ssid);
2679 wpabuf_put_str(buf, "\"");
2680 /* TODO: optional channel information */
2681 wpabuf_put_str(buf, "},");
2682
2683 return buf;
2684}
2685
2686
2687static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
2688{
2689 int num_bytes, offset;
2690
2691 num_bytes = BN_num_bytes(bn);
2692 if ((size_t) num_bytes > len)
2693 return -1;
2694 offset = len - num_bytes;
2695 os_memset(pos, 0, offset);
2696 BN_bn2bin(bn, pos + offset);
2697 return 0;
2698}
2699
2700
2701static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
2702 const char *kid, const struct dpp_curve_params *curve)
2703{
2704 struct wpabuf *pub;
2705 const u8 *pos;
2706 char *x = NULL, *y = NULL;
2707 int ret = -1;
2708
2709 pub = dpp_get_pubkey_point(key, 0);
2710 if (!pub)
2711 goto fail;
2712 pos = wpabuf_head(pub);
2713 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
2714 pos += curve->prime_len;
2715 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0);
2716
2717 wpabuf_put_str(buf, "\"");
2718 wpabuf_put_str(buf, name);
2719 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\"");
2720 wpabuf_put_str(buf, curve->jwk_crv);
2721 wpabuf_put_str(buf, "\",\"x\":\"");
2722 wpabuf_put_str(buf, x);
2723 wpabuf_put_str(buf, "\",\"y\":\"");
2724 wpabuf_put_str(buf, y);
2725 if (kid) {
2726 wpabuf_put_str(buf, "\",\"kid\":\"");
2727 wpabuf_put_str(buf, kid);
2728 }
2729 wpabuf_put_str(buf, "\"}");
2730 ret = 0;
2731out:
2732 wpabuf_free(pub);
2733 os_free(x);
2734 os_free(y);
2735 return ret;
2736fail:
2737 goto out;
2738}
2739
2740
2741static struct wpabuf *
2742dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
2743 struct dpp_configuration *conf)
2744{
2745 struct wpabuf *buf = NULL;
2746 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
2747 size_t tailroom;
2748 const struct dpp_curve_params *curve;
2749 char jws_prot_hdr[100];
2750 size_t signed1_len, signed2_len, signed3_len;
2751 struct wpabuf *dppcon = NULL;
2752 unsigned char *signature = NULL;
2753 const unsigned char *p;
2754 size_t signature_len;
2755 EVP_MD_CTX *md_ctx = NULL;
2756 ECDSA_SIG *sig = NULL;
2757 char *dot = ".";
2758 const char *alg;
2759 const EVP_MD *sign_md;
2760 const BIGNUM *r, *s;
2761 size_t extra_len = 1000;
2762
2763 if (!auth->conf) {
2764 wpa_printf(MSG_INFO,
2765 "DPP: No configurator specified - cannot generate DPP config object");
2766 goto fail;
2767 }
2768 curve = auth->conf->curve;
2769 if (curve->hash_len == SHA256_MAC_LEN) {
2770 alg = "ES256";
2771 sign_md = EVP_sha256();
2772 } else if (curve->hash_len == SHA384_MAC_LEN) {
2773 alg = "ES384";
2774 sign_md = EVP_sha384();
2775 } else if (curve->hash_len == SHA512_MAC_LEN) {
2776 alg = "ES512";
2777 sign_md = EVP_sha512();
2778 } else {
2779 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
2780 goto fail;
2781 }
2782
2783#ifdef CONFIG_TESTING_OPTIONS
2784 if (auth->groups_override)
2785 extra_len += os_strlen(auth->groups_override);
2786 if (auth->devices_override)
2787 extra_len += os_strlen(auth->devices_override);
2788#endif /* CONFIG_TESTING_OPTIONS */
2789
2790 /* Connector (JSON dppCon object) */
2791 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
2792 if (!dppcon)
2793 goto fail;
2794#ifdef CONFIG_TESTING_OPTIONS
2795 if (auth->groups_override || auth->devices_override) {
2796 wpabuf_put_u8(dppcon, '{');
2797 if (auth->groups_override) {
2798 wpa_printf(MSG_DEBUG,
2799 "DPP: TESTING - groups override: '%s'",
2800 auth->groups_override);
2801 wpabuf_put_str(dppcon, "\"groups\":");
2802 wpabuf_put_str(dppcon, auth->groups_override);
2803 wpabuf_put_u8(dppcon, ',');
2804 }
2805 if (auth->devices_override) {
2806 wpa_printf(MSG_DEBUG,
2807 "DPP: TESTING - devices override: '%s'",
2808 auth->devices_override);
2809 wpabuf_put_str(dppcon, "\"devices\":");
2810 wpabuf_put_str(dppcon, auth->devices_override);
2811 wpabuf_put_u8(dppcon, ',');
2812 }
2813 goto skip_groups;
2814 }
2815#endif /* CONFIG_TESTING_OPTIONS */
2816 wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\",");
2817 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
2818#ifdef CONFIG_TESTING_OPTIONS
2819skip_groups:
2820#endif /* CONFIG_TESTING_OPTIONS */
2821 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
2822 auth->curve) < 0) {
2823 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
2824 goto fail;
2825 }
2826 if (conf->netaccesskey_expiry) {
2827 struct os_tm tm;
2828
2829 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
2830 wpa_printf(MSG_DEBUG,
2831 "DPP: Failed to generate expiry string");
2832 goto fail;
2833 }
2834 wpabuf_printf(dppcon,
2835 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
2836 tm.year, tm.month, tm.day,
2837 tm.hour, tm.min, tm.sec);
2838 }
2839 wpabuf_put_u8(dppcon, '}');
2840 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
2841 (const char *) wpabuf_head(dppcon));
2842
2843 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr),
2844 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
2845 auth->conf->kid, alg);
2846 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr,
2847 os_strlen(jws_prot_hdr),
2848 &signed1_len, 0);
2849 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon),
2850 wpabuf_len(dppcon),
2851 &signed2_len, 0);
2852 if (!signed1 || !signed2)
2853 goto fail;
2854
2855 md_ctx = EVP_MD_CTX_create();
2856 if (!md_ctx)
2857 goto fail;
2858
2859 ERR_clear_error();
2860 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
2861 auth->conf->csign) != 1) {
2862 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
2863 ERR_error_string(ERR_get_error(), NULL));
2864 goto fail;
2865 }
2866 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
2867 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
2868 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
2869 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
2870 ERR_error_string(ERR_get_error(), NULL));
2871 goto fail;
2872 }
2873 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
2874 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
2875 ERR_error_string(ERR_get_error(), NULL));
2876 goto fail;
2877 }
2878 signature = os_malloc(signature_len);
2879 if (!signature)
2880 goto fail;
2881 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
2882 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
2883 ERR_error_string(ERR_get_error(), NULL));
2884 goto fail;
2885 }
2886 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
2887 signature, signature_len);
2888 /* Convert to raw coordinates r,s */
2889 p = signature;
2890 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
2891 if (!sig)
2892 goto fail;
2893 ECDSA_SIG_get0(sig, &r, &s);
2894 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
2895 dpp_bn2bin_pad(s, signature + curve->prime_len,
2896 curve->prime_len) < 0)
2897 goto fail;
2898 signature_len = 2 * curve->prime_len;
2899 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
2900 signature, signature_len);
2901 signed3 = (char *) base64_url_encode(signature, signature_len,
2902 &signed3_len, 0);
2903 if (!signed3)
2904 goto fail;
2905
2906 tailroom = 1000;
2907 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
2908 tailroom += signed1_len + signed2_len + signed3_len;
2909 buf = dpp_build_conf_start(auth, conf, tailroom);
2910 if (!buf)
2911 return NULL;
2912
2913 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\"");
2914 wpabuf_put_str(buf, signed1);
2915 wpabuf_put_u8(buf, '.');
2916 wpabuf_put_str(buf, signed2);
2917 wpabuf_put_u8(buf, '.');
2918 wpabuf_put_str(buf, signed3);
2919 wpabuf_put_str(buf, "\",");
2920 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
2921 curve) < 0) {
2922 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
2923 goto fail;
2924 }
2925 if (auth->conf->csign_expiry) {
2926 struct os_tm tm;
2927
2928 if (os_gmtime(auth->conf->csign_expiry, &tm) < 0) {
2929 wpa_printf(MSG_DEBUG,
2930 "DPP: Failed to generate expiry string");
2931 goto fail;
2932 }
2933 wpabuf_printf(buf,
2934 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
2935 tm.year, tm.month, tm.day,
2936 tm.hour, tm.min, tm.sec);
2937 }
2938
2939 wpabuf_put_str(buf, "}}");
2940
2941 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
2942 wpabuf_head(buf), wpabuf_len(buf));
2943
2944out:
2945 EVP_MD_CTX_destroy(md_ctx);
2946 ECDSA_SIG_free(sig);
2947 os_free(signed1);
2948 os_free(signed2);
2949 os_free(signed3);
2950 os_free(signature);
2951 wpabuf_free(dppcon);
2952 return buf;
2953fail:
2954 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
2955 wpabuf_free(buf);
2956 buf = NULL;
2957 goto out;
2958}
2959
2960
2961static struct wpabuf *
2962dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
2963 struct dpp_configuration *conf)
2964{
2965 struct wpabuf *buf;
2966
2967 buf = dpp_build_conf_start(auth, conf, 1000);
2968 if (!buf)
2969 return NULL;
2970
2971 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\",");
2972 if (conf->passphrase) {
2973 char pass[63 * 6 + 1];
2974
2975 if (os_strlen(conf->passphrase) > 63) {
2976 wpabuf_free(buf);
2977 return NULL;
2978 }
2979
2980 json_escape_string(pass, sizeof(pass), conf->passphrase,
2981 os_strlen(conf->passphrase));
2982 wpabuf_put_str(buf, "\"pass\":\"");
2983 wpabuf_put_str(buf, pass);
2984 wpabuf_put_str(buf, "\"");
2985 } else {
2986 char psk[2 * sizeof(conf->psk) + 1];
2987
2988 wpa_snprintf_hex(psk, sizeof(psk),
2989 conf->psk, sizeof(conf->psk));
2990 wpabuf_put_str(buf, "\"psk_hex\":\"");
2991 wpabuf_put_str(buf, psk);
2992 wpabuf_put_str(buf, "\"");
2993 }
2994 wpabuf_put_str(buf, "}}");
2995
2996 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
2997 wpabuf_head(buf), wpabuf_len(buf));
2998
2999 return buf;
3000}
3001
3002
3003static struct wpabuf *
3004dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
3005{
3006 struct dpp_configuration *conf;
3007
3008#ifdef CONFIG_TESTING_OPTIONS
3009 if (auth->config_obj_override) {
3010 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
3011 return wpabuf_alloc_copy(auth->config_obj_override,
3012 os_strlen(auth->config_obj_override));
3013 }
3014#endif /* CONFIG_TESTING_OPTIONS */
3015
3016 conf = ap ? auth->conf_ap : auth->conf_sta;
3017 if (!conf) {
3018 wpa_printf(MSG_DEBUG,
3019 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
3020 ap ? "ap" : "sta");
3021 return NULL;
3022 }
3023
3024 if (conf->dpp)
3025 return dpp_build_conf_obj_dpp(auth, ap, conf);
3026 return dpp_build_conf_obj_legacy(auth, ap, conf);
3027}
3028
3029
3030static struct wpabuf *
3031dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
3032 u16 e_nonce_len, int ap)
3033{
3034 struct wpabuf *conf;
3035 size_t clear_len;
3036 struct wpabuf *clear = NULL, *msg = NULL;
3037 u8 *wrapped;
3038 const u8 *addr[1];
3039 size_t len[1];
3040 enum dpp_status_error status;
3041
3042 conf = dpp_build_conf_obj(auth, ap);
3043 if (conf) {
3044 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3045 wpabuf_head(conf), wpabuf_len(conf));
3046 }
3047 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
3048
3049 /* { E-nonce, configurationObject}ke */
3050 clear_len = 4 + e_nonce_len;
3051 if (conf)
3052 clear_len += 4 + wpabuf_len(conf);
3053 clear = wpabuf_alloc(clear_len);
3054 msg = wpabuf_alloc(4 + 1 + 4 + clear_len + AES_BLOCK_SIZE);
3055 if (!clear || !msg)
3056 goto fail;
3057
3058 /* E-nonce */
3059 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3060 wpabuf_put_le16(clear, e_nonce_len);
3061 wpabuf_put_data(clear, e_nonce, e_nonce_len);
3062
3063 if (conf) {
3064 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
3065 wpabuf_put_le16(clear, wpabuf_len(conf));
3066 wpabuf_put_buf(clear, conf);
3067 wpabuf_free(conf);
3068 conf = NULL;
3069 }
3070
3071 /* DPP Status */
3072 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
3073 wpabuf_put_le16(msg, 1);
3074 wpabuf_put_u8(msg, status);
3075
3076 addr[0] = wpabuf_head(msg);
3077 len[0] = wpabuf_len(msg);
3078 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3079
3080 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3081 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3082 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3083
3084 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3085 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3086 wpabuf_head(clear), wpabuf_len(clear),
3087 1, addr, len, wrapped) < 0)
3088 goto fail;
3089 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3090 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
3091 wpabuf_free(clear);
3092 clear = NULL;
3093
3094 wpa_hexdump_buf(MSG_DEBUG,
3095 "DPP: Configuration Response attributes", msg);
3096 return msg;
3097fail:
3098 wpabuf_free(conf);
3099 wpabuf_free(clear);
3100 wpabuf_free(msg);
3101 return NULL;
3102}
3103
3104
3105struct wpabuf *
3106dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
3107 size_t attr_len)
3108{
3109 const u8 *wrapped_data, *e_nonce, *config_attr;
3110 u16 wrapped_data_len, e_nonce_len, config_attr_len;
3111 u8 *unwrapped = NULL;
3112 size_t unwrapped_len = 0;
3113 struct wpabuf *resp = NULL;
3114 struct json_token *root = NULL, *token;
3115 int ap;
3116
3117 if (dpp_check_attrs(attr_start, attr_len) < 0) {
3118 wpa_printf(MSG_DEBUG,
3119 "DPP: Invalid attribute in config request");
3120 return NULL;
3121 }
3122
3123 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3124 &wrapped_data_len);
3125 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3126 wpa_printf(MSG_DEBUG,
3127 "DPP: Missing or invalid required Wrapped data attribute");
3128 return NULL;
3129 }
3130
3131 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3132 wrapped_data, wrapped_data_len);
3133 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3134 unwrapped = os_malloc(unwrapped_len);
3135 if (!unwrapped)
3136 return NULL;
3137 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3138 wrapped_data, wrapped_data_len,
3139 0, NULL, NULL, unwrapped) < 0) {
3140 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
3141 goto fail;
3142 }
3143 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3144 unwrapped, unwrapped_len);
3145
3146 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3147 wpa_printf(MSG_DEBUG,
3148 "DPP: Invalid attribute in unwrapped data");
3149 goto fail;
3150 }
3151
3152 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3153 DPP_ATTR_ENROLLEE_NONCE,
3154 &e_nonce_len);
3155 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3156 wpa_printf(MSG_DEBUG,
3157 "DPP: Missing or invalid Enrollee Nonce attribute");
3158 goto fail;
3159 }
3160 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3161
3162 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
3163 DPP_ATTR_CONFIG_ATTR_OBJ,
3164 &config_attr_len);
3165 if (!config_attr) {
3166 wpa_printf(MSG_DEBUG,
3167 "DPP: Missing or invalid Config Attributes attribute");
3168 goto fail;
3169 }
3170 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
3171 config_attr, config_attr_len);
3172
3173 root = json_parse((const char *) config_attr, config_attr_len);
3174 if (!root) {
3175 wpa_printf(MSG_DEBUG, "DPP: Could not parse Config Attributes");
3176 goto fail;
3177 }
3178
3179 token = json_get_member(root, "name");
3180 if (!token || token->type != JSON_STRING) {
3181 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - name");
3182 goto fail;
3183 }
3184 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
3185
3186 token = json_get_member(root, "wi-fi_tech");
3187 if (!token || token->type != JSON_STRING) {
3188 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - wi-fi_tech");
3189 goto fail;
3190 }
3191 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
3192 if (os_strcmp(token->string, "infra") != 0) {
3193 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
3194 token->string);
3195 goto fail;
3196 }
3197
3198 token = json_get_member(root, "netRole");
3199 if (!token || token->type != JSON_STRING) {
3200 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - netRole");
3201 goto fail;
3202 }
3203 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
3204 if (os_strcmp(token->string, "sta") == 0) {
3205 ap = 0;
3206 } else if (os_strcmp(token->string, "ap") == 0) {
3207 ap = 1;
3208 } else {
3209 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
3210 token->string);
3211 goto fail;
3212 }
3213
3214 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap);
3215
3216fail:
3217 json_free(root);
3218 os_free(unwrapped);
3219 return resp;
3220}
3221
3222
3223static struct wpabuf *
3224dpp_parse_jws_prot_hdr(const u8 *prot_hdr, u16 prot_hdr_len,
3225 const EVP_MD **ret_md)
3226{
3227 struct json_token *root, *token;
3228 struct wpabuf *kid = NULL;
3229
3230 root = json_parse((const char *) prot_hdr, prot_hdr_len);
3231 if (!root) {
3232 wpa_printf(MSG_DEBUG,
3233 "DPP: JSON parsing failed for JWS Protected Header");
3234 goto fail;
3235 }
3236
3237 if (root->type != JSON_OBJECT) {
3238 wpa_printf(MSG_DEBUG,
3239 "DPP: JWS Protected Header root is not an object");
3240 goto fail;
3241 }
3242
3243 token = json_get_member(root, "typ");
3244 if (!token || token->type != JSON_STRING) {
3245 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
3246 goto fail;
3247 }
3248 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
3249 token->string);
3250 if (os_strcmp(token->string, "dppCon") != 0) {
3251 wpa_printf(MSG_DEBUG,
3252 "DPP: Unsupported JWS Protected Header typ=%s",
3253 token->string);
3254 goto fail;
3255 }
3256
3257 token = json_get_member(root, "alg");
3258 if (!token || token->type != JSON_STRING) {
3259 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
3260 goto fail;
3261 }
3262 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
3263 token->string);
3264 if (os_strcmp(token->string, "ES256") == 0)
3265 *ret_md = EVP_sha256();
3266 else if (os_strcmp(token->string, "ES384") == 0)
3267 *ret_md = EVP_sha384();
3268 else if (os_strcmp(token->string, "ES512") == 0)
3269 *ret_md = EVP_sha512();
3270 else
3271 *ret_md = NULL;
3272 if (!*ret_md) {
3273 wpa_printf(MSG_DEBUG,
3274 "DPP: Unsupported JWS Protected Header alg=%s",
3275 token->string);
3276 goto fail;
3277 }
3278
3279 kid = json_get_member_base64url(root, "kid");
3280 if (!kid) {
3281 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
3282 goto fail;
3283 }
3284 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
3285 kid);
3286
3287fail:
3288 json_free(root);
3289 return kid;
3290}
3291
3292
3293static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
3294 struct json_token *cred)
3295{
3296 struct json_token *pass, *psk_hex;
3297 u8 psk[32];
3298
3299 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
3300
3301 pass = json_get_member(cred, "pass");
3302 psk_hex = json_get_member(cred, "psk_hex");
3303
3304 if (pass && pass->type == JSON_STRING) {
3305 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
3306 pass->string, os_strlen(pass->string));
3307 } else if (psk_hex && psk_hex->type == JSON_STRING) {
3308 if (os_strlen(psk_hex->string) != sizeof(psk) * 2 ||
3309 hexstr2bin(psk_hex->string, psk, sizeof(psk)) < 0) {
3310 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
3311 return -1;
3312 }
3313 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK", psk, sizeof(psk));
3314 os_memset(psk, 0, sizeof(psk));
3315 } else {
3316 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
3317 return -1;
3318 }
3319
3320 return 0;
3321}
3322
3323
3324static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
3325 const struct dpp_curve_params **key_curve)
3326{
3327 struct json_token *token;
3328 const struct dpp_curve_params *curve;
3329 struct wpabuf *x = NULL, *y = NULL;
3330 EC_GROUP *group;
3331 EVP_PKEY *pkey = NULL;
3332
3333 token = json_get_member(jwk, "kty");
3334 if (!token || token->type != JSON_STRING) {
3335 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
3336 goto fail;
3337 }
3338 if (os_strcmp(token->string, "EC") != 0) {
3339 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s",
3340 token->string);
3341 goto fail;
3342 }
3343
3344 token = json_get_member(jwk, "crv");
3345 if (!token || token->type != JSON_STRING) {
3346 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
3347 goto fail;
3348 }
3349 curve = dpp_get_curve_jwk_crv(token->string);
3350 if (!curve) {
3351 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
3352 token->string);
3353 goto fail;
3354 }
3355
3356 x = json_get_member_base64url(jwk, "x");
3357 if (!x) {
3358 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
3359 goto fail;
3360 }
3361 wpa_hexdump_buf(MSG_DEBUG, "DPP: C-sign x", x);
3362 if (wpabuf_len(x) != curve->prime_len) {
3363 wpa_printf(MSG_DEBUG,
3364 "DPP: Unexpected C-sign x length %u (expected %u for curve %s)",
3365 (unsigned int) wpabuf_len(x),
3366 (unsigned int) curve->prime_len, curve->name);
3367 goto fail;
3368 }
3369
3370 y = json_get_member_base64url(jwk, "y");
3371 if (!y) {
3372 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
3373 goto fail;
3374 }
3375 wpa_hexdump_buf(MSG_DEBUG, "DPP: C-sign y", y);
3376 if (wpabuf_len(y) != curve->prime_len) {
3377 wpa_printf(MSG_DEBUG,
3378 "DPP: Unexpected C-sign y length %u (expected %u for curve %s)",
3379 (unsigned int) wpabuf_len(y),
3380 (unsigned int) curve->prime_len, curve->name);
3381 goto fail;
3382 }
3383
3384 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
3385 if (!group) {
3386 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
3387 goto fail;
3388 }
3389
3390 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
3391 wpabuf_len(x));
3392 *key_curve = curve;
3393
3394fail:
3395 wpabuf_free(x);
3396 wpabuf_free(y);
3397
3398 return pkey;
3399}
3400
3401
3402int dpp_key_expired(const char *timestamp, os_time_t *expiry)
3403{
3404 struct os_time now;
3405 unsigned int year, month, day, hour, min, sec;
3406 os_time_t utime;
3407 const char *pos;
3408
3409 /* ISO 8601 date and time:
3410 * <date>T<time>
3411 * YYYY-MM-DDTHH:MM:SSZ
3412 * YYYY-MM-DDTHH:MM:SS+03:00
3413 */
3414 if (os_strlen(timestamp) < 19) {
3415 wpa_printf(MSG_DEBUG,
3416 "DPP: Too short timestamp - assume expired key");
3417 return 1;
3418 }
3419 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
3420 &year, &month, &day, &hour, &min, &sec) != 6) {
3421 wpa_printf(MSG_DEBUG,
3422 "DPP: Failed to parse expiration day - assume expired key");
3423 return 1;
3424 }
3425
3426 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
3427 wpa_printf(MSG_DEBUG,
3428 "DPP: Invalid date/time information - assume expired key");
3429 return 1;
3430 }
3431
3432 pos = timestamp + 19;
3433 if (*pos == 'Z' || *pos == '\0') {
3434 /* In UTC - no need to adjust */
3435 } else if (*pos == '-' || *pos == '+') {
3436 int items;
3437
3438 /* Adjust local time to UTC */
3439 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
3440 if (items < 1) {
3441 wpa_printf(MSG_DEBUG,
3442 "DPP: Invalid time zone designator (%s) - assume expired key",
3443 pos);
3444 return 1;
3445 }
3446 if (*pos == '-')
3447 utime += 3600 * hour;
3448 if (*pos == '+')
3449 utime -= 3600 * hour;
3450 if (items > 1) {
3451 if (*pos == '-')
3452 utime += 60 * min;
3453 if (*pos == '+')
3454 utime -= 60 * min;
3455 }
3456 } else {
3457 wpa_printf(MSG_DEBUG,
3458 "DPP: Invalid time zone designator (%s) - assume expired key",
3459 pos);
3460 return 1;
3461 }
3462 if (expiry)
3463 *expiry = utime;
3464
3465 if (os_get_time(&now) < 0) {
3466 wpa_printf(MSG_DEBUG,
3467 "DPP: Cannot get current time - assume expired key");
3468 return 1;
3469 }
3470
3471 if (now.sec > utime) {
3472 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
3473 utime, now.sec);
3474 return 1;
3475 }
3476
3477 return 0;
3478}
3479
3480
3481static int dpp_parse_connector(struct dpp_authentication *auth,
3482 const unsigned char *payload,
3483 u16 payload_len)
3484{
3485 struct json_token *root, *groups, *devices, *netkey, *token;
3486 int ret = -1;
3487 EVP_PKEY *key = NULL;
3488 const struct dpp_curve_params *curve;
3489 unsigned int rules = 0;
3490
3491 root = json_parse((const char *) payload, payload_len);
3492 if (!root) {
3493 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
3494 goto fail;
3495 }
3496
3497 groups = json_get_member(root, "groups");
3498 if (!groups || groups->type != JSON_ARRAY) {
3499 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
3500 goto skip_groups;
3501 }
3502 for (token = groups->child; token; token = token->sibling) {
3503 struct json_token *id, *role;
3504
3505 id = json_get_member(token, "groupId");
3506 if (!id || id->type != JSON_STRING) {
3507 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
3508 goto fail;
3509 }
3510
3511 role = json_get_member(token, "netRole");
3512 if (!role || role->type != JSON_STRING) {
3513 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
3514 goto fail;
3515 }
3516 wpa_printf(MSG_DEBUG,
3517 "DPP: connector group: groupId='%s' netRole='%s'",
3518 id->string, role->string);
3519 rules++;
3520 }
3521skip_groups:
3522
3523 devices = json_get_member(root, "devices");
3524 if (!devices || devices->type != JSON_ARRAY) {
3525 wpa_printf(MSG_DEBUG, "DPP: No devices array found");
3526 goto skip_devices;
3527 }
3528 for (token = devices->child; token; token = token->sibling) {
3529 struct wpabuf *id;
3530 struct json_token *role;
3531
3532 id = json_get_member_base64url(token, "deviceId");
3533 if (!id) {
3534 wpa_printf(MSG_DEBUG,
3535 "DPP: Missing or invalid deviceId string");
3536 goto fail;
3537 }
3538 wpa_hexdump_buf(MSG_DEBUG, "DPP: deviceId", id);
3539 if (wpabuf_len(id) != SHA256_MAC_LEN) {
3540 wpa_printf(MSG_DEBUG,
3541 "DPP: Unexpected deviceId length");
3542 wpabuf_free(id);
3543 goto fail;
3544 }
3545 wpabuf_free(id);
3546
3547 role = json_get_member(token, "netRole");
3548 if (!role || role->type != JSON_STRING) {
3549 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
3550 goto fail;
3551 }
3552 wpa_printf(MSG_DEBUG, "DPP: connector device netRole='%s'",
3553 role->string);
3554 rules++;
3555 }
3556
3557skip_devices:
3558 if (!rules) {
3559 wpa_printf(MSG_DEBUG,
3560 "DPP: Connector includes no groups or devices");
3561 goto fail;
3562 }
3563
3564 token = json_get_member(root, "expiry");
3565 if (!token || token->type != JSON_STRING) {
3566 wpa_printf(MSG_DEBUG,
3567 "DPP: No expiry string found - connector does not expire");
3568 } else {
3569 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
3570 if (dpp_key_expired(token->string,
3571 &auth->net_access_key_expiry)) {
3572 wpa_printf(MSG_DEBUG,
3573 "DPP: Connector (netAccessKey) has expired");
3574 goto fail;
3575 }
3576 }
3577
3578 netkey = json_get_member(root, "netAccessKey");
3579 if (!netkey || netkey->type != JSON_OBJECT) {
3580 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
3581 goto fail;
3582 }
3583
3584 key = dpp_parse_jwk(netkey, &curve);
3585 if (!key)
3586 goto fail;
3587 dpp_debug_print_key("DPP: Received netAccessKey", key);
3588
3589 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
3590 wpa_printf(MSG_DEBUG,
3591 "DPP: netAccessKey in connector does not match own protocol key");
3592#ifdef CONFIG_TESTING_OPTIONS
3593 if (auth->ignore_netaccesskey_mismatch) {
3594 wpa_printf(MSG_DEBUG,
3595 "DPP: TESTING - skip netAccessKey mismatch");
3596 } else {
3597 goto fail;
3598 }
3599#else /* CONFIG_TESTING_OPTIONS */
3600 goto fail;
3601#endif /* CONFIG_TESTING_OPTIONS */
3602 }
3603
3604 ret = 0;
3605fail:
3606 EVP_PKEY_free(key);
3607 json_free(root);
3608 return ret;
3609}
3610
3611
3612static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
3613{
3614 struct wpabuf *uncomp;
3615 int res;
3616 u8 hash[SHA256_MAC_LEN];
3617 const u8 *addr[1];
3618 size_t len[1];
3619
3620 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
3621 return -1;
3622 uncomp = dpp_get_pubkey_point(pub, 1);
3623 if (!uncomp)
3624 return -1;
3625 addr[0] = wpabuf_head(uncomp);
3626 len[0] = wpabuf_len(uncomp);
3627 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
3628 addr[0], len[0]);
3629 res = sha256_vector(1, addr, len, hash);
3630 wpabuf_free(uncomp);
3631 if (res < 0)
3632 return -1;
3633 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
3634 wpa_printf(MSG_DEBUG,
3635 "DPP: Received hash value does not match calculated public key hash value");
3636 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
3637 hash, SHA256_MAC_LEN);
3638 return -1;
3639 }
3640 return 0;
3641}
3642
3643
3644static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
3645{
3646 unsigned char *der = NULL;
3647 int der_len;
3648
3649 der_len = i2d_PUBKEY(csign, &der);
3650 if (der_len <= 0)
3651 return;
3652 wpabuf_free(auth->c_sign_key);
3653 auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
3654 OPENSSL_free(der);
3655}
3656
3657
3658static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
3659{
3660 unsigned char *der = NULL;
3661 int der_len;
3662 EC_KEY *eckey;
3663
3664 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
3665 if (!eckey)
3666 return;
3667
3668 der_len = i2d_ECPrivateKey(eckey, &der);
3669 if (der_len <= 0) {
3670 EC_KEY_free(eckey);
3671 return;
3672 }
3673 wpabuf_free(auth->net_access_key);
3674 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
3675 OPENSSL_free(der);
3676 EC_KEY_free(eckey);
3677}
3678
3679
3680struct dpp_signed_connector_info {
3681 unsigned char *payload;
3682 size_t payload_len;
3683};
3684
3685static int
3686dpp_process_signed_connector(struct dpp_signed_connector_info *info,
3687 EVP_PKEY *csign_pub, const char *connector)
3688{
3689 int ret = -1;
3690 const char *pos, *end, *signed_start, *signed_end;
3691 struct wpabuf *kid = NULL;
3692 unsigned char *prot_hdr = NULL, *signature = NULL;
3693 size_t prot_hdr_len = 0, signature_len = 0;
3694 const EVP_MD *sign_md = NULL;
3695 unsigned char *der = NULL;
3696 int der_len;
3697 int res;
3698 EVP_MD_CTX *md_ctx = NULL;
3699 ECDSA_SIG *sig = NULL;
3700 BIGNUM *r = NULL, *s = NULL;
3701
3702 os_memset(info, 0, sizeof(*info));
3703
3704 signed_start = pos = connector;
3705 end = os_strchr(pos, '.');
3706 if (!end) {
3707 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
3708 goto fail;
3709 }
3710 prot_hdr = base64_url_decode((const unsigned char *) pos,
3711 end - pos, &prot_hdr_len);
3712 if (!prot_hdr) {
3713 wpa_printf(MSG_DEBUG,
3714 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
3715 goto fail;
3716 }
3717 wpa_hexdump_ascii(MSG_DEBUG,
3718 "DPP: signedConnector - JWS Protected Header",
3719 prot_hdr, prot_hdr_len);
3720 kid = dpp_parse_jws_prot_hdr(prot_hdr, prot_hdr_len, &sign_md);
3721 if (!kid)
3722 goto fail;
3723 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
3724 wpa_printf(MSG_DEBUG,
3725 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
3726 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
3727 goto fail;
3728 }
3729
3730 pos = end + 1;
3731 end = os_strchr(pos, '.');
3732 if (!end) {
3733 wpa_printf(MSG_DEBUG,
3734 "DPP: Missing dot(2) in signedConnector");
3735 goto fail;
3736 }
3737 signed_end = end - 1;
3738 info->payload = base64_url_decode((const unsigned char *) pos,
3739 end - pos, &info->payload_len);
3740 if (!info->payload) {
3741 wpa_printf(MSG_DEBUG,
3742 "DPP: Failed to base64url decode signedConnector JWS Payload");
3743 goto fail;
3744 }
3745 wpa_hexdump_ascii(MSG_DEBUG,
3746 "DPP: signedConnector - JWS Payload",
3747 info->payload, info->payload_len);
3748 pos = end + 1;
3749 signature = base64_url_decode((const unsigned char *) pos,
3750 os_strlen(pos), &signature_len);
3751 if (!signature) {
3752 wpa_printf(MSG_DEBUG,
3753 "DPP: Failed to base64url decode signedConnector signature");
3754 goto fail;
3755 }
3756 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
3757 signature, signature_len);
3758
3759 if (dpp_check_pubkey_match(csign_pub, kid) < 0)
3760 goto fail;
3761
3762 if (signature_len & 0x01) {
3763 wpa_printf(MSG_DEBUG,
3764 "DPP: Unexpected signedConnector signature length (%d)",
3765 (int) signature_len);
3766 goto fail;
3767 }
3768
3769 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
3770 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
3771 r = BN_bin2bn(signature, signature_len / 2, NULL);
3772 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
3773 sig = ECDSA_SIG_new();
3774 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
3775 goto fail;
3776 r = NULL;
3777 s = NULL;
3778
3779 der_len = i2d_ECDSA_SIG(sig, &der);
3780 if (der_len <= 0) {
3781 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
3782 goto fail;
3783 }
3784 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
3785 md_ctx = EVP_MD_CTX_create();
3786 if (!md_ctx)
3787 goto fail;
3788
3789 ERR_clear_error();
3790 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
3791 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
3792 ERR_error_string(ERR_get_error(), NULL));
3793 goto fail;
3794 }
3795 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
3796 signed_end - signed_start + 1) != 1) {
3797 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
3798 ERR_error_string(ERR_get_error(), NULL));
3799 goto fail;
3800 }
3801 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
3802 if (res != 1) {
3803 wpa_printf(MSG_DEBUG,
3804 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
3805 res, ERR_error_string(ERR_get_error(), NULL));
3806 goto fail;
3807 }
3808
3809 ret = 0;
3810fail:
3811 EVP_MD_CTX_destroy(md_ctx);
3812 os_free(prot_hdr);
3813 wpabuf_free(kid);
3814 os_free(signature);
3815 ECDSA_SIG_free(sig);
3816 BN_free(r);
3817 BN_free(s);
3818 OPENSSL_free(der);
3819 return ret;
3820}
3821
3822
3823static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
3824 struct json_token *cred)
3825{
3826 struct dpp_signed_connector_info info;
3827 struct json_token *token, *csign;
3828 int ret = -1;
3829 EVP_PKEY *csign_pub = NULL;
3830 const struct dpp_curve_params *key_curve = NULL;
3831 const char *signed_connector;
3832
3833 os_memset(&info, 0, sizeof(info));
3834
3835 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
3836
3837 csign = json_get_member(cred, "csign");
3838 if (!csign || csign->type != JSON_OBJECT) {
3839 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
3840 goto fail;
3841 }
3842
3843 csign_pub = dpp_parse_jwk(csign, &key_curve);
3844 if (!csign_pub) {
3845 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
3846 goto fail;
3847 }
3848 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
3849
3850 token = json_get_member(cred, "expiry");
3851 if (!token || token->type != JSON_STRING) {
3852 wpa_printf(MSG_DEBUG,
3853 "DPP: No expiry string found - C-sign-key does not expire");
3854 } else {
3855 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
3856 if (dpp_key_expired(token->string, &auth->c_sign_key_expiry)) {
3857 wpa_printf(MSG_DEBUG, "DPP: C-sign-key has expired");
3858 goto fail;
3859 }
3860 }
3861
3862 token = json_get_member(cred, "signedConnector");
3863 if (!token || token->type != JSON_STRING) {
3864 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
3865 goto fail;
3866 }
3867 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
3868 token->string, os_strlen(token->string));
3869 signed_connector = token->string;
3870
3871 if (os_strchr(signed_connector, '"') ||
3872 os_strchr(signed_connector, '\n')) {
3873 wpa_printf(MSG_DEBUG,
3874 "DPP: Unexpected character in signedConnector");
3875 goto fail;
3876 }
3877
3878 if (dpp_process_signed_connector(&info, csign_pub,
3879 signed_connector) < 0)
3880 goto fail;
3881
3882 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
3883 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
3884 goto fail;
3885 }
3886
3887 os_free(auth->connector);
3888 auth->connector = os_strdup(signed_connector);
3889
3890 dpp_copy_csign(auth, csign_pub);
3891 dpp_copy_netaccesskey(auth);
3892
3893 ret = 0;
3894fail:
3895 EVP_PKEY_free(csign_pub);
3896 os_free(info.payload);
3897 return ret;
3898}
3899
3900
3901static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3902 const u8 *conf_obj, u16 conf_obj_len)
3903{
3904 int ret = -1;
3905 struct json_token *root, *token, *discovery, *cred;
3906
3907 root = json_parse((const char *) conf_obj, conf_obj_len);
3908 if (!root)
3909 return -1;
3910 if (root->type != JSON_OBJECT) {
3911 wpa_printf(MSG_DEBUG, "DPP: JSON root is not an object");
3912 goto fail;
3913 }
3914
3915 token = json_get_member(root, "wi-fi_tech");
3916 if (!token || token->type != JSON_STRING) {
3917 wpa_printf(MSG_DEBUG, "DPP: No wi-fi_tech string value found");
3918 goto fail;
3919 }
3920 if (os_strcmp(token->string, "infra") != 0) {
3921 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3922 token->string);
3923 goto fail;
3924 }
3925
3926 discovery = json_get_member(root, "discovery");
3927 if (!discovery || discovery->type != JSON_OBJECT) {
3928 wpa_printf(MSG_DEBUG, "DPP: No discovery object in JSON");
3929 goto fail;
3930 }
3931
3932 token = json_get_member(discovery, "ssid");
3933 if (!token || token->type != JSON_STRING) {
3934 wpa_printf(MSG_DEBUG,
3935 "DPP: No discovery::ssid string value found");
3936 goto fail;
3937 }
3938 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3939 token->string, os_strlen(token->string));
3940 if (os_strlen(token->string) > SSID_MAX_LEN) {
3941 wpa_printf(MSG_DEBUG,
3942 "DPP: Too long discovery::ssid string value");
3943 goto fail;
3944 }
3945 auth->ssid_len = os_strlen(token->string);
3946 os_memcpy(auth->ssid, token->string, auth->ssid_len);
3947
3948 cred = json_get_member(root, "cred");
3949 if (!cred || cred->type != JSON_OBJECT) {
3950 wpa_printf(MSG_DEBUG, "DPP: No cred object in JSON");
3951 goto fail;
3952 }
3953
3954 token = json_get_member(cred, "akm");
3955 if (!token || token->type != JSON_STRING) {
3956 wpa_printf(MSG_DEBUG,
3957 "DPP: No cred::akm string value found");
3958 goto fail;
3959 }
3960 if (os_strcmp(token->string, "psk") == 0) {
3961 if (dpp_parse_cred_legacy(auth, cred) < 0)
3962 goto fail;
3963 } else if (os_strcmp(token->string, "dpp") == 0) {
3964 if (dpp_parse_cred_dpp(auth, cred) < 0)
3965 goto fail;
3966 } else {
3967 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3968 token->string);
3969 goto fail;
3970 }
3971
3972 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3973 ret = 0;
3974fail:
3975 json_free(root);
3976 return ret;
3977}
3978
3979
3980int dpp_conf_resp_rx(struct dpp_authentication *auth,
3981 const struct wpabuf *resp)
3982{
3983 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3984 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
3985 const u8 *addr[1];
3986 size_t len[1];
3987 u8 *unwrapped = NULL;
3988 size_t unwrapped_len = 0;
3989 int ret = -1;
3990
3991 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
3992 wpa_printf(MSG_DEBUG,
3993 "DPP: Invalid attribute in config response");
3994 return -1;
3995 }
3996
3997 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3998 DPP_ATTR_WRAPPED_DATA,
3999 &wrapped_data_len);
4000 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4001 wpa_printf(MSG_DEBUG,
4002 "DPP: Missing or invalid required Wrapped data attribute");
4003 return -1;
4004 }
4005
4006 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4007 wrapped_data, wrapped_data_len);
4008 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4009 unwrapped = os_malloc(unwrapped_len);
4010 if (!unwrapped)
4011 return -1;
4012
4013 addr[0] = wpabuf_head(resp);
4014 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
4015 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4016
4017 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4018 wrapped_data, wrapped_data_len,
4019 1, addr, len, unwrapped) < 0) {
4020 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed");
4021 goto fail;
4022 }
4023 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4024 unwrapped, unwrapped_len);
4025
4026 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4027 wpa_printf(MSG_DEBUG,
4028 "DPP: Invalid attribute in unwrapped data");
4029 goto fail;
4030 }
4031
4032 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4033 DPP_ATTR_ENROLLEE_NONCE,
4034 &e_nonce_len);
4035 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4036 wpa_printf(MSG_DEBUG,
4037 "DPP: Missing or invalid Enrollee Nonce attribute");
4038 goto fail;
4039 }
4040 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4041 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
4042 wpa_printf(MSG_DEBUG, "Enrollee Nonce mismatch");
4043 goto fail;
4044 }
4045
4046 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
4047 DPP_ATTR_STATUS, &status_len);
4048 if (!status || status_len < 1) {
4049 wpa_printf(MSG_DEBUG,
4050 "DPP: Missing or invalid required DPP Status attribute");
4051 goto fail;
4052 }
4053 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
4054 if (status[0] != DPP_STATUS_OK) {
4055 wpa_printf(MSG_DEBUG, "DPP: Configuration failed");
4056 goto fail;
4057 }
4058
4059 conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
4060 DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
4061 if (!conf_obj) {
4062 wpa_printf(MSG_DEBUG,
4063 "DPP: Missing required Configuration Object attribute");
4064 goto fail;
4065 }
4066 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4067 conf_obj, conf_obj_len);
4068 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
4069 goto fail;
4070
4071 ret = 0;
4072
4073fail:
4074 os_free(unwrapped);
4075 return ret;
4076}
4077
4078
4079void dpp_configurator_free(struct dpp_configurator *conf)
4080{
4081 if (!conf)
4082 return;
4083 EVP_PKEY_free(conf->csign);
4084 os_free(conf->kid);
4085 os_free(conf);
4086}
4087
4088
4089struct dpp_configurator *
4090dpp_keygen_configurator(const char *curve, const u8 *privkey,
4091 size_t privkey_len)
4092{
4093 struct dpp_configurator *conf;
4094 struct wpabuf *csign_pub = NULL;
4095 u8 kid_hash[SHA256_MAC_LEN];
4096 const u8 *addr[1];
4097 size_t len[1];
4098
4099 conf = os_zalloc(sizeof(*conf));
4100 if (!conf)
4101 return NULL;
4102
4103 if (!curve) {
4104 conf->curve = &dpp_curves[0];
4105 } else {
4106 conf->curve = dpp_get_curve_name(curve);
4107 if (!conf->curve) {
4108 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
4109 curve);
4110 return NULL;
4111 }
4112 }
4113 if (privkey)
4114 conf->csign = dpp_set_keypair(&conf->curve, privkey,
4115 privkey_len);
4116 else
4117 conf->csign = dpp_gen_keypair(conf->curve);
4118 if (!conf->csign)
4119 goto fail;
4120 conf->own = 1;
4121
4122 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
4123 if (!csign_pub) {
4124 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
4125 goto fail;
4126 }
4127
4128 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
4129 addr[0] = wpabuf_head(csign_pub);
4130 len[0] = wpabuf_len(csign_pub);
4131 if (sha256_vector(1, addr, len, kid_hash) < 0) {
4132 wpa_printf(MSG_DEBUG,
4133 "DPP: Failed to derive kid for C-sign-key");
4134 goto fail;
4135 }
4136
4137 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash),
4138 NULL, 0);
4139 if (!conf->kid)
4140 goto fail;
4141out:
4142 wpabuf_free(csign_pub);
4143 return conf;
4144fail:
4145 dpp_configurator_free(conf);
4146 conf = NULL;
4147 goto out;
4148}