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_WPA_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_WPA_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\n", __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 os_memset(prk, 0, 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 os_memset(prk, 0, 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 os_memset(prk, 0, 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_WPA_TESTING_OPTIONS
1004 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
1005 attr_len += 5;
1006 #endif /* CONFIG_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
1043
1044 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1045 pos = clear;
1046
1047 #ifdef CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
1164 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
1165 attr_len += 5;
1166 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
1225 pos += nonce_len;
1226 }
1227
1228 #ifdef CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
1527 u8 test_hash[SHA256_MAC_LEN];
1528 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
1566 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
1567
1568 #ifdef CONFIG_WPA_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_WPA_TESTING_OPTIONS */
1581 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1582 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
1679 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
1680 attr_len += 5;
1681 #endif /* CONFIG_WPA_TESTING_OPTIONS */
1682 msg = wpabuf_alloc(attr_len);
1683 if (!clear || !msg)
1684 goto fail;
1685
1686 #ifdef CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
1723 skip_conf_attr_obj:
1724 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
2155 u8 test_hash[SHA256_MAC_LEN];
2156 #endif /* CONFIG_WPA_TESTING_OPTIONS */
2157
2158 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
2159 if (!auth->own_bi)
2160 return -1;
2161
2162 #ifdef CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
2198 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2199 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
2333 u8 test_hash[SHA256_MAC_LEN];
2334 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
2683 u8 test_hash[SHA256_MAC_LEN];
2684 #endif /* CONFIG_WPA_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_WPA_TESTING_OPTIONS
2694 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
2695 attr_len += 5;
2696 #endif /* CONFIG_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
2718
2719 /* DPP Status */
2720 dpp_build_attr_status(msg, status);
2721
2722 #ifdef CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
2782 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
2783 goto skip_i_auth;
2784 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS */
3635 goto fail;
3636 #endif /* CONFIG_WPA_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_WPA_TESTING_OPTIONS
3838 os_free(auth->config_obj_override);
3839 os_free(auth->discovery_override);
3840 os_free(auth->groups_override);
3841 #endif /* CONFIG_WPA_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_WPA_TESTING_OPTIONS
3853 if (auth->discovery_override)
3854 tailroom += os_strlen(auth->discovery_override);
3855 #endif /* CONFIG_WPA_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_WPA_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_WPA_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 os_memset(psk, 0, 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_WPA_TESTING_OPTIONS
4018 if (auth->groups_override)
4019 extra_len += os_strlen(auth->groups_override);
4020 #endif /* CONFIG_WPA_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_WPA_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_WPA_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_WPA_TESTING_OPTIONS
4054 skip_groups:
4055 #endif /* CONFIG_WPA_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 (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
4114 dpp_bn2bin_pad(s, signature + curve->prime_len,
4115 curve->prime_len) < 0)
4116 goto fail;
4117 signature_len = 2 * curve->prime_len;
4118 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
4119 signature, signature_len);
4120 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
4121 if (!signed3)
4122 goto fail;
4123
4124 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
4125 tailroom = 1000;
4126 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
4127 tailroom += signed1_len + signed2_len + signed3_len;
4128 if (incl_legacy)
4129 tailroom += 1000;
4130 buf = dpp_build_conf_start(auth, conf, tailroom);
4131 if (!buf)
4132 goto fail;
4133
4134 if (auth->akm_use_selector && dpp_akm_ver2(akm))
4135 akm_str = dpp_akm_selector_str(akm);
4136 else
4137 akm_str = dpp_akm_str(akm);
4138 json_start_object(buf, "cred");
4139 json_add_string(buf, "akm", akm_str);
4140 json_value_sep(buf);
4141 if (incl_legacy) {
4142 dpp_build_legacy_cred_params(buf, conf);
4143 json_value_sep(buf);
4144 }
4145 wpabuf_put_str(buf, "\"signedConnector\":\"");
4146 wpabuf_put_str(buf, signed1);
4147 wpabuf_put_u8(buf, '.');
4148 wpabuf_put_str(buf, signed2);
4149 wpabuf_put_u8(buf, '.');
4150 wpabuf_put_str(buf, signed3);
4151 wpabuf_put_str(buf, "\"");
4152 json_value_sep(buf);
4153 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
4154 curve) < 0) {
4155 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
4156 goto fail;
4157 }
4158
4159 json_end_object(buf);
4160 json_end_object(buf);
4161
4162 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
4163 (u8 *)wpabuf_head(buf), wpabuf_len(buf));
4164
4165 out:
4166 if (signed1)
4167 os_free(signed1);
4168 if (signed2)
4169 os_free(signed2);
4170 if (signed3)
4171 os_free(signed3);
4172 if (hash)
4173 os_free(hash);
4174 if (signature)
4175 os_free(signature);
4176 crypto_bignum_deinit(r, 0);
4177 crypto_bignum_deinit(s, 0);
4178 wpabuf_free(dppcon);
4179 return buf;
4180 fail:
4181 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
4182 wpabuf_free(buf);
4183 buf = NULL;
4184 goto out;
4185 }
4186
4187 static struct wpabuf *
dpp_build_conf_obj_legacy(struct dpp_authentication * auth,struct dpp_configuration * conf)4188 dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
4189 struct dpp_configuration *conf)
4190 {
4191 struct wpabuf *buf;
4192 const char *akm_str;
4193
4194 buf = dpp_build_conf_start(auth, conf, 1000);
4195 if (!buf)
4196 return NULL;
4197
4198 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
4199 akm_str = dpp_akm_selector_str(conf->akm);
4200 else
4201 akm_str = dpp_akm_str(conf->akm);
4202 json_start_object(buf, "cred");
4203 json_add_string(buf, "akm", akm_str);
4204 json_value_sep(buf);
4205 dpp_build_legacy_cred_params(buf, conf);
4206 json_end_object(buf);
4207 json_end_object(buf);
4208
4209 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
4210 (u8 *)wpabuf_head(buf), wpabuf_len(buf));
4211
4212 return buf;
4213 }
4214
4215
4216 static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication * auth,enum dpp_netrole netrole,int idx)4217 dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
4218 int idx)
4219 {
4220 struct dpp_configuration *conf = NULL;
4221
4222 #ifdef CONFIG_WPA_TESTING_OPTIONS
4223 if (auth->config_obj_override) {
4224 if (idx != 0)
4225 return NULL;
4226 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
4227 return wpabuf_alloc_copy(auth->config_obj_override,
4228 os_strlen(auth->config_obj_override));
4229 }
4230 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4231
4232 if (idx == 0) {
4233 if (netrole == DPP_NETROLE_STA)
4234 conf = auth->conf_sta;
4235 else if (netrole == DPP_NETROLE_AP)
4236 conf = auth->conf_ap;
4237 } else if (idx == 1) {
4238 if (netrole == DPP_NETROLE_STA)
4239 conf = auth->conf2_sta;
4240 else if (netrole == DPP_NETROLE_AP)
4241 conf = auth->conf2_ap;
4242 }
4243 if (!conf) {
4244 if (idx == 0)
4245 wpa_printf(MSG_DEBUG,
4246 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4247 dpp_netrole_str(netrole));
4248 return NULL;
4249 }
4250
4251 if (dpp_akm_dpp(conf->akm))
4252 return dpp_build_conf_obj_dpp(auth, conf);
4253 return dpp_build_conf_obj_legacy(auth, conf);
4254 }
4255
4256
4257 static struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication * auth,const u8 * e_nonce,u16 e_nonce_len,enum dpp_netrole netrole)4258 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
4259 u16 e_nonce_len, enum dpp_netrole netrole)
4260 {
4261 struct wpabuf *conf, *conf2 = NULL;
4262 size_t clear_len, attr_len;
4263 struct wpabuf *clear = NULL, *msg = NULL;
4264 u8 *wrapped;
4265 const u8 *addr[1];
4266 size_t len[1];
4267 enum dpp_status_error status;
4268
4269 conf = dpp_build_conf_obj(auth, netrole, 0);
4270 if (conf) {
4271 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
4272 (u8 *)wpabuf_head(conf), wpabuf_len(conf));
4273 conf2 = dpp_build_conf_obj(auth, netrole, 1);
4274 }
4275 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
4276 auth->conf_resp_status = status;
4277
4278 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
4279 clear_len = 4 + e_nonce_len;
4280 if (conf)
4281 clear_len += 4 + wpabuf_len(conf);
4282 if (conf2)
4283 clear_len += 4 + wpabuf_len(conf2);
4284 if (auth->peer_version >= 2 && auth->send_conn_status &&
4285 netrole == DPP_NETROLE_STA)
4286 clear_len += 4;
4287 clear = wpabuf_alloc(clear_len);
4288 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
4289 #ifdef CONFIG_WPA_TESTING_OPTIONS
4290 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
4291 attr_len += 5;
4292 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4293 msg = wpabuf_alloc(attr_len);
4294 if (!clear || !msg)
4295 goto fail;
4296
4297 #ifdef CONFIG_WPA_TESTING_OPTIONS
4298 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
4299 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
4300 goto skip_e_nonce;
4301 }
4302 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
4303 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
4304 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4305 wpabuf_put_le16(clear, e_nonce_len);
4306 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
4307 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
4308 goto skip_e_nonce;
4309 }
4310 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
4311 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
4312 goto skip_wrapped_data;
4313 }
4314 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4315
4316 /* E-nonce */
4317 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
4318 wpabuf_put_le16(clear, e_nonce_len);
4319 wpabuf_put_data(clear, e_nonce, e_nonce_len);
4320
4321 #ifdef CONFIG_WPA_TESTING_OPTIONS
4322 skip_e_nonce:
4323 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
4324 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
4325 goto skip_config_obj;
4326 }
4327 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4328
4329 if (conf) {
4330 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4331 wpabuf_put_le16(clear, wpabuf_len(conf));
4332 wpabuf_put_buf(clear, conf);
4333 }
4334 if (auth->peer_version >= 2 && conf2) {
4335 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
4336 wpabuf_put_le16(clear, wpabuf_len(conf2));
4337 wpabuf_put_buf(clear, conf2);
4338 } else if (conf2) {
4339 wpa_printf(MSG_DEBUG,
4340 "DPP: Second Config Object available, but peer does not support more than one");
4341 }
4342
4343 if (auth->peer_version >= 2 && auth->send_conn_status &&
4344 netrole == DPP_NETROLE_STA) {
4345 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
4346 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
4347 wpabuf_put_le16(clear, 0);
4348 }
4349
4350 #ifdef CONFIG_WPA_TESTING_OPTIONS
4351 skip_config_obj:
4352 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
4353 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
4354 goto skip_status;
4355 }
4356 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
4357 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
4358 status = 255;
4359 }
4360 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4361
4362 /* DPP Status */
4363 dpp_build_attr_status(msg, status);
4364
4365 #ifdef CONFIG_WPA_TESTING_OPTIONS
4366 skip_status:
4367 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4368
4369 addr[0] = wpabuf_head(msg);
4370 len[0] = wpabuf_len(msg);
4371 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
4372
4373 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
4374 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4375 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
4376
4377 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
4378 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
4379 wpabuf_head(clear), wpabuf_len(clear),
4380 1, addr, len, wrapped) < 0)
4381 goto fail;
4382 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4383 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
4384
4385 #ifdef CONFIG_WPA_TESTING_OPTIONS
4386 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
4387 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
4388 dpp_build_attr_status(msg, DPP_STATUS_OK);
4389 }
4390 skip_wrapped_data:
4391 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4392
4393 wpa_hexdump_buf(MSG_DEBUG,
4394 "DPP: Configuration Response attributes", msg);
4395 out:
4396 wpabuf_free(conf);
4397 wpabuf_free(conf2);
4398 wpabuf_free(clear);
4399
4400 return msg;
4401 fail:
4402 wpabuf_free(msg);
4403 msg = NULL;
4404 goto out;
4405 }
4406
4407
4408 struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication * auth,const u8 * attr_start,size_t attr_len)4409 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
4410 size_t attr_len)
4411 {
4412 const u8 *wrapped_data, *e_nonce, *config_attr;
4413 u16 wrapped_data_len, e_nonce_len, config_attr_len;
4414 u8 *unwrapped = NULL;
4415 size_t unwrapped_len = 0;
4416 struct wpabuf *resp = NULL;
4417 struct json_token *root = NULL, *token;
4418 enum dpp_netrole netrole;
4419
4420 #ifdef CONFIG_WPA_TESTING_OPTIONS
4421 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
4422 wpa_printf(MSG_INFO,
4423 "DPP: TESTING - stop at Config Request");
4424 return NULL;
4425 }
4426 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4427
4428 if (dpp_check_attrs(attr_start, attr_len) < 0) {
4429 dpp_auth_fail(auth, "Invalid attribute in config request");
4430 return NULL;
4431 }
4432
4433 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4434 &wrapped_data_len);
4435 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4436 dpp_auth_fail(auth,
4437 "Missing or invalid required Wrapped Data attribute");
4438 return NULL;
4439 }
4440
4441 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4442 wrapped_data, wrapped_data_len);
4443 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4444 unwrapped = os_malloc(unwrapped_len);
4445 if (!unwrapped)
4446 return NULL;
4447 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4448 wrapped_data, wrapped_data_len,
4449 0, NULL, NULL, unwrapped) < 0) {
4450 dpp_auth_fail(auth, "AES-SIV decryption failed");
4451 goto fail;
4452 }
4453 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4454 unwrapped, unwrapped_len);
4455
4456 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4457 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4458 goto fail;
4459 }
4460
4461 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
4462 DPP_ATTR_ENROLLEE_NONCE,
4463 &e_nonce_len);
4464 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
4465 dpp_auth_fail(auth,
4466 "Missing or invalid Enrollee Nonce attribute");
4467 goto fail;
4468 }
4469 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
4470 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
4471
4472 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
4473 DPP_ATTR_CONFIG_ATTR_OBJ,
4474 &config_attr_len);
4475 if (!config_attr) {
4476 dpp_auth_fail(auth,
4477 "Missing or invalid Config Attributes attribute");
4478 goto fail;
4479 }
4480 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
4481 (u8 *)config_attr, config_attr_len);
4482
4483 root = json_parse((const char *) config_attr, config_attr_len);
4484 if (!root) {
4485 dpp_auth_fail(auth, "Could not parse Config Attributes");
4486 goto fail;
4487 }
4488
4489 token = json_get_member(root, "name");
4490 if (!token || token->type != JSON_STRING) {
4491 dpp_auth_fail(auth, "No Config Attributes - name");
4492 goto fail;
4493 }
4494 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
4495
4496 token = json_get_member(root, "wi-fi_tech");
4497 if (!token || token->type != JSON_STRING) {
4498 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
4499 goto fail;
4500 }
4501 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
4502 if (os_strcmp(token->string, "infra") != 0) {
4503 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
4504 token->string);
4505 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
4506 goto fail;
4507 }
4508
4509 token = json_get_member(root, "netRole");
4510 if (!token || token->type != JSON_STRING) {
4511 dpp_auth_fail(auth, "No Config Attributes - netRole");
4512 goto fail;
4513 }
4514 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
4515 if (os_strcmp(token->string, "sta") == 0) {
4516 netrole = DPP_NETROLE_STA;
4517 } else if (os_strcmp(token->string, "ap") == 0) {
4518 netrole = DPP_NETROLE_AP;
4519 } else if (os_strcmp(token->string, "configurator") == 0) {
4520 netrole = DPP_NETROLE_CONFIGURATOR;
4521 } else {
4522 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
4523 token->string);
4524 dpp_auth_fail(auth, "Unsupported netRole");
4525 goto fail;
4526 }
4527
4528 token = json_get_member(root, "mudurl");
4529 if (token && token->type == JSON_STRING)
4530 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
4531
4532 token = json_get_member(root, "bandSupport");
4533 if (token && token->type == JSON_ARRAY) {
4534 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
4535 token = token->child;
4536 while (token) {
4537 if (token->type != JSON_NUMBER)
4538 wpa_printf(MSG_DEBUG,
4539 "DPP: Invalid bandSupport array member type");
4540 else
4541 wpa_printf(MSG_DEBUG,
4542 "DPP: Supported global operating class: %d",
4543 token->number);
4544 token = token->sibling;
4545 }
4546 }
4547
4548 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
4549 fail:
4550 json_free(root);
4551 os_free(unwrapped);
4552 return resp;
4553 }
4554
4555
4556 static struct wpabuf *
dpp_parse_jws_prot_hdr(const struct dpp_curve_params * curve,const u8 * prot_hdr,u16 prot_hdr_len)4557 dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
4558 const u8 *prot_hdr, u16 prot_hdr_len)
4559 {
4560 struct json_token *root, *token;
4561 struct wpabuf *kid = NULL;
4562
4563 root = json_parse((const char *) prot_hdr, prot_hdr_len);
4564 if (!root) {
4565 wpa_printf(MSG_DEBUG,
4566 "DPP: JSON parsing failed for JWS Protected Header");
4567 goto fail;
4568 }
4569
4570 if (root->type != JSON_OBJECT) {
4571 wpa_printf(MSG_DEBUG,
4572 "DPP: JWS Protected Header root is not an object");
4573 goto fail;
4574 }
4575
4576 token = json_get_member(root, "typ");
4577 if (!token || token->type != JSON_STRING) {
4578 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
4579 goto fail;
4580 }
4581 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
4582 token->string);
4583 if (os_strcmp(token->string, "dppCon") != 0) {
4584 wpa_printf(MSG_DEBUG,
4585 "DPP: Unsupported JWS Protected Header typ=%s",
4586 token->string);
4587 goto fail;
4588 }
4589
4590 token = json_get_member(root, "alg");
4591 if (!token || token->type != JSON_STRING) {
4592 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
4593 goto fail;
4594 }
4595 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
4596 token->string);
4597 if (os_strcmp(token->string, curve->jws_alg) != 0) {
4598 wpa_printf(MSG_DEBUG,
4599 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
4600 token->string, curve->jws_alg);
4601 goto fail;
4602 }
4603
4604 kid = json_get_member_base64url(root, "kid");
4605 if (!kid) {
4606 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
4607 goto fail;
4608 }
4609 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
4610 kid);
4611
4612 fail:
4613 json_free(root);
4614 return kid;
4615 }
4616
4617
dpp_parse_cred_legacy(struct dpp_config_obj * conf,struct json_token * cred)4618 static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
4619 struct json_token *cred)
4620 {
4621 struct json_token *pass, *psk_hex;
4622
4623 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
4624
4625 pass = json_get_member(cred, "pass");
4626 psk_hex = json_get_member(cred, "psk_hex");
4627
4628 if (pass && pass->type == JSON_STRING) {
4629 size_t len = os_strlen(pass->string);
4630
4631 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
4632 (u8 *)pass->string, len);
4633 if (len < 8 || len > 63)
4634 return -1;
4635 os_strlcpy(conf->passphrase, pass->string,
4636 sizeof(conf->passphrase));
4637 } else if (psk_hex && psk_hex->type == JSON_STRING) {
4638 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
4639 wpa_printf(MSG_DEBUG,
4640 "DPP: Unexpected psk_hex with akm=sae");
4641 return -1;
4642 }
4643 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
4644 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
4645 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
4646 return -1;
4647 }
4648 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
4649 conf->psk, PMK_LEN);
4650 conf->psk_set = 1;
4651 } else {
4652 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
4653 return -1;
4654 }
4655
4656 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
4657 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
4658 return -1;
4659 }
4660
4661 return 0;
4662 }
4663
4664
dpp_parse_jwk(struct json_token * jwk,const struct dpp_curve_params ** key_curve)4665 static struct crypto_key * dpp_parse_jwk(struct json_token *jwk,
4666 const struct dpp_curve_params **key_curve)
4667 {
4668 struct json_token *token;
4669 const struct dpp_curve_params *curve;
4670 struct wpabuf *x = NULL, *y = NULL, *a = NULL;
4671 struct crypto_ec_group *group;
4672 struct crypto_key *pkey = NULL;
4673 size_t len;
4674
4675 token = json_get_member(jwk, "kty");
4676 if (!token || token->type != JSON_STRING) {
4677 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
4678 goto fail;
4679 }
4680 if (os_strcmp(token->string, "EC") != 0) {
4681 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
4682 token->string);
4683 goto fail;
4684 }
4685
4686 token = json_get_member(jwk, "crv");
4687 if (!token || token->type != JSON_STRING) {
4688 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
4689 goto fail;
4690 }
4691 curve = dpp_get_curve_jwk_crv(token->string);
4692 if (!curve) {
4693 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
4694 token->string);
4695 goto fail;
4696 }
4697
4698 x = json_get_member_base64url(jwk, "x");
4699 if (!x) {
4700 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
4701 goto fail;
4702 }
4703 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
4704 if (wpabuf_len(x) != curve->prime_len) {
4705 wpa_printf(MSG_DEBUG,
4706 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
4707 (unsigned int) wpabuf_len(x),
4708 (unsigned int) curve->prime_len, curve->name);
4709 goto fail;
4710 }
4711
4712 y = json_get_member_base64url(jwk, "y");
4713 if (!y) {
4714 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
4715 goto fail;
4716 }
4717 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
4718 if (wpabuf_len(y) != curve->prime_len) {
4719 wpa_printf(MSG_DEBUG,
4720 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
4721 (unsigned int) wpabuf_len(y),
4722 (unsigned int) curve->prime_len, curve->name);
4723 goto fail;
4724 }
4725
4726 group = crypto_ec_get_group_byname(curve->name);
4727 if (!group) {
4728 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
4729 goto fail;
4730 }
4731
4732 len = wpabuf_len(x);
4733 a = wpabuf_concat(x, y);
4734 pkey = crypto_ec_set_pubkey_point(group, wpabuf_head(a),
4735 len);
4736 crypto_ec_deinit((struct crypto_ec *)group);
4737 *key_curve = curve;
4738
4739 fail:
4740 wpabuf_free(a);
4741 wpabuf_free(x);
4742 wpabuf_free(y);
4743
4744 return pkey;
4745 }
4746
4747
dpp_key_expired(const char * timestamp,os_time_t * expiry)4748 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
4749 {
4750 struct os_time now;
4751 unsigned int year, month, day, hour, min, sec;
4752 os_time_t utime;
4753 const char *pos;
4754
4755 /* ISO 8601 date and time:
4756 * <date>T<time>
4757 * YYYY-MM-DDTHH:MM:SSZ
4758 * YYYY-MM-DDTHH:MM:SS+03:00
4759 */
4760 if (os_strlen(timestamp) < 19) {
4761 wpa_printf(MSG_DEBUG,
4762 "DPP: Too short timestamp - assume expired key");
4763 return 1;
4764 }
4765 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
4766 &year, &month, &day, &hour, &min, &sec) != 6) {
4767 wpa_printf(MSG_DEBUG,
4768 "DPP: Failed to parse expiration day - assume expired key");
4769 return 1;
4770 }
4771
4772 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
4773 wpa_printf(MSG_DEBUG,
4774 "DPP: Invalid date/time information - assume expired key");
4775 return 1;
4776 }
4777
4778 pos = timestamp + 19;
4779 if (*pos == 'Z' || *pos == '\0') {
4780 /* In UTC - no need to adjust */
4781 } else if (*pos == '-' || *pos == '+') {
4782 int items;
4783
4784 /* Adjust local time to UTC */
4785 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
4786 if (items < 1) {
4787 wpa_printf(MSG_DEBUG,
4788 "DPP: Invalid time zone designator (%s) - assume expired key",
4789 pos);
4790 return 1;
4791 }
4792 if (*pos == '-')
4793 utime += 3600 * hour;
4794 if (*pos == '+')
4795 utime -= 3600 * hour;
4796 if (items > 1) {
4797 if (*pos == '-')
4798 utime += 60 * min;
4799 if (*pos == '+')
4800 utime -= 60 * min;
4801 }
4802 } else {
4803 wpa_printf(MSG_DEBUG,
4804 "DPP: Invalid time zone designator (%s) - assume expired key",
4805 pos);
4806 return 1;
4807 }
4808 if (expiry)
4809 *expiry = utime;
4810
4811 if (os_get_time(&now) < 0) {
4812 wpa_printf(MSG_DEBUG,
4813 "DPP: Cannot get current time - assume expired key");
4814 return 1;
4815 }
4816
4817 if (now.sec > utime) {
4818 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
4819 utime, now.sec);
4820 return 1;
4821 }
4822
4823 return 0;
4824 }
4825
4826
dpp_parse_connector(struct dpp_authentication * auth,struct dpp_config_obj * conf,const unsigned char * payload,u16 payload_len)4827 static int dpp_parse_connector(struct dpp_authentication *auth,
4828 struct dpp_config_obj *conf,
4829 const unsigned char *payload,
4830 u16 payload_len)
4831 {
4832 struct json_token *root, *groups, *netkey, *token;
4833 int ret = -1;
4834 struct crypto_key *key = NULL;
4835 const struct dpp_curve_params *curve;
4836 unsigned int rules = 0;
4837
4838 root = json_parse((const char *) payload, payload_len);
4839 if (!root) {
4840 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4841 goto fail;
4842 }
4843
4844 groups = json_get_member(root, "groups");
4845 if (!groups || groups->type != JSON_ARRAY) {
4846 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
4847 goto skip_groups;
4848 }
4849 for (token = groups->child; token; token = token->sibling) {
4850 struct json_token *id, *role;
4851
4852 id = json_get_member(token, "groupId");
4853 if (!id || id->type != JSON_STRING) {
4854 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
4855 goto fail;
4856 }
4857
4858 role = json_get_member(token, "netRole");
4859 if (!role || role->type != JSON_STRING) {
4860 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
4861 goto fail;
4862 }
4863 wpa_printf(MSG_DEBUG,
4864 "DPP: connector group: groupId='%s' netRole='%s'",
4865 id->string, role->string);
4866 rules++;
4867 }
4868 skip_groups:
4869
4870 if (!rules) {
4871 wpa_printf(MSG_DEBUG,
4872 "DPP: Connector includes no groups");
4873 goto fail;
4874 }
4875
4876 token = json_get_member(root, "expiry");
4877 if (!token || token->type != JSON_STRING) {
4878 wpa_printf(MSG_DEBUG,
4879 "DPP: No expiry string found - connector does not expire");
4880 } else {
4881 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4882 if (dpp_key_expired(token->string,
4883 &auth->net_access_key_expiry)) {
4884 wpa_printf(MSG_DEBUG,
4885 "DPP: Connector (netAccessKey) has expired");
4886 goto fail;
4887 }
4888 }
4889
4890 netkey = json_get_member(root, "netAccessKey");
4891 if (!netkey || netkey->type != JSON_OBJECT) {
4892 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4893 goto fail;
4894 }
4895
4896 key = dpp_parse_jwk(netkey, &curve);
4897 if (!key)
4898 goto fail;
4899 dpp_debug_print_key("DPP: Received netAccessKey", key);
4900
4901 if (crypto_key_compare(key, auth->own_protocol_key) != 1) {
4902 wpa_printf(MSG_DEBUG,
4903 "DPP: netAccessKey in connector does not match own protocol key");
4904 #ifdef CONFIG_WPA_TESTING_OPTIONS
4905 if (auth->ignore_netaccesskey_mismatch) {
4906 wpa_printf(MSG_DEBUG,
4907 "DPP: TESTING - skip netAccessKey mismatch");
4908 } else {
4909 goto fail;
4910 }
4911 #else /* CONFIG_WPA_TESTING_OPTIONS */
4912 goto fail;
4913 #endif /* CONFIG_WPA_TESTING_OPTIONS */
4914 }
4915
4916 ret = 0;
4917 fail:
4918 crypto_ec_free_key(key);
4919 json_free(root);
4920 return ret;
4921 }
4922
dpp_check_pubkey_match(struct crypto_key * pub,struct wpabuf * r_hash)4923 static int dpp_check_pubkey_match(struct crypto_key *pub, struct wpabuf *r_hash)
4924 {
4925 struct wpabuf *uncomp;
4926 int res;
4927 u8 hash[SHA256_MAC_LEN];
4928 const u8 *addr[1];
4929 size_t len[1];
4930
4931 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
4932 return -1;
4933 uncomp = dpp_get_pubkey_point(pub, 1);
4934 if (!uncomp)
4935 return -1;
4936 addr[0] = wpabuf_head(uncomp);
4937 len[0] = wpabuf_len(uncomp);
4938 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
4939 addr[0], len[0]);
4940 res = sha256_vector(1, addr, len, hash);
4941 wpabuf_free(uncomp);
4942 if (res < 0)
4943 return -1;
4944 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
4945 wpa_printf(MSG_DEBUG,
4946 "DPP: Received hash value does not match calculated public key hash value");
4947 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
4948 hash, SHA256_MAC_LEN);
4949 return -1;
4950 }
4951 return 0;
4952 }
4953
4954
dpp_copy_csign(struct dpp_config_obj * conf,struct crypto_key * csign)4955 static void dpp_copy_csign(struct dpp_config_obj *conf, struct crypto_key *csign)
4956 {
4957 unsigned char *der = NULL;
4958 int der_len;
4959
4960 der_len = crypto_write_pubkey_der(csign, &der);
4961 if (der_len <= 0)
4962 return;
4963 wpabuf_free(conf->c_sign_key);
4964 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
4965 crypto_free_buffer(der);
4966 }
4967
dpp_copy_netaccesskey(struct dpp_authentication * auth,struct dpp_config_obj * conf)4968 static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
4969 struct dpp_config_obj *conf)
4970 {
4971 unsigned char *der = NULL;
4972 int der_len;
4973
4974 if (crypto_ec_get_priv_key_der(auth->own_protocol_key, &der, &der_len) < 0)
4975 return;
4976 wpabuf_free(auth->net_access_key);
4977 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
4978 crypto_free_buffer(der);
4979 }
4980
4981 struct dpp_signed_connector_info {
4982 unsigned char *payload;
4983 size_t payload_len;
4984 };
4985
4986 static enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info * info,struct crypto_key * csign_pub,const char * connector)4987 dpp_process_signed_connector(struct dpp_signed_connector_info *info,
4988 struct crypto_key *csign_pub, const char *connector)
4989 {
4990 enum dpp_status_error ret = 255;
4991 const char *pos, *end, *signed_start, *signed_end;
4992 struct wpabuf *kid = NULL;
4993 unsigned char *prot_hdr = NULL, *signature = NULL;
4994 size_t prot_hdr_len = 0, signature_len = 0;
4995 struct crypto_bignum *r = NULL, *s = NULL;
4996 const struct dpp_curve_params *curve;
4997 const struct crypto_ec_group *group;
4998 int id;
4999
5000 group = crypto_ec_get_group_from_key(csign_pub);
5001 if (!group)
5002 goto fail;
5003 id = crypto_ec_get_curve_id(group);
5004 curve = dpp_get_curve_group_id(id);
5005 if (!curve)
5006 goto fail;
5007 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
5008 os_memset(info, 0, sizeof(*info));
5009
5010 signed_start = pos = connector;
5011 end = os_strchr(pos, '.');
5012 if (!end) {
5013 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
5014 ret = DPP_STATUS_INVALID_CONNECTOR;
5015 goto fail;
5016 }
5017 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
5018 if (!prot_hdr) {
5019 wpa_printf(MSG_DEBUG,
5020 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5021 ret = DPP_STATUS_INVALID_CONNECTOR;
5022 goto fail;
5023 }
5024 wpa_hexdump_ascii(MSG_DEBUG,
5025 "DPP: signedConnector - JWS Protected Header",
5026 (u8 *)prot_hdr, prot_hdr_len);
5027 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len);
5028 if (!kid) {
5029 ret = DPP_STATUS_INVALID_CONNECTOR;
5030 goto fail;
5031 }
5032 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
5033 wpa_printf(MSG_DEBUG,
5034 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5035 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
5036 ret = DPP_STATUS_INVALID_CONNECTOR;
5037 goto fail;
5038 }
5039
5040 pos = end + 1;
5041 end = os_strchr(pos, '.');
5042 if (!end) {
5043 wpa_printf(MSG_DEBUG,
5044 "DPP: Missing dot(2) in signedConnector");
5045 ret = DPP_STATUS_INVALID_CONNECTOR;
5046 goto fail;
5047 }
5048 signed_end = end - 1;
5049 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
5050 if (!info->payload) {
5051 wpa_printf(MSG_DEBUG,
5052 "DPP: Failed to base64url decode signedConnector JWS Payload");
5053 ret = DPP_STATUS_INVALID_CONNECTOR;
5054 goto fail;
5055 }
5056 wpa_hexdump_ascii(MSG_DEBUG,
5057 "DPP: signedConnector - JWS Payload",
5058 (u8 *)info->payload, info->payload_len);
5059 pos = end + 1;
5060 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
5061 if (!signature) {
5062 wpa_printf(MSG_DEBUG,
5063 "DPP: Failed to base64url decode signedConnector signature");
5064 ret = DPP_STATUS_INVALID_CONNECTOR;
5065 goto fail;
5066 }
5067 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
5068 signature, signature_len);
5069
5070 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
5071 ret = DPP_STATUS_NO_MATCH;
5072 goto fail;
5073 }
5074
5075 if (signature_len & 0x01) {
5076 wpa_printf(MSG_DEBUG,
5077 "DPP: Unexpected signedConnector signature length (%d)",
5078 (int) signature_len);
5079 ret = DPP_STATUS_INVALID_CONNECTOR;
5080 goto fail;
5081 }
5082
5083 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5084 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5085 r = crypto_bignum_init_set(signature, signature_len / 2);
5086 s = crypto_bignum_init_set(signature + signature_len / 2, signature_len / 2);
5087
5088 if (!crypto_edcsa_sign_verify((unsigned char *)signed_start, r, s,
5089 csign_pub, signed_end - signed_start + 1)) {
5090 goto fail;
5091 }
5092
5093 ret = DPP_STATUS_OK;
5094 fail:
5095 os_free(prot_hdr);
5096 wpabuf_free(kid);
5097 os_free(signature);
5098 crypto_bignum_deinit(r, 0);
5099 crypto_bignum_deinit(s, 0);
5100 return ret;
5101 }
5102
5103
dpp_parse_cred_dpp(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)5104 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
5105 struct dpp_config_obj *conf,
5106 struct json_token *cred)
5107 {
5108 struct dpp_signed_connector_info info;
5109 struct json_token *token, *csign;
5110 int ret = -1;
5111 struct crypto_key *csign_pub = NULL;
5112 const struct dpp_curve_params *key_curve = NULL;
5113 const char *signed_connector;
5114
5115 os_memset(&info, 0, sizeof(info));
5116
5117 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
5118 wpa_printf(MSG_DEBUG,
5119 "DPP: Legacy credential included in Connector credential");
5120 if (dpp_parse_cred_legacy(conf, cred) < 0)
5121 return -1;
5122 }
5123
5124 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
5125
5126 csign = json_get_member(cred, "csign");
5127 if (!csign || csign->type != JSON_OBJECT) {
5128 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
5129 goto fail;
5130 }
5131
5132 csign_pub = dpp_parse_jwk(csign, &key_curve);
5133 if (!csign_pub) {
5134 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
5135 goto fail;
5136 }
5137 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
5138
5139 token = json_get_member(cred, "signedConnector");
5140 if (!token || token->type != JSON_STRING) {
5141 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
5142 goto fail;
5143 }
5144 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
5145 (u8 *)token->string, os_strlen(token->string));
5146 signed_connector = token->string;
5147
5148 if (os_strchr(signed_connector, '"') ||
5149 os_strchr(signed_connector, '\n')) {
5150 wpa_printf(MSG_DEBUG,
5151 "DPP: Unexpected character in signedConnector");
5152 goto fail;
5153 }
5154
5155 if (dpp_process_signed_connector(&info, csign_pub,
5156 signed_connector) != DPP_STATUS_OK)
5157 goto fail;
5158
5159 if (dpp_parse_connector(auth, conf,
5160 info.payload, info.payload_len) < 0) {
5161 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
5162 goto fail;
5163 }
5164
5165 os_free(conf->connector);
5166 conf->connector = os_strdup(signed_connector);
5167
5168 dpp_copy_csign(conf, csign_pub);
5169 dpp_copy_netaccesskey(auth, conf);
5170
5171 ret = 0;
5172 fail:
5173 crypto_ec_free_key(csign_pub);
5174 os_free(info.payload);
5175 return ret;
5176 }
5177
5178
dpp_akm_str(enum dpp_akm akm)5179 const char * dpp_akm_str(enum dpp_akm akm)
5180 {
5181 switch (akm) {
5182 case DPP_AKM_DPP:
5183 return "dpp";
5184 case DPP_AKM_PSK:
5185 return "psk";
5186 case DPP_AKM_SAE:
5187 return "sae";
5188 case DPP_AKM_PSK_SAE:
5189 return "psk+sae";
5190 case DPP_AKM_SAE_DPP:
5191 return "dpp+sae";
5192 case DPP_AKM_PSK_SAE_DPP:
5193 return "dpp+psk+sae";
5194 default:
5195 return "??";
5196 }
5197 }
5198
5199
dpp_akm_selector_str(enum dpp_akm akm)5200 const char * dpp_akm_selector_str(enum dpp_akm akm)
5201 {
5202 switch (akm) {
5203 case DPP_AKM_DPP:
5204 return "506F9A02";
5205 case DPP_AKM_PSK:
5206 return "000FAC02+000FAC06";
5207 case DPP_AKM_SAE:
5208 return "000FAC08";
5209 case DPP_AKM_PSK_SAE:
5210 return "000FAC02+000FAC06+000FAC08";
5211 case DPP_AKM_SAE_DPP:
5212 return "506F9A02+000FAC08";
5213 case DPP_AKM_PSK_SAE_DPP:
5214 return "506F9A02+000FAC08+000FAC02+000FAC06";
5215 default:
5216 return "??";
5217 }
5218 }
5219
5220
dpp_akm_from_str(const char * akm)5221 static enum dpp_akm dpp_akm_from_str(const char *akm)
5222 {
5223 const char *pos;
5224 int dpp = 0, psk = 0, sae = 0;
5225
5226 if (os_strcmp(akm, "psk") == 0)
5227 return DPP_AKM_PSK;
5228 if (os_strcmp(akm, "sae") == 0)
5229 return DPP_AKM_SAE;
5230 if (os_strcmp(akm, "psk+sae") == 0)
5231 return DPP_AKM_PSK_SAE;
5232 if (os_strcmp(akm, "dpp") == 0)
5233 return DPP_AKM_DPP;
5234 if (os_strcmp(akm, "dpp+sae") == 0)
5235 return DPP_AKM_SAE_DPP;
5236 if (os_strcmp(akm, "dpp+psk+sae") == 0)
5237 return DPP_AKM_PSK_SAE_DPP;
5238
5239 pos = akm;
5240 while (*pos) {
5241 if (os_strlen(pos) < 8)
5242 break;
5243 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
5244 dpp = 1;
5245 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
5246 psk = 1;
5247 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
5248 psk = 1;
5249 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
5250 sae = 1;
5251 pos += 8;
5252 if (*pos != '+')
5253 break;
5254 pos++;
5255 }
5256
5257 if (dpp && psk && sae)
5258 return DPP_AKM_PSK_SAE_DPP;
5259 if (dpp && sae)
5260 return DPP_AKM_SAE_DPP;
5261 if (dpp)
5262 return DPP_AKM_DPP;
5263 if (psk && sae)
5264 return DPP_AKM_PSK_SAE;
5265 if (sae)
5266 return DPP_AKM_SAE;
5267 if (psk)
5268 return DPP_AKM_PSK;
5269
5270 return DPP_AKM_UNKNOWN;
5271 }
5272
5273
dpp_parse_conf_obj(struct dpp_authentication * auth,const u8 * conf_obj,u16 conf_obj_len)5274 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
5275 const u8 *conf_obj, u16 conf_obj_len)
5276 {
5277 int ret = -1;
5278 struct json_token *root, *token, *discovery, *cred;
5279 struct dpp_config_obj *conf;
5280 struct wpabuf *ssid64 = NULL;
5281
5282 root = json_parse((const char *) conf_obj, conf_obj_len);
5283 if (!root)
5284 return -1;
5285 if (root->type != JSON_OBJECT) {
5286 dpp_auth_fail(auth, "JSON root is not an object");
5287 goto fail;
5288 }
5289
5290 token = json_get_member(root, "wi-fi_tech");
5291 if (!token || token->type != JSON_STRING) {
5292 dpp_auth_fail(auth, "No wi-fi_tech string value found");
5293 goto fail;
5294 }
5295 if (os_strcmp(token->string, "infra") != 0) {
5296 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
5297 token->string);
5298 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
5299 goto fail;
5300 }
5301
5302 discovery = json_get_member(root, "discovery");
5303 if (!discovery || discovery->type != JSON_OBJECT) {
5304 dpp_auth_fail(auth, "No discovery object in JSON");
5305 goto fail;
5306 }
5307
5308 ssid64 = json_get_member_base64url(discovery, "ssid64");
5309 if (ssid64) {
5310 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
5311 (u8 *)wpabuf_head(ssid64), wpabuf_len(ssid64));
5312 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
5313 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
5314 goto fail;
5315 }
5316 } else {
5317 token = json_get_member(discovery, "ssid");
5318 if (!token || token->type != JSON_STRING) {
5319 dpp_auth_fail(auth,
5320 "No discovery::ssid string value found");
5321 goto fail;
5322 }
5323 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
5324 (u8 *)token->string, os_strlen(token->string));
5325 if (os_strlen(token->string) > SSID_MAX_LEN) {
5326 dpp_auth_fail(auth,
5327 "Too long discovery::ssid string value");
5328 goto fail;
5329 }
5330 }
5331
5332 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
5333 wpa_printf(MSG_DEBUG,
5334 "DPP: No room for this many Config Objects - ignore this one");
5335 ret = 0;
5336 goto fail;
5337 }
5338 conf = &auth->conf_obj[auth->num_conf_obj++];
5339
5340 if (ssid64) {
5341 conf->ssid_len = wpabuf_len(ssid64);
5342 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
5343 } else {
5344 conf->ssid_len = os_strlen(token->string);
5345 os_memcpy(conf->ssid, token->string, conf->ssid_len);
5346 }
5347
5348 token = json_get_member(discovery, "ssid_charset");
5349 if (token && token->type == JSON_NUMBER) {
5350 conf->ssid_charset = token->number;
5351 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
5352 conf->ssid_charset);
5353 }
5354
5355 cred = json_get_member(root, "cred");
5356 if (!cred || cred->type != JSON_OBJECT) {
5357 dpp_auth_fail(auth, "No cred object in JSON");
5358 goto fail;
5359 }
5360
5361 token = json_get_member(cred, "akm");
5362 if (!token || token->type != JSON_STRING) {
5363 dpp_auth_fail(auth, "No cred::akm string value found");
5364 goto fail;
5365 }
5366 conf->akm = dpp_akm_from_str(token->string);
5367
5368 if (dpp_akm_legacy(conf->akm)) {
5369 if (dpp_parse_cred_legacy(conf, cred) < 0)
5370 goto fail;
5371 } else if (dpp_akm_dpp(conf->akm)) {
5372 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
5373 goto fail;
5374 } else {
5375 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
5376 token->string);
5377 dpp_auth_fail(auth, "Unsupported akm");
5378 goto fail;
5379 }
5380
5381 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
5382 ret = 0;
5383 fail:
5384 wpabuf_free(ssid64);
5385 json_free(root);
5386 return ret;
5387 }
5388
5389
dpp_conf_resp_rx(struct dpp_authentication * auth,const uint8_t * resp,uint32_t resp_len)5390 int dpp_conf_resp_rx(struct dpp_authentication *auth,
5391 const uint8_t *resp, uint32_t resp_len)
5392 {
5393 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
5394 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
5395 const u8 *addr[1];
5396 size_t len[1];
5397 u8 *unwrapped = NULL;
5398 size_t unwrapped_len = 0;
5399 int ret = -1;
5400
5401 auth->conf_resp_status = 255;
5402
5403 if (dpp_check_attrs(resp, resp_len) < 0) {
5404 dpp_auth_fail(auth, "Invalid attribute in config response");
5405 return -1;
5406 }
5407
5408 wrapped_data = dpp_get_attr(resp, resp_len,
5409 DPP_ATTR_WRAPPED_DATA,
5410 &wrapped_data_len);
5411 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
5412 dpp_auth_fail(auth,
5413 "Missing or invalid required Wrapped Data attribute");
5414 return -1;
5415 }
5416
5417 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5418 wrapped_data, wrapped_data_len);
5419 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5420 unwrapped = os_malloc(unwrapped_len);
5421 if (!unwrapped)
5422 return -1;
5423
5424 addr[0] = resp;
5425 len[0] = wrapped_data - 4 - resp;
5426 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5427
5428 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5429 wrapped_data, wrapped_data_len,
5430 1, addr, len, unwrapped) < 0) {
5431 dpp_auth_fail(auth, "AES-SIV decryption failed");
5432 goto fail;
5433 }
5434 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5435 unwrapped, unwrapped_len);
5436
5437 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
5438 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
5439 goto fail;
5440 }
5441
5442 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5443 DPP_ATTR_ENROLLEE_NONCE,
5444 &e_nonce_len);
5445 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
5446 dpp_auth_fail(auth,
5447 "Missing or invalid Enrollee Nonce attribute");
5448 goto fail;
5449 }
5450 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
5451 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
5452 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
5453 goto fail;
5454 }
5455
5456 status = dpp_get_attr(resp, resp_len,
5457 DPP_ATTR_STATUS, &status_len);
5458 if (!status || status_len < 1) {
5459 dpp_auth_fail(auth,
5460 "Missing or invalid required DPP Status attribute");
5461 goto fail;
5462 }
5463 auth->conf_resp_status = status[0];
5464 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
5465 if (status[0] != DPP_STATUS_OK) {
5466 dpp_auth_fail(auth, "Configurator rejected configuration");
5467 goto fail;
5468 }
5469
5470 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
5471 &conf_obj_len);
5472 if (!conf_obj) {
5473 dpp_auth_fail(auth,
5474 "Missing required Configuration Object attribute");
5475 goto fail;
5476 }
5477 while (conf_obj) {
5478 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
5479 (u8 *)conf_obj, conf_obj_len);
5480 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
5481 goto fail;
5482 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
5483 DPP_ATTR_CONFIG_OBJ,
5484 &conf_obj_len);
5485 }
5486
5487 ret = 0;
5488
5489 fail:
5490 os_free(unwrapped);
5491 return ret;
5492 }
5493
dpp_configurator_free(struct dpp_configurator * conf)5494 void dpp_configurator_free(struct dpp_configurator *conf)
5495 {
5496 if (!conf)
5497 return;
5498 crypto_ec_free_key(conf->csign);
5499 os_free(conf->kid);
5500 os_free(conf);
5501 }
5502
5503
dpp_configurator_get_key(const struct dpp_configurator * conf,char * buf,size_t buflen)5504 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
5505 size_t buflen)
5506 {
5507 int keylen, ret = -1;
5508 unsigned char *key = NULL;
5509
5510 if (!conf->csign)
5511 return ret;
5512
5513 crypto_ec_get_priv_key_der(conf->csign, &key, &keylen);
5514
5515 if (keylen > 0)
5516 ret = wpa_snprintf_hex(buf, buflen, key, keylen);
5517
5518 crypto_free_buffer(key);
5519
5520 return ret;
5521 }
5522
5523
5524 struct dpp_configurator *
dpp_keygen_configurator(const char * curve,u8 * privkey,size_t privkey_len)5525 dpp_keygen_configurator(const char *curve, u8 *privkey,
5526 size_t privkey_len)
5527 {
5528 struct dpp_configurator *conf;
5529 struct wpabuf *csign_pub = NULL;
5530 u8 kid_hash[SHA256_MAC_LEN];
5531 const u8 *addr[1];
5532 size_t len[1];
5533
5534 conf = os_zalloc(sizeof(*conf));
5535 if (!conf)
5536 return NULL;
5537
5538 if (!curve) {
5539 conf->curve = &dpp_curves[0];
5540 } else {
5541 conf->curve = dpp_get_curve_name(curve);
5542 if (!conf->curve) {
5543 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5544 curve);
5545 os_free(conf);
5546 return NULL;
5547 }
5548 }
5549 if (privkey)
5550 conf->csign = dpp_set_keypair(&conf->curve, privkey,
5551 privkey_len);
5552 else
5553 conf->csign = dpp_gen_keypair(conf->curve);
5554 if (!conf->csign)
5555 goto fail;
5556 conf->own = 1;
5557
5558 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
5559 if (!csign_pub) {
5560 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
5561 goto fail;
5562 }
5563
5564 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
5565 addr[0] = wpabuf_head(csign_pub);
5566 len[0] = wpabuf_len(csign_pub);
5567 if (sha256_vector(1, addr, len, kid_hash) < 0) {
5568 wpa_printf(MSG_DEBUG,
5569 "DPP: Failed to derive kid for C-sign-key");
5570 goto fail;
5571 }
5572
5573 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
5574 if (!conf->kid)
5575 goto fail;
5576 out:
5577 wpabuf_free(csign_pub);
5578 return conf;
5579 fail:
5580 dpp_configurator_free(conf);
5581 conf = NULL;
5582 goto out;
5583 }
5584
5585
dpp_configurator_own_config(struct dpp_authentication * auth,const char * curve,int ap)5586 int dpp_configurator_own_config(struct dpp_authentication *auth,
5587 const char *curve, int ap)
5588 {
5589 struct wpabuf *conf_obj;
5590 int ret = -1;
5591
5592 if (!auth->conf) {
5593 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
5594 return -1;
5595 }
5596
5597 if (!curve) {
5598 auth->curve = &dpp_curves[0];
5599 } else {
5600 auth->curve = dpp_get_curve_name(curve);
5601 if (!auth->curve) {
5602 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
5603 curve);
5604 return -1;
5605 }
5606 }
5607 wpa_printf(MSG_DEBUG,
5608 "DPP: Building own configuration/connector with curve %s",
5609 auth->curve->name);
5610
5611 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
5612 if (!auth->own_protocol_key)
5613 return -1;
5614 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
5615 auth->peer_protocol_key = auth->own_protocol_key;
5616 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
5617
5618 conf_obj = dpp_build_conf_obj(auth, ap, 0);
5619 if (!conf_obj) {
5620 wpabuf_free(auth->conf_obj[0].c_sign_key);
5621 auth->conf_obj[0].c_sign_key = NULL;
5622 goto fail;
5623 }
5624 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
5625 wpabuf_len(conf_obj));
5626 fail:
5627 wpabuf_free(conf_obj);
5628 auth->peer_protocol_key = NULL;
5629 return ret;
5630 }
5631
5632
dpp_compatible_netrole(const char * role1,const char * role2)5633 static int dpp_compatible_netrole(const char *role1, const char *role2)
5634 {
5635 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
5636 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
5637 }
5638
dpp_connector_compatible_group(struct json_token * root,const char * group_id,const char * net_role)5639 static int dpp_connector_compatible_group(struct json_token *root,
5640 const char *group_id,
5641 const char *net_role)
5642 {
5643 struct json_token *groups, *token;
5644
5645 groups = json_get_member(root, "groups");
5646 if (!groups || groups->type != JSON_ARRAY)
5647 return 0;
5648
5649 for (token = groups->child; token; token = token->sibling) {
5650 struct json_token *id, *role;
5651
5652 id = json_get_member(token, "groupId");
5653 if (!id || id->type != JSON_STRING)
5654 continue;
5655
5656 role = json_get_member(token, "netRole");
5657 if (!role || role->type != JSON_STRING)
5658 continue;
5659
5660 if (os_strcmp(id->string, "*") != 0 &&
5661 os_strcmp(group_id, "*") != 0 &&
5662 os_strcmp(id->string, group_id) != 0)
5663 continue;
5664
5665 if (dpp_compatible_netrole(role->string, net_role))
5666 return 1;
5667 }
5668
5669 return 0;
5670 }
5671
dpp_connector_match_groups(struct json_token * own_root,struct json_token * peer_root)5672 static int dpp_connector_match_groups(struct json_token *own_root,
5673 struct json_token *peer_root)
5674 {
5675 struct json_token *groups, *token;
5676
5677 groups = json_get_member(peer_root, "groups");
5678 if (!groups || groups->type != JSON_ARRAY) {
5679 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
5680 return 0;
5681 }
5682
5683 for (token = groups->child; token; token = token->sibling) {
5684 struct json_token *id, *role;
5685
5686 id = json_get_member(token, "groupId");
5687 if (!id || id->type != JSON_STRING) {
5688 wpa_printf(MSG_DEBUG,
5689 "DPP: Missing peer groupId string");
5690 continue;
5691 }
5692
5693 role = json_get_member(token, "netRole");
5694 if (!role || role->type != JSON_STRING) {
5695 wpa_printf(MSG_DEBUG,
5696 "DPP: Missing peer groups::netRole string");
5697 continue;
5698 }
5699 wpa_printf(MSG_DEBUG,
5700 "DPP: peer connector group: groupId='%s' netRole='%s'",
5701 id->string, role->string);
5702 if (dpp_connector_compatible_group(own_root, id->string,
5703 role->string)) {
5704 wpa_printf(MSG_DEBUG,
5705 "DPP: Compatible group/netRole in own connector");
5706 return 1;
5707 }
5708 }
5709
5710 return 0;
5711 }
5712
dpp_derive_pmk(const u8 * Nx,size_t Nx_len,u8 * pmk,unsigned int hash_len)5713 static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
5714 unsigned int hash_len)
5715 {
5716 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
5717 const char *info = "DPP PMK";
5718 int res;
5719
5720 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5721
5722 /* HKDF-Extract(<>, N.x) */
5723 os_memset(salt, 0, hash_len);
5724 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
5725 return -1;
5726 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
5727 prk, hash_len);
5728
5729 /* HKDF-Expand(PRK, info, L) */
5730 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
5731 os_memset(prk, 0, hash_len);
5732 if (res < 0)
5733 return -1;
5734
5735 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
5736 pmk, hash_len);
5737 return 0;
5738 }
5739
5740
dpp_derive_pmkid(const struct dpp_curve_params * curve,struct crypto_key * own_key,struct crypto_key * peer_key,u8 * pmkid)5741 static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
5742 struct crypto_key *own_key, struct crypto_key *peer_key, u8 *pmkid)
5743 {
5744 struct wpabuf *nkx, *pkx;
5745 int ret = -1, res;
5746 const u8 *addr[2];
5747 size_t len[2];
5748 u8 hash[SHA256_MAC_LEN];
5749
5750 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5751 nkx = dpp_get_pubkey_point(own_key, 0);
5752 pkx = dpp_get_pubkey_point(peer_key, 0);
5753 if (!nkx || !pkx)
5754 goto fail;
5755 addr[0] = wpabuf_head(nkx);
5756 len[0] = wpabuf_len(nkx) / 2;
5757 addr[1] = wpabuf_head(pkx);
5758 len[1] = wpabuf_len(pkx) / 2;
5759 if (len[0] != len[1])
5760 goto fail;
5761 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
5762 addr[0] = wpabuf_head(pkx);
5763 addr[1] = wpabuf_head(nkx);
5764 }
5765 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
5766 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
5767 res = sha256_vector(2, addr, len, hash);
5768 if (res < 0)
5769 goto fail;
5770 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
5771 os_memcpy(pmkid, hash, PMKID_LEN);
5772 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
5773 ret = 0;
5774 fail:
5775 wpabuf_free(nkx);
5776 wpabuf_free(pkx);
5777 return ret;
5778 }
5779
5780
5781 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)5782 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
5783 const u8 *net_access_key, size_t net_access_key_len,
5784 const u8 *csign_key, size_t csign_key_len,
5785 const u8 *peer_connector, size_t peer_connector_len,
5786 os_time_t *expiry)
5787 {
5788 struct json_token *root = NULL, *netkey, *token;
5789 struct json_token *own_root = NULL;
5790 enum dpp_status_error ret = 255, res;
5791 struct crypto_key *own_key = NULL, *peer_key = NULL;
5792 struct wpabuf *own_key_pub = NULL;
5793 const struct dpp_curve_params *curve, *own_curve;
5794 struct dpp_signed_connector_info info;
5795 const unsigned char *p;
5796 struct crypto_key *csign = NULL;
5797 char *signed_connector = NULL;
5798 const char *pos, *end;
5799 unsigned char *own_conn = NULL;
5800 size_t own_conn_len;
5801 size_t Nx_len;
5802 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
5803
5804 os_memset(intro, 0, sizeof(*intro));
5805 os_memset(&info, 0, sizeof(info));
5806 if (expiry)
5807 *expiry = 0;
5808
5809 p = csign_key;
5810 csign = crypto_ec_parse_subpub_key(p, csign_key_len);
5811 if (!csign) {
5812 wpa_printf(MSG_ERROR,
5813 "DPP: Failed to parse local C-sign-key information");
5814 goto fail;
5815 }
5816
5817 own_key = dpp_set_keypair(&own_curve, net_access_key,
5818 net_access_key_len);
5819 if (!own_key) {
5820 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
5821 goto fail;
5822 }
5823
5824 pos = os_strchr(own_connector, '.');
5825 if (!pos) {
5826 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
5827 goto fail;
5828 }
5829 pos++;
5830 end = os_strchr(pos, '.');
5831 if (!end) {
5832 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
5833 goto fail;
5834 }
5835 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
5836 if (!own_conn) {
5837 wpa_printf(MSG_DEBUG,
5838 "DPP: Failed to base64url decode own signedConnector JWS Payload");
5839 goto fail;
5840 }
5841
5842 own_root = json_parse((const char *) own_conn, own_conn_len);
5843 if (!own_root) {
5844 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
5845 goto fail;
5846 }
5847
5848 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
5849 (u8 *)peer_connector, peer_connector_len);
5850 signed_connector = os_malloc(peer_connector_len + 1);
5851 if (!signed_connector)
5852 goto fail;
5853 os_memcpy(signed_connector, peer_connector, peer_connector_len);
5854 signed_connector[peer_connector_len] = '\0';
5855
5856 res = dpp_process_signed_connector(&info, csign, signed_connector);
5857 if (res != DPP_STATUS_OK) {
5858 ret = res;
5859 goto fail;
5860 }
5861
5862 root = json_parse((const char *) info.payload, info.payload_len);
5863 if (!root) {
5864 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
5865 ret = DPP_STATUS_INVALID_CONNECTOR;
5866 goto fail;
5867 }
5868
5869 if (!dpp_connector_match_groups(own_root, root)) {
5870 wpa_printf(MSG_DEBUG,
5871 "DPP: Peer connector does not include compatible group netrole with own connector");
5872 ret = DPP_STATUS_NO_MATCH;
5873 goto fail;
5874 }
5875
5876 token = json_get_member(root, "expiry");
5877 if (!token || token->type != JSON_STRING) {
5878 wpa_printf(MSG_DEBUG,
5879 "DPP: No expiry string found - connector does not expire");
5880 } else {
5881 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
5882 if (dpp_key_expired(token->string, expiry)) {
5883 wpa_printf(MSG_DEBUG,
5884 "DPP: Connector (netAccessKey) has expired");
5885 ret = DPP_STATUS_INVALID_CONNECTOR;
5886 goto fail;
5887 }
5888 }
5889
5890 netkey = json_get_member(root, "netAccessKey");
5891 if (!netkey || netkey->type != JSON_OBJECT) {
5892 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
5893 ret = DPP_STATUS_INVALID_CONNECTOR;
5894 goto fail;
5895 }
5896
5897 peer_key = dpp_parse_jwk(netkey, &curve);
5898 if (!peer_key) {
5899 ret = DPP_STATUS_INVALID_CONNECTOR;
5900 goto fail;
5901 }
5902 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
5903
5904 if (own_curve != curve) {
5905 wpa_printf(MSG_DEBUG,
5906 "DPP: Mismatching netAccessKey curves (%s != %s)",
5907 own_curve->name, curve->name);
5908 ret = DPP_STATUS_INVALID_CONNECTOR;
5909 goto fail;
5910 }
5911
5912 /* ECDH: N = nk * PK */
5913 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
5914 goto fail;
5915
5916 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
5917 Nx, Nx_len);
5918
5919 /* PMK = HKDF(<>, "DPP PMK", N.x) */
5920 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
5921 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
5922 goto fail;
5923 }
5924 intro->pmk_len = curve->hash_len;
5925
5926 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
5927 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
5928 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
5929 goto fail;
5930 }
5931
5932 ret = DPP_STATUS_OK;
5933 fail:
5934 if (ret != DPP_STATUS_OK)
5935 os_memset(intro, 0, sizeof(*intro));
5936 os_memset(Nx, 0, sizeof(Nx));
5937 os_free(own_conn);
5938 os_free(signed_connector);
5939 os_free(info.payload);
5940 crypto_ec_free_key(own_key);
5941 wpabuf_free(own_key_pub);
5942 crypto_ec_free_key(peer_key);
5943 crypto_ec_free_key(csign);
5944 json_free(root);
5945 json_free(own_root);
5946 return ret;
5947 }
5948
5949 #ifdef CONFIG_WPA_TESTING_OPTIONS
dpp_test_gen_invalid_key(struct wpabuf * msg,const struct dpp_curve_params * curve)5950 static int dpp_test_gen_invalid_key(struct wpabuf *msg,
5951 const struct dpp_curve_params *curve)
5952 {
5953 return 0;
5954 }
5955
dpp_corrupt_connector_signature(const char * connector)5956 char * dpp_corrupt_connector_signature(const char *connector)
5957 {
5958 char *tmp, *pos, *signed3 = NULL;
5959 unsigned char *signature = NULL;
5960 size_t signature_len = 0, signed3_len;
5961
5962 tmp = os_zalloc(os_strlen(connector) + 5);
5963 if (!tmp)
5964 goto fail;
5965 os_memcpy(tmp, connector, os_strlen(connector));
5966
5967 pos = os_strchr(tmp, '.');
5968 if (!pos)
5969 goto fail;
5970
5971 pos = os_strchr(pos + 1, '.');
5972 if (!pos)
5973 goto fail;
5974 pos++;
5975
5976 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
5977 pos);
5978 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
5979 if (!signature || signature_len == 0)
5980 goto fail;
5981 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
5982 signature, signature_len);
5983 signature[signature_len - 1] ^= 0x01;
5984 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
5985 signature, signature_len);
5986 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
5987 if (!signed3)
5988 goto fail;
5989 os_memcpy(pos, signed3, signed3_len);
5990 pos[signed3_len] = '\0';
5991 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
5992 pos);
5993
5994 out:
5995 os_free(signature);
5996 os_free(signed3);
5997 return tmp;
5998 fail:
5999 os_free(tmp);
6000 tmp = NULL;
6001 goto out;
6002 }
6003 #endif /* CONFIG_WPA_TESTING_OPTIONS */
6004
dpp_next_id(struct dpp_global * dpp)6005 static unsigned int dpp_next_id(struct dpp_global *dpp)
6006 {
6007 struct dpp_bootstrap_info *bi;
6008 unsigned int max_id = 0;
6009
6010 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6011 if (bi->id > max_id)
6012 max_id = bi->id;
6013 }
6014 return max_id + 1;
6015 }
6016
dpp_bootstrap_del(struct dpp_global * dpp,unsigned int id)6017 static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
6018 {
6019 struct dpp_bootstrap_info *bi, *tmp;
6020 int found = 0;
6021
6022 if (!dpp)
6023 return -1;
6024
6025 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
6026 struct dpp_bootstrap_info, list) {
6027 if (id && bi->id != id)
6028 continue;
6029 found = 1;
6030 dl_list_del(&bi->list);
6031 dpp_bootstrap_info_free(bi);
6032 }
6033
6034 if (id == 0)
6035 return 0; /* flush succeeds regardless of entries found */
6036 return found ? 0 : -1;
6037 }
6038
6039
dpp_add_qr_code(struct dpp_global * dpp,const char * uri)6040 struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
6041 const char *uri)
6042 {
6043 struct dpp_bootstrap_info *bi;
6044
6045 if (!dpp)
6046 return NULL;
6047
6048 bi = dpp_parse_uri(uri);
6049 if (!bi)
6050 return NULL;
6051
6052 bi->type = DPP_BOOTSTRAP_QR_CODE;
6053 bi->id = dpp_next_id(dpp);
6054 dl_list_add(&dpp->bootstrap, &bi->list);
6055 return bi;
6056 }
6057
6058
dpp_add_nfc_uri(struct dpp_global * dpp,const char * uri)6059 struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
6060 const char *uri)
6061 {
6062 struct dpp_bootstrap_info *bi;
6063
6064 if (!dpp)
6065 return NULL;
6066
6067 bi = dpp_parse_uri(uri);
6068 if (!bi)
6069 return NULL;
6070
6071 bi->type = DPP_BOOTSTRAP_NFC_URI;
6072 bi->id = dpp_next_id(dpp);
6073 dl_list_add(&dpp->bootstrap, &bi->list);
6074 return bi;
6075 }
6076
6077
dpp_bootstrap_gen(struct dpp_global * dpp,const char * cmd)6078 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
6079 {
6080 char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL;
6081 char *key = NULL;
6082 u8 *privkey = NULL;
6083 size_t privkey_len = 0;
6084 size_t len;
6085 int ret = -1;
6086 struct dpp_bootstrap_info *bi;
6087
6088 bi = os_zalloc(sizeof(*bi));
6089 if (!bi)
6090 goto fail;
6091
6092 if (os_strstr(cmd, "type=qrcode"))
6093 bi->type = DPP_BOOTSTRAP_QR_CODE;
6094 else if (os_strstr(cmd, "type=pkex"))
6095 bi->type = DPP_BOOTSTRAP_PKEX;
6096 else if (os_strstr(cmd, "type=nfc-uri"))
6097 bi->type = DPP_BOOTSTRAP_NFC_URI;
6098 else
6099 goto fail;
6100
6101 chan = get_param(cmd, " chan=");
6102 mac = get_param(cmd, " mac=");
6103 info = get_param(cmd, " info=");
6104 curve = get_param(cmd, " curve=");
6105 key = get_param(cmd, " key=");
6106
6107 if (key) {
6108 privkey_len = os_strlen(key) / 2;
6109 privkey = os_malloc(privkey_len);
6110 if (!privkey ||
6111 hexstr2bin(key, privkey, privkey_len) < 0)
6112 goto fail;
6113 }
6114 wpa_hexdump(MSG_DEBUG, "private key", privkey, privkey_len);
6115
6116 pk = dpp_keygen(bi, curve, privkey, privkey_len);
6117 if (!pk)
6118 goto fail;
6119
6120 len = 4; /* "DPP:" */
6121 if (chan) {
6122 if (dpp_parse_uri_chan_list(bi, chan) < 0)
6123 goto fail;
6124 len += 3 + os_strlen(chan); /* C:...; */
6125 }
6126 if (mac) {
6127 if (dpp_parse_uri_mac(bi, mac) < 0)
6128 goto fail;
6129 len += 3 + os_strlen(mac); /* M:...; */
6130 }
6131 if (info) {
6132 if (dpp_parse_uri_info(bi, info) < 0)
6133 goto fail;
6134 len += 3 + os_strlen(info); /* I:...; */
6135 }
6136 len += 4 + os_strlen(pk);
6137 bi->uri = os_malloc(len + 1);
6138 if (!bi->uri)
6139 goto fail;
6140 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
6141 chan ? "C:" : "", chan ? chan : "", chan ? ";" : "",
6142 mac ? "M:" : "", mac ? mac : "", mac ? ";" : "",
6143 info ? "I:" : "", info ? info : "", info ? ";" : "",
6144 pk);
6145
6146 bi->id = dpp_next_id(dpp);
6147 dl_list_add(&dpp->bootstrap, &bi->list);
6148 ret = bi->id;
6149 bi = NULL;
6150 fail:
6151 os_free(curve);
6152 os_free(pk);
6153 os_free(chan);
6154 os_free(mac);
6155 os_free(info);
6156 str_clear_free(key);
6157 bin_clear_free(privkey, privkey_len);
6158 dpp_bootstrap_info_free(bi);
6159 return ret;
6160 }
6161
6162
6163 struct dpp_bootstrap_info *
dpp_bootstrap_get_id(struct dpp_global * dpp,unsigned int id)6164 dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
6165 {
6166 struct dpp_bootstrap_info *bi;
6167
6168 if (!dpp)
6169 return NULL;
6170
6171 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6172 if (bi->id == id)
6173 return bi;
6174 }
6175 return NULL;
6176 }
6177
6178
dpp_bootstrap_remove(struct dpp_global * dpp,const char * id)6179 int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
6180 {
6181 unsigned int id_val;
6182
6183 if (os_strcmp(id, "*") == 0) {
6184 id_val = 0;
6185 } else {
6186 id_val = atoi(id);
6187 if (id_val == 0)
6188 return -1;
6189 }
6190
6191 return dpp_bootstrap_del(dpp, id_val);
6192 }
6193
dpp_bootstrap_get_uri(struct dpp_global * dpp,unsigned int id)6194 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
6195 {
6196 struct dpp_bootstrap_info *bi;
6197
6198 bi = dpp_bootstrap_get_id(dpp, id);
6199 if (!bi)
6200 return NULL;
6201 return bi->uri;
6202 }
6203
dpp_get_bootstrap_info(struct dpp_global * dpp,int id,char * reply,int reply_size)6204 int dpp_get_bootstrap_info(struct dpp_global *dpp, int id,
6205 char *reply, int reply_size)
6206 {
6207 struct dpp_bootstrap_info *bi;
6208 char pkhash[2 * SHA256_MAC_LEN + 1];
6209
6210 bi = dpp_bootstrap_get_id(dpp, id);
6211 if (!bi)
6212 return -1;
6213 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
6214 SHA256_MAC_LEN);
6215 return os_snprintf(reply, reply_size, "type=%s\n"
6216 "mac_addr=" MACSTR "\n"
6217 "info=%s\n"
6218 "num_freq=%u\n"
6219 "curve=%s\n"
6220 "pkhash=%s\n",
6221 dpp_bootstrap_type_txt(bi->type),
6222 MAC2STR(bi->mac_addr),
6223 bi->info ? bi->info : "",
6224 bi->num_freq,
6225 bi->curve->name,
6226 pkhash);
6227 }
6228
6229
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)6230 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
6231 const u8 *r_bootstrap,
6232 struct dpp_bootstrap_info **own_bi,
6233 struct dpp_bootstrap_info **peer_bi)
6234 {
6235 struct dpp_bootstrap_info *bi;
6236
6237 *own_bi = NULL;
6238 *peer_bi = NULL;
6239 if (!dpp)
6240 return;
6241
6242 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
6243 if (!*own_bi && bi->own &&
6244 os_memcmp(bi->pubkey_hash, r_bootstrap,
6245 SHA256_MAC_LEN) == 0) {
6246 wpa_printf(MSG_DEBUG,
6247 "DPP: Found matching own bootstrapping information");
6248 *own_bi = bi;
6249 }
6250
6251 if (!*peer_bi && !bi->own &&
6252 os_memcmp(bi->pubkey_hash, i_bootstrap,
6253 SHA256_MAC_LEN) == 0) {
6254 wpa_printf(MSG_DEBUG,
6255 "DPP: Found matching peer bootstrapping information");
6256 *peer_bi = bi;
6257 }
6258
6259 if (*own_bi && *peer_bi)
6260 break;
6261 }
6262
6263 }
6264
6265
dpp_next_configurator_id(struct dpp_global * dpp)6266 static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
6267 {
6268 struct dpp_configurator *conf;
6269 unsigned int max_id = 0;
6270
6271 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
6272 list) {
6273 if (conf->id > max_id)
6274 max_id = conf->id;
6275 }
6276 return max_id + 1;
6277 }
6278
6279
dpp_configurator_add(struct dpp_global * dpp,const char * cmd)6280 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
6281 {
6282 char *curve = NULL;
6283 char *key = NULL;
6284 u8 *privkey = NULL;
6285 size_t privkey_len = 0;
6286 int ret = -1;
6287 struct dpp_configurator *conf = NULL;
6288
6289 curve = get_param(cmd, " curve=");
6290 key = get_param(cmd, " key=");
6291
6292 if (key) {
6293 privkey_len = os_strlen(key) / 2;
6294 privkey = os_malloc(privkey_len);
6295 if (!privkey ||
6296 hexstr2bin(key, privkey, privkey_len) < 0)
6297 goto fail;
6298 }
6299
6300 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
6301 if (!conf)
6302 goto fail;
6303
6304 conf->id = dpp_next_configurator_id(dpp);
6305 dl_list_add(&dpp->configurator, &conf->list);
6306 ret = conf->id;
6307 conf = NULL;
6308 fail:
6309 os_free(curve);
6310 str_clear_free(key);
6311 bin_clear_free(privkey, privkey_len);
6312 dpp_configurator_free(conf);
6313 return ret;
6314 }
6315
6316
dpp_configurator_del(struct dpp_global * dpp,unsigned int id)6317 static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
6318 {
6319 struct dpp_configurator *conf, *tmp;
6320 int found = 0;
6321
6322 if (!dpp)
6323 return -1;
6324
6325 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
6326 struct dpp_configurator, list) {
6327 if (id && conf->id != id)
6328 continue;
6329 found = 1;
6330 dl_list_del(&conf->list);
6331 dpp_configurator_free(conf);
6332 }
6333
6334 if (id == 0)
6335 return 0; /* flush succeeds regardless of entries found */
6336 return found ? 0 : -1;
6337 }
6338
6339
dpp_configurator_remove(struct dpp_global * dpp,const char * id)6340 int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
6341 {
6342 unsigned int id_val;
6343
6344 if (os_strcmp(id, "*") == 0) {
6345 id_val = 0;
6346 } else {
6347 id_val = atoi(id);
6348 if (id_val == 0)
6349 return -1;
6350 }
6351
6352 return dpp_configurator_del(dpp, id_val);
6353 }
6354
6355
dpp_configurator_get_key_id(struct dpp_global * dpp,unsigned int id,char * buf,size_t buflen)6356 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
6357 char *buf, size_t buflen)
6358 {
6359 struct dpp_configurator *conf;
6360
6361 conf = dpp_configurator_get_id(dpp, id);
6362 if (!conf)
6363 return -1;
6364
6365 return dpp_configurator_get_key(conf, buf, buflen);
6366 }
6367
dpp_global_init(struct dpp_global_config * config)6368 struct dpp_global * dpp_global_init(struct dpp_global_config *config)
6369 {
6370 struct dpp_global *dpp;
6371
6372 dpp = os_zalloc(sizeof(*dpp));
6373 if (!dpp)
6374 return NULL;
6375 dpp->msg_ctx = config->msg_ctx;
6376
6377 dl_list_init(&dpp->bootstrap);
6378 dl_list_init(&dpp->configurator);
6379
6380 return dpp;
6381 }
6382
6383
dpp_global_clear(struct dpp_global * dpp)6384 void dpp_global_clear(struct dpp_global *dpp)
6385 {
6386 if (!dpp)
6387 return;
6388
6389 dpp_bootstrap_del(dpp, 0);
6390 dpp_configurator_del(dpp, 0);
6391 }
6392
6393
dpp_global_deinit(struct dpp_global * dpp)6394 void dpp_global_deinit(struct dpp_global *dpp)
6395 {
6396 dpp_global_clear(dpp);
6397 os_free(dpp);
6398 }
6399