1 /*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, The Linux Foundation
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10 #include "utils/includes.h"
11 #include <fcntl.h>
12
13 #include "utils/common.h"
14 #include "common/defs.h"
15 #include "utils/base64.h"
16 #include "utils/json.h"
17 #include "crypto/crypto.h"
18 #include "crypto/random.h"
19 #include "crypto/aes.h"
20 #include "crypto/aes_siv.h"
21 #include "crypto/sha256.h"
22 #include "dpp.h"
23
24 static const char * dpp_netrole_str(enum dpp_netrole netrole);
25
26 #ifdef CONFIG_TESTING_OPTIONS
27 enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
28 u8 dpp_protocol_key_override[600];
29 size_t dpp_protocol_key_override_len = 0;
30 u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
31 size_t dpp_nonce_override_len = 0;
32
33 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
34 const struct dpp_curve_params *curve);
35 #endif /* CONFIG_TESTING_OPTIONS */
36
37 struct dpp_global {
38 void *msg_ctx;
39 struct dl_list bootstrap; /* struct dpp_bootstrap_info */
40 struct dl_list configurator; /* struct dpp_configurator */
41 };
42
43 static const struct dpp_curve_params dpp_curves[] = {
44 /* The mandatory to support and the default NIST P-256 curve needs to
45 * be the first entry on this list. */
46 { "sec256r1", 32, 32, 16, 32, "P-256", 19, "ES256" },
47 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
48 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
49 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
50 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
51 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
52 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
53 };
54
55 static struct wpabuf *
gas_build_req(u8 action,u8 dialog_token,size_t size)56 gas_build_req(u8 action, u8 dialog_token, size_t size)
57 {
58 struct wpabuf *buf;
59
60 buf = wpabuf_alloc(100 + size);
61 if (buf == NULL)
62 return NULL;
63
64 wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
65 wpabuf_put_u8(buf, action);
66 wpabuf_put_u8(buf, dialog_token);
67
68 return buf;
69 }
70
71
gas_build_initial_req(u8 dialog_token,size_t size)72 struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
73 {
74 return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
75 size);
76 }
77
dpp_debug_print_key(const char * title,struct crypto_key * key)78 static void dpp_debug_print_key(const char *title, struct crypto_key *key)
79 {
80 crypto_debug_print_ec_key(title, key);
81 }
82
dpp_debug_print_point(const char * title,struct crypto_ec * e,const struct crypto_ec_point * point)83 void dpp_debug_print_point(const char *title, struct crypto_ec *e,
84 const struct crypto_ec_point *point)
85 {
86 u8 x[64], y[64];
87
88 if (crypto_ec_point_to_bin(e, point, x, y) < 0) {
89 printf("error: failed to get corrdinates\n");
90 return;
91 }
92
93 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x, y);
94 }
95
dpp_hash_vector(const struct dpp_curve_params * curve,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)96 static int dpp_hash_vector(const struct dpp_curve_params *curve,
97 size_t num_elem, const u8 *addr[], const size_t *len,
98 u8 *mac)
99 {
100 if (curve->hash_len == 32)
101 return sha256_vector(num_elem, addr, len, mac);
102 #ifndef ESP_SUPPLICANT
103 if (curve->hash_len == 48)
104 return sha384_vector(num_elem, addr, len, mac);
105 if (curve->hash_len == 64)
106 return sha512_vector(num_elem, addr, len, mac);
107 #endif
108 return -1;
109 }
110
111
dpp_hkdf_expand(size_t hash_len,const u8 * secret,size_t secret_len,const char * label,u8 * out,size_t outlen)112 static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
113 const char *label, u8 *out, size_t outlen)
114 {
115 if (hash_len == 32)
116 return hmac_sha256_kdf(secret, secret_len, NULL,
117 (const u8 *) label, os_strlen(label),
118 out, outlen);
119 #ifndef ESP_SUPPLICANT
120 if (hash_len == 48)
121 return hmac_sha384_kdf(secret, secret_len, NULL,
122 (const u8 *) label, os_strlen(label),
123 out, outlen);
124 if (hash_len == 64)
125 return hmac_sha512_kdf(secret, secret_len, NULL,
126 (const u8 *) label, os_strlen(label),
127 out, outlen);
128 #endif
129 return -1;
130 }
131
132
dpp_hmac_vector(size_t hash_len,const u8 * key,size_t key_len,size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)133 static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
134 size_t num_elem, const u8 *addr[],
135 const size_t *len, u8 *mac)
136 {
137 if (hash_len == 32)
138 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
139 mac);
140 #ifndef ESP_SUPPLICANT
141 if (hash_len == 48)
142 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
143 mac);
144 if (hash_len == 64)
145 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
146 mac);
147 #endif
148 return -1;
149 }
150
151
dpp_hmac(size_t hash_len,const u8 * key,size_t key_len,const u8 * data,size_t data_len,u8 * mac)152 static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
153 const u8 *data, size_t data_len, u8 *mac)
154 {
155 if (hash_len == 32)
156 return hmac_sha256(key, key_len, data, data_len, mac);
157 #ifndef ESP_SUPPLICANT
158 if (hash_len == 48)
159 return hmac_sha384(key, key_len, data, data_len, mac);
160 if (hash_len == 64)
161 return hmac_sha512(key, key_len, data, data_len, mac);
162 #endif
163 return -1;
164 }
165
166
dpp_bn2bin_pad(const struct crypto_bignum * bn,u8 * pos,size_t len)167 static int dpp_bn2bin_pad(const struct crypto_bignum *bn, u8 *pos, size_t len)
168 {
169 if (crypto_bignum_to_bin(bn, pos, len, 0) < 0)
170 return -1;
171
172 return 0;
173 }
174
dpp_get_pubkey_point(struct crypto_key * pkey,int prefix)175 static struct wpabuf * dpp_get_pubkey_point(struct crypto_key *pkey, int prefix)
176 {
177 int len, res;
178 struct wpabuf *buf;
179 unsigned char *pos = NULL;
180
181 len = crypto_ec_get_publickey_buf(pkey, pos, 0);
182 if (len <= 0) {
183 wpa_printf(MSG_ERROR,
184 "DDP: Failed to determine public key encoding length");
185 return NULL;
186 }
187
188 buf = wpabuf_alloc(len);
189 if (!buf) {
190 return NULL;
191 }
192
193 pos = wpabuf_put(buf, len);
194
195 res = crypto_ec_get_publickey_buf(pkey, pos, len);
196 if (res != len) {
197 wpa_printf(MSG_ERROR,
198 "DDP: Failed to encode public key (res=%d/%d)",
199 res, len);
200 wpabuf_free(buf);
201 return NULL;
202 }
203
204 if (!prefix) {
205 /* Remove 0x04 prefix to match DPP definition */
206 pos = wpabuf_mhead(buf);
207 os_memmove(pos, pos + 1, len - 1);
208 buf->used--;
209 }
210
211 return buf;
212 }
213
dpp_set_pubkey_point(struct crypto_key * group_key,const u8 * buf,size_t len)214 static struct crypto_key * dpp_set_pubkey_point(struct crypto_key *group_key,
215 const u8 *buf, size_t len)
216 {
217 const struct crypto_ec_group *group;
218 struct crypto_key *pkey = NULL;
219
220 if (len & 1)
221 return NULL;
222
223 group = crypto_ec_get_group_from_key(group_key);
224 if (group)
225 pkey = crypto_ec_set_pubkey_point(group, buf,
226 len);
227 else
228 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
229
230 return pkey;
231 }
232
dpp_ecdh(struct crypto_key * own,struct crypto_key * peer,u8 * secret,size_t * secret_len)233 static int dpp_ecdh(struct crypto_key *own, struct crypto_key *peer,
234 u8 *secret, size_t *secret_len)
235 {
236 return crypto_ecdh(own, peer, secret, secret_len);
237 }
238
239
dpp_auth_fail(struct dpp_authentication * auth,const char * txt)240 static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
241 {
242 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
243 }
244
245
dpp_alloc_msg(enum dpp_public_action_frame_type type,size_t len)246 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
247 size_t len)
248 {
249 struct wpabuf *msg;
250
251 msg = wpabuf_alloc(8 + len);
252 if (!msg)
253 return NULL;
254 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
255 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
256 wpabuf_put_be24(msg, OUI_WFA);
257 wpabuf_put_u8(msg, DPP_OUI_TYPE);
258 wpabuf_put_u8(msg, 1); /* Crypto Suite */
259 wpabuf_put_u8(msg, type);
260 return msg;
261 }
262
263
dpp_get_attr(const u8 * buf,size_t len,u16 req_id,u16 * ret_len)264 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
265 {
266 u16 id, alen;
267 const u8 *pos = buf, *end = buf + len;
268
269 while (end - pos >= 4) {
270 id = WPA_GET_LE16(pos);
271 pos += 2;
272 alen = WPA_GET_LE16(pos);
273 pos += 2;
274 if (alen > end - pos)
275 return NULL;
276 if (id == req_id) {
277 *ret_len = alen;
278 return pos;
279 }
280 pos += alen;
281 }
282
283 return NULL;
284 }
285
286
dpp_get_attr_next(const u8 * prev,const u8 * buf,size_t len,u16 req_id,u16 * ret_len)287 static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
288 u16 req_id, u16 *ret_len)
289 {
290 u16 id, alen;
291 const u8 *pos, *end = buf + len;
292
293 if (!prev)
294 pos = buf;
295 else
296 pos = prev + WPA_GET_LE16(prev - 2);
297 while (end - pos >= 4) {
298 id = WPA_GET_LE16(pos);
299 pos += 2;
300 alen = WPA_GET_LE16(pos);
301 pos += 2;
302 if (alen > end - pos)
303 return NULL;
304 if (id == req_id) {
305 *ret_len = alen;
306 return pos;
307 }
308 pos += alen;
309 }
310
311 return NULL;
312 }
313
314
dpp_check_attrs(const u8 * buf,size_t len)315 int dpp_check_attrs(const u8 *buf, size_t len)
316 {
317 const u8 *pos, *end;
318 int wrapped_data = 0;
319
320 pos = buf;
321 end = buf + len;
322 while (end - pos >= 4) {
323 u16 id, alen;
324
325 id = WPA_GET_LE16(pos);
326 pos += 2;
327 alen = WPA_GET_LE16(pos);
328 pos += 2;
329 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
330 id, alen);
331 if (alen > end - pos) {
332 wpa_printf(MSG_DEBUG,
333 "DPP: Truncated message - not enough room for the attribute - dropped");
334 return -1;
335 }
336 if (wrapped_data) {
337 wpa_printf(MSG_DEBUG,
338 "DPP: An unexpected attribute included after the Wrapped Data attribute");
339 return -1;
340 }
341 if (id == DPP_ATTR_WRAPPED_DATA)
342 wrapped_data = 1;
343 pos += alen;
344 }
345
346 if (end != pos) {
347 wpa_printf(MSG_DEBUG,
348 "DPP: Unexpected octets (%d) after the last attribute",
349 (int) (end - pos));
350 return -1;
351 }
352
353 return 0;
354 }
355
356
dpp_bootstrap_info_free(struct dpp_bootstrap_info * info)357 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
358 {
359 if (!info)
360 return;
361 os_free(info->uri);
362 os_free(info->info);
363 crypto_ec_free_key(info->pubkey);
364 os_free(info);
365 }
366
367
dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)368 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
369 {
370 switch (type) {
371 case DPP_BOOTSTRAP_QR_CODE:
372 return "QRCODE";
373 case DPP_BOOTSTRAP_PKEX:
374 return "PKEX";
375 case DPP_BOOTSTRAP_NFC_URI:
376 return "NFC-URI";
377 }
378 return "??";
379 }
380
381
dpp_uri_valid_info(const char * info)382 static int dpp_uri_valid_info(const char *info)
383 {
384 while (*info) {
385 unsigned char val = *info++;
386
387 if (val < 0x20 || val > 0x7e || val == 0x3b)
388 return 0;
389 }
390
391 return 1;
392 }
393
394
dpp_clone_uri(struct dpp_bootstrap_info * bi,const char * uri)395 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
396 {
397 bi->uri = os_strdup(uri);
398 return bi->uri ? 0 : -1;
399 }
400
dpp_parse_uri_chan_list(struct dpp_bootstrap_info * bi,const char * chan_list)401 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
402 const char *chan_list)
403 {
404 #ifndef ESP_SUPPLICANT
405 const char *pos = chan_list, *pos2;
406 int opclass = -1, channel, freq;
407
408 while (pos && *pos && *pos != ';') {
409 pos2 = pos;
410 while (*pos2 >= '0' && *pos2 <= '9')
411 pos2++;
412 if (*pos2 == '/') {
413 opclass = atoi(pos);
414 pos = pos2 + 1;
415 }
416 if (opclass <= 0)
417 goto fail;
418 channel = atoi(pos);
419 if (channel <= 0)
420 goto fail;
421 while (*pos >= '0' && *pos <= '9')
422 pos++;
423 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
424 wpa_printf(MSG_DEBUG,
425 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
426 opclass, channel, freq);
427 if (freq < 0) {
428 wpa_printf(MSG_DEBUG,
429 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
430 opclass, channel);
431 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
432 wpa_printf(MSG_DEBUG,
433 "DPP: Too many channels in URI channel-list - ignore list");
434 bi->num_freq = 0;
435 break;
436 } else {
437 bi->freq[bi->num_freq++] = freq;
438 }
439
440 if (*pos == ';' || *pos == '\0')
441 break;
442 if (*pos != ',')
443 goto fail;
444 pos++;
445 }
446
447 return 0;
448 fail:
449 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
450 return -1;
451 #endif
452 return 0;
453 }
454
455
dpp_parse_uri_mac(struct dpp_bootstrap_info * bi,const char * mac)456 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
457 {
458 if (!mac)
459 return 0;
460
461 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
462 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
463 return -1;
464 }
465
466 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
467
468 return 0;
469 }
470
dpp_parse_uri_info(struct dpp_bootstrap_info * bi,const char * info)471 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
472 {
473 const char *end;
474
475 if (!info)
476 return 0;
477
478 end = os_strchr(info, ';');
479 if (!end)
480 end = info + os_strlen(info);
481 bi->info = os_malloc(end - info + 1);
482 if (!bi->info)
483 return -1;
484 os_memcpy(bi->info, info, end - info);
485 bi->info[end - info] = '\0';
486 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
487 if (!dpp_uri_valid_info(bi->info)) {
488 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
489 return -1;
490 }
491
492 return 0;
493 }
494
dpp_get_curve_group_id(int group_id)495 static const struct dpp_curve_params * dpp_get_curve_group_id(int group_id)
496 {
497 unsigned int i;
498
499 if (!group_id)
500 return NULL;
501
502 for (i = 0; dpp_curves[i].ike_group; i++) {
503 if (group_id == dpp_curves[i].ike_group)
504 return &dpp_curves[i];
505 }
506 return NULL;
507 }
508
dpp_parse_uri_pk(struct dpp_bootstrap_info * bi,const char * info)509 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
510 {
511 const char *end;
512 u8 *data;
513 size_t data_len;
514 struct crypto_key *pkey;
515 const unsigned char *p;
516 struct crypto_ec_group *group;
517 int id;
518
519 end = os_strchr(info, ';');
520 if (!end)
521 return -1;
522
523 data = (unsigned char *)base64_decode(info, end - info, &data_len);
524 if (!data) {
525 wpa_printf(MSG_DEBUG,
526 "DPP: Invalid base64 encoding on URI public-key");
527 return -1;
528 }
529 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
530 data, data_len);
531
532 if (sha256_vector(1, (const u8 **) &data, &data_len,
533 bi->pubkey_hash) < 0) {
534 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
535 os_free(data);
536 return -1;
537 }
538 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
539 bi->pubkey_hash, SHA256_MAC_LEN);
540
541 /* DER encoded ASN.1 SubjectPublicKeyInfo
542 *
543 * SubjectPublicKeyInfo ::= SEQUENCE {
544 * algorithm AlgorithmIdentifier,
545 * subjectPublicKey BIT STRING }
546 *
547 * AlgorithmIdentifier ::= SEQUENCE {
548 * algorithm OBJECT IDENTIFIER,
549 * parameters ANY DEFINED BY algorithm OPTIONAL }
550 *
551 * subjectPublicKey = compressed format public key per ANSI X9.63
552 * algorithm = ecPublicKey (1.2.840.10045.2.1)
553 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
554 * prime256v1 (1.2.840.10045.3.1.7)
555 */
556
557 p = data;
558
559 pkey = crypto_ec_parse_subpub_key((unsigned char *)p, data_len);
560 os_free(data);
561
562 if (!pkey) {
563 wpa_printf(MSG_DEBUG,
564 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
565 return -1;
566 }
567
568 if (!crypto_is_ec_key(pkey)) {
569 wpa_printf(MSG_DEBUG,
570 "DPP: SubjectPublicKeyInfo does not describe an EC key");
571 crypto_ec_free_key(pkey);
572 return -1;
573 }
574
575 group = crypto_ec_get_group_from_key(pkey);
576 if (!group) {
577 return -1;
578 }
579 id = crypto_ec_get_curve_id(group);
580 bi->curve = dpp_get_curve_group_id(id);
581 if (!bi->curve) {
582 wpa_printf(MSG_DEBUG,
583 "DPP: Unsupported SubjectPublicKeyInfo curve");
584 goto fail;
585 }
586
587 bi->pubkey = pkey;
588 return 0;
589 fail:
590 crypto_ec_free_key(pkey);
591 return -1;
592 }
593
594
dpp_parse_uri(const char * uri)595 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
596 {
597 const char *pos = uri;
598 const char *end;
599 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
600 struct dpp_bootstrap_info *bi;
601
602 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", (u8 *)uri, os_strlen(uri));
603
604 if (os_strncmp(pos, "DPP:", 4) != 0) {
605 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
606 return NULL;
607 }
608 pos += 4;
609
610 for (;;) {
611 end = os_strchr(pos, ';');
612 if (!end)
613 break;
614
615 if (end == pos) {
616 /* Handle terminating ";;" and ignore unexpected ";"
617 * for parsing robustness. */
618 pos++;
619 continue;
620 }
621
622 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
623 chan_list = pos + 2;
624 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
625 mac = pos + 2;
626 else if (pos[0] == 'I' && pos[1] == ':' && !info)
627 info = pos + 2;
628 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
629 pk = pos + 2;
630 else
631 wpa_hexdump_ascii(MSG_DEBUG,
632 "DPP: Ignore unrecognized URI parameter",
633 (u8 *)pos, end - pos);
634 pos = end + 1;
635 }
636
637 if (!pk) {
638 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
639 return NULL;
640 }
641
642 bi = os_zalloc(sizeof(*bi));
643 if (!bi)
644 return NULL;
645
646 if (dpp_clone_uri(bi, uri) < 0 ||
647 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
648 dpp_parse_uri_mac(bi, mac) < 0 ||
649 dpp_parse_uri_info(bi, info) < 0 ||
650 dpp_parse_uri_pk(bi, pk) < 0) {
651 dpp_bootstrap_info_free(bi);
652 bi = NULL;
653 }
654
655 return bi;
656 }
657
658
dpp_gen_keypair(const struct dpp_curve_params * curve)659 static struct crypto_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
660 {
661 struct crypto_key *key = crypto_ec_gen_keypair(curve->ike_group);
662
663 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
664 dpp_debug_print_key("Own generated key", key);
665
666 return key;
667 }
668
dpp_get_curve_name(const char * name)669 static const struct dpp_curve_params *dpp_get_curve_name(const char *name)
670 {
671 int i;
672
673 for (i = 0; dpp_curves[i].name; i++) {
674 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
675 (dpp_curves[i].jwk_crv &&
676 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
677 return &dpp_curves[i];
678 }
679 return NULL;
680 }
681
682
dpp_get_curve_jwk_crv(const char * name)683 static const struct dpp_curve_params *dpp_get_curve_jwk_crv(const char *name)
684 {
685 int i;
686
687 for (i = 0; dpp_curves[i].name; i++) {
688 if (dpp_curves[i].jwk_crv &&
689 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
690 return &dpp_curves[i];
691 }
692
693 return NULL;
694 }
695
696
dpp_set_keypair(const struct dpp_curve_params ** curve,const u8 * privkey,size_t privkey_len)697 static struct crypto_key * dpp_set_keypair(const struct dpp_curve_params **curve,
698 const u8 *privkey, size_t privkey_len)
699 {
700 struct crypto_ec_group *group;
701 struct crypto_key *pkey = crypto_ec_get_key(privkey, privkey_len);
702 int id;
703
704 if (!pkey) {
705 wpa_printf(MSG_ERROR, "%s: failed to get pkey", __func__);
706 return NULL;
707 }
708 group = crypto_ec_get_group_from_key(pkey);
709 if (!group) {
710 return NULL;
711 }
712 id = crypto_ec_get_curve_id(group);
713 *curve = dpp_get_curve_group_id(id);
714 if (!*curve) {
715 wpa_printf(MSG_INFO,
716 "DPP: Unsupported curve (id=%d) in pre-assigned key",
717 id);
718 crypto_ec_free_key(pkey);
719 return NULL;
720 }
721
722 return pkey;
723 }
724
dpp_bootstrap_key_der(struct crypto_key * key)725 static struct wpabuf * dpp_bootstrap_key_der(struct crypto_key *key)
726 {
727 unsigned char *der = NULL;
728 struct wpabuf *ret = NULL;
729 int der_len;
730
731 der_len = crypto_ec_write_pub_key(key, &der);
732 if (!der) {
733 printf("failed to get der for bootstrapping key\n");
734 return NULL;
735 }
736 ret = wpabuf_alloc_copy(der, der_len);
737
738 os_free(der);
739 return ret;
740 }
741
dpp_bootstrap_key_hash(struct dpp_bootstrap_info * bi)742 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
743 {
744 struct wpabuf *der;
745 int res;
746 const u8 *addr[1];
747 size_t len[1];
748
749 der = dpp_bootstrap_key_der(bi->pubkey);
750 if (!der)
751 return -1;
752 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
753 der);
754
755 addr[0] = wpabuf_head(der);
756 len[0] = wpabuf_len(der);
757 res = sha256_vector(1, addr, len, bi->pubkey_hash);
758 if (res < 0)
759 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
760 else
761 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
762 SHA256_MAC_LEN);
763 wpabuf_free(der);
764 return res;
765 }
766
767
dpp_keygen(struct dpp_bootstrap_info * bi,const char * curve,u8 * privkey,size_t privkey_len)768 char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
769 u8 *privkey, size_t privkey_len)
770 {
771 char *base64 = NULL;
772 char *pos, *end;
773 size_t len;
774 struct wpabuf *der = NULL;
775 const u8 *addr[1];
776 int res;
777
778 if (!curve) {
779 bi->curve = &dpp_curves[0];
780 } else {
781 bi->curve = dpp_get_curve_name(curve);
782 if (!bi->curve) {
783 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
784 curve);
785 return NULL;
786 }
787 }
788 if (privkey)
789 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
790 else
791 bi->pubkey = dpp_gen_keypair(bi->curve);
792 if (!bi->pubkey)
793 goto fail;
794 bi->own = 1;
795
796 der = dpp_bootstrap_key_der(bi->pubkey);
797 if (!der)
798 goto fail;
799 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
800 der);
801
802 addr[0] = wpabuf_head(der);
803 len = wpabuf_len(der);
804 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
805 if (res < 0) {
806 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
807 goto fail;
808 }
809 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
810 SHA256_MAC_LEN);
811
812 base64 = (char *)base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
813 wpabuf_free(der);
814 der = NULL;
815 if (!base64)
816 goto fail;
817 pos = base64;
818 end = pos + len;
819 for (;;) {
820 pos = os_strchr(pos, '\n');
821 if (!pos)
822 break;
823 os_memmove(pos, pos + 1, end - pos);
824 }
825 return base64;
826 fail:
827 os_free(base64);
828 wpabuf_free(der);
829 return NULL;
830 }
831
dpp_derive_k1(const u8 * Mx,size_t Mx_len,u8 * k1,unsigned int hash_len)832 static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
833 unsigned int hash_len)
834 {
835 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
836 const char *info = "first intermediate key";
837 int res;
838
839 /* k1 = HKDF(<>, "first intermediate key", M.x) */
840
841 /* HKDF-Extract(<>, M.x) */
842 os_memset(salt, 0, hash_len);
843 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
844 return -1;
845 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
846 prk, hash_len);
847
848 /* HKDF-Expand(PRK, info, L) */
849 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
850 forced_memzero(prk, hash_len);
851 if (res < 0)
852 return -1;
853
854 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
855 k1, hash_len);
856 return 0;
857 }
858
859
dpp_derive_k2(const u8 * Nx,size_t Nx_len,u8 * k2,unsigned int hash_len)860 static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
861 unsigned int hash_len)
862 {
863 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
864 const char *info = "second intermediate key";
865 int res;
866
867 /* k2 = HKDF(<>, "second intermediate key", N.x) */
868
869 /* HKDF-Extract(<>, N.x) */
870 os_memset(salt, 0, hash_len);
871 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
872 if (res < 0)
873 return -1;
874 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
875 prk, hash_len);
876
877 /* HKDF-Expand(PRK, info, L) */
878 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
879 forced_memzero(prk, hash_len);
880 if (res < 0)
881 return -1;
882
883 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
884 k2, hash_len);
885 return 0;
886 }
887
888
dpp_derive_ke(struct dpp_authentication * auth,u8 * ke,unsigned int hash_len)889 static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
890 unsigned int hash_len)
891 {
892 size_t nonce_len;
893 u8 nonces[2 * DPP_MAX_NONCE_LEN];
894 const char *info_ke = "DPP Key";
895 u8 prk[DPP_MAX_HASH_LEN];
896 int res;
897 const u8 *addr[3];
898 size_t len[3];
899 size_t num_elem = 0;
900
901 if (!auth->Mx_len || !auth->Nx_len) {
902 wpa_printf(MSG_DEBUG,
903 "DPP: Mx/Nx not available - cannot derive ke");
904 return -1;
905 }
906
907 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
908
909 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
910 nonce_len = auth->curve->nonce_len;
911 os_memcpy(nonces, auth->i_nonce, nonce_len);
912 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
913 addr[num_elem] = auth->Mx;
914 len[num_elem] = auth->Mx_len;
915 num_elem++;
916 addr[num_elem] = auth->Nx;
917 len[num_elem] = auth->Nx_len;
918 num_elem++;
919 if (auth->peer_bi && auth->own_bi) {
920 if (!auth->Lx_len) {
921 wpa_printf(MSG_DEBUG,
922 "DPP: Lx not available - cannot derive ke");
923 return -1;
924 }
925 addr[num_elem] = auth->Lx;
926 len[num_elem] = auth->secret_len;
927 num_elem++;
928 }
929 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
930 num_elem, addr, len, prk);
931 if (res < 0)
932 return -1;
933 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
934 prk, hash_len);
935
936 /* HKDF-Expand(PRK, info, L) */
937 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
938 forced_memzero(prk, hash_len);
939 if (res < 0)
940 return -1;
941
942 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
943 ke, hash_len);
944 return 0;
945 }
946
947
dpp_build_attr_status(struct wpabuf * msg,enum dpp_status_error status)948 static void dpp_build_attr_status(struct wpabuf *msg,
949 enum dpp_status_error status)
950 {
951 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
952 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
953 wpabuf_put_le16(msg, 1);
954 wpabuf_put_u8(msg, status);
955 }
956
957
dpp_build_attr_r_bootstrap_key_hash(struct wpabuf * msg,const u8 * hash)958 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
959 const u8 *hash)
960 {
961 if (hash) {
962 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
963 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
964 wpabuf_put_le16(msg, SHA256_MAC_LEN);
965 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
966 }
967 }
968
969
dpp_build_attr_i_bootstrap_key_hash(struct wpabuf * msg,const u8 * hash)970 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
971 const u8 *hash)
972 {
973 if (hash) {
974 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
975 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
976 wpabuf_put_le16(msg, SHA256_MAC_LEN);
977 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
978 }
979 }
980
981
dpp_auth_build_req(struct dpp_authentication * auth,const struct wpabuf * pi,size_t nonce_len,const u8 * r_pubkey_hash,const u8 * i_pubkey_hash,unsigned int neg_freq)982 static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
983 const struct wpabuf *pi,
984 size_t nonce_len,
985 const u8 *r_pubkey_hash,
986 const u8 *i_pubkey_hash,
987 unsigned int neg_freq)
988 {
989 struct wpabuf *msg;
990 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
991 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
992 u8 *pos;
993 const u8 *addr[2];
994
995 size_t len[2], siv_len, attr_len;
996 u8 *attr_start, *attr_end;
997
998 /* Build DPP Authentication Request frame attributes */
999 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
1000 4 + sizeof(wrapped_data);
1001 if (neg_freq > 0)
1002 attr_len += 4 + 2;
1003 #ifdef CONFIG_TESTING_OPTIONS
1004 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1005 attr_len += 5;
1006 #endif /* CONFIG_TESTING_OPTIONS */
1007 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
1008 if (!msg)
1009 return NULL;
1010
1011 attr_start = wpabuf_put(msg, 0);
1012
1013 /* Responder Bootstrapping Key Hash */
1014 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1015
1016 /* Initiator Bootstrapping Key Hash */
1017 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1018
1019 /* Initiator Protocol Key */
1020 if (pi) {
1021 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1022 wpabuf_put_le16(msg, wpabuf_len(pi));
1023 wpabuf_put_buf(msg, pi);
1024 }
1025
1026 /* Channel */
1027 if (neg_freq > 0) {
1028 //TODO correct and fill
1029 u8 op_class = 81, channel = 6;
1030
1031 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1032 wpabuf_put_le16(msg, 2);
1033 wpabuf_put_u8(msg, op_class);
1034 wpabuf_put_u8(msg, channel);
1035 }
1036
1037 #ifdef CONFIG_TESTING_OPTIONS
1038 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1039 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1040 goto skip_wrapped_data;
1041 }
1042 #endif /* CONFIG_TESTING_OPTIONS */
1043
1044 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1045 pos = clear;
1046
1047 #ifdef CONFIG_TESTING_OPTIONS
1048 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1049 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1050 goto skip_i_nonce;
1051 }
1052 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1053 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1054 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1055 pos += 2;
1056 WPA_PUT_LE16(pos, nonce_len - 1);
1057 pos += 2;
1058 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1059 pos += nonce_len - 1;
1060 goto skip_i_nonce;
1061 }
1062 #endif /* CONFIG_TESTING_OPTIONS */
1063
1064 /* I-nonce */
1065 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1066 pos += 2;
1067 WPA_PUT_LE16(pos, nonce_len);
1068 pos += 2;
1069 os_memcpy(pos, auth->i_nonce, nonce_len);
1070 pos += nonce_len;
1071
1072 #ifdef CONFIG_TESTING_OPTIONS
1073 skip_i_nonce:
1074 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1075 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1076 goto skip_i_capab;
1077 }
1078 #endif /* CONFIG_TESTING_OPTIONS */
1079
1080 /* I-capabilities */
1081 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1082 pos += 2;
1083 WPA_PUT_LE16(pos, 1);
1084 pos += 2;
1085 auth->i_capab = auth->allowed_roles;
1086 *pos++ = auth->i_capab;
1087 #ifdef CONFIG_TESTING_OPTIONS
1088 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1089 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1090 pos[-1] = 0;
1091 }
1092 skip_i_capab:
1093 #endif /* CONFIG_TESTING_OPTIONS */
1094
1095 attr_end = wpabuf_put(msg, 0);
1096
1097 /* OUI, OUI type, Crypto Suite, DPP frame type */
1098 addr[0] = wpabuf_head_u8(msg) + 2;
1099 len[0] = 3 + 1 + 1 + 1;
1100 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1101
1102 /* Attributes before Wrapped Data */
1103 addr[1] = attr_start;
1104 len[1] = attr_end - attr_start;
1105 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1106
1107 siv_len = pos - clear;
1108 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1109 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
1110 2, addr, len, wrapped_data) < 0) {
1111 wpabuf_free(msg);
1112 return NULL;
1113 }
1114 siv_len += AES_BLOCK_SIZE;
1115 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1116 wrapped_data, siv_len);
1117
1118 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1119 wpabuf_put_le16(msg, siv_len);
1120 wpabuf_put_data(msg, wrapped_data, siv_len);
1121
1122 #ifdef CONFIG_TESTING_OPTIONS
1123 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1124 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1125 dpp_build_attr_status(msg, DPP_STATUS_OK);
1126 }
1127 skip_wrapped_data:
1128 #endif /* CONFIG_TESTING_OPTIONS */
1129
1130 wpa_hexdump_buf(MSG_DEBUG,
1131 "DPP: Authentication Request frame attributes", msg);
1132
1133 return msg;
1134 }
1135
1136
dpp_auth_build_resp(struct dpp_authentication * auth,enum dpp_status_error status,const struct wpabuf * pr,size_t nonce_len,const u8 * r_pubkey_hash,const u8 * i_pubkey_hash,const u8 * r_nonce,const u8 * i_nonce,const u8 * wrapped_r_auth,size_t wrapped_r_auth_len,const u8 * siv_key)1137 static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1138 enum dpp_status_error status,
1139 const struct wpabuf *pr,
1140 size_t nonce_len,
1141 const u8 *r_pubkey_hash,
1142 const u8 *i_pubkey_hash,
1143 const u8 *r_nonce, const u8 *i_nonce,
1144 const u8 *wrapped_r_auth,
1145 size_t wrapped_r_auth_len,
1146 const u8 *siv_key)
1147 {
1148 struct wpabuf *msg;
1149 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1150 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1151 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1152 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1153 const u8 *addr[2];
1154 size_t len[2], siv_len, attr_len;
1155 u8 *attr_start, *attr_end, *pos;
1156
1157 auth->waiting_auth_conf = 1;
1158 auth->auth_resp_tries = 0;
1159
1160 /* Build DPP Authentication Response frame attributes */
1161 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1162 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
1163 #ifdef CONFIG_TESTING_OPTIONS
1164 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1165 attr_len += 5;
1166 #endif /* CONFIG_TESTING_OPTIONS */
1167 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1168 if (!msg)
1169 return NULL;
1170
1171 attr_start = wpabuf_put(msg, 0);
1172
1173 /* DPP Status */
1174 if (status != 255)
1175 dpp_build_attr_status(msg, status);
1176
1177 /* Responder Bootstrapping Key Hash */
1178 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1179
1180 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1181 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1182
1183 /* Responder Protocol Key */
1184 if (pr) {
1185 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1186 wpabuf_put_le16(msg, wpabuf_len(pr));
1187 wpabuf_put_buf(msg, pr);
1188 }
1189
1190 attr_end = wpabuf_put(msg, 0);
1191
1192 #ifdef CONFIG_TESTING_OPTIONS
1193 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
1194 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1195 goto skip_wrapped_data;
1196 }
1197 #endif /* CONFIG_TESTING_OPTIONS */
1198
1199 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1200 pos = clear;
1201
1202 if (r_nonce) {
1203 /* R-nonce */
1204 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
1205 pos += 2;
1206 WPA_PUT_LE16(pos, nonce_len);
1207 pos += 2;
1208 os_memcpy(pos, r_nonce, nonce_len);
1209 pos += nonce_len;
1210 }
1211
1212 if (i_nonce) {
1213 /* I-nonce */
1214 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1215 pos += 2;
1216 WPA_PUT_LE16(pos, nonce_len);
1217 pos += 2;
1218 os_memcpy(pos, i_nonce, nonce_len);
1219 #ifdef CONFIG_TESTING_OPTIONS
1220 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
1221 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
1222 pos[nonce_len / 2] ^= 0x01;
1223 }
1224 #endif /* CONFIG_TESTING_OPTIONS */
1225 pos += nonce_len;
1226 }
1227
1228 #ifdef CONFIG_TESTING_OPTIONS
1229 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
1230 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
1231 goto skip_r_capab;
1232 }
1233 #endif /* CONFIG_TESTING_OPTIONS */
1234
1235 /* R-capabilities */
1236 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
1237 pos += 2;
1238 WPA_PUT_LE16(pos, 1);
1239 pos += 2;
1240 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
1241 DPP_CAPAB_ENROLLEE;
1242 *pos++ = auth->r_capab;
1243 #ifdef CONFIG_TESTING_OPTIONS
1244 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
1245 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
1246 pos[-1] = 0;
1247 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
1248 wpa_printf(MSG_INFO,
1249 "DPP: TESTING - incompatible R-capabilities");
1250 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
1251 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
1252 pos[-1] = 0;
1253 else
1254 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
1255 DPP_CAPAB_CONFIGURATOR;
1256 }
1257 skip_r_capab:
1258 #endif /* CONFIG_TESTING_OPTIONS */
1259
1260 if (wrapped_r_auth) {
1261 /* {R-auth}ke */
1262 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
1263 pos += 2;
1264 WPA_PUT_LE16(pos, wrapped_r_auth_len);
1265 pos += 2;
1266 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
1267 pos += wrapped_r_auth_len;
1268 }
1269
1270 /* OUI, OUI type, Crypto Suite, DPP frame type */
1271 addr[0] = wpabuf_head_u8(msg) + 2;
1272 len[0] = 3 + 1 + 1 + 1;
1273 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1274
1275 /* Attributes before Wrapped Data */
1276 addr[1] = attr_start;
1277 len[1] = attr_end - attr_start;
1278 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1279
1280 siv_len = pos - clear;
1281 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1282 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
1283 2, addr, len, wrapped_data) < 0) {
1284 wpabuf_free(msg);
1285 return NULL;
1286 }
1287 siv_len += AES_BLOCK_SIZE;
1288 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1289 wrapped_data, siv_len);
1290
1291 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1292 wpabuf_put_le16(msg, siv_len);
1293 wpabuf_put_data(msg, wrapped_data, siv_len);
1294
1295 #ifdef CONFIG_TESTING_OPTIONS
1296 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
1297 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1298 dpp_build_attr_status(msg, DPP_STATUS_OK);
1299 }
1300 skip_wrapped_data:
1301 #endif /* CONFIG_TESTING_OPTIONS */
1302
1303 wpa_hexdump_buf(MSG_DEBUG,
1304 "DPP: Authentication Response frame attributes", msg);
1305 return msg;
1306 }
1307
1308
dpp_channel_ok_init(struct hostapd_hw_modes * own_modes,u16 num_modes,unsigned int freq)1309 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
1310 u16 num_modes, unsigned int freq)
1311 {
1312 #ifndef ESP_SUPPLICANT
1313 u16 m;
1314 int c, flag;
1315
1316 if (!own_modes || !num_modes)
1317 return 1;
1318
1319 for (m = 0; m < num_modes; m++) {
1320 for (c = 0; c < own_modes[m].num_channels; c++) {
1321 if ((unsigned int) own_modes[m].channels[c].freq !=
1322 freq)
1323 continue;
1324 flag = own_modes[m].channels[c].flag;
1325 if (!(flag & (HOSTAPD_CHAN_DISABLED |
1326 HOSTAPD_CHAN_NO_IR |
1327 HOSTAPD_CHAN_RADAR)))
1328 return 1;
1329 }
1330 }
1331
1332 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
1333 return 0;
1334 #endif
1335 return 1;
1336 }
1337
1338
freq_included(const unsigned int freqs[],unsigned int num,unsigned int freq)1339 static int freq_included(const unsigned int freqs[], unsigned int num,
1340 unsigned int freq)
1341 {
1342 while (num > 0) {
1343 if (freqs[--num] == freq)
1344 return 1;
1345 }
1346 return 0;
1347 }
1348
1349
freq_to_start(unsigned int freqs[],unsigned int num,unsigned int freq)1350 static void freq_to_start(unsigned int freqs[], unsigned int num,
1351 unsigned int freq)
1352 {
1353 unsigned int i;
1354
1355 for (i = 0; i < num; i++) {
1356 if (freqs[i] == freq)
1357 break;
1358 }
1359 if (i == 0 || i >= num)
1360 return;
1361 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
1362 freqs[0] = freq;
1363 }
1364
1365
dpp_channel_intersect(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)1366 static int dpp_channel_intersect(struct dpp_authentication *auth,
1367 struct hostapd_hw_modes *own_modes,
1368 u16 num_modes)
1369 {
1370 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
1371 unsigned int i, freq;
1372
1373 for (i = 0; i < peer_bi->num_freq; i++) {
1374 freq = peer_bi->freq[i];
1375 if (freq_included(auth->freq, auth->num_freq, freq))
1376 continue;
1377 if (dpp_channel_ok_init(own_modes, num_modes, freq))
1378 auth->freq[auth->num_freq++] = freq;
1379 }
1380 if (!auth->num_freq) {
1381 wpa_printf(MSG_INFO,
1382 "DPP: No available channels for initiating DPP Authentication");
1383 return -1;
1384 }
1385 auth->curr_freq = auth->freq[0];
1386 return 0;
1387 }
1388
1389
dpp_channel_local_list(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)1390 static int dpp_channel_local_list(struct dpp_authentication *auth,
1391 struct hostapd_hw_modes *own_modes,
1392 u16 num_modes)
1393 {
1394 #ifndef ESP_SUPPLICANT
1395 u16 m;
1396 int c, flag;
1397 unsigned int freq;
1398
1399 if (!own_modes || !num_modes) {
1400 auth->freq[0] = 2412;
1401 auth->freq[1] = 2437;
1402 auth->freq[2] = 2462;
1403 auth->num_freq = 3;
1404 return 0;
1405 }
1406
1407 for (m = 0; m < num_modes; m++) {
1408 for (c = 0; c < own_modes[m].num_channels; c++) {
1409 freq = own_modes[m].channels[c].freq;
1410 flag = own_modes[m].channels[c].flag;
1411 if (flag & (HOSTAPD_CHAN_DISABLED |
1412 HOSTAPD_CHAN_NO_IR |
1413 HOSTAPD_CHAN_RADAR))
1414 continue;
1415 if (freq_included(auth->freq, auth->num_freq, freq))
1416 continue;
1417 auth->freq[auth->num_freq++] = freq;
1418 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
1419 m = num_modes;
1420 break;
1421 }
1422 }
1423 }
1424 #else
1425 auth->freq[0] = 2412;
1426 auth->freq[1] = 2437;
1427 auth->freq[2] = 2462;
1428 auth->num_freq = 3;
1429 #endif
1430 return auth->num_freq == 0 ? -1 : 0;
1431 }
1432
1433
dpp_prepare_channel_list(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)1434 static int dpp_prepare_channel_list(struct dpp_authentication *auth,
1435 struct hostapd_hw_modes *own_modes,
1436 u16 num_modes)
1437 {
1438 int res;
1439 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
1440 unsigned int i;
1441
1442 if (auth->peer_bi->num_freq > 0)
1443 res = dpp_channel_intersect(auth, own_modes, num_modes);
1444 else
1445 res = dpp_channel_local_list(auth, own_modes, num_modes);
1446 if (res < 0)
1447 return res;
1448
1449 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
1450 * likely channels first. */
1451 freq_to_start(auth->freq, auth->num_freq, 2462);
1452 freq_to_start(auth->freq, auth->num_freq, 2412);
1453 freq_to_start(auth->freq, auth->num_freq, 2437);
1454
1455 auth->freq_idx = 0;
1456 auth->curr_freq = auth->freq[0];
1457
1458 pos = freqs;
1459 end = pos + sizeof(freqs);
1460 for (i = 0; i < auth->num_freq; i++) {
1461 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
1462 if (os_snprintf_error(end - pos, res))
1463 break;
1464 pos += res;
1465 }
1466 *pos = '\0';
1467 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
1468 freqs);
1469
1470 return 0;
1471 }
1472
1473
dpp_autogen_bootstrap_key(struct dpp_authentication * auth)1474 static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
1475 {
1476 struct dpp_bootstrap_info *bi;
1477 char *pk = NULL;
1478 size_t len;
1479
1480 if (auth->own_bi)
1481 return 0; /* already generated */
1482
1483 bi = os_zalloc(sizeof(*bi));
1484 if (!bi)
1485 return -1;
1486 bi->type = DPP_BOOTSTRAP_QR_CODE;
1487 pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0);
1488 if (!pk)
1489 goto fail;
1490
1491 len = 4; /* "DPP:" */
1492 len += 4 + os_strlen(pk);
1493 bi->uri = os_malloc(len + 1);
1494 if (!bi->uri)
1495 goto fail;
1496 os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk);
1497 wpa_printf(MSG_DEBUG,
1498 "DPP: Auto-generated own bootstrapping key info: URI %s",
1499 bi->uri);
1500
1501 auth->tmp_own_bi = auth->own_bi = bi;
1502
1503 os_free(pk);
1504
1505 return 0;
1506 fail:
1507 os_free(pk);
1508 dpp_bootstrap_info_free(bi);
1509 return -1;
1510 }
1511
1512
dpp_auth_init(void * msg_ctx,struct dpp_bootstrap_info * peer_bi,struct dpp_bootstrap_info * own_bi,u8 dpp_allowed_roles,unsigned int neg_freq,struct hostapd_hw_modes * own_modes,u16 num_modes)1513 struct dpp_authentication * dpp_auth_init(void *msg_ctx,
1514 struct dpp_bootstrap_info *peer_bi,
1515 struct dpp_bootstrap_info *own_bi,
1516 u8 dpp_allowed_roles,
1517 unsigned int neg_freq,
1518 struct hostapd_hw_modes *own_modes,
1519 u16 num_modes)
1520 {
1521 struct dpp_authentication *auth;
1522 size_t nonce_len;
1523 size_t secret_len;
1524 struct wpabuf *pi = NULL;
1525 const u8 *r_pubkey_hash, *i_pubkey_hash;
1526 #ifdef CONFIG_TESTING_OPTIONS
1527 u8 test_hash[SHA256_MAC_LEN];
1528 #endif /* CONFIG_TESTING_OPTIONS */
1529
1530 auth = os_zalloc(sizeof(*auth));
1531 if (!auth)
1532 return NULL;
1533 auth->msg_ctx = msg_ctx;
1534 auth->initiator = 1;
1535 auth->waiting_auth_resp = 1;
1536 auth->allowed_roles = dpp_allowed_roles;
1537 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
1538 auth->peer_bi = peer_bi;
1539 auth->own_bi = own_bi;
1540 auth->curve = peer_bi->curve;
1541
1542 if (dpp_autogen_bootstrap_key(auth) < 0 ||
1543 dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
1544 goto fail;
1545
1546 #ifdef CONFIG_TESTING_OPTIONS
1547 if (dpp_nonce_override_len > 0) {
1548 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
1549 nonce_len = dpp_nonce_override_len;
1550 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
1551 } else {
1552 nonce_len = auth->curve->nonce_len;
1553 if (random_get_bytes(auth->i_nonce, nonce_len)) {
1554 wpa_printf(MSG_ERROR,
1555 "DPP: Failed to generate I-nonce");
1556 goto fail;
1557 }
1558 }
1559 #else /* CONFIG_TESTING_OPTIONS */
1560 nonce_len = auth->curve->nonce_len;
1561 if (random_get_bytes(auth->i_nonce, nonce_len)) {
1562 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
1563 goto fail;
1564 }
1565 #endif /* CONFIG_TESTING_OPTIONS */
1566 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
1567
1568 #ifdef CONFIG_TESTING_OPTIONS
1569 if (dpp_protocol_key_override_len) {
1570 const struct dpp_curve_params *tmp_curve;
1571
1572 wpa_printf(MSG_INFO,
1573 "DPP: TESTING - override protocol key");
1574 auth->own_protocol_key = dpp_set_keypair(
1575 &tmp_curve, dpp_protocol_key_override,
1576 dpp_protocol_key_override_len);
1577 } else {
1578 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1579 }
1580 #else /* CONFIG_TESTING_OPTIONS */
1581 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1582 #endif /* CONFIG_TESTING_OPTIONS */
1583 if (!auth->own_protocol_key)
1584 goto fail;
1585
1586 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1587 if (!pi)
1588 goto fail;
1589
1590 /* ECDH: M = pI * BR */
1591 if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
1592 auth->Mx, &secret_len) < 0)
1593 goto fail;
1594 auth->secret_len = secret_len;
1595
1596 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
1597 auth->Mx, auth->secret_len);
1598 auth->Mx_len = auth->secret_len;
1599
1600 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
1601 auth->curve->hash_len) < 0)
1602 goto fail;
1603
1604 r_pubkey_hash = auth->peer_bi->pubkey_hash;
1605 i_pubkey_hash = auth->own_bi->pubkey_hash;
1606
1607 #ifdef CONFIG_TESTING_OPTIONS
1608 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1609 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
1610 r_pubkey_hash = NULL;
1611 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1612 wpa_printf(MSG_INFO,
1613 "DPP: TESTING - invalid R-Bootstrap Key Hash");
1614 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
1615 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1616 r_pubkey_hash = test_hash;
1617 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1618 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
1619 i_pubkey_hash = NULL;
1620 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1621 wpa_printf(MSG_INFO,
1622 "DPP: TESTING - invalid I-Bootstrap Key Hash");
1623 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
1624 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1625 i_pubkey_hash = test_hash;
1626 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
1627 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
1628 wpabuf_free(pi);
1629 pi = NULL;
1630 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
1631 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
1632 wpabuf_free(pi);
1633 pi = wpabuf_alloc(2 * auth->curve->prime_len);
1634 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
1635 goto fail;
1636 }
1637 #endif /* CONFIG_TESTING_OPTIONS */
1638
1639 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
1640 i_pubkey_hash, neg_freq);
1641 if (!auth->req_msg)
1642 goto fail;
1643
1644 out:
1645 wpabuf_free(pi);
1646 return auth;
1647 fail:
1648 dpp_auth_deinit(auth);
1649 auth = NULL;
1650 goto out;
1651 }
1652
1653
dpp_build_conf_req_attr(struct dpp_authentication * auth,const char * json)1654 static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
1655 const char *json)
1656 {
1657 size_t nonce_len;
1658 size_t json_len, clear_len;
1659 struct wpabuf *clear = NULL, *msg = NULL;
1660 u8 *wrapped;
1661 size_t attr_len;
1662
1663 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
1664
1665 nonce_len = auth->curve->nonce_len;
1666 if (random_get_bytes(auth->e_nonce, nonce_len)) {
1667 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
1668 goto fail;
1669 }
1670 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
1671 json_len = os_strlen(json);
1672 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", (u8 *)json, json_len);
1673
1674 /* { E-nonce, configAttrib }ke */
1675 clear_len = 4 + nonce_len + 4 + json_len;
1676 clear = wpabuf_alloc(clear_len);
1677 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
1678 #ifdef CONFIG_TESTING_OPTIONS
1679 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
1680 attr_len += 5;
1681 #endif /* CONFIG_TESTING_OPTIONS */
1682 msg = wpabuf_alloc(attr_len);
1683 if (!clear || !msg)
1684 goto fail;
1685
1686 #ifdef CONFIG_TESTING_OPTIONS
1687 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
1688 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
1689 goto skip_e_nonce;
1690 }
1691 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
1692 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
1693 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
1694 wpabuf_put_le16(clear, nonce_len - 1);
1695 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
1696 goto skip_e_nonce;
1697 }
1698 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
1699 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1700 goto skip_wrapped_data;
1701 }
1702 #endif /* CONFIG_TESTING_OPTIONS */
1703
1704 /* E-nonce */
1705 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
1706 wpabuf_put_le16(clear, nonce_len);
1707 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
1708
1709 #ifdef CONFIG_TESTING_OPTIONS
1710 skip_e_nonce:
1711 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
1712 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
1713 goto skip_conf_attr_obj;
1714 }
1715 #endif /* CONFIG_TESTING_OPTIONS */
1716
1717 /* configAttrib */
1718 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
1719 wpabuf_put_le16(clear, json_len);
1720 wpabuf_put_data(clear, json, json_len);
1721
1722 #ifdef CONFIG_TESTING_OPTIONS
1723 skip_conf_attr_obj:
1724 #endif /* CONFIG_TESTING_OPTIONS */
1725
1726 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1727 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1728 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1729
1730 /* No AES-SIV AD */
1731 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
1732 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
1733 wpabuf_head(clear), wpabuf_len(clear),
1734 0, NULL, NULL, wrapped) < 0)
1735 goto fail;
1736 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1737 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
1738
1739 #ifdef CONFIG_TESTING_OPTIONS
1740 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
1741 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1742 dpp_build_attr_status(msg, DPP_STATUS_OK);
1743 }
1744 skip_wrapped_data:
1745 #endif /* CONFIG_TESTING_OPTIONS */
1746
1747 wpa_hexdump_buf(MSG_DEBUG,
1748 "DPP: Configuration Request frame attributes", msg);
1749 wpabuf_free(clear);
1750 return msg;
1751
1752 fail:
1753 wpabuf_free(clear);
1754 wpabuf_free(msg);
1755 return NULL;
1756 }
1757
1758
dpp_write_adv_proto(struct wpabuf * buf)1759 static void dpp_write_adv_proto(struct wpabuf *buf)
1760 {
1761 /* Advertisement Protocol IE */
1762 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
1763 wpabuf_put_u8(buf, 8); /* Length */
1764 wpabuf_put_u8(buf, 0x7f);
1765 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
1766 wpabuf_put_u8(buf, 5);
1767 wpabuf_put_be24(buf, OUI_WFA);
1768 wpabuf_put_u8(buf, DPP_OUI_TYPE);
1769 wpabuf_put_u8(buf, 0x01);
1770 }
1771
1772
dpp_write_gas_query(struct wpabuf * buf,struct wpabuf * query)1773 static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
1774 {
1775 /* GAS Query */
1776 wpabuf_put_le16(buf, wpabuf_len(query));
1777 wpabuf_put_buf(buf, query);
1778 }
1779
1780
dpp_build_conf_req(struct dpp_authentication * auth,const char * json)1781 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
1782 const char *json)
1783 {
1784 struct wpabuf *buf, *conf_req;
1785
1786 conf_req = dpp_build_conf_req_attr(auth, json);
1787 if (!conf_req) {
1788 wpa_printf(MSG_DEBUG,
1789 "DPP: No configuration request data available");
1790 return NULL;
1791 }
1792
1793 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
1794 if (!buf) {
1795 wpabuf_free(conf_req);
1796 return NULL;
1797 }
1798
1799 dpp_write_adv_proto(buf);
1800 dpp_write_gas_query(buf, conf_req);
1801 wpabuf_free(conf_req);
1802 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
1803
1804 return buf;
1805 }
1806
1807
dpp_build_conf_req_helper(struct dpp_authentication * auth,const char * name,enum dpp_netrole netrole,const char * mud_url,int * opclasses)1808 struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
1809 const char *name,
1810 enum dpp_netrole netrole,
1811 const char *mud_url, int *opclasses)
1812 {
1813 size_t len, name_len;
1814 const char *tech = "infra";
1815 const char *dpp_name;
1816 struct wpabuf *buf, *json;
1817
1818 #ifdef CONFIG_TESTING_OPTIONS
1819 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
1820 static const char *bogus_tech = "knfra";
1821
1822 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
1823 tech = bogus_tech;
1824 }
1825 #endif /* CONFIG_TESTING_OPTIONS */
1826
1827 dpp_name = name ? name : "Test";
1828 name_len = os_strlen(dpp_name);
1829
1830 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
1831 if (mud_url && mud_url[0])
1832 len += 10 + os_strlen(mud_url);
1833 json = wpabuf_alloc(len);
1834 if (!json)
1835 return NULL;
1836
1837 json_start_object(json, NULL);
1838 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
1839 wpabuf_free(json);
1840 return NULL;
1841 }
1842 json_value_sep(json);
1843 json_add_string(json, "wi-fi_tech", tech);
1844 json_value_sep(json);
1845 json_add_string(json, "netRole", dpp_netrole_str(netrole));
1846 if (mud_url && mud_url[0]) {
1847 json_value_sep(json);
1848 json_add_string(json, "mudurl", mud_url);
1849 }
1850 if (opclasses) {
1851 int i;
1852
1853 json_value_sep(json);
1854 json_start_array(json, "bandSupport");
1855 for (i = 0; opclasses[i]; i++)
1856 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
1857 json_end_array(json);
1858 }
1859 json_end_object(json);
1860
1861 buf = dpp_build_conf_req(auth, wpabuf_head(json));
1862 wpabuf_free(json);
1863
1864 return buf;
1865 }
1866
1867
dpp_auth_success(struct dpp_authentication * auth)1868 static void dpp_auth_success(struct dpp_authentication *auth)
1869 {
1870 wpa_printf(MSG_DEBUG,
1871 "DPP: Authentication success - clear temporary keys");
1872 os_memset(auth->Mx, 0, sizeof(auth->Mx));
1873 auth->Mx_len = 0;
1874 os_memset(auth->Nx, 0, sizeof(auth->Nx));
1875 auth->Nx_len = 0;
1876 os_memset(auth->Lx, 0, sizeof(auth->Lx));
1877 auth->Lx_len = 0;
1878 os_memset(auth->k1, 0, sizeof(auth->k1));
1879 os_memset(auth->k2, 0, sizeof(auth->k2));
1880
1881 auth->auth_success = 1;
1882 }
1883
1884
dpp_gen_r_auth(struct dpp_authentication * auth,u8 * r_auth)1885 static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
1886 {
1887 struct wpabuf *pix, *prx, *bix, *brx;
1888 const u8 *addr[7];
1889 size_t len[7];
1890 size_t i, num_elem = 0;
1891 size_t nonce_len;
1892 u8 zero = 0;
1893 int res = -1;
1894
1895 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1896 nonce_len = auth->curve->nonce_len;
1897
1898 if (auth->initiator) {
1899 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1900 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1901 if (auth->own_bi)
1902 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1903 else
1904 bix = NULL;
1905 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1906 } else {
1907 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1908 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1909 if (auth->peer_bi)
1910 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1911 else
1912 bix = NULL;
1913 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1914 }
1915 if (!pix || !prx || !brx)
1916 goto fail;
1917
1918 addr[num_elem] = auth->i_nonce;
1919 len[num_elem] = nonce_len;
1920 num_elem++;
1921
1922 addr[num_elem] = auth->r_nonce;
1923 len[num_elem] = nonce_len;
1924 num_elem++;
1925
1926 addr[num_elem] = wpabuf_head(pix);
1927 len[num_elem] = wpabuf_len(pix) / 2;
1928 num_elem++;
1929
1930 addr[num_elem] = wpabuf_head(prx);
1931 len[num_elem] = wpabuf_len(prx) / 2;
1932 num_elem++;
1933
1934 if (bix) {
1935 addr[num_elem] = wpabuf_head(bix);
1936 len[num_elem] = wpabuf_len(bix) / 2;
1937 num_elem++;
1938 }
1939
1940 addr[num_elem] = wpabuf_head(brx);
1941 len[num_elem] = wpabuf_len(brx) / 2;
1942 num_elem++;
1943
1944 addr[num_elem] = &zero;
1945 len[num_elem] = 1;
1946 num_elem++;
1947
1948 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
1949 for (i = 0; i < num_elem; i++)
1950 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
1951 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
1952 if (res == 0)
1953 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
1954 auth->curve->hash_len);
1955 fail:
1956 wpabuf_free(pix);
1957 wpabuf_free(prx);
1958 wpabuf_free(bix);
1959 wpabuf_free(brx);
1960 return res;
1961 }
1962
dpp_gen_i_auth(struct dpp_authentication * auth,u8 * i_auth)1963 static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
1964 {
1965 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
1966 const u8 *addr[7];
1967 size_t len[7];
1968 size_t i, num_elem = 0;
1969 size_t nonce_len;
1970 u8 one = 1;
1971 int res = -1;
1972
1973 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
1974 nonce_len = auth->curve->nonce_len;
1975
1976 if (auth->initiator) {
1977 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1978 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1979 if (auth->own_bi)
1980 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1981 else
1982 bix = NULL;
1983 if (!auth->peer_bi)
1984 goto fail;
1985 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1986 } else {
1987 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
1988 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
1989 if (auth->peer_bi)
1990 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
1991 else
1992 bix = NULL;
1993 if (!auth->own_bi)
1994 goto fail;
1995 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
1996 }
1997 if (!pix || !prx || !brx)
1998 goto fail;
1999
2000 addr[num_elem] = auth->r_nonce;
2001 len[num_elem] = nonce_len;
2002 num_elem++;
2003
2004 addr[num_elem] = auth->i_nonce;
2005 len[num_elem] = nonce_len;
2006 num_elem++;
2007
2008 addr[num_elem] = wpabuf_head(prx);
2009 len[num_elem] = wpabuf_len(prx) / 2;
2010 num_elem++;
2011
2012 addr[num_elem] = wpabuf_head(pix);
2013 len[num_elem] = wpabuf_len(pix) / 2;
2014 num_elem++;
2015
2016 addr[num_elem] = wpabuf_head(brx);
2017 len[num_elem] = wpabuf_len(brx) / 2;
2018 num_elem++;
2019
2020 if (bix) {
2021 addr[num_elem] = wpabuf_head(bix);
2022 len[num_elem] = wpabuf_len(bix) / 2;
2023 num_elem++;
2024 }
2025
2026 addr[num_elem] = &one;
2027 len[num_elem] = 1;
2028 num_elem++;
2029
2030 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2031 for (i = 0; i < num_elem; i++)
2032 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
2033 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
2034 if (res == 0)
2035 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2036 auth->curve->hash_len);
2037 fail:
2038 wpabuf_free(pix);
2039 wpabuf_free(prx);
2040 wpabuf_free(bix);
2041 wpabuf_free(brx);
2042 return res;
2043 }
2044
2045
dpp_auth_derive_l_responder(struct dpp_authentication * auth)2046 static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2047 {
2048 struct crypto_ec_group *group;
2049 struct crypto_ec_point *l = NULL;
2050 struct crypto_ec_point *BI_point;
2051 struct crypto_bignum *lx, *sum, *q;
2052 struct crypto_bignum *bR_bn, *pR_bn;
2053 int ret = -1;
2054
2055 /* L = ((bR + pR) modulo q) * BI */
2056
2057 sum = crypto_bignum_init();
2058 q = crypto_bignum_init();
2059 lx = crypto_bignum_init();
2060 if (!sum || !q || !lx)
2061 goto fail;
2062
2063 BI_point = crypto_ec_get_public_key(auth->peer_bi->pubkey);
2064 group = crypto_ec_get_group_from_key(auth->peer_bi->pubkey);
2065 bR_bn = crypto_ec_get_private_key(auth->own_bi->pubkey);
2066 pR_bn = crypto_ec_get_private_key(auth->own_protocol_key);
2067
2068 if (!bR_bn || !pR_bn)
2069 goto fail;
2070
2071 if ((crypto_get_order(group, q) != 0) ||
2072 (crypto_bignum_addmod(sum, bR_bn, pR_bn, q) != 0))
2073 goto fail;
2074
2075 l = crypto_ec_point_init((struct crypto_ec *)group);
2076 if (!l || (crypto_ec_point_mul((struct crypto_ec *)group, BI_point, sum, l) != 0) ||
2077 (crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0)) {
2078 wpa_printf(MSG_ERROR,
2079 "OpenSSL: failed: %s", __func__);
2080 goto fail;
2081 }
2082 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2083 goto fail;
2084 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2085 auth->Lx_len = auth->secret_len;
2086 ret = 0;
2087 fail:
2088 crypto_ec_point_deinit(l, 1);
2089 crypto_bignum_deinit(lx, 0);
2090 crypto_bignum_deinit(sum, 0);
2091 crypto_bignum_deinit(q, 0);
2092
2093 return ret;
2094 }
2095
dpp_auth_derive_l_initiator(struct dpp_authentication * auth)2096 static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2097 {
2098 struct crypto_ec_group *group;
2099 struct crypto_ec_point *l = NULL, *sum = NULL;
2100 struct crypto_ec_point *BR_point, *PR_point;
2101 struct crypto_bignum *lx;
2102 struct crypto_bignum *bI_bn;
2103 int ret = -1;
2104
2105 /* L = bI * (BR + PR) */
2106
2107 lx = crypto_bignum_init();
2108 if (!lx)
2109 goto fail;
2110 BR_point = crypto_ec_get_public_key(auth->peer_bi->pubkey);
2111 PR_point = crypto_ec_get_public_key(auth->peer_protocol_key);
2112
2113 group = crypto_ec_get_group_from_key(auth->own_bi->pubkey);
2114 bI_bn = crypto_ec_get_private_key(auth->own_bi->pubkey);
2115 if (!group || !bI_bn)
2116 goto fail;
2117 sum = crypto_ec_point_init((struct crypto_ec *)group);
2118 l = crypto_ec_point_init((struct crypto_ec *)group);
2119 if (!sum || !l ||
2120 crypto_ec_point_add((struct crypto_ec *)group, BR_point, PR_point, sum) != 0 ||
2121 crypto_ec_point_mul((struct crypto_ec *)group, sum, bI_bn, l) != 0 ||
2122 crypto_ec_get_affine_coordinates((struct crypto_ec *)group, l, lx, NULL) != 0) {
2123 wpa_printf(MSG_ERROR,
2124 "OpenSSL: failed: %s", __func__);
2125 goto fail;
2126 }
2127
2128 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
2129 goto fail;
2130 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
2131 auth->Lx_len = auth->secret_len;
2132 ret = 0;
2133 fail:
2134 crypto_ec_point_deinit(l, 1);
2135 crypto_ec_point_deinit(sum, 1);
2136 crypto_bignum_deinit(lx, 0);
2137
2138
2139 return ret;
2140 }
2141
2142
dpp_auth_build_resp_ok(struct dpp_authentication * auth)2143 static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
2144 {
2145 size_t nonce_len;
2146 size_t secret_len;
2147 struct wpabuf *msg, *pr = NULL;
2148 u8 r_auth[4 + DPP_MAX_HASH_LEN];
2149 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
2150 size_t wrapped_r_auth_len;
2151 int ret = -1;
2152 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
2153 enum dpp_status_error status = DPP_STATUS_OK;
2154 #ifdef CONFIG_TESTING_OPTIONS
2155 u8 test_hash[SHA256_MAC_LEN];
2156 #endif /* CONFIG_TESTING_OPTIONS */
2157
2158 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2159 if (!auth->own_bi)
2160 return -1;
2161
2162 #ifdef CONFIG_TESTING_OPTIONS
2163 if (dpp_nonce_override_len > 0) {
2164 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
2165 nonce_len = dpp_nonce_override_len;
2166 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
2167 } else {
2168 nonce_len = auth->curve->nonce_len;
2169 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2170 wpa_printf(MSG_ERROR,
2171 "DPP: Failed to generate R-nonce");
2172 goto fail;
2173 }
2174 }
2175 #else /* CONFIG_TESTING_OPTIONS */
2176 nonce_len = auth->curve->nonce_len;
2177 if (random_get_bytes(auth->r_nonce, nonce_len)) {
2178 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
2179 goto fail;
2180 }
2181 #endif /* CONFIG_TESTING_OPTIONS */
2182 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
2183
2184 crypto_ec_free_key(auth->own_protocol_key);
2185 #ifdef CONFIG_TESTING_OPTIONS
2186 if (dpp_protocol_key_override_len) {
2187 const struct dpp_curve_params *tmp_curve;
2188
2189 wpa_printf(MSG_INFO,
2190 "DPP: TESTING - override protocol key");
2191 auth->own_protocol_key = dpp_set_keypair(
2192 &tmp_curve, dpp_protocol_key_override,
2193 dpp_protocol_key_override_len);
2194 } else {
2195 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2196 }
2197 #else /* CONFIG_TESTING_OPTIONS */
2198 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2199 #endif /* CONFIG_TESTING_OPTIONS */
2200 if (!auth->own_protocol_key)
2201 goto fail;
2202
2203 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2204 if (!pr)
2205 goto fail;
2206
2207 /* ECDH: N = pR * PI */
2208 if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
2209 auth->Nx, &secret_len) < 0)
2210 goto fail;
2211
2212 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
2213 auth->Nx, auth->secret_len);
2214 auth->Nx_len = auth->secret_len;
2215
2216 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
2217 auth->curve->hash_len) < 0)
2218 goto fail;
2219
2220 if (auth->own_bi && auth->peer_bi) {
2221 /* Mutual authentication */
2222 if (dpp_auth_derive_l_responder(auth) < 0)
2223 goto fail;
2224 }
2225
2226 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
2227 goto fail;
2228
2229 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2230 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
2231 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
2232 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
2233 goto fail;
2234 #ifdef CONFIG_TESTING_OPTIONS
2235 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
2236 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
2237 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2238 }
2239 #endif /* CONFIG_TESTING_OPTIONS */
2240 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2241 r_auth, 4 + auth->curve->hash_len,
2242 0, NULL, NULL, wrapped_r_auth) < 0)
2243 goto fail;
2244 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
2245 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
2246 wrapped_r_auth, wrapped_r_auth_len);
2247 w_r_auth = wrapped_r_auth;
2248
2249 r_pubkey_hash = auth->own_bi->pubkey_hash;
2250 if (auth->peer_bi)
2251 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2252 else
2253 i_pubkey_hash = NULL;
2254
2255 i_nonce = auth->i_nonce;
2256 r_nonce = auth->r_nonce;
2257
2258 #ifdef CONFIG_TESTING_OPTIONS
2259 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2260 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2261 r_pubkey_hash = NULL;
2262 } else if (dpp_test ==
2263 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2264 wpa_printf(MSG_INFO,
2265 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2266 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2267 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2268 r_pubkey_hash = test_hash;
2269 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2270 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2271 i_pubkey_hash = NULL;
2272 } else if (dpp_test ==
2273 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2274 wpa_printf(MSG_INFO,
2275 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2276 if (i_pubkey_hash)
2277 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2278 else
2279 os_memset(test_hash, 0, SHA256_MAC_LEN);
2280 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2281 i_pubkey_hash = test_hash;
2282 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
2283 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
2284 wpabuf_free(pr);
2285 pr = NULL;
2286 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
2287 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
2288 wpabuf_free(pr);
2289 pr = wpabuf_alloc(2 * auth->curve->prime_len);
2290 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
2291 goto fail;
2292 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
2293 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
2294 w_r_auth = NULL;
2295 wrapped_r_auth_len = 0;
2296 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2297 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2298 status = 255;
2299 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
2300 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2301 status = 254;
2302 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
2303 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
2304 r_nonce = NULL;
2305 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2306 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2307 i_nonce = NULL;
2308 }
2309 #endif /* CONFIG_TESTING_OPTIONS */
2310
2311 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
2312 r_pubkey_hash, i_pubkey_hash,
2313 r_nonce, i_nonce,
2314 w_r_auth, wrapped_r_auth_len,
2315 auth->k2);
2316 if (!msg)
2317 goto fail;
2318 wpabuf_free(auth->resp_msg);
2319 auth->resp_msg = msg;
2320 ret = 0;
2321 fail:
2322 wpabuf_free(pr);
2323 return ret;
2324 }
2325
2326
dpp_auth_build_resp_status(struct dpp_authentication * auth,enum dpp_status_error status)2327 static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
2328 enum dpp_status_error status)
2329 {
2330 struct wpabuf *msg;
2331 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
2332 #ifdef CONFIG_TESTING_OPTIONS
2333 u8 test_hash[SHA256_MAC_LEN];
2334 #endif /* CONFIG_TESTING_OPTIONS */
2335
2336 if (!auth->own_bi)
2337 return -1;
2338 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2339
2340 r_pubkey_hash = auth->own_bi->pubkey_hash;
2341 if (auth->peer_bi)
2342 i_pubkey_hash = auth->peer_bi->pubkey_hash;
2343 else
2344 i_pubkey_hash = NULL;
2345
2346 i_nonce = auth->i_nonce;
2347
2348 #ifdef CONFIG_TESTING_OPTIONS
2349 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2350 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2351 r_pubkey_hash = NULL;
2352 } else if (dpp_test ==
2353 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2354 wpa_printf(MSG_INFO,
2355 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2356 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2357 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2358 r_pubkey_hash = test_hash;
2359 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2360 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2361 i_pubkey_hash = NULL;
2362 } else if (dpp_test ==
2363 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
2364 wpa_printf(MSG_INFO,
2365 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2366 if (i_pubkey_hash)
2367 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2368 else
2369 os_memset(test_hash, 0, SHA256_MAC_LEN);
2370 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2371 i_pubkey_hash = test_hash;
2372 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
2373 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2374 status = 255;
2375 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
2376 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
2377 i_nonce = NULL;
2378 }
2379 #endif /* CONFIG_TESTING_OPTIONS */
2380
2381 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
2382 r_pubkey_hash, i_pubkey_hash,
2383 NULL, i_nonce, NULL, 0, auth->k1);
2384 if (!msg)
2385 return -1;
2386 wpabuf_free(auth->resp_msg);
2387 auth->resp_msg = msg;
2388 return 0;
2389 }
2390
2391
2392 struct dpp_authentication *
dpp_auth_req_rx(void * msg_ctx,u8 dpp_allowed_roles,int qr_mutual,struct dpp_bootstrap_info * peer_bi,struct dpp_bootstrap_info * own_bi,unsigned int curr_chan,const u8 * hdr,const u8 * attr_start,size_t attr_len)2393 dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
2394 struct dpp_bootstrap_info *peer_bi,
2395 struct dpp_bootstrap_info *own_bi,
2396 unsigned int curr_chan, const u8 *hdr, const u8 *attr_start,
2397 size_t attr_len)
2398 {
2399 struct crypto_key *pi = NULL;
2400 size_t secret_len;
2401 const u8 *addr[2];
2402 size_t len[2];
2403 u8 *unwrapped = NULL;
2404 size_t unwrapped_len = 0;
2405 const u8 *wrapped_data;
2406 const u8 *i_proto;
2407 const u8 *i_nonce;
2408 const u8 *i_capab;
2409 const u8 *i_bootstrap;
2410 u16 wrapped_data_len;
2411 u16 i_proto_len;
2412 u16 i_nonce_len;
2413 u16 i_capab_len;
2414 u16 i_bootstrap_len;
2415 struct dpp_authentication *auth = NULL;
2416
2417 #ifdef CONFIG_TESTING_OPTIONS
2418 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
2419 wpa_printf(MSG_INFO,
2420 "DPP: TESTING - stop at Authentication Request");
2421 return NULL;
2422 }
2423 #endif /* CONFIG_TESTING_OPTIONS */
2424
2425 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2426 &wrapped_data_len);
2427 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2428 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
2429 "Missing or invalid required Wrapped Data attribute");
2430 return NULL;
2431 }
2432 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
2433 wrapped_data, wrapped_data_len);
2434 attr_len = wrapped_data - 4 - attr_start;
2435
2436 auth = os_zalloc(sizeof(*auth));
2437 if (!auth)
2438 goto fail;
2439 auth->msg_ctx = msg_ctx;
2440 auth->peer_bi = peer_bi;
2441 auth->own_bi = own_bi;
2442 auth->curve = own_bi->curve;
2443 auth->curr_chan = curr_chan;
2444
2445 auth->peer_version = 1; /* default to the first version */
2446
2447 #if 0
2448 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
2449 &channel_len);
2450 if (channel) {
2451 //int neg_freq;
2452
2453 if (channel_len < 2) {
2454 dpp_auth_fail(auth, "Too short Channel attribute");
2455 goto fail;
2456 }
2457
2458 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
2459 wpa_printf(MSG_DEBUG,
2460 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
2461 channel[0], channel[1], neg_freq);
2462 if (neg_freq < 0) {
2463 dpp_auth_fail(auth,
2464 "Unsupported Channel attribute value");
2465 goto fail;
2466 }
2467
2468 if (auth->curr_freq != (unsigned int) neg_freq) {
2469 wpa_printf(MSG_DEBUG,
2470 "DPP: Changing negotiation channel from %u MHz to %u MHz",
2471 freq, neg_freq);
2472 auth->curr_freq = neg_freq;
2473 }
2474 /* rename it to chan */
2475 auth->curr_chan = *channel;
2476 }
2477 #endif
2478
2479 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
2480 &i_proto_len);
2481 if (!i_proto) {
2482 dpp_auth_fail(auth,
2483 "Missing required Initiator Protocol Key attribute");
2484 goto fail;
2485 }
2486 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
2487 i_proto, i_proto_len);
2488
2489 /* M = bR * PI */
2490 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
2491 if (!pi) {
2492 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
2493 goto fail;
2494 }
2495 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
2496
2497 if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
2498 goto fail;
2499 auth->secret_len = secret_len;
2500
2501 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2502 auth->Mx, auth->secret_len);
2503 auth->Mx_len = auth->secret_len;
2504
2505 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2506 auth->curve->hash_len) < 0)
2507 goto fail;
2508
2509 addr[0] = hdr;
2510 len[0] = DPP_HDR_LEN;
2511 addr[1] = attr_start;
2512 len[1] = attr_len;
2513 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2514 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2515 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2516 wrapped_data, wrapped_data_len);
2517 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2518 unwrapped = os_malloc(unwrapped_len);
2519 if (!unwrapped)
2520 goto fail;
2521 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
2522 wrapped_data, wrapped_data_len,
2523 2, addr, len, unwrapped) < 0) {
2524 dpp_auth_fail(auth, "AES-SIV decryption failed");
2525 goto fail;
2526 }
2527 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2528 unwrapped, unwrapped_len);
2529
2530 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2531 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
2532 goto fail;
2533 }
2534
2535 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2536 &i_nonce_len);
2537 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
2538 dpp_auth_fail(auth, "Missing or invalid I-nonce");
2539 goto fail;
2540 }
2541 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2542 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
2543
2544 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
2545 DPP_ATTR_I_CAPABILITIES,
2546 &i_capab_len);
2547 if (!i_capab || i_capab_len < 1) {
2548 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
2549 goto fail;
2550 }
2551 auth->i_capab = i_capab[0];
2552 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
2553
2554 bin_clear_free(unwrapped, unwrapped_len);
2555 unwrapped = NULL;
2556
2557 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
2558 case DPP_CAPAB_ENROLLEE:
2559 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
2560 wpa_printf(MSG_DEBUG,
2561 "DPP: Local policy does not allow Configurator role");
2562 goto not_compatible;
2563 }
2564 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2565 auth->configurator = 1;
2566 break;
2567 case DPP_CAPAB_CONFIGURATOR:
2568 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
2569 wpa_printf(MSG_DEBUG,
2570 "DPP: Local policy does not allow Enrollee role");
2571 goto not_compatible;
2572 }
2573 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2574 auth->configurator = 0;
2575 break;
2576 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
2577 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
2578 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
2579 auth->configurator = 0;
2580 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
2581 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
2582 auth->configurator = 1;
2583 } else {
2584 wpa_printf(MSG_DEBUG,
2585 "DPP: Local policy does not allow Configurator/Enrollee role");
2586 goto not_compatible;
2587 }
2588 break;
2589 default:
2590 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
2591 goto fail;
2592 }
2593
2594 auth->peer_protocol_key = pi;
2595 pi = NULL;
2596 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
2597 char hex[SHA256_MAC_LEN * 2 + 1];
2598
2599 wpa_printf(MSG_DEBUG,
2600 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
2601 if (dpp_auth_build_resp_status(auth,
2602 DPP_STATUS_RESPONSE_PENDING) < 0)
2603 goto fail;
2604 i_bootstrap = dpp_get_attr(attr_start, attr_len,
2605 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
2606 &i_bootstrap_len);
2607 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
2608 auth->response_pending = 1;
2609 os_memcpy(auth->waiting_pubkey_hash,
2610 i_bootstrap, i_bootstrap_len);
2611 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
2612 i_bootstrap_len);
2613 } else {
2614 hex[0] = '\0';
2615 }
2616
2617 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
2618 "%s", hex);
2619 return auth;
2620 }
2621 if (dpp_auth_build_resp_ok(auth) < 0)
2622 goto fail;
2623
2624 return auth;
2625
2626 not_compatible:
2627 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2628 "i-capab=0x%02x", auth->i_capab);
2629 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
2630 auth->configurator = 1;
2631 else
2632 auth->configurator = 0;
2633 auth->peer_protocol_key = pi;
2634 pi = NULL;
2635 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
2636 goto fail;
2637
2638 auth->remove_on_tx_status = 1;
2639 return auth;
2640 fail:
2641 bin_clear_free(unwrapped, unwrapped_len);
2642 crypto_ec_free_key(pi);
2643 dpp_auth_deinit(auth);
2644 return NULL;
2645 }
2646
2647
dpp_notify_new_qr_code(struct dpp_authentication * auth,struct dpp_bootstrap_info * peer_bi)2648 int dpp_notify_new_qr_code(struct dpp_authentication *auth,
2649 struct dpp_bootstrap_info *peer_bi)
2650 {
2651 if (!auth || !auth->response_pending ||
2652 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
2653 SHA256_MAC_LEN) != 0)
2654 return 0;
2655
2656 wpa_printf(MSG_DEBUG,
2657 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
2658 MACSTR, MAC2STR(auth->peer_mac_addr));
2659 auth->peer_bi = peer_bi;
2660
2661 if (dpp_auth_build_resp_ok(auth) < 0)
2662 return -1;
2663
2664 return 1;
2665 }
2666
2667
dpp_auth_build_conf(struct dpp_authentication * auth,enum dpp_status_error status)2668 static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
2669 enum dpp_status_error status)
2670 {
2671 struct wpabuf *msg;
2672 u8 i_auth[4 + DPP_MAX_HASH_LEN];
2673 size_t i_auth_len;
2674 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
2675 size_t r_nonce_len;
2676 const u8 *addr[2];
2677 size_t len[2], attr_len;
2678 u8 *wrapped_i_auth;
2679 u8 *wrapped_r_nonce;
2680 u8 *attr_start, *attr_end;
2681 const u8 *r_pubkey_hash, *i_pubkey_hash;
2682 #ifdef CONFIG_TESTING_OPTIONS
2683 u8 test_hash[SHA256_MAC_LEN];
2684 #endif /* CONFIG_TESTING_OPTIONS */
2685
2686 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
2687
2688 i_auth_len = 4 + auth->curve->hash_len;
2689 r_nonce_len = 4 + auth->curve->nonce_len;
2690 /* Build DPP Authentication Confirmation frame attributes */
2691 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
2692 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
2693 #ifdef CONFIG_TESTING_OPTIONS
2694 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
2695 attr_len += 5;
2696 #endif /* CONFIG_TESTING_OPTIONS */
2697 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
2698 if (!msg)
2699 goto fail;
2700
2701 attr_start = wpabuf_put(msg, 0);
2702
2703 r_pubkey_hash = auth->peer_bi->pubkey_hash;
2704 if (auth->own_bi)
2705 i_pubkey_hash = auth->own_bi->pubkey_hash;
2706 else
2707 i_pubkey_hash = NULL;
2708
2709 #ifdef CONFIG_TESTING_OPTIONS
2710 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
2711 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
2712 goto skip_status;
2713 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
2714 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2715 status = 254;
2716 }
2717 #endif /* CONFIG_TESTING_OPTIONS */
2718
2719 /* DPP Status */
2720 dpp_build_attr_status(msg, status);
2721
2722 #ifdef CONFIG_TESTING_OPTIONS
2723 skip_status:
2724 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
2725 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2726 r_pubkey_hash = NULL;
2727 } else if (dpp_test ==
2728 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
2729 wpa_printf(MSG_INFO,
2730 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2731 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2732 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2733 r_pubkey_hash = test_hash;
2734 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
2735 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2736 i_pubkey_hash = NULL;
2737 } else if (dpp_test ==
2738 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
2739 wpa_printf(MSG_INFO,
2740 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2741 if (i_pubkey_hash)
2742 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2743 else
2744 os_memset(test_hash, 0, SHA256_MAC_LEN);
2745 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2746 i_pubkey_hash = test_hash;
2747 }
2748 #endif /* CONFIG_TESTING_OPTIONS */
2749
2750 /* Responder Bootstrapping Key Hash */
2751 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
2752
2753 /* Initiator Bootstrapping Key Hash (mutual authentication) */
2754 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
2755
2756 #ifdef CONFIG_TESTING_OPTIONS
2757 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
2758 goto skip_wrapped_data;
2759 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
2760 i_auth_len = 0;
2761 #endif /* CONFIG_TESTING_OPTIONS */
2762
2763 attr_end = wpabuf_put(msg, 0);
2764
2765 /* OUI, OUI type, Crypto Suite, DPP frame type */
2766 addr[0] = wpabuf_head_u8(msg) + 2;
2767 len[0] = 3 + 1 + 1 + 1;
2768 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2769
2770 /* Attributes before Wrapped Data */
2771 addr[1] = attr_start;
2772 len[1] = attr_end - attr_start;
2773 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2774
2775 if (status == DPP_STATUS_OK) {
2776 /* I-auth wrapped with ke */
2777 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2778 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
2779 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
2780
2781 #ifdef CONFIG_TESTING_OPTIONS
2782 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
2783 goto skip_i_auth;
2784 #endif /* CONFIG_TESTING_OPTIONS */
2785
2786 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
2787 * 1) */
2788 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
2789 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
2790 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
2791 goto fail;
2792
2793 #ifdef CONFIG_TESTING_OPTIONS
2794 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
2795 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
2796 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
2797 }
2798 skip_i_auth:
2799 #endif /* CONFIG_TESTING_OPTIONS */
2800 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2801 i_auth, i_auth_len,
2802 2, addr, len, wrapped_i_auth) < 0)
2803 goto fail;
2804 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
2805 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
2806 } else {
2807 /* R-nonce wrapped with k2 */
2808 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2809 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
2810 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
2811
2812 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
2813 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
2814 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
2815
2816 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
2817 r_nonce, r_nonce_len,
2818 2, addr, len, wrapped_r_nonce) < 0)
2819 goto fail;
2820 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
2821 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
2822 }
2823
2824 #ifdef CONFIG_TESTING_OPTIONS
2825 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
2826 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2827 dpp_build_attr_status(msg, DPP_STATUS_OK);
2828 }
2829 skip_wrapped_data:
2830 #endif /* CONFIG_TESTING_OPTIONS */
2831
2832 wpa_hexdump_buf(MSG_DEBUG,
2833 "DPP: Authentication Confirmation frame attributes",
2834 msg);
2835 if (status == DPP_STATUS_OK)
2836 dpp_auth_success(auth);
2837
2838 return msg;
2839
2840 fail:
2841 wpabuf_free(msg);
2842 return NULL;
2843 }
2844
2845
2846 static void
dpp_auth_resp_rx_status(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,const u8 * wrapped_data,u16 wrapped_data_len,enum dpp_status_error status)2847 dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
2848 const u8 *attr_start, size_t attr_len,
2849 const u8 *wrapped_data, u16 wrapped_data_len,
2850 enum dpp_status_error status)
2851 {
2852 const u8 *addr[2];
2853 size_t len[2];
2854 u8 *unwrapped = NULL;
2855 size_t unwrapped_len = 0;
2856 const u8 *i_nonce, *r_capab;
2857 u16 i_nonce_len, r_capab_len;
2858
2859 if (status == DPP_STATUS_NOT_COMPATIBLE) {
2860 wpa_printf(MSG_DEBUG,
2861 "DPP: Responder reported incompatible roles");
2862 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
2863 wpa_printf(MSG_DEBUG,
2864 "DPP: Responder reported more time needed");
2865 } else {
2866 wpa_printf(MSG_DEBUG,
2867 "DPP: Responder reported failure (status %d)",
2868 status);
2869 dpp_auth_fail(auth, "Responder reported failure");
2870 return;
2871 }
2872
2873 addr[0] = hdr;
2874 len[0] = DPP_HDR_LEN;
2875 addr[1] = attr_start;
2876 len[1] = attr_len;
2877 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2878 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2879 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2880 wrapped_data, wrapped_data_len);
2881 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2882 unwrapped = os_malloc(unwrapped_len);
2883 if (!unwrapped)
2884 goto fail;
2885 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
2886 wrapped_data, wrapped_data_len,
2887 2, addr, len, unwrapped) < 0) {
2888 dpp_auth_fail(auth, "AES-SIV decryption failed");
2889 goto fail;
2890 }
2891 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2892 unwrapped, unwrapped_len);
2893
2894 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2895 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
2896 goto fail;
2897 }
2898
2899 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
2900 &i_nonce_len);
2901 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
2902 dpp_auth_fail(auth, "Missing or invalid I-nonce");
2903 goto fail;
2904 }
2905 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
2906 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
2907 dpp_auth_fail(auth, "I-nonce mismatch");
2908 goto fail;
2909 }
2910
2911 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
2912 DPP_ATTR_R_CAPABILITIES,
2913 &r_capab_len);
2914 if (!r_capab || r_capab_len < 1) {
2915 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
2916 goto fail;
2917 }
2918 auth->r_capab = r_capab[0];
2919 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
2920 if (status == DPP_STATUS_NOT_COMPATIBLE) {
2921 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
2922 "r-capab=0x%02x", auth->r_capab);
2923 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
2924 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
2925
2926 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
2927 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
2928 wpa_msg(auth->msg_ctx, MSG_INFO,
2929 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
2930 role);
2931 } else {
2932 wpa_printf(MSG_DEBUG,
2933 "DPP: Continue waiting for full DPP Authentication Response");
2934 wpa_msg(auth->msg_ctx, MSG_INFO,
2935 DPP_EVENT_RESPONSE_PENDING "%s",
2936 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
2937 }
2938 }
2939 fail:
2940 bin_clear_free(unwrapped, unwrapped_len);
2941 }
2942
2943
2944 struct wpabuf *
dpp_auth_resp_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)2945 dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
2946 const u8 *attr_start, size_t attr_len)
2947 {
2948 struct crypto_key *pr;
2949 size_t secret_len;
2950 const u8 *addr[2];
2951 size_t len[2];
2952 u8 *unwrapped = NULL, *unwrapped2 = NULL;
2953 size_t unwrapped_len = 0, unwrapped2_len = 0;
2954 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
2955 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
2956 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
2957 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
2958 wrapped2_len, r_auth_len;
2959 u8 r_auth2[DPP_MAX_HASH_LEN];
2960 u8 role;
2961
2962 #ifdef CONFIG_TESTING_OPTIONS
2963 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
2964 wpa_printf(MSG_INFO,
2965 "DPP: TESTING - stop at Authentication Response");
2966 return NULL;
2967 }
2968 #endif /* CONFIG_TESTING_OPTIONS */
2969
2970 if (!auth->initiator || !auth->peer_bi) {
2971 dpp_auth_fail(auth, "Unexpected Authentication Response");
2972 return NULL;
2973 }
2974
2975 auth->waiting_auth_resp = 0;
2976
2977 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2978 &wrapped_data_len);
2979 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2980 dpp_auth_fail(auth,
2981 "Missing or invalid required Wrapped Data attribute");
2982 return NULL;
2983 }
2984 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
2985 wrapped_data, wrapped_data_len);
2986
2987 attr_len = wrapped_data - 4 - attr_start;
2988
2989 r_bootstrap = dpp_get_attr(attr_start, attr_len,
2990 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
2991 &r_bootstrap_len);
2992 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
2993 dpp_auth_fail(auth,
2994 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
2995 return NULL;
2996 }
2997 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
2998 r_bootstrap, r_bootstrap_len);
2999 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3000 SHA256_MAC_LEN) != 0) {
3001 dpp_auth_fail(auth,
3002 "Unexpected Responder Bootstrapping Key Hash value");
3003 wpa_hexdump(MSG_DEBUG,
3004 "DPP: Expected Responder Bootstrapping Key Hash",
3005 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3006 return NULL;
3007 }
3008
3009 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3010 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3011 &i_bootstrap_len);
3012 if (i_bootstrap) {
3013 if (i_bootstrap_len != SHA256_MAC_LEN) {
3014 dpp_auth_fail(auth,
3015 "Invalid Initiator Bootstrapping Key Hash attribute");
3016 return NULL;
3017 }
3018 wpa_hexdump(MSG_MSGDUMP,
3019 "DPP: Initiator Bootstrapping Key Hash",
3020 i_bootstrap, i_bootstrap_len);
3021 if (!auth->own_bi ||
3022 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3023 SHA256_MAC_LEN) != 0) {
3024 dpp_auth_fail(auth,
3025 "Initiator Bootstrapping Key Hash attribute did not match");
3026 return NULL;
3027 }
3028 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3029 /* PKEX bootstrapping mandates use of mutual authentication */
3030 dpp_auth_fail(auth,
3031 "Missing Initiator Bootstrapping Key Hash attribute");
3032 return NULL;
3033 }
3034
3035 auth->peer_version = 1; /* default to the first version */
3036
3037 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3038 &status_len);
3039 if (!status || status_len < 1) {
3040 dpp_auth_fail(auth,
3041 "Missing or invalid required DPP Status attribute");
3042 return NULL;
3043 }
3044 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3045 auth->auth_resp_status = status[0];
3046 if (status[0] != DPP_STATUS_OK) {
3047 dpp_auth_resp_rx_status(auth, hdr, attr_start,
3048 attr_len, wrapped_data,
3049 wrapped_data_len, status[0]);
3050 return NULL;
3051 }
3052
3053 if (!i_bootstrap && auth->own_bi) {
3054 wpa_printf(MSG_DEBUG,
3055 "DPP: Responder decided not to use mutual authentication");
3056 auth->own_bi = NULL;
3057 }
3058
3059 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3060 auth->own_bi != NULL);
3061
3062 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3063 &r_proto_len);
3064 if (!r_proto) {
3065 dpp_auth_fail(auth,
3066 "Missing required Responder Protocol Key attribute");
3067 return NULL;
3068 }
3069 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3070 r_proto, r_proto_len);
3071
3072 /* N = pI * PR */
3073 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3074 if (!pr) {
3075 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
3076 return NULL;
3077 }
3078 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3079
3080 if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
3081 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
3082 goto fail;
3083 }
3084 crypto_ec_free_key(auth->peer_protocol_key);
3085 auth->peer_protocol_key = pr;
3086 pr = NULL;
3087
3088 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3089 auth->Nx, auth->secret_len);
3090 auth->Nx_len = auth->secret_len;
3091
3092 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3093 auth->curve->hash_len) < 0)
3094 goto fail;
3095
3096 addr[0] = hdr;
3097 len[0] = DPP_HDR_LEN;
3098 addr[1] = attr_start;
3099 len[1] = attr_len;
3100 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3101 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3102 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3103 wrapped_data, wrapped_data_len);
3104 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3105 unwrapped = os_malloc(unwrapped_len);
3106 if (!unwrapped)
3107 goto fail;
3108 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3109 wrapped_data, wrapped_data_len,
3110 2, addr, len, unwrapped) < 0) {
3111 dpp_auth_fail(auth, "AES-SIV decryption failed");
3112 goto fail;
3113 }
3114 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3115 unwrapped, unwrapped_len);
3116
3117 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3118 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3119 goto fail;
3120 }
3121
3122 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3123 &r_nonce_len);
3124 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3125 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3126 goto fail;
3127 }
3128 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
3129 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
3130
3131 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3132 &i_nonce_len);
3133 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
3134 dpp_auth_fail(auth, "Missing or invalid I-nonce");
3135 goto fail;
3136 }
3137 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3138 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
3139 dpp_auth_fail(auth, "I-nonce mismatch");
3140 goto fail;
3141 }
3142
3143 if (auth->own_bi) {
3144 /* Mutual authentication */
3145 if (dpp_auth_derive_l_initiator(auth) < 0)
3146 goto fail;
3147 }
3148
3149 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3150 DPP_ATTR_R_CAPABILITIES,
3151 &r_capab_len);
3152 if (!r_capab || r_capab_len < 1) {
3153 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
3154 goto fail;
3155 }
3156 auth->r_capab = r_capab[0];
3157 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3158 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3159 if ((auth->allowed_roles ==
3160 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
3161 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
3162 /* Peer selected its role, so move from "either role" to the
3163 * role that is compatible with peer's selection. */
3164 auth->configurator = role == DPP_CAPAB_ENROLLEE;
3165 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
3166 auth->configurator ? "Configurator" : "Enrollee");
3167 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3168 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3169 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
3170 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3171 "Unexpected role in R-capabilities 0x%02x",
3172 role);
3173 if (role != DPP_CAPAB_ENROLLEE &&
3174 role != DPP_CAPAB_CONFIGURATOR)
3175 goto fail;
3176 bin_clear_free(unwrapped, unwrapped_len);
3177 auth->remove_on_tx_status = 1;
3178 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
3179 }
3180
3181 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
3182 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
3183 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
3184 dpp_auth_fail(auth,
3185 "Missing or invalid Secondary Wrapped Data");
3186 goto fail;
3187 }
3188
3189 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3190 wrapped2, wrapped2_len);
3191
3192 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3193 goto fail;
3194
3195 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
3196 unwrapped2 = os_malloc(unwrapped2_len);
3197 if (!unwrapped2)
3198 goto fail;
3199 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3200 wrapped2, wrapped2_len,
3201 0, NULL, NULL, unwrapped2) < 0) {
3202 dpp_auth_fail(auth, "AES-SIV decryption failed");
3203 goto fail;
3204 }
3205 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3206 unwrapped2, unwrapped2_len);
3207
3208 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
3209 dpp_auth_fail(auth,
3210 "Invalid attribute in secondary unwrapped data");
3211 goto fail;
3212 }
3213
3214 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
3215 &r_auth_len);
3216 if (!r_auth || r_auth_len != auth->curve->hash_len) {
3217 dpp_auth_fail(auth,
3218 "Missing or invalid Responder Authenticating Tag");
3219 goto fail;
3220 }
3221 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
3222 r_auth, r_auth_len);
3223 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3224 if (dpp_gen_r_auth(auth, r_auth2) < 0)
3225 goto fail;
3226 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
3227 r_auth2, r_auth_len);
3228 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
3229 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
3230 bin_clear_free(unwrapped, unwrapped_len);
3231 bin_clear_free(unwrapped2, unwrapped2_len);
3232 auth->remove_on_tx_status = 1;
3233 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
3234 }
3235
3236 bin_clear_free(unwrapped, unwrapped_len);
3237 bin_clear_free(unwrapped2, unwrapped2_len);
3238
3239 #ifdef CONFIG_TESTING_OPTIONS
3240 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
3241 wpa_printf(MSG_INFO,
3242 "DPP: TESTING - Authentication Response in place of Confirm");
3243 if (dpp_auth_build_resp_ok(auth) < 0)
3244 return NULL;
3245 return wpabuf_dup(auth->resp_msg);
3246 }
3247 #endif /* CONFIG_TESTING_OPTIONS */
3248
3249 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
3250
3251 fail:
3252 bin_clear_free(unwrapped, unwrapped_len);
3253 bin_clear_free(unwrapped2, unwrapped2_len);
3254 crypto_ec_free_key(pr);
3255 return NULL;
3256 }
3257
3258
dpp_auth_conf_rx_failure(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,const u8 * wrapped_data,u16 wrapped_data_len,enum dpp_status_error status)3259 static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
3260 const u8 *hdr,
3261 const u8 *attr_start, size_t attr_len,
3262 const u8 *wrapped_data,
3263 u16 wrapped_data_len,
3264 enum dpp_status_error status)
3265 {
3266 const u8 *addr[2];
3267 size_t len[2];
3268 u8 *unwrapped = NULL;
3269 size_t unwrapped_len = 0;
3270 const u8 *r_nonce;
3271 u16 r_nonce_len;
3272
3273 /* Authentication Confirm failure cases are expected to include
3274 * {R-nonce}k2 in the Wrapped Data attribute. */
3275
3276 addr[0] = hdr;
3277 len[0] = DPP_HDR_LEN;
3278 addr[1] = attr_start;
3279 len[1] = attr_len;
3280 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3281 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3282 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3283 wrapped_data, wrapped_data_len);
3284 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3285 unwrapped = os_malloc(unwrapped_len);
3286 if (!unwrapped) {
3287 dpp_auth_fail(auth, "Authentication failed");
3288 goto fail;
3289 }
3290 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
3291 wrapped_data, wrapped_data_len,
3292 2, addr, len, unwrapped) < 0) {
3293 dpp_auth_fail(auth, "AES-SIV decryption failed");
3294 goto fail;
3295 }
3296 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3297 unwrapped, unwrapped_len);
3298
3299 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3300 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3301 goto fail;
3302 }
3303
3304 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
3305 &r_nonce_len);
3306 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
3307 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
3308 goto fail;
3309 }
3310 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
3311 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
3312 r_nonce, r_nonce_len);
3313 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
3314 auth->r_nonce, r_nonce_len);
3315 dpp_auth_fail(auth, "R-nonce mismatch");
3316 goto fail;
3317 }
3318
3319 if (status == DPP_STATUS_NOT_COMPATIBLE)
3320 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
3321 else if (status == DPP_STATUS_AUTH_FAILURE)
3322 dpp_auth_fail(auth, "Peer reported authentication failure)");
3323
3324 fail:
3325 bin_clear_free(unwrapped, unwrapped_len);
3326 return -1;
3327 }
3328
3329
dpp_auth_conf_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)3330 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
3331 const u8 *attr_start, size_t attr_len)
3332 {
3333 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
3334 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3335 i_auth_len;
3336 const u8 *addr[2];
3337 size_t len[2];
3338 u8 *unwrapped = NULL;
3339 size_t unwrapped_len = 0;
3340 u8 i_auth2[DPP_MAX_HASH_LEN];
3341
3342 #ifdef CONFIG_TESTING_OPTIONS
3343 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
3344 wpa_printf(MSG_INFO,
3345 "DPP: TESTING - stop at Authentication Confirm");
3346 return -1;
3347 }
3348 #endif /* CONFIG_TESTING_OPTIONS */
3349
3350 if (auth->initiator || !auth->own_bi) {
3351 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
3352 return -1;
3353 }
3354
3355 auth->waiting_auth_conf = 0;
3356
3357 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3358 &wrapped_data_len);
3359 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3360 dpp_auth_fail(auth,
3361 "Missing or invalid required Wrapped Data attribute");
3362 return -1;
3363 }
3364 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3365 wrapped_data, wrapped_data_len);
3366
3367 attr_len = wrapped_data - 4 - attr_start;
3368
3369 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3370 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3371 &r_bootstrap_len);
3372 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
3373 dpp_auth_fail(auth,
3374 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3375 return -1;
3376 }
3377 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3378 r_bootstrap, r_bootstrap_len);
3379 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
3380 SHA256_MAC_LEN) != 0) {
3381 wpa_hexdump(MSG_DEBUG,
3382 "DPP: Expected Responder Bootstrapping Key Hash",
3383 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3384 dpp_auth_fail(auth,
3385 "Responder Bootstrapping Key Hash mismatch");
3386 return -1;
3387 }
3388
3389 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3390 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3391 &i_bootstrap_len);
3392 if (i_bootstrap) {
3393 if (i_bootstrap_len != SHA256_MAC_LEN) {
3394 dpp_auth_fail(auth,
3395 "Invalid Initiator Bootstrapping Key Hash attribute");
3396 return -1;
3397 }
3398 wpa_hexdump(MSG_MSGDUMP,
3399 "DPP: Initiator Bootstrapping Key Hash",
3400 i_bootstrap, i_bootstrap_len);
3401 if (!auth->peer_bi ||
3402 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
3403 SHA256_MAC_LEN) != 0) {
3404 dpp_auth_fail(auth,
3405 "Initiator Bootstrapping Key Hash mismatch");
3406 return -1;
3407 }
3408 } else if (auth->peer_bi) {
3409 /* Mutual authentication and peer did not include its
3410 * Bootstrapping Key Hash attribute. */
3411 dpp_auth_fail(auth,
3412 "Missing Initiator Bootstrapping Key Hash attribute");
3413 return -1;
3414 }
3415
3416 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3417 &status_len);
3418 if (!status || status_len < 1) {
3419 dpp_auth_fail(auth,
3420 "Missing or invalid required DPP Status attribute");
3421 return -1;
3422 }
3423 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3424 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
3425 status[0] == DPP_STATUS_AUTH_FAILURE)
3426 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
3427 attr_len, wrapped_data,
3428 wrapped_data_len, status[0]);
3429
3430 if (status[0] != DPP_STATUS_OK) {
3431 dpp_auth_fail(auth, "Authentication failed");
3432 return -1;
3433 }
3434
3435 addr[0] = hdr;
3436 len[0] = DPP_HDR_LEN;
3437 addr[1] = attr_start;
3438 len[1] = attr_len;
3439 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3440 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3441 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3442 wrapped_data, wrapped_data_len);
3443 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3444 unwrapped = os_malloc(unwrapped_len);
3445 if (!unwrapped)
3446 return -1;
3447 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3448 wrapped_data, wrapped_data_len,
3449 2, addr, len, unwrapped) < 0) {
3450 dpp_auth_fail(auth, "AES-SIV decryption failed");
3451 goto fail;
3452 }
3453 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3454 unwrapped, unwrapped_len);
3455
3456 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3457 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3458 goto fail;
3459 }
3460
3461 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
3462 &i_auth_len);
3463 if (!i_auth || i_auth_len != auth->curve->hash_len) {
3464 dpp_auth_fail(auth,
3465 "Missing or invalid Initiator Authenticating Tag");
3466 goto fail;
3467 }
3468 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
3469 i_auth, i_auth_len);
3470 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
3471 if (dpp_gen_i_auth(auth, i_auth2) < 0)
3472 goto fail;
3473 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
3474 i_auth2, i_auth_len);
3475 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
3476 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
3477 goto fail;
3478 }
3479
3480 bin_clear_free(unwrapped, unwrapped_len);
3481 dpp_auth_success(auth);
3482 return 0;
3483 fail:
3484 bin_clear_free(unwrapped, unwrapped_len);
3485 return -1;
3486 }
3487
3488
bin_str_eq(const char * val,size_t len,const char * cmp)3489 static int bin_str_eq(const char *val, size_t len, const char *cmp)
3490 {
3491 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
3492 }
3493
3494
dpp_configuration_alloc(const char * type)3495 struct dpp_configuration * dpp_configuration_alloc(const char *type)
3496 {
3497 struct dpp_configuration *conf;
3498 const char *end;
3499 size_t len;
3500
3501 conf = os_zalloc(sizeof(*conf));
3502 if (!conf)
3503 goto fail;
3504
3505 end = os_strchr(type, ' ');
3506 if (end)
3507 len = end - type;
3508 else
3509 len = os_strlen(type);
3510
3511 if (bin_str_eq(type, len, "psk"))
3512 conf->akm = DPP_AKM_PSK;
3513 else if (bin_str_eq(type, len, "sae"))
3514 conf->akm = DPP_AKM_SAE;
3515 else if (bin_str_eq(type, len, "psk-sae") ||
3516 bin_str_eq(type, len, "psk+sae"))
3517 conf->akm = DPP_AKM_PSK_SAE;
3518 else if (bin_str_eq(type, len, "sae-dpp") ||
3519 bin_str_eq(type, len, "dpp+sae"))
3520 conf->akm = DPP_AKM_SAE_DPP;
3521 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
3522 bin_str_eq(type, len, "dpp+psk+sae"))
3523 conf->akm = DPP_AKM_PSK_SAE_DPP;
3524 else if (bin_str_eq(type, len, "dpp"))
3525 conf->akm = DPP_AKM_DPP;
3526 else
3527 goto fail;
3528
3529 return conf;
3530 fail:
3531 dpp_configuration_free(conf);
3532 return NULL;
3533 }
3534
3535
dpp_akm_psk(enum dpp_akm akm)3536 int dpp_akm_psk(enum dpp_akm akm)
3537 {
3538 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
3539 akm == DPP_AKM_PSK_SAE_DPP;
3540 }
3541
3542
dpp_akm_sae(enum dpp_akm akm)3543 int dpp_akm_sae(enum dpp_akm akm)
3544 {
3545 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
3546 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
3547 }
3548
3549
dpp_akm_legacy(enum dpp_akm akm)3550 int dpp_akm_legacy(enum dpp_akm akm)
3551 {
3552 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
3553 akm == DPP_AKM_SAE;
3554 }
3555
3556
dpp_akm_dpp(enum dpp_akm akm)3557 int dpp_akm_dpp(enum dpp_akm akm)
3558 {
3559 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
3560 akm == DPP_AKM_PSK_SAE_DPP;
3561 }
3562
3563
dpp_akm_ver2(enum dpp_akm akm)3564 int dpp_akm_ver2(enum dpp_akm akm)
3565 {
3566 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
3567 }
3568
3569
dpp_configuration_valid(const struct dpp_configuration * conf)3570 int dpp_configuration_valid(const struct dpp_configuration *conf)
3571 {
3572 if (conf->ssid_len == 0)
3573 return 0;
3574 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
3575 return 0;
3576 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
3577 return 0;
3578 return 1;
3579 }
3580
3581
dpp_configuration_free(struct dpp_configuration * conf)3582 void dpp_configuration_free(struct dpp_configuration *conf)
3583 {
3584 if (!conf)
3585 return;
3586 str_clear_free(conf->passphrase);
3587 os_free(conf->group_id);
3588 bin_clear_free(conf, sizeof(*conf));
3589 }
3590
3591
dpp_configuration_parse_helper(struct dpp_authentication * auth,const char * cmd,int idx)3592 static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
3593 const char *cmd, int idx)
3594 {
3595 const char *pos, *end;
3596 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
3597 struct dpp_configuration *conf = NULL;
3598
3599 pos = os_strstr(cmd, " conf=sta-");
3600 if (pos) {
3601 conf_sta = dpp_configuration_alloc(pos + 10);
3602 if (!conf_sta)
3603 goto fail;
3604 conf_sta->netrole = DPP_NETROLE_STA;
3605 conf = conf_sta;
3606 }
3607
3608 pos = os_strstr(cmd, " conf=ap-");
3609 if (pos) {
3610 conf_ap = dpp_configuration_alloc(pos + 9);
3611 if (!conf_ap)
3612 goto fail;
3613 conf_ap->netrole = DPP_NETROLE_AP;
3614 conf = conf_ap;
3615 }
3616
3617 if (!conf)
3618 return 0;
3619
3620 pos = os_strstr(cmd, " ssid=");
3621 if (pos) {
3622 pos += 6;
3623 end = os_strchr(pos, ' ');
3624 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
3625 conf->ssid_len /= 2;
3626 if (conf->ssid_len > sizeof(conf->ssid) ||
3627 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
3628 goto fail;
3629 } else {
3630 #ifdef CONFIG_TESTING_OPTIONS
3631 /* use a default SSID for legacy testing reasons */
3632 os_memcpy(conf->ssid, "test", 4);
3633 conf->ssid_len = 4;
3634 #else /* CONFIG_TESTING_OPTIONS */
3635 goto fail;
3636 #endif /* CONFIG_TESTING_OPTIONS */
3637 }
3638
3639 pos = os_strstr(cmd, " ssid_charset=");
3640 if (pos) {
3641 if (conf_ap) {
3642 wpa_printf(MSG_INFO,
3643 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
3644 goto fail;
3645 }
3646 conf->ssid_charset = atoi(pos + 14);
3647 }
3648
3649 pos = os_strstr(cmd, " pass=");
3650 if (pos) {
3651 size_t pass_len;
3652
3653 pos += 6;
3654 end = os_strchr(pos, ' ');
3655 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
3656 pass_len /= 2;
3657 if (pass_len > 63 || pass_len < 8)
3658 goto fail;
3659 conf->passphrase = os_zalloc(pass_len + 1);
3660 if (!conf->passphrase ||
3661 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
3662 goto fail;
3663 }
3664
3665 pos = os_strstr(cmd, " psk=");
3666 if (pos) {
3667 pos += 5;
3668 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
3669 goto fail;
3670 conf->psk_set = 1;
3671 }
3672
3673 pos = os_strstr(cmd, " group_id=");
3674 if (pos) {
3675 size_t group_id_len;
3676
3677 pos += 10;
3678 end = os_strchr(pos, ' ');
3679 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
3680 conf->group_id = os_malloc(group_id_len + 1);
3681 if (!conf->group_id)
3682 goto fail;
3683 os_memcpy(conf->group_id, pos, group_id_len);
3684 conf->group_id[group_id_len] = '\0';
3685 }
3686
3687 pos = os_strstr(cmd, " expiry=");
3688 if (pos) {
3689 long int val;
3690
3691 pos += 8;
3692 val = strtol(pos, NULL, 0);
3693 if (val <= 0)
3694 goto fail;
3695 conf->netaccesskey_expiry = val;
3696 }
3697
3698 if (!dpp_configuration_valid(conf))
3699 goto fail;
3700
3701 if (idx == 0) {
3702 auth->conf_sta = conf_sta;
3703 auth->conf_ap = conf_ap;
3704 } else if (idx == 1) {
3705 auth->conf2_sta = conf_sta;
3706 auth->conf2_ap = conf_ap;
3707 } else {
3708 goto fail;
3709 }
3710 return 0;
3711
3712 fail:
3713 dpp_configuration_free(conf_sta);
3714 dpp_configuration_free(conf_ap);
3715 return -1;
3716 }
3717
3718
dpp_configuration_parse(struct dpp_authentication * auth,const char * cmd)3719 static int dpp_configuration_parse(struct dpp_authentication *auth,
3720 const char *cmd)
3721 {
3722 const char *pos;
3723 char *tmp;
3724 size_t len;
3725 int res;
3726
3727 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
3728 if (!pos)
3729 return dpp_configuration_parse_helper(auth, cmd, 0);
3730
3731 len = pos - cmd;
3732 tmp = os_malloc(len + 1);
3733 if (!tmp)
3734 goto fail;
3735 os_memcpy(tmp, cmd, len);
3736 tmp[len] = '\0';
3737 res = dpp_configuration_parse_helper(auth, cmd, 0);
3738 str_clear_free(tmp);
3739 if (res)
3740 goto fail;
3741 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
3742 if (res)
3743 goto fail;
3744 return 0;
3745 fail:
3746 dpp_configuration_free(auth->conf_sta);
3747 dpp_configuration_free(auth->conf2_sta);
3748 dpp_configuration_free(auth->conf_ap);
3749 dpp_configuration_free(auth->conf2_ap);
3750 return -1;
3751 }
3752
3753
3754 static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global * dpp,unsigned int id)3755 dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
3756 {
3757 struct dpp_configurator *conf;
3758
3759 if (!dpp)
3760 return NULL;
3761
3762 dl_list_for_each(conf, &dpp->configurator,
3763 struct dpp_configurator, list) {
3764 if (conf->id == id)
3765 return conf;
3766 }
3767 return NULL;
3768 }
3769
3770
dpp_set_configurator(struct dpp_global * dpp,void * msg_ctx,struct dpp_authentication * auth,const char * cmd)3771 int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
3772 struct dpp_authentication *auth,
3773 const char *cmd)
3774 {
3775 const char *pos;
3776
3777 if (!cmd)
3778 return 0;
3779
3780 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
3781
3782 pos = os_strstr(cmd, " configurator=");
3783 if (pos) {
3784 pos += 14;
3785 auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
3786 if (!auth->conf) {
3787 wpa_printf(MSG_INFO,
3788 "DPP: Could not find the specified configurator");
3789 return -1;
3790 }
3791 }
3792
3793 pos = os_strstr(cmd, " conn_status=");
3794 if (pos) {
3795 pos += 13;
3796 auth->send_conn_status = atoi(pos);
3797 }
3798
3799 pos = os_strstr(cmd, " akm_use_selector=");
3800 if (pos) {
3801 pos += 18;
3802 auth->akm_use_selector = atoi(pos);
3803 }
3804
3805 if (dpp_configuration_parse(auth, cmd) < 0) {
3806 wpa_msg(msg_ctx, MSG_INFO,
3807 "DPP: Failed to set configurator parameters");
3808 return -1;
3809 }
3810 return 0;
3811 }
3812
3813
dpp_auth_deinit(struct dpp_authentication * auth)3814 void dpp_auth_deinit(struct dpp_authentication *auth)
3815 {
3816 unsigned int i;
3817
3818 if (!auth)
3819 return;
3820 dpp_configuration_free(auth->conf_ap);
3821 dpp_configuration_free(auth->conf2_ap);
3822 dpp_configuration_free(auth->conf_sta);
3823 dpp_configuration_free(auth->conf2_sta);
3824 crypto_ec_free_key(auth->own_protocol_key);
3825 crypto_ec_free_key(auth->peer_protocol_key);
3826 wpabuf_free(auth->req_msg);
3827 wpabuf_free(auth->resp_msg);
3828 wpabuf_free(auth->conf_req);
3829 for (i = 0; i < auth->num_conf_obj; i++) {
3830 struct dpp_config_obj *conf = &auth->conf_obj[i];
3831
3832 os_free(conf->connector);
3833 wpabuf_free(conf->c_sign_key);
3834 }
3835 wpabuf_free(auth->net_access_key);
3836 dpp_bootstrap_info_free(auth->tmp_own_bi);
3837 #ifdef CONFIG_TESTING_OPTIONS
3838 os_free(auth->config_obj_override);
3839 os_free(auth->discovery_override);
3840 os_free(auth->groups_override);
3841 #endif /* CONFIG_TESTING_OPTIONS */
3842 bin_clear_free(auth, sizeof(*auth));
3843 }
3844
3845
3846 static struct wpabuf *
dpp_build_conf_start(struct dpp_authentication * auth,struct dpp_configuration * conf,size_t tailroom)3847 dpp_build_conf_start(struct dpp_authentication *auth,
3848 struct dpp_configuration *conf, size_t tailroom)
3849 {
3850 struct wpabuf *buf;
3851
3852 #ifdef CONFIG_TESTING_OPTIONS
3853 if (auth->discovery_override)
3854 tailroom += os_strlen(auth->discovery_override);
3855 #endif /* CONFIG_TESTING_OPTIONS */
3856
3857 buf = wpabuf_alloc(200 + tailroom);
3858 if (!buf)
3859 return NULL;
3860 json_start_object(buf, NULL);
3861 json_add_string(buf, "wi-fi_tech", "infra");
3862 json_value_sep(buf);
3863 #ifdef CONFIG_TESTING_OPTIONS
3864 if (auth->discovery_override) {
3865 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
3866 auth->discovery_override);
3867 wpabuf_put_str(buf, "\"discovery\":");
3868 wpabuf_put_str(buf, auth->discovery_override);
3869 json_value_sep(buf);
3870 return buf;
3871 }
3872 #endif /* CONFIG_TESTING_OPTIONS */
3873 json_start_object(buf, "discovery");
3874 if (((!conf->ssid_charset || auth->peer_version < 2) &&
3875 json_add_string_escape(buf, "ssid", conf->ssid,
3876 conf->ssid_len) < 0) ||
3877 ((conf->ssid_charset && auth->peer_version >= 2) &&
3878 json_add_base64url(buf, "ssid64", conf->ssid,
3879 conf->ssid_len) < 0)) {
3880 wpabuf_free(buf);
3881 return NULL;
3882 }
3883 if (conf->ssid_charset > 0) {
3884 json_value_sep(buf);
3885 json_add_int(buf, "ssid_charset", conf->ssid_charset);
3886 }
3887 json_end_object(buf);
3888 json_value_sep(buf);
3889
3890 return buf;
3891 }
3892
3893
dpp_build_jwk(struct wpabuf * buf,const char * name,struct crypto_key * key,const char * kid,const struct dpp_curve_params * curve)3894 static int dpp_build_jwk(struct wpabuf *buf, const char *name, struct crypto_key *key,
3895 const char *kid, const struct dpp_curve_params *curve)
3896 {
3897 struct wpabuf *pub;
3898 const u8 *pos;
3899 int ret = -1;
3900
3901 pub = dpp_get_pubkey_point(key, 0);
3902 if (!pub)
3903 goto fail;
3904
3905 json_start_object(buf, name);
3906 json_add_string(buf, "kty", "EC");
3907 json_value_sep(buf);
3908 json_add_string(buf, "crv", curve->jwk_crv);
3909 json_value_sep(buf);
3910 pos = wpabuf_head(pub);
3911 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
3912 goto fail;
3913 json_value_sep(buf);
3914 pos += curve->prime_len;
3915 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
3916 goto fail;
3917 if (kid) {
3918 json_value_sep(buf);
3919 json_add_string(buf, "kid", kid);
3920 }
3921 json_end_object(buf);
3922 ret = 0;
3923 fail:
3924 wpabuf_free(pub);
3925 return ret;
3926 }
3927
3928
dpp_build_legacy_cred_params(struct wpabuf * buf,struct dpp_configuration * conf)3929 static void dpp_build_legacy_cred_params(struct wpabuf *buf,
3930 struct dpp_configuration *conf)
3931 {
3932 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
3933 json_add_string_escape(buf, "pass", conf->passphrase,
3934 os_strlen(conf->passphrase));
3935 } else if (conf->psk_set) {
3936 char psk[2 * sizeof(conf->psk) + 1];
3937
3938 wpa_snprintf_hex(psk, sizeof(psk),
3939 conf->psk, sizeof(conf->psk));
3940 json_add_string(buf, "psk_hex", psk);
3941 forced_memzero(psk, sizeof(psk));
3942 }
3943 }
3944
3945
dpp_netrole_str(enum dpp_netrole netrole)3946 static const char * dpp_netrole_str(enum dpp_netrole netrole)
3947 {
3948 switch (netrole) {
3949 case DPP_NETROLE_STA:
3950 return "sta";
3951 case DPP_NETROLE_AP:
3952 return "ap";
3953 case DPP_NETROLE_CONFIGURATOR:
3954 return "configurator";
3955 default:
3956 return "??";
3957 }
3958 }
3959
dpp_get_config_obj_hash(char * signed1,size_t signed1_len,char * signed2,size_t signed2_len,unsigned char * hash,int hash_len)3960 int dpp_get_config_obj_hash(char *signed1, size_t signed1_len,
3961 char *signed2, size_t signed2_len,
3962 unsigned char *hash, int hash_len)
3963 {
3964 const char *dot = ".";
3965 int ret = -1;
3966 const u8 *addr[3];
3967 size_t len[3];
3968
3969 #ifdef ESP_SUPPLICANT
3970 if (hash_len != SHA256_MAC_LEN)
3971 return ret;
3972 #endif
3973 addr[0] = (unsigned char *)signed1;
3974 len[0] = signed1_len;
3975 addr[1] = (unsigned char *)dot;
3976 len[1] = 1;
3977 addr[2] = (unsigned char *)signed2;
3978 len[2] = signed2_len;
3979 ret = sha256_vector(3, addr, len, hash);
3980
3981 return ret;
3982 }
3983
3984 static struct wpabuf *
dpp_build_conf_obj_dpp(struct dpp_authentication * auth,struct dpp_configuration * conf)3985 dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
3986 struct dpp_configuration *conf)
3987 {
3988 struct wpabuf *buf = NULL;
3989 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
3990 size_t tailroom;
3991 const struct dpp_curve_params *curve;
3992 struct wpabuf *jws_prot_hdr;
3993 size_t signed1_len, signed2_len, signed3_len;
3994 struct wpabuf *dppcon = NULL;
3995 unsigned char *signature = NULL;
3996 size_t signature_len;
3997 struct crypto_bignum *r = NULL, *s = NULL;
3998 size_t extra_len = 1000;
3999 int incl_legacy;
4000 enum dpp_akm akm;
4001 const char *akm_str;
4002 unsigned char *hash = NULL;
4003
4004 if (!auth->conf) {
4005 wpa_printf(MSG_INFO,
4006 "DPP: No configurator specified - cannot generate DPP config object");
4007 goto fail;
4008 }
4009 curve = auth->conf->curve;
4010 akm = conf->akm;
4011 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4012 wpa_printf(MSG_DEBUG,
4013 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4014 akm = DPP_AKM_DPP;
4015 }
4016
4017 #ifdef CONFIG_TESTING_OPTIONS
4018 if (auth->groups_override)
4019 extra_len += os_strlen(auth->groups_override);
4020 #endif /* CONFIG_TESTING_OPTIONS */
4021
4022 if (conf->group_id)
4023 extra_len += os_strlen(conf->group_id);
4024
4025 /* Connector (JSON dppCon object) */
4026 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4027 if (!dppcon)
4028 goto fail;
4029 #ifdef CONFIG_TESTING_OPTIONS
4030 if (auth->groups_override) {
4031 wpabuf_put_u8(dppcon, '{');
4032 if (auth->groups_override) {
4033 wpa_printf(MSG_DEBUG,
4034 "DPP: TESTING - groups override: '%s'",
4035 auth->groups_override);
4036 wpabuf_put_str(dppcon, "\"groups\":");
4037 wpabuf_put_str(dppcon, auth->groups_override);
4038 json_value_sep(dppcon);
4039 }
4040 goto skip_groups;
4041 }
4042 #endif /* CONFIG_TESTING_OPTIONS */
4043 json_start_object(dppcon, NULL);
4044 json_start_array(dppcon, "groups");
4045 json_start_object(dppcon, NULL);
4046 json_add_string(dppcon, "groupId",
4047 conf->group_id ? conf->group_id : "*");
4048 json_value_sep(dppcon);
4049 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
4050 json_end_object(dppcon);
4051 json_end_array(dppcon);
4052 json_value_sep(dppcon);
4053 #ifdef CONFIG_TESTING_OPTIONS
4054 skip_groups:
4055 #endif /* CONFIG_TESTING_OPTIONS */
4056 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4057 auth->curve) < 0) {
4058 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4059 goto fail;
4060 }
4061 if (conf->netaccesskey_expiry) {
4062 struct os_tm tm;
4063 char expiry[30];
4064
4065 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4066 wpa_printf(MSG_DEBUG,
4067 "DPP: Failed to generate expiry string");
4068 goto fail;
4069 }
4070 os_snprintf(expiry, sizeof(expiry),
4071 "%04u-%02u-%02uT%02u:%02u:%02uZ",
4072 tm.year, tm.month, tm.day,
4073 tm.hour, tm.min, tm.sec);
4074 json_value_sep(dppcon);
4075 json_add_string(dppcon, "expiry", expiry);
4076 }
4077 json_end_object(dppcon);
4078 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
4079 (const char *) wpabuf_head(dppcon));
4080
4081 jws_prot_hdr = wpabuf_alloc(100);
4082 if (!jws_prot_hdr)
4083 goto fail;
4084 json_start_object(jws_prot_hdr, NULL);
4085 json_add_string(jws_prot_hdr, "typ", "dppCon");
4086 json_value_sep(jws_prot_hdr);
4087 json_add_string(jws_prot_hdr, "kid", auth->conf->kid);
4088 json_value_sep(jws_prot_hdr);
4089 json_add_string(jws_prot_hdr, "alg", curve->jws_alg);
4090 json_end_object(jws_prot_hdr);
4091 signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
4092 wpabuf_len(jws_prot_hdr),
4093 &signed1_len);
4094 wpabuf_free(jws_prot_hdr);
4095 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
4096 &signed2_len);
4097 if (!signed1 || !signed2)
4098 goto fail;
4099
4100 hash = os_malloc(curve->hash_len);
4101 if (!hash) {
4102 goto fail;
4103 }
4104 if (dpp_get_config_obj_hash(signed1, signed1_len, signed2, signed1_len, hash, curve->hash_len) < 0)
4105 goto fail;
4106
4107 r = crypto_bignum_init();
4108 s = crypto_bignum_init();
4109 if (crypto_ecdsa_get_sign(hash, r, s, auth->conf->csign, curve->hash_len) < 0)
4110 goto fail;
4111
4112 signature = os_malloc(2 * curve->prime_len);
4113 if (!signature)
4114 goto fail;
4115 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4116 dpp_bn2bin_pad(s, signature + curve->prime_len,
4117 curve->prime_len) < 0)
4118 goto fail;
4119 signature_len = 2 * curve->prime_len;
4120 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4121 signature, signature_len);
4122 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
4123 if (!signed3)
4124 goto fail;
4125
4126 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
4127 tailroom = 1000;
4128 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4129 tailroom += signed1_len + signed2_len + signed3_len;
4130 if (incl_legacy)
4131 tailroom += 1000;
4132 buf = dpp_build_conf_start(auth, conf, tailroom);
4133 if (!buf)
4134 goto fail;
4135
4136 if (auth->akm_use_selector && dpp_akm_ver2(akm))
4137 akm_str = dpp_akm_selector_str(akm);
4138 else
4139 akm_str = dpp_akm_str(akm);
4140 json_start_object(buf, "cred");
4141 json_add_string(buf, "akm", akm_str);
4142 json_value_sep(buf);
4143 if (incl_legacy) {
4144 dpp_build_legacy_cred_params(buf, conf);
4145 json_value_sep(buf);
4146 }
4147 wpabuf_put_str(buf, "\"signedConnector\":\"");
4148 wpabuf_put_str(buf, signed1);
4149 wpabuf_put_u8(buf, '.');
4150 wpabuf_put_str(buf, signed2);
4151 wpabuf_put_u8(buf, '.');
4152 wpabuf_put_str(buf, signed3);
4153 wpabuf_put_str(buf, "\"");
4154 json_value_sep(buf);
4155 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4156 curve) < 0) {
4157 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4158 goto fail;
4159 }
4160
4161 json_end_object(buf);
4162 json_end_object(buf);
4163
4164 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4165 (u8 *)wpabuf_head(buf), wpabuf_len(buf));
4166
4167 out:
4168 if (signed1)
4169 os_free(signed1);
4170 if (signed2)
4171 os_free(signed2);
4172 if (signed3)
4173 os_free(signed3);
4174 if (hash)
4175 os_free(hash);
4176 if (signature)
4177 os_free(signature);
4178 crypto_bignum_deinit(r, 0);
4179 crypto_bignum_deinit(s, 0);
4180 wpabuf_free(dppcon);
4181 return buf;
4182 fail:
4183 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4184 wpabuf_free(buf);
4185 buf = NULL;
4186 goto out;
4187 }
4188
4189 static struct wpabuf *
dpp_build_conf_obj_legacy(struct dpp_authentication * auth,struct dpp_configuration * conf)4190 dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
4191 struct dpp_configuration *conf)
4192 {
4193 struct wpabuf *buf;
4194 const char *akm_str;
4195
4196 buf = dpp_build_conf_start(auth, conf, 1000);
4197 if (!buf)
4198 return NULL;
4199
4200 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
4201 akm_str = dpp_akm_selector_str(conf->akm);
4202 else
4203 akm_str = dpp_akm_str(conf->akm);
4204 json_start_object(buf, "cred");
4205 json_add_string(buf, "akm", akm_str);
4206 json_value_sep(buf);
4207 dpp_build_legacy_cred_params(buf, conf);
4208 json_end_object(buf);
4209 json_end_object(buf);
4210
4211 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4212 (u8 *)wpabuf_head(buf), wpabuf_len(buf));
4213
4214 return buf;
4215 }
4216
4217
4218 static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication * auth,enum dpp_netrole netrole,int idx)4219 dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
4220 int idx)
4221 {
4222 struct dpp_configuration *conf = NULL;
4223
4224 #ifdef CONFIG_TESTING_OPTIONS
4225 if (auth->config_obj_override) {
4226 if (idx != 0)
4227 return NULL;
4228 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4229 return wpabuf_alloc_copy(auth->config_obj_override,
4230 os_strlen(auth->config_obj_override));
4231 }
4232 #endif /* CONFIG_TESTING_OPTIONS */
4233
4234 if (idx == 0) {
4235 if (netrole == DPP_NETROLE_STA)
4236 conf = auth->conf_sta;
4237 else if (netrole == DPP_NETROLE_AP)
4238 conf = auth->conf_ap;
4239 } else if (idx == 1) {
4240 if (netrole == DPP_NETROLE_STA)
4241 conf = auth->conf2_sta;
4242 else if (netrole == DPP_NETROLE_AP)
4243 conf = auth->conf2_ap;
4244 }
4245 if (!conf) {
4246 if (idx == 0)
4247 wpa_printf(MSG_DEBUG,
4248 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4249 dpp_netrole_str(netrole));
4250 return NULL;
4251 }
4252
4253 if (dpp_akm_dpp(conf->akm))
4254 return dpp_build_conf_obj_dpp(auth, conf);
4255 return dpp_build_conf_obj_legacy(auth, conf);
4256 }
4257
4258
4259 static struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication * auth,const u8 * e_nonce,u16 e_nonce_len,enum dpp_netrole netrole)4260 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4261 u16 e_nonce_len, enum dpp_netrole netrole)
4262 {
4263 struct wpabuf *conf, *conf2 = NULL;
4264 size_t clear_len, attr_len;
4265 struct wpabuf *clear = NULL, *msg = NULL;
4266 u8 *wrapped;
4267 const u8 *addr[1];
4268 size_t len[1];
4269 enum dpp_status_error status;
4270
4271 conf = dpp_build_conf_obj(auth, netrole, 0);
4272 if (conf) {
4273 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4274 (u8 *)wpabuf_head(conf), wpabuf_len(conf));
4275 conf2 = dpp_build_conf_obj(auth, netrole, 1);
4276 }
4277 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4278 auth->conf_resp_status = status;
4279
4280 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
4281 clear_len = 4 + e_nonce_len;
4282 if (conf)
4283 clear_len += 4 + wpabuf_len(conf);
4284 if (conf2)
4285 clear_len += 4 + wpabuf_len(conf2);
4286 if (auth->peer_version >= 2 && auth->send_conn_status &&
4287 netrole == DPP_NETROLE_STA)
4288 clear_len += 4;
4289 clear = wpabuf_alloc(clear_len);
4290 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4291 #ifdef CONFIG_TESTING_OPTIONS
4292 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4293 attr_len += 5;
4294 #endif /* CONFIG_TESTING_OPTIONS */
4295 msg = wpabuf_alloc(attr_len);
4296 if (!clear || !msg)
4297 goto fail;
4298
4299 #ifdef CONFIG_TESTING_OPTIONS
4300 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4301 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4302 goto skip_e_nonce;
4303 }
4304 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4305 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4306 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4307 wpabuf_put_le16(clear, e_nonce_len);
4308 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4309 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4310 goto skip_e_nonce;
4311 }
4312 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4313 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4314 goto skip_wrapped_data;
4315 }
4316 #endif /* CONFIG_TESTING_OPTIONS */
4317
4318 /* E-nonce */
4319 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4320 wpabuf_put_le16(clear, e_nonce_len);
4321 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4322
4323 #ifdef CONFIG_TESTING_OPTIONS
4324 skip_e_nonce:
4325 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4326 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4327 goto skip_config_obj;
4328 }
4329 #endif /* CONFIG_TESTING_OPTIONS */
4330
4331 if (conf) {
4332 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4333 wpabuf_put_le16(clear, wpabuf_len(conf));
4334 wpabuf_put_buf(clear, conf);
4335 }
4336 if (auth->peer_version >= 2 && conf2) {
4337 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4338 wpabuf_put_le16(clear, wpabuf_len(conf2));
4339 wpabuf_put_buf(clear, conf2);
4340 } else if (conf2) {
4341 wpa_printf(MSG_DEBUG,
4342 "DPP: Second Config Object available, but peer does not support more than one");
4343 }
4344
4345 if (auth->peer_version >= 2 && auth->send_conn_status &&
4346 netrole == DPP_NETROLE_STA) {
4347 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
4348 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
4349 wpabuf_put_le16(clear, 0);
4350 }
4351
4352 #ifdef CONFIG_TESTING_OPTIONS
4353 skip_config_obj:
4354 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4355 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4356 goto skip_status;
4357 }
4358 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4359 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4360 status = 255;
4361 }
4362 #endif /* CONFIG_TESTING_OPTIONS */
4363
4364 /* DPP Status */
4365 dpp_build_attr_status(msg, status);
4366
4367 #ifdef CONFIG_TESTING_OPTIONS
4368 skip_status:
4369 #endif /* CONFIG_TESTING_OPTIONS */
4370
4371 addr[0] = wpabuf_head(msg);
4372 len[0] = wpabuf_len(msg);
4373 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4374
4375 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4376 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4377 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4378
4379 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4380 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4381 wpabuf_head(clear), wpabuf_len(clear),
4382 1, addr, len, wrapped) < 0)
4383 goto fail;
4384 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4385 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
4386
4387 #ifdef CONFIG_TESTING_OPTIONS
4388 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4389 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4390 dpp_build_attr_status(msg, DPP_STATUS_OK);
4391 }
4392 skip_wrapped_data:
4393 #endif /* CONFIG_TESTING_OPTIONS */
4394
4395 wpa_hexdump_buf(MSG_DEBUG,
4396 "DPP: Configuration Response attributes", msg);
4397 out:
4398 wpabuf_free(conf);
4399 wpabuf_free(conf2);
4400 wpabuf_free(clear);
4401
4402 return msg;
4403 fail:
4404 wpabuf_free(msg);
4405 msg = NULL;
4406 goto out;
4407 }
4408
4409
4410 struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication * auth,const u8 * attr_start,size_t attr_len)4411 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4412 size_t attr_len)
4413 {
4414 const u8 *wrapped_data, *e_nonce, *config_attr;
4415 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4416 u8 *unwrapped = NULL;
4417 size_t unwrapped_len = 0;
4418 struct wpabuf *resp = NULL;
4419 struct json_token *root = NULL, *token;
4420 enum dpp_netrole netrole;
4421
4422 #ifdef CONFIG_TESTING_OPTIONS
4423 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
4424 wpa_printf(MSG_INFO,
4425 "DPP: TESTING - stop at Config Request");
4426 return NULL;
4427 }
4428 #endif /* CONFIG_TESTING_OPTIONS */
4429
4430 if (dpp_check_attrs(attr_start, attr_len) < 0) {
4431 dpp_auth_fail(auth, "Invalid attribute in config request");
4432 return NULL;
4433 }
4434
4435 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4436 &wrapped_data_len);
4437 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4438 dpp_auth_fail(auth,
4439 "Missing or invalid required Wrapped Data attribute");
4440 return NULL;
4441 }
4442
4443 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4444 wrapped_data, wrapped_data_len);
4445 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4446 unwrapped = os_malloc(unwrapped_len);
4447 if (!unwrapped)
4448 return NULL;
4449 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4450 wrapped_data, wrapped_data_len,
4451 0, NULL, NULL, unwrapped) < 0) {
4452 dpp_auth_fail(auth, "AES-SIV decryption failed");
4453 goto fail;
4454 }
4455 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4456 unwrapped, unwrapped_len);
4457
4458 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4459 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4460 goto fail;
4461 }
4462
4463 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4464 DPP_ATTR_ENROLLEE_NONCE,
4465 &e_nonce_len);
4466 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4467 dpp_auth_fail(auth,
4468 "Missing or invalid Enrollee Nonce attribute");
4469 goto fail;
4470 }
4471 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4472 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
4473
4474 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4475 DPP_ATTR_CONFIG_ATTR_OBJ,
4476 &config_attr_len);
4477 if (!config_attr) {
4478 dpp_auth_fail(auth,
4479 "Missing or invalid Config Attributes attribute");
4480 goto fail;
4481 }
4482 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4483 (u8 *)config_attr, config_attr_len);
4484
4485 root = json_parse((const char *) config_attr, config_attr_len);
4486 if (!root) {
4487 dpp_auth_fail(auth, "Could not parse Config Attributes");
4488 goto fail;
4489 }
4490
4491 token = json_get_member(root, "name");
4492 if (!token || token->type != JSON_STRING) {
4493 dpp_auth_fail(auth, "No Config Attributes - name");
4494 goto fail;
4495 }
4496 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4497
4498 token = json_get_member(root, "wi-fi_tech");
4499 if (!token || token->type != JSON_STRING) {
4500 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
4501 goto fail;
4502 }
4503 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4504 if (os_strcmp(token->string, "infra") != 0) {
4505 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4506 token->string);
4507 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
4508 goto fail;
4509 }
4510
4511 token = json_get_member(root, "netRole");
4512 if (!token || token->type != JSON_STRING) {
4513 dpp_auth_fail(auth, "No Config Attributes - netRole");
4514 goto fail;
4515 }
4516 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4517 if (os_strcmp(token->string, "sta") == 0) {
4518 netrole = DPP_NETROLE_STA;
4519 } else if (os_strcmp(token->string, "ap") == 0) {
4520 netrole = DPP_NETROLE_AP;
4521 } else if (os_strcmp(token->string, "configurator") == 0) {
4522 netrole = DPP_NETROLE_CONFIGURATOR;
4523 } else {
4524 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4525 token->string);
4526 dpp_auth_fail(auth, "Unsupported netRole");
4527 goto fail;
4528 }
4529
4530 token = json_get_member(root, "mudurl");
4531 if (token && token->type == JSON_STRING)
4532 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
4533
4534 token = json_get_member(root, "bandSupport");
4535 if (token && token->type == JSON_ARRAY) {
4536 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
4537 token = token->child;
4538 while (token) {
4539 if (token->type != JSON_NUMBER)
4540 wpa_printf(MSG_DEBUG,
4541 "DPP: Invalid bandSupport array member type");
4542 else
4543 wpa_printf(MSG_DEBUG,
4544 "DPP: Supported global operating class: %d",
4545 token->number);
4546 token = token->sibling;
4547 }
4548 }
4549
4550 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
4551 fail:
4552 json_free(root);
4553 os_free(unwrapped);
4554 return resp;
4555 }
4556
4557
4558 static struct wpabuf *
dpp_parse_jws_prot_hdr(const struct dpp_curve_params * curve,const u8 * prot_hdr,u16 prot_hdr_len)4559 dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
4560 const u8 *prot_hdr, u16 prot_hdr_len)
4561 {
4562 struct json_token *root, *token;
4563 struct wpabuf *kid = NULL;
4564
4565 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4566 if (!root) {
4567 wpa_printf(MSG_DEBUG,
4568 "DPP: JSON parsing failed for JWS Protected Header");
4569 goto fail;
4570 }
4571
4572 if (root->type != JSON_OBJECT) {
4573 wpa_printf(MSG_DEBUG,
4574 "DPP: JWS Protected Header root is not an object");
4575 goto fail;
4576 }
4577
4578 token = json_get_member(root, "typ");
4579 if (!token || token->type != JSON_STRING) {
4580 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
4581 goto fail;
4582 }
4583 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4584 token->string);
4585 if (os_strcmp(token->string, "dppCon") != 0) {
4586 wpa_printf(MSG_DEBUG,
4587 "DPP: Unsupported JWS Protected Header typ=%s",
4588 token->string);
4589 goto fail;
4590 }
4591
4592 token = json_get_member(root, "alg");
4593 if (!token || token->type != JSON_STRING) {
4594 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4595 goto fail;
4596 }
4597 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4598 token->string);
4599 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4600 wpa_printf(MSG_DEBUG,
4601 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4602 token->string, curve->jws_alg);
4603 goto fail;
4604 }
4605
4606 kid = json_get_member_base64url(root, "kid");
4607 if (!kid) {
4608 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4609 goto fail;
4610 }
4611 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4612 kid);
4613
4614 fail:
4615 json_free(root);
4616 return kid;
4617 }
4618
4619
dpp_parse_cred_legacy(struct dpp_config_obj * conf,struct json_token * cred)4620 static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
4621 struct json_token *cred)
4622 {
4623 struct json_token *pass, *psk_hex;
4624
4625 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4626
4627 pass = json_get_member(cred, "pass");
4628 psk_hex = json_get_member(cred, "psk_hex");
4629
4630 if (pass && pass->type == JSON_STRING) {
4631 size_t len = os_strlen(pass->string);
4632
4633 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
4634 (u8 *)pass->string, len);
4635 if (len < 8 || len > 63)
4636 return -1;
4637 os_strlcpy(conf->passphrase, pass->string,
4638 sizeof(conf->passphrase));
4639 } else if (psk_hex && psk_hex->type == JSON_STRING) {
4640 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
4641 wpa_printf(MSG_DEBUG,
4642 "DPP: Unexpected psk_hex with akm=sae");
4643 return -1;
4644 }
4645 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4646 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
4647 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4648 return -1;
4649 }
4650 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4651 conf->psk, PMK_LEN);
4652 conf->psk_set = 1;
4653 } else {
4654 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4655 return -1;
4656 }
4657
4658 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
4659 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
4660 return -1;
4661 }
4662
4663 return 0;
4664 }
4665
4666
dpp_parse_jwk(struct json_token * jwk,const struct dpp_curve_params ** key_curve)4667 static struct crypto_key * dpp_parse_jwk(struct json_token *jwk,
4668 const struct dpp_curve_params **key_curve)
4669 {
4670 struct json_token *token;
4671 const struct dpp_curve_params *curve;
4672 struct wpabuf *x = NULL, *y = NULL, *a = NULL;
4673 struct crypto_ec_group *group;
4674 struct crypto_key *pkey = NULL;
4675 size_t len;
4676
4677 token = json_get_member(jwk, "kty");
4678 if (!token || token->type != JSON_STRING) {
4679 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4680 goto fail;
4681 }
4682 if (os_strcmp(token->string, "EC") != 0) {
4683 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
4684 token->string);
4685 goto fail;
4686 }
4687
4688 token = json_get_member(jwk, "crv");
4689 if (!token || token->type != JSON_STRING) {
4690 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4691 goto fail;
4692 }
4693 curve = dpp_get_curve_jwk_crv(token->string);
4694 if (!curve) {
4695 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4696 token->string);
4697 goto fail;
4698 }
4699
4700 x = json_get_member_base64url(jwk, "x");
4701 if (!x) {
4702 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4703 goto fail;
4704 }
4705 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
4706 if (wpabuf_len(x) != curve->prime_len) {
4707 wpa_printf(MSG_DEBUG,
4708 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4709 (unsigned int) wpabuf_len(x),
4710 (unsigned int) curve->prime_len, curve->name);
4711 goto fail;
4712 }
4713
4714 y = json_get_member_base64url(jwk, "y");
4715 if (!y) {
4716 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4717 goto fail;
4718 }
4719 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
4720 if (wpabuf_len(y) != curve->prime_len) {
4721 wpa_printf(MSG_DEBUG,
4722 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4723 (unsigned int) wpabuf_len(y),
4724 (unsigned int) curve->prime_len, curve->name);
4725 goto fail;
4726 }
4727
4728 group = crypto_ec_get_group_byname(curve->name);
4729 if (!group) {
4730 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4731 goto fail;
4732 }
4733
4734 len = wpabuf_len(x);
4735 a = wpabuf_concat(x, y);
4736 pkey = crypto_ec_set_pubkey_point(group, wpabuf_head(a),
4737 len);
4738 crypto_ec_deinit((struct crypto_ec *)group);
4739 *key_curve = curve;
4740
4741 fail:
4742 wpabuf_free(a);
4743 wpabuf_free(x);
4744 wpabuf_free(y);
4745
4746 return pkey;
4747 }
4748
4749
dpp_key_expired(const char * timestamp,os_time_t * expiry)4750 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4751 {
4752 struct os_time now;
4753 unsigned int year, month, day, hour, min, sec;
4754 os_time_t utime;
4755 const char *pos;
4756
4757 /* ISO 8601 date and time:
4758 * <date>T<time>
4759 * YYYY-MM-DDTHH:MM:SSZ
4760 * YYYY-MM-DDTHH:MM:SS+03:00
4761 */
4762 if (os_strlen(timestamp) < 19) {
4763 wpa_printf(MSG_DEBUG,
4764 "DPP: Too short timestamp - assume expired key");
4765 return 1;
4766 }
4767 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4768 &year, &month, &day, &hour, &min, &sec) != 6) {
4769 wpa_printf(MSG_DEBUG,
4770 "DPP: Failed to parse expiration day - assume expired key");
4771 return 1;
4772 }
4773
4774 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4775 wpa_printf(MSG_DEBUG,
4776 "DPP: Invalid date/time information - assume expired key");
4777 return 1;
4778 }
4779
4780 pos = timestamp + 19;
4781 if (*pos == 'Z' || *pos == '\0') {
4782 /* In UTC - no need to adjust */
4783 } else if (*pos == '-' || *pos == '+') {
4784 int items;
4785
4786 /* Adjust local time to UTC */
4787 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4788 if (items < 1) {
4789 wpa_printf(MSG_DEBUG,
4790 "DPP: Invalid time zone designator (%s) - assume expired key",
4791 pos);
4792 return 1;
4793 }
4794 if (*pos == '-')
4795 utime += 3600 * hour;
4796 if (*pos == '+')
4797 utime -= 3600 * hour;
4798 if (items > 1) {
4799 if (*pos == '-')
4800 utime += 60 * min;
4801 if (*pos == '+')
4802 utime -= 60 * min;
4803 }
4804 } else {
4805 wpa_printf(MSG_DEBUG,
4806 "DPP: Invalid time zone designator (%s) - assume expired key",
4807 pos);
4808 return 1;
4809 }
4810 if (expiry)
4811 *expiry = utime;
4812
4813 if (os_get_time(&now) < 0) {
4814 wpa_printf(MSG_DEBUG,
4815 "DPP: Cannot get current time - assume expired key");
4816 return 1;
4817 }
4818
4819 if (now.sec > utime) {
4820 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4821 utime, now.sec);
4822 return 1;
4823 }
4824
4825 return 0;
4826 }
4827
4828
dpp_parse_connector(struct dpp_authentication * auth,struct dpp_config_obj * conf,const unsigned char * payload,u16 payload_len)4829 static int dpp_parse_connector(struct dpp_authentication *auth,
4830 struct dpp_config_obj *conf,
4831 const unsigned char *payload,
4832 u16 payload_len)
4833 {
4834 struct json_token *root, *groups, *netkey, *token;
4835 int ret = -1;
4836 struct crypto_key *key = NULL;
4837 const struct dpp_curve_params *curve;
4838 unsigned int rules = 0;
4839
4840 root = json_parse((const char *) payload, payload_len);
4841 if (!root) {
4842 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4843 goto fail;
4844 }
4845
4846 groups = json_get_member(root, "groups");
4847 if (!groups || groups->type != JSON_ARRAY) {
4848 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4849 goto skip_groups;
4850 }
4851 for (token = groups->child; token; token = token->sibling) {
4852 struct json_token *id, *role;
4853
4854 id = json_get_member(token, "groupId");
4855 if (!id || id->type != JSON_STRING) {
4856 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4857 goto fail;
4858 }
4859
4860 role = json_get_member(token, "netRole");
4861 if (!role || role->type != JSON_STRING) {
4862 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4863 goto fail;
4864 }
4865 wpa_printf(MSG_DEBUG,
4866 "DPP: connector group: groupId='%s' netRole='%s'",
4867 id->string, role->string);
4868 rules++;
4869 }
4870 skip_groups:
4871
4872 if (!rules) {
4873 wpa_printf(MSG_DEBUG,
4874 "DPP: Connector includes no groups");
4875 goto fail;
4876 }
4877
4878 token = json_get_member(root, "expiry");
4879 if (!token || token->type != JSON_STRING) {
4880 wpa_printf(MSG_DEBUG,
4881 "DPP: No expiry string found - connector does not expire");
4882 } else {
4883 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4884 if (dpp_key_expired(token->string,
4885 &auth->net_access_key_expiry)) {
4886 wpa_printf(MSG_DEBUG,
4887 "DPP: Connector (netAccessKey) has expired");
4888 goto fail;
4889 }
4890 }
4891
4892 netkey = json_get_member(root, "netAccessKey");
4893 if (!netkey || netkey->type != JSON_OBJECT) {
4894 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4895 goto fail;
4896 }
4897
4898 key = dpp_parse_jwk(netkey, &curve);
4899 if (!key)
4900 goto fail;
4901 dpp_debug_print_key("DPP: Received netAccessKey", key);
4902
4903 if (crypto_key_compare(key, auth->own_protocol_key) != 1) {
4904 wpa_printf(MSG_DEBUG,
4905 "DPP: netAccessKey in connector does not match own protocol key");
4906 #ifdef CONFIG_TESTING_OPTIONS
4907 if (auth->ignore_netaccesskey_mismatch) {
4908 wpa_printf(MSG_DEBUG,
4909 "DPP: TESTING - skip netAccessKey mismatch");
4910 } else {
4911 goto fail;
4912 }
4913 #else /* CONFIG_TESTING_OPTIONS */
4914 goto fail;
4915 #endif /* CONFIG_TESTING_OPTIONS */
4916 }
4917
4918 ret = 0;
4919 fail:
4920 crypto_ec_free_key(key);
4921 json_free(root);
4922 return ret;
4923 }
4924
dpp_check_pubkey_match(struct crypto_key * pub,struct wpabuf * r_hash)4925 static int dpp_check_pubkey_match(struct crypto_key *pub, struct wpabuf *r_hash)
4926 {
4927 struct wpabuf *uncomp;
4928 int res;
4929 u8 hash[SHA256_MAC_LEN];
4930 const u8 *addr[1];
4931 size_t len[1];
4932
4933 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4934 return -1;
4935 uncomp = dpp_get_pubkey_point(pub, 1);
4936 if (!uncomp)
4937 return -1;
4938 addr[0] = wpabuf_head(uncomp);
4939 len[0] = wpabuf_len(uncomp);
4940 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
4941 addr[0], len[0]);
4942 res = sha256_vector(1, addr, len, hash);
4943 wpabuf_free(uncomp);
4944 if (res < 0)
4945 return -1;
4946 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
4947 wpa_printf(MSG_DEBUG,
4948 "DPP: Received hash value does not match calculated public key hash value");
4949 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
4950 hash, SHA256_MAC_LEN);
4951 return -1;
4952 }
4953 return 0;
4954 }
4955
4956
dpp_copy_csign(struct dpp_config_obj * conf,struct crypto_key * csign)4957 static void dpp_copy_csign(struct dpp_config_obj *conf, struct crypto_key *csign)
4958 {
4959 unsigned char *der = NULL;
4960 int der_len;
4961
4962 der_len = crypto_write_pubkey_der(csign, &der);
4963 if (der_len <= 0)
4964 return;
4965 wpabuf_free(conf->c_sign_key);
4966 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
4967 crypto_free_buffer(der);
4968 }
4969
dpp_copy_netaccesskey(struct dpp_authentication * auth,struct dpp_config_obj * conf)4970 static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
4971 struct dpp_config_obj *conf)
4972 {
4973 unsigned char *der = NULL;
4974 int der_len;
4975
4976 if (crypto_ec_get_priv_key_der(auth->own_protocol_key, &der, &der_len) < 0)
4977 return;
4978 wpabuf_free(auth->net_access_key);
4979 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
4980 crypto_free_buffer(der);
4981 }
4982
4983 struct dpp_signed_connector_info {
4984 unsigned char *payload;
4985 size_t payload_len;
4986 };
4987
4988 static enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info * info,struct crypto_key * csign_pub,const char * connector)4989 dpp_process_signed_connector(struct dpp_signed_connector_info *info,
4990 struct crypto_key *csign_pub, const char *connector)
4991 {
4992 enum dpp_status_error ret = 255;
4993 const char *pos, *end, *signed_start, *signed_end;
4994 struct wpabuf *kid = NULL;
4995 unsigned char *prot_hdr = NULL, *signature = NULL;
4996 size_t prot_hdr_len = 0, signature_len = 0;
4997 struct crypto_bignum *r = NULL, *s = NULL;
4998 const struct dpp_curve_params *curve;
4999 const struct crypto_ec_group *group;
5000 int id;
5001
5002 group = crypto_ec_get_group_from_key(csign_pub);
5003 if (!group)
5004 goto fail;
5005 id = crypto_ec_get_curve_id(group);
5006 curve = dpp_get_curve_group_id(id);
5007 if (!curve)
5008 goto fail;
5009 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5010 os_memset(info, 0, sizeof(*info));
5011
5012 signed_start = pos = connector;
5013 end = os_strchr(pos, '.');
5014 if (!end) {
5015 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
5016 ret = DPP_STATUS_INVALID_CONNECTOR;
5017 goto fail;
5018 }
5019 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
5020 if (!prot_hdr) {
5021 wpa_printf(MSG_DEBUG,
5022 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5023 ret = DPP_STATUS_INVALID_CONNECTOR;
5024 goto fail;
5025 }
5026 wpa_hexdump_ascii(MSG_DEBUG,
5027 "DPP: signedConnector - JWS Protected Header",
5028 (u8 *)prot_hdr, prot_hdr_len);
5029 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len);
5030 if (!kid) {
5031 ret = DPP_STATUS_INVALID_CONNECTOR;
5032 goto fail;
5033 }
5034 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5035 wpa_printf(MSG_DEBUG,
5036 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5037 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
5038 ret = DPP_STATUS_INVALID_CONNECTOR;
5039 goto fail;
5040 }
5041
5042 pos = end + 1;
5043 end = os_strchr(pos, '.');
5044 if (!end) {
5045 wpa_printf(MSG_DEBUG,
5046 "DPP: Missing dot(2) in signedConnector");
5047 ret = DPP_STATUS_INVALID_CONNECTOR;
5048 goto fail;
5049 }
5050 signed_end = end - 1;
5051 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
5052 if (!info->payload) {
5053 wpa_printf(MSG_DEBUG,
5054 "DPP: Failed to base64url decode signedConnector JWS Payload");
5055 ret = DPP_STATUS_INVALID_CONNECTOR;
5056 goto fail;
5057 }
5058 wpa_hexdump_ascii(MSG_DEBUG,
5059 "DPP: signedConnector - JWS Payload",
5060 (u8 *)info->payload, info->payload_len);
5061 pos = end + 1;
5062 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
5063 if (!signature) {
5064 wpa_printf(MSG_DEBUG,
5065 "DPP: Failed to base64url decode signedConnector signature");
5066 ret = DPP_STATUS_INVALID_CONNECTOR;
5067 goto fail;
5068 }
5069 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5070 signature, signature_len);
5071
5072 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5073 ret = DPP_STATUS_NO_MATCH;
5074 goto fail;
5075 }
5076
5077 if (signature_len & 0x01) {
5078 wpa_printf(MSG_DEBUG,
5079 "DPP: Unexpected signedConnector signature length (%d)",
5080 (int) signature_len);
5081 ret = DPP_STATUS_INVALID_CONNECTOR;
5082 goto fail;
5083 }
5084
5085 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5086 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5087 r = crypto_bignum_init_set(signature, signature_len / 2);
5088 s = crypto_bignum_init_set(signature + signature_len / 2, signature_len / 2);
5089
5090 if (!crypto_edcsa_sign_verify((unsigned char *)signed_start, r, s,
5091 csign_pub, signed_end - signed_start + 1)) {
5092 goto fail;
5093 }
5094
5095 ret = DPP_STATUS_OK;
5096 fail:
5097 os_free(prot_hdr);
5098 wpabuf_free(kid);
5099 os_free(signature);
5100 crypto_bignum_deinit(r, 0);
5101 crypto_bignum_deinit(s, 0);
5102 return ret;
5103 }
5104
5105
dpp_parse_cred_dpp(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)5106 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5107 struct dpp_config_obj *conf,
5108 struct json_token *cred)
5109 {
5110 struct dpp_signed_connector_info info;
5111 struct json_token *token, *csign;
5112 int ret = -1;
5113 struct crypto_key *csign_pub = NULL;
5114 const struct dpp_curve_params *key_curve = NULL;
5115 const char *signed_connector;
5116
5117 os_memset(&info, 0, sizeof(info));
5118
5119 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
5120 wpa_printf(MSG_DEBUG,
5121 "DPP: Legacy credential included in Connector credential");
5122 if (dpp_parse_cred_legacy(conf, cred) < 0)
5123 return -1;
5124 }
5125
5126 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5127
5128 csign = json_get_member(cred, "csign");
5129 if (!csign || csign->type != JSON_OBJECT) {
5130 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5131 goto fail;
5132 }
5133
5134 csign_pub = dpp_parse_jwk(csign, &key_curve);
5135 if (!csign_pub) {
5136 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5137 goto fail;
5138 }
5139 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5140
5141 token = json_get_member(cred, "signedConnector");
5142 if (!token || token->type != JSON_STRING) {
5143 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5144 goto fail;
5145 }
5146 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5147 (u8 *)token->string, os_strlen(token->string));
5148 signed_connector = token->string;
5149
5150 if (os_strchr(signed_connector, '"') ||
5151 os_strchr(signed_connector, '\n')) {
5152 wpa_printf(MSG_DEBUG,
5153 "DPP: Unexpected character in signedConnector");
5154 goto fail;
5155 }
5156
5157 if (dpp_process_signed_connector(&info, csign_pub,
5158 signed_connector) != DPP_STATUS_OK)
5159 goto fail;
5160
5161 if (dpp_parse_connector(auth, conf,
5162 info.payload, info.payload_len) < 0) {
5163 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5164 goto fail;
5165 }
5166
5167 os_free(conf->connector);
5168 conf->connector = os_strdup(signed_connector);
5169
5170 dpp_copy_csign(conf, csign_pub);
5171 dpp_copy_netaccesskey(auth, conf);
5172
5173 ret = 0;
5174 fail:
5175 crypto_ec_free_key(csign_pub);
5176 os_free(info.payload);
5177 return ret;
5178 }
5179
5180
dpp_akm_str(enum dpp_akm akm)5181 const char * dpp_akm_str(enum dpp_akm akm)
5182 {
5183 switch (akm) {
5184 case DPP_AKM_DPP:
5185 return "dpp";
5186 case DPP_AKM_PSK:
5187 return "psk";
5188 case DPP_AKM_SAE:
5189 return "sae";
5190 case DPP_AKM_PSK_SAE:
5191 return "psk+sae";
5192 case DPP_AKM_SAE_DPP:
5193 return "dpp+sae";
5194 case DPP_AKM_PSK_SAE_DPP:
5195 return "dpp+psk+sae";
5196 default:
5197 return "??";
5198 }
5199 }
5200
5201
dpp_akm_selector_str(enum dpp_akm akm)5202 const char * dpp_akm_selector_str(enum dpp_akm akm)
5203 {
5204 switch (akm) {
5205 case DPP_AKM_DPP:
5206 return "506F9A02";
5207 case DPP_AKM_PSK:
5208 return "000FAC02+000FAC06";
5209 case DPP_AKM_SAE:
5210 return "000FAC08";
5211 case DPP_AKM_PSK_SAE:
5212 return "000FAC02+000FAC06+000FAC08";
5213 case DPP_AKM_SAE_DPP:
5214 return "506F9A02+000FAC08";
5215 case DPP_AKM_PSK_SAE_DPP:
5216 return "506F9A02+000FAC08+000FAC02+000FAC06";
5217 default:
5218 return "??";
5219 }
5220 }
5221
5222
dpp_akm_from_str(const char * akm)5223 static enum dpp_akm dpp_akm_from_str(const char *akm)
5224 {
5225 const char *pos;
5226 int dpp = 0, psk = 0, sae = 0;
5227
5228 if (os_strcmp(akm, "psk") == 0)
5229 return DPP_AKM_PSK;
5230 if (os_strcmp(akm, "sae") == 0)
5231 return DPP_AKM_SAE;
5232 if (os_strcmp(akm, "psk+sae") == 0)
5233 return DPP_AKM_PSK_SAE;
5234 if (os_strcmp(akm, "dpp") == 0)
5235 return DPP_AKM_DPP;
5236 if (os_strcmp(akm, "dpp+sae") == 0)
5237 return DPP_AKM_SAE_DPP;
5238 if (os_strcmp(akm, "dpp+psk+sae") == 0)
5239 return DPP_AKM_PSK_SAE_DPP;
5240
5241 pos = akm;
5242 while (*pos) {
5243 if (os_strlen(pos) < 8)
5244 break;
5245 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
5246 dpp = 1;
5247 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
5248 psk = 1;
5249 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
5250 psk = 1;
5251 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
5252 sae = 1;
5253 pos += 8;
5254 if (*pos != '+')
5255 break;
5256 pos++;
5257 }
5258
5259 if (dpp && psk && sae)
5260 return DPP_AKM_PSK_SAE_DPP;
5261 if (dpp && sae)
5262 return DPP_AKM_SAE_DPP;
5263 if (dpp)
5264 return DPP_AKM_DPP;
5265 if (psk && sae)
5266 return DPP_AKM_PSK_SAE;
5267 if (sae)
5268 return DPP_AKM_SAE;
5269 if (psk)
5270 return DPP_AKM_PSK;
5271
5272 return DPP_AKM_UNKNOWN;
5273 }
5274
5275
dpp_parse_conf_obj(struct dpp_authentication * auth,const u8 * conf_obj,u16 conf_obj_len)5276 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5277 const u8 *conf_obj, u16 conf_obj_len)
5278 {
5279 int ret = -1;
5280 struct json_token *root, *token, *discovery, *cred;
5281 struct dpp_config_obj *conf;
5282 struct wpabuf *ssid64 = NULL;
5283
5284 root = json_parse((const char *) conf_obj, conf_obj_len);
5285 if (!root)
5286 return -1;
5287 if (root->type != JSON_OBJECT) {
5288 dpp_auth_fail(auth, "JSON root is not an object");
5289 goto fail;
5290 }
5291
5292 token = json_get_member(root, "wi-fi_tech");
5293 if (!token || token->type != JSON_STRING) {
5294 dpp_auth_fail(auth, "No wi-fi_tech string value found");
5295 goto fail;
5296 }
5297 if (os_strcmp(token->string, "infra") != 0) {
5298 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5299 token->string);
5300 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
5301 goto fail;
5302 }
5303
5304 discovery = json_get_member(root, "discovery");
5305 if (!discovery || discovery->type != JSON_OBJECT) {
5306 dpp_auth_fail(auth, "No discovery object in JSON");
5307 goto fail;
5308 }
5309
5310 ssid64 = json_get_member_base64url(discovery, "ssid64");
5311 if (ssid64) {
5312 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
5313 (u8 *)wpabuf_head(ssid64), wpabuf_len(ssid64));
5314 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
5315 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
5316 goto fail;
5317 }
5318 } else {
5319 token = json_get_member(discovery, "ssid");
5320 if (!token || token->type != JSON_STRING) {
5321 dpp_auth_fail(auth,
5322 "No discovery::ssid string value found");
5323 goto fail;
5324 }
5325 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5326 (u8 *)token->string, os_strlen(token->string));
5327 if (os_strlen(token->string) > SSID_MAX_LEN) {
5328 dpp_auth_fail(auth,
5329 "Too long discovery::ssid string value");
5330 goto fail;
5331 }
5332 }
5333
5334 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
5335 wpa_printf(MSG_DEBUG,
5336 "DPP: No room for this many Config Objects - ignore this one");
5337 ret = 0;
5338 goto fail;
5339 }
5340 conf = &auth->conf_obj[auth->num_conf_obj++];
5341
5342 if (ssid64) {
5343 conf->ssid_len = wpabuf_len(ssid64);
5344 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
5345 } else {
5346 conf->ssid_len = os_strlen(token->string);
5347 os_memcpy(conf->ssid, token->string, conf->ssid_len);
5348 }
5349
5350 token = json_get_member(discovery, "ssid_charset");
5351 if (token && token->type == JSON_NUMBER) {
5352 conf->ssid_charset = token->number;
5353 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
5354 conf->ssid_charset);
5355 }
5356
5357 cred = json_get_member(root, "cred");
5358 if (!cred || cred->type != JSON_OBJECT) {
5359 dpp_auth_fail(auth, "No cred object in JSON");
5360 goto fail;
5361 }
5362
5363 token = json_get_member(cred, "akm");
5364 if (!token || token->type != JSON_STRING) {
5365 dpp_auth_fail(auth, "No cred::akm string value found");
5366 goto fail;
5367 }
5368 conf->akm = dpp_akm_from_str(token->string);
5369
5370 if (dpp_akm_legacy(conf->akm)) {
5371 if (dpp_parse_cred_legacy(conf, cred) < 0)
5372 goto fail;
5373 } else if (dpp_akm_dpp(conf->akm)) {
5374 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
5375 goto fail;
5376 } else {
5377 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5378 token->string);
5379 dpp_auth_fail(auth, "Unsupported akm");
5380 goto fail;
5381 }
5382
5383 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5384 ret = 0;
5385 fail:
5386 wpabuf_free(ssid64);
5387 json_free(root);
5388 return ret;
5389 }
5390
5391
dpp_conf_resp_rx(struct dpp_authentication * auth,const uint8_t * resp,uint32_t resp_len)5392 int dpp_conf_resp_rx(struct dpp_authentication *auth,
5393 const uint8_t *resp, uint32_t resp_len)
5394 {
5395 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5396 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5397 const u8 *addr[1];
5398 size_t len[1];
5399 u8 *unwrapped = NULL;
5400 size_t unwrapped_len = 0;
5401 int ret = -1;
5402
5403 auth->conf_resp_status = 255;
5404
5405 if (dpp_check_attrs(resp, resp_len) < 0) {
5406 dpp_auth_fail(auth, "Invalid attribute in config response");
5407 return -1;
5408 }
5409
5410 wrapped_data = dpp_get_attr(resp, resp_len,
5411 DPP_ATTR_WRAPPED_DATA,
5412 &wrapped_data_len);
5413 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5414 dpp_auth_fail(auth,
5415 "Missing or invalid required Wrapped Data attribute");
5416 return -1;
5417 }
5418
5419 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5420 wrapped_data, wrapped_data_len);
5421 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5422 unwrapped = os_malloc(unwrapped_len);
5423 if (!unwrapped)
5424 return -1;
5425
5426 addr[0] = resp;
5427 len[0] = wrapped_data - 4 - resp;
5428 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5429
5430 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5431 wrapped_data, wrapped_data_len,
5432 1, addr, len, unwrapped) < 0) {
5433 dpp_auth_fail(auth, "AES-SIV decryption failed");
5434 goto fail;
5435 }
5436 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5437 unwrapped, unwrapped_len);
5438
5439 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5440 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5441 goto fail;
5442 }
5443
5444 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5445 DPP_ATTR_ENROLLEE_NONCE,
5446 &e_nonce_len);
5447 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5448 dpp_auth_fail(auth,
5449 "Missing or invalid Enrollee Nonce attribute");
5450 goto fail;
5451 }
5452 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5453 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
5454 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
5455 goto fail;
5456 }
5457
5458 status = dpp_get_attr(resp, resp_len,
5459 DPP_ATTR_STATUS, &status_len);
5460 if (!status || status_len < 1) {
5461 dpp_auth_fail(auth,
5462 "Missing or invalid required DPP Status attribute");
5463 goto fail;
5464 }
5465 auth->conf_resp_status = status[0];
5466 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5467 if (status[0] != DPP_STATUS_OK) {
5468 dpp_auth_fail(auth, "Configurator rejected configuration");
5469 goto fail;
5470 }
5471
5472 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
5473 &conf_obj_len);
5474 if (!conf_obj) {
5475 dpp_auth_fail(auth,
5476 "Missing required Configuration Object attribute");
5477 goto fail;
5478 }
5479 while (conf_obj) {
5480 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5481 (u8 *)conf_obj, conf_obj_len);
5482 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5483 goto fail;
5484 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
5485 DPP_ATTR_CONFIG_OBJ,
5486 &conf_obj_len);
5487 }
5488
5489 ret = 0;
5490
5491 fail:
5492 os_free(unwrapped);
5493 return ret;
5494 }
5495
dpp_configurator_free(struct dpp_configurator * conf)5496 void dpp_configurator_free(struct dpp_configurator *conf)
5497 {
5498 if (!conf)
5499 return;
5500 crypto_ec_free_key(conf->csign);
5501 os_free(conf->kid);
5502 os_free(conf);
5503 }
5504
5505
dpp_configurator_get_key(const struct dpp_configurator * conf,char * buf,size_t buflen)5506 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
5507 size_t buflen)
5508 {
5509 int keylen, ret = -1;
5510 unsigned char *key = NULL;
5511
5512 if (!conf->csign)
5513 return ret;
5514
5515 crypto_ec_get_priv_key_der(conf->csign, &key, &keylen);
5516
5517 if (keylen > 0)
5518 ret = wpa_snprintf_hex(buf, buflen, key, keylen);
5519
5520 crypto_free_buffer(key);
5521
5522 return ret;
5523 }
5524
5525
5526 struct dpp_configurator *
dpp_keygen_configurator(const char * curve,u8 * privkey,size_t privkey_len)5527 dpp_keygen_configurator(const char *curve, u8 *privkey,
5528 size_t privkey_len)
5529 {
5530 struct dpp_configurator *conf;
5531 struct wpabuf *csign_pub = NULL;
5532 u8 kid_hash[SHA256_MAC_LEN];
5533 const u8 *addr[1];
5534 size_t len[1];
5535
5536 conf = os_zalloc(sizeof(*conf));
5537 if (!conf)
5538 return NULL;
5539
5540 if (!curve) {
5541 conf->curve = &dpp_curves[0];
5542 } else {
5543 conf->curve = dpp_get_curve_name(curve);
5544 if (!conf->curve) {
5545 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5546 curve);
5547 os_free(conf);
5548 return NULL;
5549 }
5550 }
5551 if (privkey)
5552 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5553 privkey_len);
5554 else
5555 conf->csign = dpp_gen_keypair(conf->curve);
5556 if (!conf->csign)
5557 goto fail;
5558 conf->own = 1;
5559
5560 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5561 if (!csign_pub) {
5562 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5563 goto fail;
5564 }
5565
5566 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5567 addr[0] = wpabuf_head(csign_pub);
5568 len[0] = wpabuf_len(csign_pub);
5569 if (sha256_vector(1, addr, len, kid_hash) < 0) {
5570 wpa_printf(MSG_DEBUG,
5571 "DPP: Failed to derive kid for C-sign-key");
5572 goto fail;
5573 }
5574
5575 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
5576 if (!conf->kid)
5577 goto fail;
5578 out:
5579 wpabuf_free(csign_pub);
5580 return conf;
5581 fail:
5582 dpp_configurator_free(conf);
5583 conf = NULL;
5584 goto out;
5585 }
5586
5587
dpp_configurator_own_config(struct dpp_authentication * auth,const char * curve,int ap)5588 int dpp_configurator_own_config(struct dpp_authentication *auth,
5589 const char *curve, int ap)
5590 {
5591 struct wpabuf *conf_obj;
5592 int ret = -1;
5593
5594 if (!auth->conf) {
5595 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5596 return -1;
5597 }
5598
5599 if (!curve) {
5600 auth->curve = &dpp_curves[0];
5601 } else {
5602 auth->curve = dpp_get_curve_name(curve);
5603 if (!auth->curve) {
5604 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5605 curve);
5606 return -1;
5607 }
5608 }
5609 wpa_printf(MSG_DEBUG,
5610 "DPP: Building own configuration/connector with curve %s",
5611 auth->curve->name);
5612
5613 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5614 if (!auth->own_protocol_key)
5615 return -1;
5616 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
5617 auth->peer_protocol_key = auth->own_protocol_key;
5618 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
5619
5620 conf_obj = dpp_build_conf_obj(auth, ap, 0);
5621 if (!conf_obj) {
5622 wpabuf_free(auth->conf_obj[0].c_sign_key);
5623 auth->conf_obj[0].c_sign_key = NULL;
5624 goto fail;
5625 }
5626 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5627 wpabuf_len(conf_obj));
5628 fail:
5629 wpabuf_free(conf_obj);
5630 auth->peer_protocol_key = NULL;
5631 return ret;
5632 }
5633
5634
dpp_compatible_netrole(const char * role1,const char * role2)5635 static int dpp_compatible_netrole(const char *role1, const char *role2)
5636 {
5637 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5638 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5639 }
5640
dpp_connector_compatible_group(struct json_token * root,const char * group_id,const char * net_role)5641 static int dpp_connector_compatible_group(struct json_token *root,
5642 const char *group_id,
5643 const char *net_role)
5644 {
5645 struct json_token *groups, *token;
5646
5647 groups = json_get_member(root, "groups");
5648 if (!groups || groups->type != JSON_ARRAY)
5649 return 0;
5650
5651 for (token = groups->child; token; token = token->sibling) {
5652 struct json_token *id, *role;
5653
5654 id = json_get_member(token, "groupId");
5655 if (!id || id->type != JSON_STRING)
5656 continue;
5657
5658 role = json_get_member(token, "netRole");
5659 if (!role || role->type != JSON_STRING)
5660 continue;
5661
5662 if (os_strcmp(id->string, "*") != 0 &&
5663 os_strcmp(group_id, "*") != 0 &&
5664 os_strcmp(id->string, group_id) != 0)
5665 continue;
5666
5667 if (dpp_compatible_netrole(role->string, net_role))
5668 return 1;
5669 }
5670
5671 return 0;
5672 }
5673
dpp_connector_match_groups(struct json_token * own_root,struct json_token * peer_root)5674 static int dpp_connector_match_groups(struct json_token *own_root,
5675 struct json_token *peer_root)
5676 {
5677 struct json_token *groups, *token;
5678
5679 groups = json_get_member(peer_root, "groups");
5680 if (!groups || groups->type != JSON_ARRAY) {
5681 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
5682 return 0;
5683 }
5684
5685 for (token = groups->child; token; token = token->sibling) {
5686 struct json_token *id, *role;
5687
5688 id = json_get_member(token, "groupId");
5689 if (!id || id->type != JSON_STRING) {
5690 wpa_printf(MSG_DEBUG,
5691 "DPP: Missing peer groupId string");
5692 continue;
5693 }
5694
5695 role = json_get_member(token, "netRole");
5696 if (!role || role->type != JSON_STRING) {
5697 wpa_printf(MSG_DEBUG,
5698 "DPP: Missing peer groups::netRole string");
5699 continue;
5700 }
5701 wpa_printf(MSG_DEBUG,
5702 "DPP: peer connector group: groupId='%s' netRole='%s'",
5703 id->string, role->string);
5704 if (dpp_connector_compatible_group(own_root, id->string,
5705 role->string)) {
5706 wpa_printf(MSG_DEBUG,
5707 "DPP: Compatible group/netRole in own connector");
5708 return 1;
5709 }
5710 }
5711
5712 return 0;
5713 }
5714
dpp_derive_pmk(const u8 * Nx,size_t Nx_len,u8 * pmk,unsigned int hash_len)5715 static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5716 unsigned int hash_len)
5717 {
5718 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5719 const char *info = "DPP PMK";
5720 int res;
5721
5722 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5723
5724 /* HKDF-Extract(<>, N.x) */
5725 os_memset(salt, 0, hash_len);
5726 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
5727 return -1;
5728 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5729 prk, hash_len);
5730
5731 /* HKDF-Expand(PRK, info, L) */
5732 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
5733 forced_memzero(prk, hash_len);
5734 if (res < 0)
5735 return -1;
5736
5737 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5738 pmk, hash_len);
5739 return 0;
5740 }
5741
5742
dpp_derive_pmkid(const struct dpp_curve_params * curve,struct crypto_key * own_key,struct crypto_key * peer_key,u8 * pmkid)5743 static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5744 struct crypto_key *own_key, struct crypto_key *peer_key, u8 *pmkid)
5745 {
5746 struct wpabuf *nkx, *pkx;
5747 int ret = -1, res;
5748 const u8 *addr[2];
5749 size_t len[2];
5750 u8 hash[SHA256_MAC_LEN];
5751
5752 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5753 nkx = dpp_get_pubkey_point(own_key, 0);
5754 pkx = dpp_get_pubkey_point(peer_key, 0);
5755 if (!nkx || !pkx)
5756 goto fail;
5757 addr[0] = wpabuf_head(nkx);
5758 len[0] = wpabuf_len(nkx) / 2;
5759 addr[1] = wpabuf_head(pkx);
5760 len[1] = wpabuf_len(pkx) / 2;
5761 if (len[0] != len[1])
5762 goto fail;
5763 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5764 addr[0] = wpabuf_head(pkx);
5765 addr[1] = wpabuf_head(nkx);
5766 }
5767 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5768 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
5769 res = sha256_vector(2, addr, len, hash);
5770 if (res < 0)
5771 goto fail;
5772 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
5773 os_memcpy(pmkid, hash, PMKID_LEN);
5774 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5775 ret = 0;
5776 fail:
5777 wpabuf_free(nkx);
5778 wpabuf_free(pkx);
5779 return ret;
5780 }
5781
5782
5783 enum dpp_status_error
dpp_peer_intro(struct dpp_introduction * intro,const char * own_connector,const u8 * net_access_key,size_t net_access_key_len,const u8 * csign_key,size_t csign_key_len,const u8 * peer_connector,size_t peer_connector_len,os_time_t * expiry)5784 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5785 const u8 *net_access_key, size_t net_access_key_len,
5786 const u8 *csign_key, size_t csign_key_len,
5787 const u8 *peer_connector, size_t peer_connector_len,
5788 os_time_t *expiry)
5789 {
5790 struct json_token *root = NULL, *netkey, *token;
5791 struct json_token *own_root = NULL;
5792 enum dpp_status_error ret = 255, res;
5793 struct crypto_key *own_key = NULL, *peer_key = NULL;
5794 struct wpabuf *own_key_pub = NULL;
5795 const struct dpp_curve_params *curve, *own_curve;
5796 struct dpp_signed_connector_info info;
5797 const unsigned char *p;
5798 struct crypto_key *csign = NULL;
5799 char *signed_connector = NULL;
5800 const char *pos, *end;
5801 unsigned char *own_conn = NULL;
5802 size_t own_conn_len;
5803 size_t Nx_len;
5804 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
5805
5806 os_memset(intro, 0, sizeof(*intro));
5807 os_memset(&info, 0, sizeof(info));
5808 if (expiry)
5809 *expiry = 0;
5810
5811 p = csign_key;
5812 csign = crypto_ec_parse_subpub_key(p, csign_key_len);
5813 if (!csign) {
5814 wpa_printf(MSG_ERROR,
5815 "DPP: Failed to parse local C-sign-key information");
5816 goto fail;
5817 }
5818
5819 own_key = dpp_set_keypair(&own_curve, net_access_key,
5820 net_access_key_len);
5821 if (!own_key) {
5822 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5823 goto fail;
5824 }
5825
5826 pos = os_strchr(own_connector, '.');
5827 if (!pos) {
5828 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
5829 goto fail;
5830 }
5831 pos++;
5832 end = os_strchr(pos, '.');
5833 if (!end) {
5834 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
5835 goto fail;
5836 }
5837 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
5838 if (!own_conn) {
5839 wpa_printf(MSG_DEBUG,
5840 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5841 goto fail;
5842 }
5843
5844 own_root = json_parse((const char *) own_conn, own_conn_len);
5845 if (!own_root) {
5846 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5847 goto fail;
5848 }
5849
5850 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5851 (u8 *)peer_connector, peer_connector_len);
5852 signed_connector = os_malloc(peer_connector_len + 1);
5853 if (!signed_connector)
5854 goto fail;
5855 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5856 signed_connector[peer_connector_len] = '\0';
5857
5858 res = dpp_process_signed_connector(&info, csign, signed_connector);
5859 if (res != DPP_STATUS_OK) {
5860 ret = res;
5861 goto fail;
5862 }
5863
5864 root = json_parse((const char *) info.payload, info.payload_len);
5865 if (!root) {
5866 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5867 ret = DPP_STATUS_INVALID_CONNECTOR;
5868 goto fail;
5869 }
5870
5871 if (!dpp_connector_match_groups(own_root, root)) {
5872 wpa_printf(MSG_DEBUG,
5873 "DPP: Peer connector does not include compatible group netrole with own connector");
5874 ret = DPP_STATUS_NO_MATCH;
5875 goto fail;
5876 }
5877
5878 token = json_get_member(root, "expiry");
5879 if (!token || token->type != JSON_STRING) {
5880 wpa_printf(MSG_DEBUG,
5881 "DPP: No expiry string found - connector does not expire");
5882 } else {
5883 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5884 if (dpp_key_expired(token->string, expiry)) {
5885 wpa_printf(MSG_DEBUG,
5886 "DPP: Connector (netAccessKey) has expired");
5887 ret = DPP_STATUS_INVALID_CONNECTOR;
5888 goto fail;
5889 }
5890 }
5891
5892 netkey = json_get_member(root, "netAccessKey");
5893 if (!netkey || netkey->type != JSON_OBJECT) {
5894 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5895 ret = DPP_STATUS_INVALID_CONNECTOR;
5896 goto fail;
5897 }
5898
5899 peer_key = dpp_parse_jwk(netkey, &curve);
5900 if (!peer_key) {
5901 ret = DPP_STATUS_INVALID_CONNECTOR;
5902 goto fail;
5903 }
5904 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5905
5906 if (own_curve != curve) {
5907 wpa_printf(MSG_DEBUG,
5908 "DPP: Mismatching netAccessKey curves (%s != %s)",
5909 own_curve->name, curve->name);
5910 ret = DPP_STATUS_INVALID_CONNECTOR;
5911 goto fail;
5912 }
5913
5914 /* ECDH: N = nk * PK */
5915 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
5916 goto fail;
5917
5918 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5919 Nx, Nx_len);
5920
5921 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5922 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5923 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5924 goto fail;
5925 }
5926 intro->pmk_len = curve->hash_len;
5927
5928 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5929 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5930 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5931 goto fail;
5932 }
5933
5934 ret = DPP_STATUS_OK;
5935 fail:
5936 if (ret != DPP_STATUS_OK)
5937 os_memset(intro, 0, sizeof(*intro));
5938 forced_memzero(Nx, sizeof(Nx));
5939 os_free(own_conn);
5940 os_free(signed_connector);
5941 os_free(info.payload);
5942 crypto_ec_free_key(own_key);
5943 wpabuf_free(own_key_pub);
5944 crypto_ec_free_key(peer_key);
5945 crypto_ec_free_key(csign);
5946 json_free(root);
5947 json_free(own_root);
5948 return ret;
5949 }
5950
5951 #ifdef CONFIG_TESTING_OPTIONS
dpp_test_gen_invalid_key(struct wpabuf * msg,const struct dpp_curve_params * curve)5952 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
5953 const struct dpp_curve_params *curve)
5954 {
5955 return 0;
5956 }
5957
dpp_corrupt_connector_signature(const char * connector)5958 char * dpp_corrupt_connector_signature(const char *connector)
5959 {
5960 char *tmp, *pos, *signed3 = NULL;
5961 unsigned char *signature = NULL;
5962 size_t signature_len = 0, signed3_len;
5963
5964 tmp = os_zalloc(os_strlen(connector) + 5);
5965 if (!tmp)
5966 goto fail;
5967 os_memcpy(tmp, connector, os_strlen(connector));
5968
5969 pos = os_strchr(tmp, '.');
5970 if (!pos)
5971 goto fail;
5972
5973 pos = os_strchr(pos + 1, '.');
5974 if (!pos)
5975 goto fail;
5976 pos++;
5977
5978 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
5979 pos);
5980 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
5981 if (!signature || signature_len == 0)
5982 goto fail;
5983 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
5984 signature, signature_len);
5985 signature[signature_len - 1] ^= 0x01;
5986 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
5987 signature, signature_len);
5988 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
5989 if (!signed3)
5990 goto fail;
5991 os_memcpy(pos, signed3, signed3_len);
5992 pos[signed3_len] = '\0';
5993 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
5994 pos);
5995
5996 out:
5997 os_free(signature);
5998 os_free(signed3);
5999 return tmp;
6000 fail:
6001 os_free(tmp);
6002 tmp = NULL;
6003 goto out;
6004 }
6005 #endif /* CONFIG_TESTING_OPTIONS */
6006
dpp_next_id(struct dpp_global * dpp)6007 static unsigned int dpp_next_id(struct dpp_global *dpp)
6008 {
6009 struct dpp_bootstrap_info *bi;
6010 unsigned int max_id = 0;
6011
6012 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6013 if (bi->id > max_id)
6014 max_id = bi->id;
6015 }
6016 return max_id + 1;
6017 }
6018
dpp_bootstrap_del(struct dpp_global * dpp,unsigned int id)6019 static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
6020 {
6021 struct dpp_bootstrap_info *bi, *tmp;
6022 int found = 0;
6023
6024 if (!dpp)
6025 return -1;
6026
6027 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
6028 struct dpp_bootstrap_info, list) {
6029 if (id && bi->id != id)
6030 continue;
6031 found = 1;
6032 dl_list_del(&bi->list);
6033 dpp_bootstrap_info_free(bi);
6034 }
6035
6036 if (id == 0)
6037 return 0; /* flush succeeds regardless of entries found */
6038 return found ? 0 : -1;
6039 }
6040
6041
dpp_add_qr_code(struct dpp_global * dpp,const char * uri)6042 struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
6043 const char *uri)
6044 {
6045 struct dpp_bootstrap_info *bi;
6046
6047 if (!dpp)
6048 return NULL;
6049
6050 bi = dpp_parse_uri(uri);
6051 if (!bi)
6052 return NULL;
6053
6054 bi->type = DPP_BOOTSTRAP_QR_CODE;
6055 bi->id = dpp_next_id(dpp);
6056 dl_list_add(&dpp->bootstrap, &bi->list);
6057 return bi;
6058 }
6059
6060
dpp_add_nfc_uri(struct dpp_global * dpp,const char * uri)6061 struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
6062 const char *uri)
6063 {
6064 struct dpp_bootstrap_info *bi;
6065
6066 if (!dpp)
6067 return NULL;
6068
6069 bi = dpp_parse_uri(uri);
6070 if (!bi)
6071 return NULL;
6072
6073 bi->type = DPP_BOOTSTRAP_NFC_URI;
6074 bi->id = dpp_next_id(dpp);
6075 dl_list_add(&dpp->bootstrap, &bi->list);
6076 return bi;
6077 }
6078
6079
dpp_bootstrap_gen(struct dpp_global * dpp,const char * cmd)6080 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
6081 {
6082 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
6083 char *key = NULL;
6084 u8 *privkey = NULL;
6085 size_t privkey_len = 0;
6086 size_t len;
6087 int ret = -1;
6088 struct dpp_bootstrap_info *bi;
6089
6090 bi = os_zalloc(sizeof(*bi));
6091 if (!bi)
6092 goto fail;
6093
6094 if (os_strstr(cmd, "type=qrcode"))
6095 bi->type = DPP_BOOTSTRAP_QR_CODE;
6096 else if (os_strstr(cmd, "type=pkex"))
6097 bi->type = DPP_BOOTSTRAP_PKEX;
6098 else if (os_strstr(cmd, "type=nfc-uri"))
6099 bi->type = DPP_BOOTSTRAP_NFC_URI;
6100 else
6101 goto fail;
6102
6103 chan = get_param(cmd, " chan=");
6104 mac = get_param(cmd, " mac=");
6105 info = get_param(cmd, " info=");
6106 curve = get_param(cmd, " curve=");
6107 key = get_param(cmd, " key=");
6108
6109 if (key) {
6110 privkey_len = os_strlen(key) / 2;
6111 privkey = os_malloc(privkey_len);
6112 if (!privkey ||
6113 hexstr2bin(key, privkey, privkey_len) < 0)
6114 goto fail;
6115 }
6116 wpa_hexdump(MSG_DEBUG, "private key", privkey, privkey_len);
6117
6118 pk = dpp_keygen(bi, curve, privkey, privkey_len);
6119 if (!pk)
6120 goto fail;
6121
6122 len = 4; /* "DPP:" */
6123 if (chan) {
6124 if (dpp_parse_uri_chan_list(bi, chan) < 0)
6125 goto fail;
6126 len += 3 + os_strlen(chan); /* C:...; */
6127 }
6128 if (mac) {
6129 if (dpp_parse_uri_mac(bi, mac) < 0)
6130 goto fail;
6131 len += 3 + os_strlen(mac); /* M:...; */
6132 }
6133 if (info) {
6134 if (dpp_parse_uri_info(bi, info) < 0)
6135 goto fail;
6136 len += 3 + os_strlen(info); /* I:...; */
6137 }
6138 len += 4 + os_strlen(pk);
6139 bi->uri = os_malloc(len + 1);
6140 if (!bi->uri)
6141 goto fail;
6142 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
6143 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
6144 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
6145 info ? "I:" : "", info ? info : "", info ? ";" : "",
6146 pk);
6147
6148 bi->id = dpp_next_id(dpp);
6149 dl_list_add(&dpp->bootstrap, &bi->list);
6150 ret = bi->id;
6151 bi = NULL;
6152 fail:
6153 os_free(curve);
6154 os_free(pk);
6155 os_free(chan);
6156 os_free(mac);
6157 os_free(info);
6158 str_clear_free(key);
6159 bin_clear_free(privkey, privkey_len);
6160 dpp_bootstrap_info_free(bi);
6161 return ret;
6162 }
6163
6164
6165 struct dpp_bootstrap_info *
dpp_bootstrap_get_id(struct dpp_global * dpp,unsigned int id)6166 dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
6167 {
6168 struct dpp_bootstrap_info *bi;
6169
6170 if (!dpp)
6171 return NULL;
6172
6173 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6174 if (bi->id == id)
6175 return bi;
6176 }
6177 return NULL;
6178 }
6179
6180
dpp_bootstrap_remove(struct dpp_global * dpp,const char * id)6181 int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
6182 {
6183 unsigned int id_val;
6184
6185 if (os_strcmp(id, "*") == 0) {
6186 id_val = 0;
6187 } else {
6188 id_val = atoi(id);
6189 if (id_val == 0)
6190 return -1;
6191 }
6192
6193 return dpp_bootstrap_del(dpp, id_val);
6194 }
6195
dpp_bootstrap_get_uri(struct dpp_global * dpp,unsigned int id)6196 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
6197 {
6198 struct dpp_bootstrap_info *bi;
6199
6200 bi = dpp_bootstrap_get_id(dpp, id);
6201 if (!bi)
6202 return NULL;
6203 return bi->uri;
6204 }
6205
dpp_get_bootstrap_info(struct dpp_global * dpp,int id,char * reply,int reply_size)6206 int dpp_get_bootstrap_info(struct dpp_global *dpp, int id,
6207 char *reply, int reply_size)
6208 {
6209 struct dpp_bootstrap_info *bi;
6210 char pkhash[2 * SHA256_MAC_LEN + 1];
6211
6212 bi = dpp_bootstrap_get_id(dpp, id);
6213 if (!bi)
6214 return -1;
6215 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
6216 SHA256_MAC_LEN);
6217 return os_snprintf(reply, reply_size, "type=%s\n"
6218 "mac_addr=" MACSTR "\n"
6219 "info=%s\n"
6220 "num_freq=%u\n"
6221 "curve=%s\n"
6222 "pkhash=%s\n",
6223 dpp_bootstrap_type_txt(bi->type),
6224 MAC2STR(bi->mac_addr),
6225 bi->info ? bi->info : "",
6226 bi->num_freq,
6227 bi->curve->name,
6228 pkhash);
6229 }
6230
6231
dpp_bootstrap_find_pair(struct dpp_global * dpp,const u8 * i_bootstrap,const u8 * r_bootstrap,struct dpp_bootstrap_info ** own_bi,struct dpp_bootstrap_info ** peer_bi)6232 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
6233 const u8 *r_bootstrap,
6234 struct dpp_bootstrap_info **own_bi,
6235 struct dpp_bootstrap_info **peer_bi)
6236 {
6237 struct dpp_bootstrap_info *bi;
6238
6239 *own_bi = NULL;
6240 *peer_bi = NULL;
6241 if (!dpp)
6242 return;
6243
6244 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6245 if (!*own_bi && bi->own &&
6246 os_memcmp(bi->pubkey_hash, r_bootstrap,
6247 SHA256_MAC_LEN) == 0) {
6248 wpa_printf(MSG_DEBUG,
6249 "DPP: Found matching own bootstrapping information");
6250 *own_bi = bi;
6251 }
6252
6253 if (!*peer_bi && !bi->own &&
6254 os_memcmp(bi->pubkey_hash, i_bootstrap,
6255 SHA256_MAC_LEN) == 0) {
6256 wpa_printf(MSG_DEBUG,
6257 "DPP: Found matching peer bootstrapping information");
6258 *peer_bi = bi;
6259 }
6260
6261 if (*own_bi && *peer_bi)
6262 break;
6263 }
6264
6265 }
6266
6267
dpp_next_configurator_id(struct dpp_global * dpp)6268 static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
6269 {
6270 struct dpp_configurator *conf;
6271 unsigned int max_id = 0;
6272
6273 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
6274 list) {
6275 if (conf->id > max_id)
6276 max_id = conf->id;
6277 }
6278 return max_id + 1;
6279 }
6280
6281
dpp_configurator_add(struct dpp_global * dpp,const char * cmd)6282 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
6283 {
6284 char *curve = NULL;
6285 char *key = NULL;
6286 u8 *privkey = NULL;
6287 size_t privkey_len = 0;
6288 int ret = -1;
6289 struct dpp_configurator *conf = NULL;
6290
6291 curve = get_param(cmd, " curve=");
6292 key = get_param(cmd, " key=");
6293
6294 if (key) {
6295 privkey_len = os_strlen(key) / 2;
6296 privkey = os_malloc(privkey_len);
6297 if (!privkey ||
6298 hexstr2bin(key, privkey, privkey_len) < 0)
6299 goto fail;
6300 }
6301
6302 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
6303 if (!conf)
6304 goto fail;
6305
6306 conf->id = dpp_next_configurator_id(dpp);
6307 dl_list_add(&dpp->configurator, &conf->list);
6308 ret = conf->id;
6309 conf = NULL;
6310 fail:
6311 os_free(curve);
6312 str_clear_free(key);
6313 bin_clear_free(privkey, privkey_len);
6314 dpp_configurator_free(conf);
6315 return ret;
6316 }
6317
6318
dpp_configurator_del(struct dpp_global * dpp,unsigned int id)6319 static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
6320 {
6321 struct dpp_configurator *conf, *tmp;
6322 int found = 0;
6323
6324 if (!dpp)
6325 return -1;
6326
6327 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
6328 struct dpp_configurator, list) {
6329 if (id && conf->id != id)
6330 continue;
6331 found = 1;
6332 dl_list_del(&conf->list);
6333 dpp_configurator_free(conf);
6334 }
6335
6336 if (id == 0)
6337 return 0; /* flush succeeds regardless of entries found */
6338 return found ? 0 : -1;
6339 }
6340
6341
dpp_configurator_remove(struct dpp_global * dpp,const char * id)6342 int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
6343 {
6344 unsigned int id_val;
6345
6346 if (os_strcmp(id, "*") == 0) {
6347 id_val = 0;
6348 } else {
6349 id_val = atoi(id);
6350 if (id_val == 0)
6351 return -1;
6352 }
6353
6354 return dpp_configurator_del(dpp, id_val);
6355 }
6356
6357
dpp_configurator_get_key_id(struct dpp_global * dpp,unsigned int id,char * buf,size_t buflen)6358 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
6359 char *buf, size_t buflen)
6360 {
6361 struct dpp_configurator *conf;
6362
6363 conf = dpp_configurator_get_id(dpp, id);
6364 if (!conf)
6365 return -1;
6366
6367 return dpp_configurator_get_key(conf, buf, buflen);
6368 }
6369
dpp_global_init(struct dpp_global_config * config)6370 struct dpp_global * dpp_global_init(struct dpp_global_config *config)
6371 {
6372 struct dpp_global *dpp;
6373
6374 dpp = os_zalloc(sizeof(*dpp));
6375 if (!dpp)
6376 return NULL;
6377 dpp->msg_ctx = config->msg_ctx;
6378
6379 dl_list_init(&dpp->bootstrap);
6380 dl_list_init(&dpp->configurator);
6381
6382 return dpp;
6383 }
6384
6385
dpp_global_clear(struct dpp_global * dpp)6386 void dpp_global_clear(struct dpp_global *dpp)
6387 {
6388 if (!dpp)
6389 return;
6390
6391 dpp_bootstrap_del(dpp, 0);
6392 dpp_configurator_del(dpp, 0);
6393 }
6394
6395
dpp_global_deinit(struct dpp_global * dpp)6396 void dpp_global_deinit(struct dpp_global *dpp)
6397 {
6398 dpp_global_clear(dpp);
6399 os_free(dpp);
6400 }
6401