1 /*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2020, The Linux Foundation
5 * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
6 *
7 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
9 */
10
11 #include "utils/includes.h"
12
13 #include "utils/common.h"
14 #include "utils/base64.h"
15 #include "utils/json.h"
16 #include "utils/ip_addr.h"
17 #include "common/ieee802_11_common.h"
18 #include "common/wpa_ctrl.h"
19 #include "common/gas.h"
20 #include "eap_common/eap_defs.h"
21 #include "crypto/crypto.h"
22 #include "crypto/random.h"
23 #include "crypto/aes.h"
24 #include "crypto/aes_siv.h"
25 #include "drivers/driver.h"
26 #include "dpp.h"
27 #include "dpp_i.h"
28
29
30 #ifdef CONFIG_TESTING_OPTIONS
31 #ifdef CONFIG_DPP3
32 int dpp_version_override = 3;
33 #elif defined(CONFIG_DPP2)
34 int dpp_version_override = 2;
35 #else
36 int dpp_version_override = 1;
37 #endif
38 enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
39 #endif /* CONFIG_TESTING_OPTIONS */
40
41
dpp_auth_fail(struct dpp_authentication * auth,const char * txt)42 void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
43 {
44 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
45 }
46
47
dpp_alloc_msg(enum dpp_public_action_frame_type type,size_t len)48 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
49 size_t len)
50 {
51 struct wpabuf *msg;
52
53 msg = wpabuf_alloc(8 + len);
54 if (!msg)
55 return NULL;
56 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
57 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
58 wpabuf_put_be24(msg, OUI_WFA);
59 wpabuf_put_u8(msg, DPP_OUI_TYPE);
60 wpabuf_put_u8(msg, 1); /* Crypto Suite */
61 wpabuf_put_u8(msg, type);
62 return msg;
63 }
64
65
dpp_get_attr(const u8 * buf,size_t len,u16 req_id,u16 * ret_len)66 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
67 {
68 u16 id, alen;
69 const u8 *pos = buf, *end = buf + len;
70
71 while (end - pos >= 4) {
72 id = WPA_GET_LE16(pos);
73 pos += 2;
74 alen = WPA_GET_LE16(pos);
75 pos += 2;
76 if (alen > end - pos)
77 return NULL;
78 if (id == req_id) {
79 *ret_len = alen;
80 return pos;
81 }
82 pos += alen;
83 }
84
85 return NULL;
86 }
87
88
dpp_get_attr_next(const u8 * prev,const u8 * buf,size_t len,u16 req_id,u16 * ret_len)89 static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
90 u16 req_id, u16 *ret_len)
91 {
92 u16 id, alen;
93 const u8 *pos, *end = buf + len;
94
95 if (!prev)
96 pos = buf;
97 else
98 pos = prev + WPA_GET_LE16(prev - 2);
99 while (end - pos >= 4) {
100 id = WPA_GET_LE16(pos);
101 pos += 2;
102 alen = WPA_GET_LE16(pos);
103 pos += 2;
104 if (alen > end - pos)
105 return NULL;
106 if (id == req_id) {
107 *ret_len = alen;
108 return pos;
109 }
110 pos += alen;
111 }
112
113 return NULL;
114 }
115
116
dpp_check_attrs(const u8 * buf,size_t len)117 int dpp_check_attrs(const u8 *buf, size_t len)
118 {
119 const u8 *pos, *end;
120 int wrapped_data = 0;
121
122 pos = buf;
123 end = buf + len;
124 while (end - pos >= 4) {
125 u16 id, alen;
126
127 id = WPA_GET_LE16(pos);
128 pos += 2;
129 alen = WPA_GET_LE16(pos);
130 pos += 2;
131 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
132 id, alen);
133 if (alen > end - pos) {
134 wpa_printf(MSG_DEBUG,
135 "DPP: Truncated message - not enough room for the attribute - dropped");
136 return -1;
137 }
138 if (wrapped_data) {
139 wpa_printf(MSG_DEBUG,
140 "DPP: An unexpected attribute included after the Wrapped Data attribute");
141 return -1;
142 }
143 if (id == DPP_ATTR_WRAPPED_DATA)
144 wrapped_data = 1;
145 pos += alen;
146 }
147
148 if (end != pos) {
149 wpa_printf(MSG_DEBUG,
150 "DPP: Unexpected octets (%d) after the last attribute",
151 (int) (end - pos));
152 return -1;
153 }
154
155 return 0;
156 }
157
158
dpp_bootstrap_info_free(struct dpp_bootstrap_info * info)159 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
160 {
161 if (!info)
162 return;
163 os_free(info->uri);
164 os_free(info->info);
165 os_free(info->chan);
166 os_free(info->host);
167 os_free(info->pk);
168 crypto_ec_key_deinit(info->pubkey);
169 str_clear_free(info->configurator_params);
170 os_free(info);
171 }
172
173
dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)174 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
175 {
176 switch (type) {
177 case DPP_BOOTSTRAP_QR_CODE:
178 return "QRCODE";
179 case DPP_BOOTSTRAP_PKEX:
180 return "PKEX";
181 case DPP_BOOTSTRAP_NFC_URI:
182 return "NFC-URI";
183 }
184 return "??";
185 }
186
187
dpp_uri_valid_info(const char * info)188 static int dpp_uri_valid_info(const char *info)
189 {
190 while (*info) {
191 unsigned char val = *info++;
192
193 if (val < 0x20 || val > 0x7e || val == 0x3b)
194 return 0;
195 }
196
197 return 1;
198 }
199
200
dpp_clone_uri(struct dpp_bootstrap_info * bi,const char * uri)201 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
202 {
203 bi->uri = os_strdup(uri);
204 return bi->uri ? 0 : -1;
205 }
206
207
dpp_parse_uri_chan_list(struct dpp_bootstrap_info * bi,const char * chan_list)208 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
209 const char *chan_list)
210 {
211 const char *pos = chan_list, *pos2;
212 int opclass = -1, channel, freq;
213
214 while (pos && *pos && *pos != ';') {
215 pos2 = pos;
216 while (*pos2 >= '0' && *pos2 <= '9')
217 pos2++;
218 if (*pos2 == '/') {
219 opclass = atoi(pos);
220 pos = pos2 + 1;
221 }
222 if (opclass <= 0)
223 goto fail;
224 channel = atoi(pos);
225 if (channel <= 0)
226 goto fail;
227 while (*pos >= '0' && *pos <= '9')
228 pos++;
229 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
230 wpa_printf(MSG_DEBUG,
231 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
232 opclass, channel, freq);
233 bi->channels_listed = true;
234 if (freq < 0) {
235 wpa_printf(MSG_DEBUG,
236 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
237 opclass, channel);
238 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
239 wpa_printf(MSG_DEBUG,
240 "DPP: Too many channels in URI channel-list - ignore list");
241 bi->num_freq = 0;
242 break;
243 } else {
244 bi->freq[bi->num_freq++] = freq;
245 }
246
247 if (*pos == ';' || *pos == '\0')
248 break;
249 if (*pos != ',')
250 goto fail;
251 pos++;
252 }
253
254 return 0;
255 fail:
256 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
257 return -1;
258 }
259
260
dpp_parse_uri_mac(struct dpp_bootstrap_info * bi,const char * mac)261 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
262 {
263 if (!mac)
264 return 0;
265
266 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
267 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
268 return -1;
269 }
270
271 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
272
273 return 0;
274 }
275
276
dpp_parse_uri_info(struct dpp_bootstrap_info * bi,const char * info)277 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
278 {
279 const char *end;
280
281 if (!info)
282 return 0;
283
284 end = os_strchr(info, ';');
285 if (!end)
286 end = info + os_strlen(info);
287 bi->info = os_malloc(end - info + 1);
288 if (!bi->info)
289 return -1;
290 os_memcpy(bi->info, info, end - info);
291 bi->info[end - info] = '\0';
292 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
293 if (!dpp_uri_valid_info(bi->info)) {
294 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
295 return -1;
296 }
297
298 return 0;
299 }
300
301
dpp_parse_uri_version(struct dpp_bootstrap_info * bi,const char * version)302 int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
303 {
304 #ifdef CONFIG_DPP2
305 if (!version || DPP_VERSION < 2)
306 return 0;
307
308 if (*version == '1')
309 bi->version = 1;
310 else if (*version == '2')
311 bi->version = 2;
312 else if (*version == '3')
313 bi->version = 3;
314 else
315 wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
316
317 wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
318 #endif /* CONFIG_DPP2 */
319
320 return 0;
321 }
322
323
dpp_parse_uri_pk(struct dpp_bootstrap_info * bi,const char * info)324 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
325 {
326 u8 *data;
327 size_t data_len;
328 int res;
329 const char *end;
330
331 end = os_strchr(info, ';');
332 if (!end)
333 return -1;
334
335 data = base64_decode(info, end - info, &data_len);
336 if (!data) {
337 wpa_printf(MSG_DEBUG,
338 "DPP: Invalid base64 encoding on URI public-key");
339 return -1;
340 }
341 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
342 data, data_len);
343
344 res = dpp_get_subject_public_key(bi, data, data_len);
345 os_free(data);
346 return res;
347 }
348
349
dpp_parse_uri_supported_curves(struct dpp_bootstrap_info * bi,const char * txt)350 static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
351 const char *txt)
352 {
353 int val;
354
355 if (!txt)
356 return 0;
357
358 val = hex2num(txt[0]);
359 if (val < 0)
360 return -1;
361 bi->supported_curves = val;
362
363 val = hex2num(txt[1]);
364 if (val > 0)
365 bi->supported_curves |= val << 4;
366
367 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
368 bi->supported_curves);
369
370 return 0;
371 }
372
373
dpp_parse_uri_host(struct dpp_bootstrap_info * bi,const char * txt)374 static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
375 {
376 const char *end;
377 char *port;
378 struct hostapd_ip_addr addr;
379 char buf[100], *pos;
380
381 if (!txt)
382 return 0;
383
384 end = os_strchr(txt, ';');
385 if (!end)
386 end = txt + os_strlen(txt);
387 if (end - txt > (int) sizeof(buf) - 1)
388 return -1;
389 os_memcpy(buf, txt, end - txt);
390 buf[end - txt] = '\0';
391
392 bi->port = DPP_TCP_PORT;
393
394 pos = buf;
395 if (*pos == '[') {
396 pos = &buf[1];
397 port = os_strchr(pos, ']');
398 if (!port)
399 return -1;
400 *port++ = '\0';
401 if (*port == ':')
402 bi->port = atoi(port + 1);
403 }
404
405 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
406 if (buf[0] != '[') {
407 port = os_strrchr(pos, ':');
408 if (port) {
409 *port++ = '\0';
410 bi->port = atoi(port);
411 }
412 }
413 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
414 wpa_printf(MSG_INFO,
415 "DPP: Invalid IP address in URI host entry: %s",
416 pos);
417 return -1;
418 }
419 }
420 os_free(bi->host);
421 bi->host = os_memdup(&addr, sizeof(addr));
422 if (!bi->host)
423 return -1;
424
425 wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
426 hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
427
428 return 0;
429 }
430
431
dpp_parse_uri(const char * uri)432 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
433 {
434 const char *pos = uri;
435 const char *end;
436 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
437 const char *version = NULL, *supported_curves = NULL, *host = NULL;
438 struct dpp_bootstrap_info *bi;
439
440 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
441
442 if (os_strncmp(pos, "DPP:", 4) != 0) {
443 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
444 return NULL;
445 }
446 pos += 4;
447
448 for (;;) {
449 end = os_strchr(pos, ';');
450 if (!end)
451 break;
452
453 if (end == pos) {
454 /* Handle terminating ";;" and ignore unexpected ";"
455 * for parsing robustness. */
456 pos++;
457 continue;
458 }
459
460 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
461 chan_list = pos + 2;
462 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
463 mac = pos + 2;
464 else if (pos[0] == 'I' && pos[1] == ':' && !info)
465 info = pos + 2;
466 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
467 pk = pos + 2;
468 else if (pos[0] == 'V' && pos[1] == ':' && !version)
469 version = pos + 2;
470 else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
471 supported_curves = pos + 2;
472 else if (pos[0] == 'H' && pos[1] == ':' && !host)
473 host = pos + 2;
474 else
475 wpa_hexdump_ascii(MSG_DEBUG,
476 "DPP: Ignore unrecognized URI parameter",
477 pos, end - pos);
478 pos = end + 1;
479 }
480
481 if (!pk) {
482 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
483 return NULL;
484 }
485
486 bi = os_zalloc(sizeof(*bi));
487 if (!bi)
488 return NULL;
489
490 if (dpp_clone_uri(bi, uri) < 0 ||
491 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
492 dpp_parse_uri_mac(bi, mac) < 0 ||
493 dpp_parse_uri_info(bi, info) < 0 ||
494 dpp_parse_uri_version(bi, version) < 0 ||
495 dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
496 dpp_parse_uri_host(bi, host) < 0 ||
497 dpp_parse_uri_pk(bi, pk) < 0) {
498 dpp_bootstrap_info_free(bi);
499 bi = NULL;
500 }
501
502 return bi;
503 }
504
505
dpp_build_attr_status(struct wpabuf * msg,enum dpp_status_error status)506 void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
507 {
508 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
509 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
510 wpabuf_put_le16(msg, 1);
511 wpabuf_put_u8(msg, status);
512 }
513
514
dpp_build_attr_r_bootstrap_key_hash(struct wpabuf * msg,const u8 * hash)515 void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
516 {
517 if (hash) {
518 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
519 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
520 wpabuf_put_le16(msg, SHA256_MAC_LEN);
521 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
522 }
523 }
524
525
dpp_channel_ok_init(struct hostapd_hw_modes * own_modes,u16 num_modes,unsigned int freq)526 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
527 u16 num_modes, unsigned int freq)
528 {
529 u16 m;
530 int c, flag;
531
532 if (!own_modes || !num_modes)
533 return 1;
534
535 for (m = 0; m < num_modes; m++) {
536 for (c = 0; c < own_modes[m].num_channels; c++) {
537 if ((unsigned int) own_modes[m].channels[c].freq !=
538 freq)
539 continue;
540 flag = own_modes[m].channels[c].flag;
541 if (!(flag & (HOSTAPD_CHAN_DISABLED |
542 HOSTAPD_CHAN_NO_IR |
543 HOSTAPD_CHAN_RADAR)))
544 return 1;
545 }
546 }
547
548 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
549 return 0;
550 }
551
552
freq_included(const unsigned int freqs[],unsigned int num,unsigned int freq)553 static int freq_included(const unsigned int freqs[], unsigned int num,
554 unsigned int freq)
555 {
556 while (num > 0) {
557 if (freqs[--num] == freq)
558 return 1;
559 }
560 return 0;
561 }
562
563
freq_to_start(unsigned int freqs[],unsigned int num,unsigned int freq)564 static void freq_to_start(unsigned int freqs[], unsigned int num,
565 unsigned int freq)
566 {
567 unsigned int i;
568
569 for (i = 0; i < num; i++) {
570 if (freqs[i] == freq)
571 break;
572 }
573 if (i == 0 || i >= num)
574 return;
575 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
576 freqs[0] = freq;
577 }
578
579
dpp_channel_intersect(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)580 static int dpp_channel_intersect(struct dpp_authentication *auth,
581 struct hostapd_hw_modes *own_modes,
582 u16 num_modes)
583 {
584 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
585 unsigned int i, freq;
586
587 for (i = 0; i < peer_bi->num_freq; i++) {
588 freq = peer_bi->freq[i];
589 if (freq_included(auth->freq, auth->num_freq, freq))
590 continue;
591 if (dpp_channel_ok_init(own_modes, num_modes, freq))
592 auth->freq[auth->num_freq++] = freq;
593 }
594 if (!auth->num_freq) {
595 wpa_printf(MSG_INFO,
596 "DPP: No available channels for initiating DPP Authentication");
597 return -1;
598 }
599 auth->curr_freq = auth->freq[0];
600 return 0;
601 }
602
603
dpp_channel_local_list(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)604 static int dpp_channel_local_list(struct dpp_authentication *auth,
605 struct hostapd_hw_modes *own_modes,
606 u16 num_modes)
607 {
608 u16 m;
609 int c, flag;
610 unsigned int freq;
611
612 auth->num_freq = 0;
613
614 if (!own_modes || !num_modes) {
615 auth->freq[0] = 2412;
616 auth->freq[1] = 2437;
617 auth->freq[2] = 2462;
618 auth->num_freq = 3;
619 return 0;
620 }
621
622 for (m = 0; m < num_modes; m++) {
623 for (c = 0; c < own_modes[m].num_channels; c++) {
624 freq = own_modes[m].channels[c].freq;
625 flag = own_modes[m].channels[c].flag;
626 if (flag & (HOSTAPD_CHAN_DISABLED |
627 HOSTAPD_CHAN_NO_IR |
628 HOSTAPD_CHAN_RADAR))
629 continue;
630 if (freq_included(auth->freq, auth->num_freq, freq))
631 continue;
632 auth->freq[auth->num_freq++] = freq;
633 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
634 m = num_modes;
635 break;
636 }
637 }
638 }
639
640 return auth->num_freq == 0 ? -1 : 0;
641 }
642
643
dpp_prepare_channel_list(struct dpp_authentication * auth,unsigned int neg_freq,struct hostapd_hw_modes * own_modes,u16 num_modes)644 int dpp_prepare_channel_list(struct dpp_authentication *auth,
645 unsigned int neg_freq,
646 struct hostapd_hw_modes *own_modes, u16 num_modes)
647 {
648 int res;
649 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
650 unsigned int i;
651
652 if (!own_modes) {
653 if (!neg_freq)
654 return -1;
655 auth->num_freq = 1;
656 auth->freq[0] = neg_freq;
657 auth->curr_freq = neg_freq;
658 return 0;
659 }
660
661 if (auth->peer_bi->num_freq > 0)
662 res = dpp_channel_intersect(auth, own_modes, num_modes);
663 else
664 res = dpp_channel_local_list(auth, own_modes, num_modes);
665 if (res < 0)
666 return res;
667
668 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
669 * likely channels first. */
670 freq_to_start(auth->freq, auth->num_freq, 2462);
671 freq_to_start(auth->freq, auth->num_freq, 2412);
672 freq_to_start(auth->freq, auth->num_freq, 2437);
673
674 auth->freq_idx = 0;
675 auth->curr_freq = auth->freq[0];
676
677 pos = freqs;
678 end = pos + sizeof(freqs);
679 for (i = 0; i < auth->num_freq; i++) {
680 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
681 if (os_snprintf_error(end - pos, res))
682 break;
683 pos += res;
684 }
685 *pos = '\0';
686 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
687 freqs);
688
689 return 0;
690 }
691
692
dpp_gen_uri(struct dpp_bootstrap_info * bi)693 int dpp_gen_uri(struct dpp_bootstrap_info *bi)
694 {
695 char macstr[ETH_ALEN * 2 + 10];
696 size_t len;
697 char supp_curves[10];
698 char host[100];
699
700 len = 4; /* "DPP:" */
701 if (bi->chan)
702 len += 3 + os_strlen(bi->chan); /* C:...; */
703 if (is_zero_ether_addr(bi->mac_addr))
704 macstr[0] = '\0';
705 else
706 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
707 MAC2STR(bi->mac_addr));
708 len += os_strlen(macstr); /* M:...; */
709 if (bi->info)
710 len += 3 + os_strlen(bi->info); /* I:...; */
711 #ifdef CONFIG_DPP2
712 len += 4; /* V:2; */
713 #endif /* CONFIG_DPP2 */
714 len += 4 + os_strlen(bi->pk); /* K:...;; */
715
716 if (bi->supported_curves) {
717 u8 val = bi->supported_curves;
718
719 if (val & 0xf0) {
720 val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
721 len += os_snprintf(supp_curves, sizeof(supp_curves),
722 "B:%02x;", val);
723 } else {
724 len += os_snprintf(supp_curves, sizeof(supp_curves),
725 "B:%x;", val);
726 }
727 } else {
728 supp_curves[0] = '\0';
729 }
730
731 host[0] = '\0';
732 if (bi->host) {
733 char buf[100];
734 const char *addr;
735
736 addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
737 if (!addr)
738 return -1;
739 if (bi->port == DPP_TCP_PORT)
740 len += os_snprintf(host, sizeof(host), "H:%s;", addr);
741 else if (bi->host->af == AF_INET)
742 len += os_snprintf(host, sizeof(host), "H:%s:%u;",
743 addr, bi->port);
744 else
745 len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
746 addr, bi->port);
747 }
748
749 os_free(bi->uri);
750 bi->uri = os_malloc(len + 1);
751 if (!bi->uri)
752 return -1;
753 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
754 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
755 bi->chan ? ";" : "",
756 macstr,
757 bi->info ? "I:" : "", bi->info ? bi->info : "",
758 bi->info ? ";" : "",
759 DPP_VERSION == 3 ? "V:3;" :
760 (DPP_VERSION == 2 ? "V:2;" : ""),
761 supp_curves,
762 host,
763 bi->pk);
764 return 0;
765 }
766
767
768 struct dpp_authentication *
dpp_alloc_auth(struct dpp_global * dpp,void * msg_ctx)769 dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
770 {
771 struct dpp_authentication *auth;
772
773 auth = os_zalloc(sizeof(*auth));
774 if (!auth)
775 return NULL;
776 auth->global = dpp;
777 auth->msg_ctx = msg_ctx;
778 auth->conf_resp_status = 255;
779 return auth;
780 }
781
782
dpp_build_conf_req_attr(struct dpp_authentication * auth,const char * json)783 static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
784 const char *json)
785 {
786 size_t nonce_len;
787 size_t json_len, clear_len;
788 struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
789 u8 *wrapped;
790 size_t attr_len;
791 #ifdef CONFIG_DPP3
792 u8 auth_i[DPP_MAX_HASH_LEN];
793 #endif /* CONFIG_DPP3 */
794
795 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
796
797 nonce_len = auth->curve->nonce_len;
798 if (random_get_bytes(auth->e_nonce, nonce_len)) {
799 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
800 goto fail;
801 }
802 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
803 json_len = os_strlen(json);
804 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
805
806 /* { E-nonce, configAttrib }ke */
807 clear_len = 4 + nonce_len + 4 + json_len;
808 #ifdef CONFIG_DPP3
809 if (auth->waiting_new_key) {
810 pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
811 if (!pe)
812 goto fail;
813 clear_len += 4 + wpabuf_len(pe);
814
815 if (dpp_derive_auth_i(auth, auth_i) < 0)
816 goto fail;
817 clear_len += 4 + auth->curve->hash_len;
818 }
819 #endif /* CONFIG_DPP3 */
820 clear = wpabuf_alloc(clear_len);
821 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
822 #ifdef CONFIG_TESTING_OPTIONS
823 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
824 attr_len += 5;
825 #endif /* CONFIG_TESTING_OPTIONS */
826 msg = wpabuf_alloc(attr_len);
827 if (!clear || !msg)
828 goto fail;
829
830 #ifdef CONFIG_TESTING_OPTIONS
831 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
832 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
833 goto skip_e_nonce;
834 }
835 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
836 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
837 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
838 wpabuf_put_le16(clear, nonce_len - 1);
839 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
840 goto skip_e_nonce;
841 }
842 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
843 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
844 goto skip_wrapped_data;
845 }
846 #endif /* CONFIG_TESTING_OPTIONS */
847
848 /* E-nonce */
849 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
850 wpabuf_put_le16(clear, nonce_len);
851 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
852
853 #ifdef CONFIG_TESTING_OPTIONS
854 skip_e_nonce:
855 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
856 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
857 goto skip_conf_attr_obj;
858 }
859 #endif /* CONFIG_TESTING_OPTIONS */
860
861 #ifdef CONFIG_DPP3
862 if (pe) {
863 wpa_printf(MSG_DEBUG, "DPP: Pe");
864 wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
865 wpabuf_put_le16(clear, wpabuf_len(pe));
866 wpabuf_put_buf(clear, pe);
867 }
868 if (auth->waiting_new_key) {
869 wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
870 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
871 wpabuf_put_le16(clear, auth->curve->hash_len);
872 wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
873 }
874 #endif /* CONFIG_DPP3 */
875
876 /* configAttrib */
877 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
878 wpabuf_put_le16(clear, json_len);
879 wpabuf_put_data(clear, json, json_len);
880
881 #ifdef CONFIG_TESTING_OPTIONS
882 skip_conf_attr_obj:
883 #endif /* CONFIG_TESTING_OPTIONS */
884
885 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
886 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
887 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
888
889 /* No AES-SIV AD */
890 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
891 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
892 wpabuf_head(clear), wpabuf_len(clear),
893 0, NULL, NULL, wrapped) < 0)
894 goto fail;
895 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
896 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
897
898 #ifdef CONFIG_TESTING_OPTIONS
899 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
900 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
901 dpp_build_attr_status(msg, DPP_STATUS_OK);
902 }
903 skip_wrapped_data:
904 #endif /* CONFIG_TESTING_OPTIONS */
905
906 wpa_hexdump_buf(MSG_DEBUG,
907 "DPP: Configuration Request frame attributes", msg);
908 out:
909 wpabuf_free(clear);
910 wpabuf_free(pe);
911 return msg;
912
913 fail:
914 wpabuf_free(msg);
915 msg = NULL;
916 goto out;
917 }
918
919
dpp_write_adv_proto(struct wpabuf * buf)920 void dpp_write_adv_proto(struct wpabuf *buf)
921 {
922 /* Advertisement Protocol IE */
923 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
924 wpabuf_put_u8(buf, 8); /* Length */
925 wpabuf_put_u8(buf, 0x7f);
926 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
927 wpabuf_put_u8(buf, 5);
928 wpabuf_put_be24(buf, OUI_WFA);
929 wpabuf_put_u8(buf, DPP_OUI_TYPE);
930 wpabuf_put_u8(buf, 0x01);
931 }
932
933
dpp_write_gas_query(struct wpabuf * buf,struct wpabuf * query)934 void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
935 {
936 /* GAS Query */
937 wpabuf_put_le16(buf, wpabuf_len(query));
938 wpabuf_put_buf(buf, query);
939 }
940
941
dpp_build_conf_req(struct dpp_authentication * auth,const char * json)942 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
943 const char *json)
944 {
945 struct wpabuf *buf, *conf_req;
946
947 conf_req = dpp_build_conf_req_attr(auth, json);
948 if (!conf_req) {
949 wpa_printf(MSG_DEBUG,
950 "DPP: No configuration request data available");
951 return NULL;
952 }
953
954 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
955 if (!buf) {
956 wpabuf_free(conf_req);
957 return NULL;
958 }
959
960 dpp_write_adv_proto(buf);
961 dpp_write_gas_query(buf, conf_req);
962 wpabuf_free(conf_req);
963 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
964
965 return buf;
966 }
967
968
dpp_build_conf_req_helper(struct dpp_authentication * auth,const char * name,enum dpp_netrole netrole,const char * mud_url,int * opclasses,const char * extra_name,const char * extra_value)969 struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
970 const char *name,
971 enum dpp_netrole netrole,
972 const char *mud_url, int *opclasses,
973 const char *extra_name,
974 const char *extra_value)
975 {
976 size_t len, name_len;
977 const char *tech = "infra";
978 const char *dpp_name;
979 struct wpabuf *buf = NULL, *json = NULL;
980 char *csr = NULL;
981
982 #ifdef CONFIG_TESTING_OPTIONS
983 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
984 static const char *bogus_tech = "knfra";
985
986 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
987 tech = bogus_tech;
988 }
989 #endif /* CONFIG_TESTING_OPTIONS */
990
991 dpp_name = name ? name : "Test";
992 name_len = os_strlen(dpp_name);
993
994 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
995 if (mud_url && mud_url[0])
996 len += 10 + os_strlen(mud_url);
997 if (extra_name && extra_value && extra_name[0] && extra_value[0])
998 len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
999 #ifdef CONFIG_DPP2
1000 if (auth->csr) {
1001 size_t csr_len;
1002
1003 csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1004 wpabuf_len(auth->csr), &csr_len);
1005 if (!csr)
1006 goto fail;
1007 len += 30 + csr_len;
1008 }
1009 #endif /* CONFIG_DPP2 */
1010 json = wpabuf_alloc(len);
1011 if (!json)
1012 goto fail;
1013
1014 json_start_object(json, NULL);
1015 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1016 goto fail;
1017 json_value_sep(json);
1018 json_add_string(json, "wi-fi_tech", tech);
1019 json_value_sep(json);
1020 json_add_string(json, "netRole", dpp_netrole_str(netrole));
1021 if (mud_url && mud_url[0]) {
1022 json_value_sep(json);
1023 json_add_string(json, "mudurl", mud_url);
1024 }
1025 if (opclasses) {
1026 int i;
1027
1028 json_value_sep(json);
1029 json_start_array(json, "bandSupport");
1030 for (i = 0; opclasses[i]; i++)
1031 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
1032 json_end_array(json);
1033 }
1034 if (csr) {
1035 json_value_sep(json);
1036 json_add_string(json, "pkcs10", csr);
1037 }
1038 if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1039 json_value_sep(json);
1040 wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1041 }
1042 json_end_object(json);
1043
1044 buf = dpp_build_conf_req(auth, wpabuf_head(json));
1045 fail:
1046 wpabuf_free(json);
1047 os_free(csr);
1048
1049 return buf;
1050 }
1051
1052
bin_str_eq(const char * val,size_t len,const char * cmp)1053 static int bin_str_eq(const char *val, size_t len, const char *cmp)
1054 {
1055 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1056 }
1057
1058
dpp_configuration_alloc(const char * type)1059 struct dpp_configuration * dpp_configuration_alloc(const char *type)
1060 {
1061 struct dpp_configuration *conf;
1062 const char *end;
1063 size_t len;
1064
1065 conf = os_zalloc(sizeof(*conf));
1066 if (!conf)
1067 goto fail;
1068
1069 end = os_strchr(type, ' ');
1070 if (end)
1071 len = end - type;
1072 else
1073 len = os_strlen(type);
1074
1075 if (bin_str_eq(type, len, "psk"))
1076 conf->akm = DPP_AKM_PSK;
1077 else if (bin_str_eq(type, len, "sae"))
1078 conf->akm = DPP_AKM_SAE;
1079 else if (bin_str_eq(type, len, "psk-sae") ||
1080 bin_str_eq(type, len, "psk+sae"))
1081 conf->akm = DPP_AKM_PSK_SAE;
1082 else if (bin_str_eq(type, len, "sae-dpp") ||
1083 bin_str_eq(type, len, "dpp+sae"))
1084 conf->akm = DPP_AKM_SAE_DPP;
1085 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1086 bin_str_eq(type, len, "dpp+psk+sae"))
1087 conf->akm = DPP_AKM_PSK_SAE_DPP;
1088 else if (bin_str_eq(type, len, "dpp"))
1089 conf->akm = DPP_AKM_DPP;
1090 else if (bin_str_eq(type, len, "dot1x"))
1091 conf->akm = DPP_AKM_DOT1X;
1092 else
1093 goto fail;
1094
1095 return conf;
1096 fail:
1097 dpp_configuration_free(conf);
1098 return NULL;
1099 }
1100
1101
dpp_akm_psk(enum dpp_akm akm)1102 int dpp_akm_psk(enum dpp_akm akm)
1103 {
1104 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1105 akm == DPP_AKM_PSK_SAE_DPP;
1106 }
1107
1108
dpp_akm_sae(enum dpp_akm akm)1109 int dpp_akm_sae(enum dpp_akm akm)
1110 {
1111 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1112 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1113 }
1114
1115
dpp_akm_legacy(enum dpp_akm akm)1116 int dpp_akm_legacy(enum dpp_akm akm)
1117 {
1118 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1119 akm == DPP_AKM_SAE;
1120 }
1121
1122
dpp_akm_dpp(enum dpp_akm akm)1123 int dpp_akm_dpp(enum dpp_akm akm)
1124 {
1125 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1126 akm == DPP_AKM_PSK_SAE_DPP;
1127 }
1128
1129
dpp_akm_ver2(enum dpp_akm akm)1130 int dpp_akm_ver2(enum dpp_akm akm)
1131 {
1132 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1133 }
1134
1135
dpp_configuration_valid(const struct dpp_configuration * conf)1136 int dpp_configuration_valid(const struct dpp_configuration *conf)
1137 {
1138 if (conf->ssid_len == 0)
1139 return 0;
1140 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1141 return 0;
1142 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1143 return 0;
1144 return 1;
1145 }
1146
1147
dpp_configuration_free(struct dpp_configuration * conf)1148 void dpp_configuration_free(struct dpp_configuration *conf)
1149 {
1150 if (!conf)
1151 return;
1152 str_clear_free(conf->passphrase);
1153 os_free(conf->group_id);
1154 os_free(conf->csrattrs);
1155 os_free(conf->extra_name);
1156 os_free(conf->extra_value);
1157 bin_clear_free(conf, sizeof(*conf));
1158 }
1159
1160
dpp_configuration_parse_helper(struct dpp_authentication * auth,const char * cmd,int idx)1161 static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1162 const char *cmd, int idx)
1163 {
1164 const char *pos, *end;
1165 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1166 struct dpp_configuration *conf = NULL;
1167 size_t len;
1168
1169 pos = os_strstr(cmd, " conf=sta-");
1170 if (pos) {
1171 conf_sta = dpp_configuration_alloc(pos + 10);
1172 if (!conf_sta)
1173 goto fail;
1174 conf_sta->netrole = DPP_NETROLE_STA;
1175 conf = conf_sta;
1176 }
1177
1178 pos = os_strstr(cmd, " conf=ap-");
1179 if (pos) {
1180 conf_ap = dpp_configuration_alloc(pos + 9);
1181 if (!conf_ap)
1182 goto fail;
1183 conf_ap->netrole = DPP_NETROLE_AP;
1184 conf = conf_ap;
1185 }
1186
1187 pos = os_strstr(cmd, " conf=configurator");
1188 if (pos)
1189 auth->provision_configurator = 1;
1190
1191 if (!conf)
1192 return 0;
1193
1194 pos = os_strstr(cmd, " ssid=");
1195 if (pos) {
1196 pos += 6;
1197 end = os_strchr(pos, ' ');
1198 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1199 conf->ssid_len /= 2;
1200 if (conf->ssid_len > sizeof(conf->ssid) ||
1201 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1202 goto fail;
1203 } else {
1204 #ifdef CONFIG_TESTING_OPTIONS
1205 /* use a default SSID for legacy testing reasons */
1206 os_memcpy(conf->ssid, "test", 4);
1207 conf->ssid_len = 4;
1208 #else /* CONFIG_TESTING_OPTIONS */
1209 goto fail;
1210 #endif /* CONFIG_TESTING_OPTIONS */
1211 }
1212
1213 pos = os_strstr(cmd, " ssid_charset=");
1214 if (pos) {
1215 if (conf_ap) {
1216 wpa_printf(MSG_INFO,
1217 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1218 goto fail;
1219 }
1220 conf->ssid_charset = atoi(pos + 14);
1221 }
1222
1223 pos = os_strstr(cmd, " pass=");
1224 if (pos) {
1225 size_t pass_len;
1226
1227 pos += 6;
1228 end = os_strchr(pos, ' ');
1229 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1230 pass_len /= 2;
1231 if (pass_len > 63 || pass_len < 8)
1232 goto fail;
1233 conf->passphrase = os_zalloc(pass_len + 1);
1234 if (!conf->passphrase ||
1235 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1236 goto fail;
1237 }
1238
1239 pos = os_strstr(cmd, " psk=");
1240 if (pos) {
1241 pos += 5;
1242 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1243 goto fail;
1244 conf->psk_set = 1;
1245 }
1246
1247 pos = os_strstr(cmd, " group_id=");
1248 if (pos) {
1249 size_t group_id_len;
1250
1251 pos += 10;
1252 end = os_strchr(pos, ' ');
1253 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1254 conf->group_id = os_malloc(group_id_len + 1);
1255 if (!conf->group_id)
1256 goto fail;
1257 os_memcpy(conf->group_id, pos, group_id_len);
1258 conf->group_id[group_id_len] = '\0';
1259 }
1260
1261 pos = os_strstr(cmd, " expiry=");
1262 if (pos) {
1263 long int val;
1264
1265 pos += 8;
1266 val = strtol(pos, NULL, 0);
1267 if (val <= 0)
1268 goto fail;
1269 conf->netaccesskey_expiry = val;
1270 }
1271
1272 pos = os_strstr(cmd, " csrattrs=");
1273 if (pos) {
1274 pos += 10;
1275 end = os_strchr(pos, ' ');
1276 len = end ? (size_t) (end - pos) : os_strlen(pos);
1277 conf->csrattrs = os_zalloc(len + 1);
1278 if (!conf->csrattrs)
1279 goto fail;
1280 os_memcpy(conf->csrattrs, pos, len);
1281 }
1282
1283 pos = os_strstr(cmd, " conf_extra_name=");
1284 if (pos) {
1285 pos += 17;
1286 end = os_strchr(pos, ' ');
1287 len = end ? (size_t) (end - pos) : os_strlen(pos);
1288 conf->extra_name = os_zalloc(len + 1);
1289 if (!conf->extra_name)
1290 goto fail;
1291 os_memcpy(conf->extra_name, pos, len);
1292 }
1293
1294 pos = os_strstr(cmd, " conf_extra_value=");
1295 if (pos) {
1296 pos += 18;
1297 end = os_strchr(pos, ' ');
1298 len = end ? (size_t) (end - pos) : os_strlen(pos);
1299 len /= 2;
1300 conf->extra_value = os_zalloc(len + 1);
1301 if (!conf->extra_value ||
1302 hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1303 goto fail;
1304 }
1305
1306 if (!dpp_configuration_valid(conf))
1307 goto fail;
1308
1309 if (idx == 0) {
1310 auth->conf_sta = conf_sta;
1311 auth->conf_ap = conf_ap;
1312 } else if (idx == 1) {
1313 if (!auth->conf_sta)
1314 auth->conf_sta = conf_sta;
1315 else
1316 auth->conf2_sta = conf_sta;
1317 if (!auth->conf_ap)
1318 auth->conf_ap = conf_ap;
1319 else
1320 auth->conf2_ap = conf_ap;
1321 } else {
1322 goto fail;
1323 }
1324 return 0;
1325
1326 fail:
1327 dpp_configuration_free(conf_sta);
1328 dpp_configuration_free(conf_ap);
1329 return -1;
1330 }
1331
1332
dpp_configuration_parse(struct dpp_authentication * auth,const char * cmd)1333 static int dpp_configuration_parse(struct dpp_authentication *auth,
1334 const char *cmd)
1335 {
1336 const char *pos;
1337 char *tmp;
1338 size_t len;
1339 int res;
1340
1341 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1342 if (!pos)
1343 return dpp_configuration_parse_helper(auth, cmd, 0);
1344
1345 len = pos - cmd;
1346 tmp = os_malloc(len + 1);
1347 if (!tmp)
1348 goto fail;
1349 os_memcpy(tmp, cmd, len);
1350 tmp[len] = '\0';
1351 res = dpp_configuration_parse_helper(auth, tmp, 0);
1352 str_clear_free(tmp);
1353 if (res)
1354 goto fail;
1355 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1356 if (res)
1357 goto fail;
1358 return 0;
1359 fail:
1360 dpp_configuration_free(auth->conf_sta);
1361 dpp_configuration_free(auth->conf2_sta);
1362 dpp_configuration_free(auth->conf_ap);
1363 dpp_configuration_free(auth->conf2_ap);
1364 return -1;
1365 }
1366
1367
1368 static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global * dpp,unsigned int id)1369 dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1370 {
1371 struct dpp_configurator *conf;
1372
1373 if (!dpp)
1374 return NULL;
1375
1376 dl_list_for_each(conf, &dpp->configurator,
1377 struct dpp_configurator, list) {
1378 if (conf->id == id)
1379 return conf;
1380 }
1381 return NULL;
1382 }
1383
1384
dpp_set_configurator(struct dpp_authentication * auth,const char * cmd)1385 int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
1386 {
1387 const char *pos;
1388 char *tmp = NULL;
1389 int ret = -1;
1390
1391 if (!cmd || auth->configurator_set)
1392 return 0;
1393 auth->configurator_set = 1;
1394
1395 if (cmd[0] != ' ') {
1396 size_t len;
1397
1398 len = os_strlen(cmd);
1399 tmp = os_malloc(len + 2);
1400 if (!tmp)
1401 goto fail;
1402 tmp[0] = ' ';
1403 os_memcpy(tmp + 1, cmd, len + 1);
1404 cmd = tmp;
1405 }
1406
1407 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1408
1409 if (os_strstr(cmd, " conf=query")) {
1410 auth->configurator_set = 0;
1411 auth->use_config_query = true;
1412 ret = 0;
1413 goto fail;
1414 }
1415
1416 pos = os_strstr(cmd, " configurator=");
1417 if (!auth->conf && pos) {
1418 pos += 14;
1419 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
1420 if (!auth->conf) {
1421 wpa_printf(MSG_INFO,
1422 "DPP: Could not find the specified configurator");
1423 goto fail;
1424 }
1425 }
1426
1427 pos = os_strstr(cmd, " conn_status=");
1428 if (pos) {
1429 pos += 13;
1430 auth->send_conn_status = atoi(pos);
1431 }
1432
1433 pos = os_strstr(cmd, " akm_use_selector=");
1434 if (pos) {
1435 pos += 18;
1436 auth->akm_use_selector = atoi(pos);
1437 }
1438
1439 if (dpp_configuration_parse(auth, cmd) < 0) {
1440 wpa_msg(auth->msg_ctx, MSG_INFO,
1441 "DPP: Failed to set configurator parameters");
1442 goto fail;
1443 }
1444 ret = 0;
1445 fail:
1446 os_free(tmp);
1447 return ret;
1448 }
1449
1450
dpp_auth_deinit(struct dpp_authentication * auth)1451 void dpp_auth_deinit(struct dpp_authentication *auth)
1452 {
1453 unsigned int i;
1454
1455 if (!auth)
1456 return;
1457 dpp_configuration_free(auth->conf_ap);
1458 dpp_configuration_free(auth->conf2_ap);
1459 dpp_configuration_free(auth->conf_sta);
1460 dpp_configuration_free(auth->conf2_sta);
1461 crypto_ec_key_deinit(auth->own_protocol_key);
1462 crypto_ec_key_deinit(auth->peer_protocol_key);
1463 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
1464 wpabuf_free(auth->req_msg);
1465 wpabuf_free(auth->resp_msg);
1466 wpabuf_free(auth->conf_req);
1467 wpabuf_free(auth->reconfig_req_msg);
1468 wpabuf_free(auth->reconfig_resp_msg);
1469 for (i = 0; i < auth->num_conf_obj; i++) {
1470 struct dpp_config_obj *conf = &auth->conf_obj[i];
1471
1472 os_free(conf->connector);
1473 wpabuf_free(conf->c_sign_key);
1474 wpabuf_free(conf->certbag);
1475 wpabuf_free(conf->certs);
1476 wpabuf_free(conf->cacert);
1477 os_free(conf->server_name);
1478 wpabuf_free(conf->pp_key);
1479 }
1480 #ifdef CONFIG_DPP2
1481 dpp_free_asymmetric_key(auth->conf_key_pkg);
1482 os_free(auth->csrattrs);
1483 wpabuf_free(auth->csr);
1484 wpabuf_free(auth->priv_key);
1485 wpabuf_free(auth->cacert);
1486 wpabuf_free(auth->certbag);
1487 os_free(auth->trusted_eap_server_name);
1488 wpabuf_free(auth->conf_resp_tcp);
1489 #endif /* CONFIG_DPP2 */
1490 wpabuf_free(auth->net_access_key);
1491 dpp_bootstrap_info_free(auth->tmp_own_bi);
1492 if (auth->tmp_peer_bi) {
1493 dl_list_del(&auth->tmp_peer_bi->list);
1494 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1495 }
1496 os_free(auth->e_name);
1497 os_free(auth->e_mud_url);
1498 os_free(auth->e_band_support);
1499 #ifdef CONFIG_TESTING_OPTIONS
1500 os_free(auth->config_obj_override);
1501 os_free(auth->discovery_override);
1502 os_free(auth->groups_override);
1503 #endif /* CONFIG_TESTING_OPTIONS */
1504 bin_clear_free(auth, sizeof(*auth));
1505 }
1506
1507
1508 static struct wpabuf *
dpp_build_conf_start(struct dpp_authentication * auth,struct dpp_configuration * conf,size_t tailroom)1509 dpp_build_conf_start(struct dpp_authentication *auth,
1510 struct dpp_configuration *conf, size_t tailroom)
1511 {
1512 struct wpabuf *buf;
1513
1514 #ifdef CONFIG_TESTING_OPTIONS
1515 if (auth->discovery_override)
1516 tailroom += os_strlen(auth->discovery_override);
1517 #endif /* CONFIG_TESTING_OPTIONS */
1518
1519 buf = wpabuf_alloc(200 + tailroom);
1520 if (!buf)
1521 return NULL;
1522 json_start_object(buf, NULL);
1523 json_add_string(buf, "wi-fi_tech", "infra");
1524 json_value_sep(buf);
1525 #ifdef CONFIG_TESTING_OPTIONS
1526 if (auth->discovery_override) {
1527 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1528 auth->discovery_override);
1529 wpabuf_put_str(buf, "\"discovery\":");
1530 wpabuf_put_str(buf, auth->discovery_override);
1531 json_value_sep(buf);
1532 return buf;
1533 }
1534 #endif /* CONFIG_TESTING_OPTIONS */
1535 json_start_object(buf, "discovery");
1536 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1537 json_add_string_escape(buf, "ssid", conf->ssid,
1538 conf->ssid_len) < 0) ||
1539 ((conf->ssid_charset && auth->peer_version >= 2) &&
1540 json_add_base64url(buf, "ssid64", conf->ssid,
1541 conf->ssid_len) < 0)) {
1542 wpabuf_free(buf);
1543 return NULL;
1544 }
1545 if (conf->ssid_charset > 0) {
1546 json_value_sep(buf);
1547 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1548 }
1549 json_end_object(buf);
1550 json_value_sep(buf);
1551
1552 return buf;
1553 }
1554
1555
dpp_build_jwk(struct wpabuf * buf,const char * name,struct crypto_ec_key * key,const char * kid,const struct dpp_curve_params * curve)1556 int dpp_build_jwk(struct wpabuf *buf, const char *name,
1557 struct crypto_ec_key *key, const char *kid,
1558 const struct dpp_curve_params *curve)
1559 {
1560 struct wpabuf *pub;
1561 const u8 *pos;
1562 int ret = -1;
1563
1564 pub = crypto_ec_key_get_pubkey_point(key, 0);
1565 if (!pub)
1566 goto fail;
1567
1568 json_start_object(buf, name);
1569 json_add_string(buf, "kty", "EC");
1570 json_value_sep(buf);
1571 json_add_string(buf, "crv", curve->jwk_crv);
1572 json_value_sep(buf);
1573 pos = wpabuf_head(pub);
1574 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1575 goto fail;
1576 json_value_sep(buf);
1577 pos += curve->prime_len;
1578 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1579 goto fail;
1580 if (kid) {
1581 json_value_sep(buf);
1582 json_add_string(buf, "kid", kid);
1583 }
1584 json_end_object(buf);
1585 ret = 0;
1586 fail:
1587 wpabuf_free(pub);
1588 return ret;
1589 }
1590
1591
dpp_build_legacy_cred_params(struct wpabuf * buf,struct dpp_configuration * conf)1592 static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1593 struct dpp_configuration *conf)
1594 {
1595 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
1596 json_add_string_escape(buf, "pass", conf->passphrase,
1597 os_strlen(conf->passphrase));
1598 } else if (conf->psk_set) {
1599 char psk[2 * sizeof(conf->psk) + 1];
1600
1601 wpa_snprintf_hex(psk, sizeof(psk),
1602 conf->psk, sizeof(conf->psk));
1603 json_add_string(buf, "psk_hex", psk);
1604 forced_memzero(psk, sizeof(psk));
1605 }
1606 }
1607
1608
dpp_netrole_str(enum dpp_netrole netrole)1609 const char * dpp_netrole_str(enum dpp_netrole netrole)
1610 {
1611 switch (netrole) {
1612 case DPP_NETROLE_STA:
1613 return "sta";
1614 case DPP_NETROLE_AP:
1615 return "ap";
1616 case DPP_NETROLE_CONFIGURATOR:
1617 return "configurator";
1618 default:
1619 return "??";
1620 }
1621 }
1622
1623
dpp_supports_curve(const char * curve,struct dpp_bootstrap_info * bi)1624 static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1625 {
1626 enum dpp_bootstrap_supported_curves idx;
1627
1628 if (!bi || !bi->supported_curves)
1629 return true; /* no support indication available */
1630
1631 if (os_strcmp(curve, "prime256v1") == 0)
1632 idx = DPP_BOOTSTRAP_CURVE_P_256;
1633 else if (os_strcmp(curve, "secp384r1") == 0)
1634 idx = DPP_BOOTSTRAP_CURVE_P_384;
1635 else if (os_strcmp(curve, "secp521r1") == 0)
1636 idx = DPP_BOOTSTRAP_CURVE_P_521;
1637 else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1638 idx = DPP_BOOTSTRAP_CURVE_BP_256;
1639 else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1640 idx = DPP_BOOTSTRAP_CURVE_BP_384;
1641 else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1642 idx = DPP_BOOTSTRAP_CURVE_BP_512;
1643 else
1644 return true;
1645
1646 return bi->supported_curves & BIT(idx);
1647 }
1648
1649
1650 static struct wpabuf *
dpp_build_conf_obj_dpp(struct dpp_authentication * auth,struct dpp_configuration * conf)1651 dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
1652 struct dpp_configuration *conf)
1653 {
1654 struct wpabuf *buf = NULL;
1655 char *signed_conn = NULL;
1656 size_t tailroom;
1657 const struct dpp_curve_params *curve; /* C-sign-key curve */
1658 const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
1659 struct wpabuf *dppcon = NULL;
1660 size_t extra_len = 1000;
1661 int incl_legacy;
1662 enum dpp_akm akm;
1663 const char *akm_str;
1664
1665 if (!auth->conf) {
1666 wpa_printf(MSG_INFO,
1667 "DPP: No configurator specified - cannot generate DPP config object");
1668 goto fail;
1669 }
1670 curve = auth->conf->curve;
1671 if (dpp_akm_dpp(conf->akm) &&
1672 !dpp_supports_curve(curve->name, auth->peer_bi)) {
1673 wpa_printf(MSG_DEBUG,
1674 "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1675 curve->name);
1676 goto fail;
1677 }
1678 if (auth->new_curve && auth->new_key_received)
1679 nak_curve = auth->new_curve;
1680 else
1681 nak_curve = auth->curve;
1682 if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1683 wpa_printf(MSG_DEBUG,
1684 "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1685 nak_curve->name);
1686 goto fail;
1687 }
1688
1689 akm = conf->akm;
1690 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1691 wpa_printf(MSG_DEBUG,
1692 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1693 akm = DPP_AKM_DPP;
1694 }
1695
1696 #ifdef CONFIG_TESTING_OPTIONS
1697 if (auth->groups_override)
1698 extra_len += os_strlen(auth->groups_override);
1699 #endif /* CONFIG_TESTING_OPTIONS */
1700
1701 if (conf->group_id)
1702 extra_len += os_strlen(conf->group_id);
1703
1704 /* Connector (JSON dppCon object) */
1705 dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
1706 if (!dppcon)
1707 goto fail;
1708 #ifdef CONFIG_TESTING_OPTIONS
1709 if (auth->groups_override) {
1710 wpabuf_put_u8(dppcon, '{');
1711 if (auth->groups_override) {
1712 wpa_printf(MSG_DEBUG,
1713 "DPP: TESTING - groups override: '%s'",
1714 auth->groups_override);
1715 wpabuf_put_str(dppcon, "\"groups\":");
1716 wpabuf_put_str(dppcon, auth->groups_override);
1717 json_value_sep(dppcon);
1718 }
1719 goto skip_groups;
1720 }
1721 #endif /* CONFIG_TESTING_OPTIONS */
1722 json_start_object(dppcon, NULL);
1723 json_start_array(dppcon, "groups");
1724 json_start_object(dppcon, NULL);
1725 json_add_string(dppcon, "groupId",
1726 conf->group_id ? conf->group_id : "*");
1727 json_value_sep(dppcon);
1728 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1729 json_end_object(dppcon);
1730 json_end_array(dppcon);
1731 json_value_sep(dppcon);
1732 #ifdef CONFIG_TESTING_OPTIONS
1733 skip_groups:
1734 #endif /* CONFIG_TESTING_OPTIONS */
1735 if (!auth->peer_protocol_key) {
1736 wpa_printf(MSG_DEBUG,
1737 "DPP: No peer protocol key available to build netAccessKey JWK");
1738 goto fail;
1739 }
1740 #ifdef CONFIG_DPP3
1741 if (auth->conf->net_access_key_curve &&
1742 auth->curve != auth->conf->net_access_key_curve &&
1743 !auth->new_key_received) {
1744 if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1745 auth->peer_bi)) {
1746 wpa_printf(MSG_DEBUG,
1747 "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1748 auth->conf->net_access_key_curve->name);
1749 goto fail;
1750 }
1751 wpa_printf(MSG_DEBUG,
1752 "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1753 auth->curve->name,
1754 auth->conf->net_access_key_curve->name,
1755 auth->waiting_new_key ?
1756 "the required key not received" :
1757 "request a new key");
1758 if (auth->waiting_new_key)
1759 auth->waiting_new_key = false; /* failed */
1760 else
1761 auth->waiting_new_key = true;
1762 goto fail;
1763 }
1764 #endif /* CONFIG_DPP3 */
1765 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1766 nak_curve) < 0) {
1767 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1768 goto fail;
1769 }
1770 if (conf->netaccesskey_expiry) {
1771 struct os_tm tm;
1772 char expiry[30];
1773
1774 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1775 wpa_printf(MSG_DEBUG,
1776 "DPP: Failed to generate expiry string");
1777 goto fail;
1778 }
1779 os_snprintf(expiry, sizeof(expiry),
1780 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1781 tm.year, tm.month, tm.day,
1782 tm.hour, tm.min, tm.sec);
1783 json_value_sep(dppcon);
1784 json_add_string(dppcon, "expiry", expiry);
1785 }
1786 #ifdef CONFIG_DPP3
1787 json_value_sep(dppcon);
1788 json_add_int(dppcon, "version", auth->peer_version);
1789 #endif /* CONFIG_DPP3 */
1790 json_end_object(dppcon);
1791 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1792 (const char *) wpabuf_head(dppcon));
1793
1794 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1795 if (!signed_conn)
1796 goto fail;
1797
1798 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
1799 tailroom = 1000;
1800 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
1801 tailroom += os_strlen(signed_conn);
1802 if (incl_legacy)
1803 tailroom += 1000;
1804 if (akm == DPP_AKM_DOT1X) {
1805 if (auth->certbag)
1806 tailroom += 2 * wpabuf_len(auth->certbag);
1807 if (auth->cacert)
1808 tailroom += 2 * wpabuf_len(auth->cacert);
1809 if (auth->trusted_eap_server_name)
1810 tailroom += os_strlen(auth->trusted_eap_server_name);
1811 tailroom += 1000;
1812 }
1813 if (conf->extra_name && conf->extra_value)
1814 tailroom += 10 + os_strlen(conf->extra_name) +
1815 os_strlen(conf->extra_value);
1816 buf = dpp_build_conf_start(auth, conf, tailroom);
1817 if (!buf)
1818 goto fail;
1819
1820 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1821 akm_str = dpp_akm_selector_str(akm);
1822 else
1823 akm_str = dpp_akm_str(akm);
1824 json_start_object(buf, "cred");
1825 json_add_string(buf, "akm", akm_str);
1826 json_value_sep(buf);
1827 if (incl_legacy) {
1828 dpp_build_legacy_cred_params(buf, conf);
1829 json_value_sep(buf);
1830 }
1831 if (akm == DPP_AKM_DOT1X) {
1832 json_start_object(buf, "entCreds");
1833 if (!auth->certbag)
1834 goto fail;
1835 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1836 wpabuf_len(auth->certbag));
1837 if (auth->cacert) {
1838 json_value_sep(buf);
1839 json_add_base64(buf, "caCert",
1840 wpabuf_head(auth->cacert),
1841 wpabuf_len(auth->cacert));
1842 }
1843 if (auth->trusted_eap_server_name) {
1844 json_value_sep(buf);
1845 json_add_string(buf, "trustedEapServerName",
1846 auth->trusted_eap_server_name);
1847 }
1848 json_value_sep(buf);
1849 json_start_array(buf, "eapMethods");
1850 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1851 json_end_array(buf);
1852 json_end_object(buf);
1853 json_value_sep(buf);
1854 }
1855 wpabuf_put_str(buf, "\"signedConnector\":\"");
1856 wpabuf_put_str(buf, signed_conn);
1857 wpabuf_put_str(buf, "\"");
1858 json_value_sep(buf);
1859 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1860 curve) < 0) {
1861 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1862 goto fail;
1863 }
1864 #ifdef CONFIG_DPP2
1865 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1866 json_value_sep(buf);
1867 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1868 curve) < 0) {
1869 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1870 goto fail;
1871 }
1872 }
1873 #endif /* CONFIG_DPP2 */
1874
1875 json_end_object(buf);
1876 if (conf->extra_name && conf->extra_value) {
1877 json_value_sep(buf);
1878 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1879 conf->extra_value);
1880 }
1881 json_end_object(buf);
1882
1883 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1884 wpabuf_head(buf), wpabuf_len(buf));
1885
1886 #ifdef CONFIG_DPP3
1887 if (!auth->conf->net_access_key_curve) {
1888 /* All netAccessKey values used in the network will have to be
1889 * from the same curve for network introduction to work, so
1890 * hardcode the first used netAccessKey curve for consecutive
1891 * operations if there was no explicit configuration of which
1892 * curve to use. */
1893 wpa_printf(MSG_DEBUG,
1894 "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1895 nak_curve->name);
1896 auth->conf->net_access_key_curve = nak_curve;
1897 }
1898 #endif /* CONFIG_DPP3 */
1899
1900 out:
1901 os_free(signed_conn);
1902 wpabuf_free(dppcon);
1903 return buf;
1904 fail:
1905 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1906 wpabuf_free(buf);
1907 buf = NULL;
1908 goto out;
1909 }
1910
1911
1912 static struct wpabuf *
dpp_build_conf_obj_legacy(struct dpp_authentication * auth,struct dpp_configuration * conf)1913 dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
1914 struct dpp_configuration *conf)
1915 {
1916 struct wpabuf *buf;
1917 const char *akm_str;
1918 size_t len = 1000;
1919
1920 if (conf->extra_name && conf->extra_value)
1921 len += 10 + os_strlen(conf->extra_name) +
1922 os_strlen(conf->extra_value);
1923 buf = dpp_build_conf_start(auth, conf, len);
1924 if (!buf)
1925 return NULL;
1926
1927 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1928 akm_str = dpp_akm_selector_str(conf->akm);
1929 else
1930 akm_str = dpp_akm_str(conf->akm);
1931 json_start_object(buf, "cred");
1932 json_add_string(buf, "akm", akm_str);
1933 json_value_sep(buf);
1934 dpp_build_legacy_cred_params(buf, conf);
1935 json_end_object(buf);
1936 if (conf->extra_name && conf->extra_value) {
1937 json_value_sep(buf);
1938 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1939 conf->extra_value);
1940 }
1941 json_end_object(buf);
1942
1943 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1944 wpabuf_head(buf), wpabuf_len(buf));
1945
1946 return buf;
1947 }
1948
1949
dpp_get_peer_bi_id(struct dpp_authentication * auth)1950 static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1951 {
1952 struct dpp_bootstrap_info *bi;
1953
1954 if (auth->peer_bi)
1955 return auth->peer_bi->id;
1956 if (auth->tmp_peer_bi)
1957 return auth->tmp_peer_bi->id;
1958
1959 bi = os_zalloc(sizeof(*bi));
1960 if (!bi)
1961 return -1;
1962 bi->id = dpp_next_id(auth->global);
1963 dl_list_add(&auth->global->bootstrap, &bi->list);
1964 auth->tmp_peer_bi = bi;
1965 return bi->id;
1966 }
1967
1968
1969 static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication * auth,enum dpp_netrole netrole,int idx,bool cert_req)1970 dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
1971 int idx, bool cert_req)
1972 {
1973 struct dpp_configuration *conf = NULL;
1974
1975 #ifdef CONFIG_TESTING_OPTIONS
1976 if (auth->config_obj_override) {
1977 if (idx != 0)
1978 return NULL;
1979 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
1980 return wpabuf_alloc_copy(auth->config_obj_override,
1981 os_strlen(auth->config_obj_override));
1982 }
1983 #endif /* CONFIG_TESTING_OPTIONS */
1984
1985 if (idx == 0) {
1986 if (netrole == DPP_NETROLE_STA)
1987 conf = auth->conf_sta;
1988 else if (netrole == DPP_NETROLE_AP)
1989 conf = auth->conf_ap;
1990 } else if (idx == 1) {
1991 if (netrole == DPP_NETROLE_STA)
1992 conf = auth->conf2_sta;
1993 else if (netrole == DPP_NETROLE_AP)
1994 conf = auth->conf2_ap;
1995 }
1996 if (!conf) {
1997 if (idx == 0) {
1998 if (auth->use_config_query) {
1999 wpa_printf(MSG_DEBUG,
2000 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
2001 dpp_netrole_str(netrole));
2002 auth->waiting_config = true;
2003 dpp_get_peer_bi_id(auth);
2004 return NULL;
2005 }
2006 wpa_printf(MSG_DEBUG,
2007 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
2008 dpp_netrole_str(netrole));
2009 }
2010 return NULL;
2011 }
2012
2013 if (conf->akm == DPP_AKM_DOT1X) {
2014 if (!auth->conf) {
2015 wpa_printf(MSG_DEBUG,
2016 "DPP: No Configurator data available");
2017 return NULL;
2018 }
2019 if (!cert_req && !auth->certbag) {
2020 wpa_printf(MSG_DEBUG,
2021 "DPP: No certificate data available for dot1x configuration");
2022 return NULL;
2023 }
2024 return dpp_build_conf_obj_dpp(auth, conf);
2025 }
2026 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
2027 return dpp_build_conf_obj_dpp(auth, conf);
2028 return dpp_build_conf_obj_legacy(auth, conf);
2029 }
2030
2031
2032 struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication * auth,const u8 * e_nonce,u16 e_nonce_len,enum dpp_netrole netrole,bool cert_req)2033 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
2034 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
2035 {
2036 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
2037 size_t clear_len, attr_len;
2038 struct wpabuf *clear = NULL, *msg = NULL;
2039 u8 *wrapped;
2040 const u8 *addr[1];
2041 size_t len[1];
2042 enum dpp_status_error status;
2043
2044 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2045 status = auth->force_conf_resp_status;
2046 goto forced_status;
2047 }
2048
2049 if (netrole == DPP_NETROLE_CONFIGURATOR) {
2050 #ifdef CONFIG_DPP2
2051 env_data = dpp_build_enveloped_data(auth);
2052 #endif /* CONFIG_DPP2 */
2053 } else {
2054 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
2055 if (conf) {
2056 wpa_hexdump_ascii(MSG_DEBUG,
2057 "DPP: configurationObject JSON",
2058 wpabuf_head(conf), wpabuf_len(conf));
2059 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
2060 }
2061 }
2062
2063 if (!conf && auth->waiting_config)
2064 return NULL;
2065 if (conf || env_data)
2066 status = DPP_STATUS_OK;
2067 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2068 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2069 status = DPP_STATUS_CSR_NEEDED;
2070 #ifdef CONFIG_DPP3
2071 else if (auth->waiting_new_key)
2072 status = DPP_STATUS_NEW_KEY_NEEDED;
2073 #endif /* CONFIG_DPP3 */
2074 else
2075 status = DPP_STATUS_CONFIGURE_FAILURE;
2076 forced_status:
2077 auth->conf_resp_status = status;
2078
2079 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
2080 clear_len = 4 + e_nonce_len;
2081 if (conf)
2082 clear_len += 4 + wpabuf_len(conf);
2083 if (conf2)
2084 clear_len += 4 + wpabuf_len(conf2);
2085 if (env_data)
2086 clear_len += 4 + wpabuf_len(env_data);
2087 if (auth->peer_version >= 2 && auth->send_conn_status &&
2088 netrole == DPP_NETROLE_STA)
2089 clear_len += 4;
2090 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2091 auth->conf_sta->csrattrs)
2092 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
2093 #ifdef CONFIG_DPP3
2094 if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2095 struct crypto_ec_key *new_pc;
2096
2097 clear_len += 6; /* Finite Cyclic Group attribute */
2098
2099 wpa_printf(MSG_DEBUG,
2100 "DPP: Generate a new own protocol key for the curve %s",
2101 auth->conf->net_access_key_curve->name);
2102 new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2103 if (!new_pc) {
2104 wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2105 return NULL;
2106 }
2107 pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2108 if (!pc) {
2109 crypto_ec_key_deinit(new_pc);
2110 return NULL;
2111 }
2112 crypto_ec_key_deinit(auth->own_protocol_key);
2113 auth->own_protocol_key = new_pc;
2114 auth->new_curve = auth->conf->net_access_key_curve;
2115 clear_len += 4 + wpabuf_len(pc);
2116 }
2117 #endif /* CONFIG_DPP3 */
2118 clear = wpabuf_alloc(clear_len);
2119 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2120 #ifdef CONFIG_TESTING_OPTIONS
2121 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2122 attr_len += 5;
2123 #endif /* CONFIG_TESTING_OPTIONS */
2124 msg = wpabuf_alloc(attr_len);
2125 if (!clear || !msg)
2126 goto fail;
2127
2128 #ifdef CONFIG_TESTING_OPTIONS
2129 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2130 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2131 goto skip_e_nonce;
2132 }
2133 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2134 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2135 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2136 wpabuf_put_le16(clear, e_nonce_len);
2137 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2138 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2139 goto skip_e_nonce;
2140 }
2141 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2142 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2143 goto skip_wrapped_data;
2144 }
2145 #endif /* CONFIG_TESTING_OPTIONS */
2146
2147 /* E-nonce */
2148 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2149 wpabuf_put_le16(clear, e_nonce_len);
2150 wpabuf_put_data(clear, e_nonce, e_nonce_len);
2151
2152 #ifdef CONFIG_TESTING_OPTIONS
2153 skip_e_nonce:
2154 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2155 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2156 goto skip_config_obj;
2157 }
2158 #endif /* CONFIG_TESTING_OPTIONS */
2159
2160 if (conf) {
2161 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2162 wpabuf_put_le16(clear, wpabuf_len(conf));
2163 wpabuf_put_buf(clear, conf);
2164 }
2165 if (auth->peer_version >= 2 && conf2) {
2166 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2167 wpabuf_put_le16(clear, wpabuf_len(conf2));
2168 wpabuf_put_buf(clear, conf2);
2169 } else if (conf2) {
2170 wpa_printf(MSG_DEBUG,
2171 "DPP: Second Config Object available, but peer does not support more than one");
2172 }
2173 if (env_data) {
2174 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2175 wpabuf_put_le16(clear, wpabuf_len(env_data));
2176 wpabuf_put_buf(clear, env_data);
2177 }
2178
2179 if (auth->peer_version >= 2 && auth->send_conn_status &&
2180 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
2181 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2182 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2183 wpabuf_put_le16(clear, 0);
2184 }
2185
2186 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2187 auth->conf_sta->csrattrs) {
2188 auth->waiting_csr = true;
2189 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2190 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2191 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2192 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2193 }
2194
2195 #ifdef CONFIG_DPP3
2196 if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2197 auth->conf->net_access_key_curve) {
2198 u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2199
2200 /* Finite Cyclic Group attribute */
2201 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2202 ike_group);
2203 wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2204 wpabuf_put_le16(clear, 2);
2205 wpabuf_put_le16(clear, ike_group);
2206
2207 if (pc) {
2208 wpa_printf(MSG_DEBUG, "DPP: Pc");
2209 wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2210 wpabuf_put_le16(clear, wpabuf_len(pc));
2211 wpabuf_put_buf(clear, pc);
2212 }
2213 }
2214 #endif /* CONFIG_DPP3 */
2215
2216 #ifdef CONFIG_TESTING_OPTIONS
2217 skip_config_obj:
2218 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2219 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2220 goto skip_status;
2221 }
2222 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2223 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2224 status = 255;
2225 }
2226 #endif /* CONFIG_TESTING_OPTIONS */
2227
2228 /* DPP Status */
2229 dpp_build_attr_status(msg, status);
2230
2231 #ifdef CONFIG_TESTING_OPTIONS
2232 skip_status:
2233 #endif /* CONFIG_TESTING_OPTIONS */
2234
2235 addr[0] = wpabuf_head(msg);
2236 len[0] = wpabuf_len(msg);
2237 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2238
2239 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2240 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2241 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2242
2243 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2244 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2245 wpabuf_head(clear), wpabuf_len(clear),
2246 1, addr, len, wrapped) < 0)
2247 goto fail;
2248 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2249 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2250
2251 #ifdef CONFIG_TESTING_OPTIONS
2252 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2253 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2254 dpp_build_attr_status(msg, DPP_STATUS_OK);
2255 }
2256 skip_wrapped_data:
2257 #endif /* CONFIG_TESTING_OPTIONS */
2258
2259 wpa_hexdump_buf(MSG_DEBUG,
2260 "DPP: Configuration Response attributes", msg);
2261 out:
2262 wpabuf_clear_free(conf);
2263 wpabuf_clear_free(conf2);
2264 wpabuf_clear_free(env_data);
2265 wpabuf_clear_free(clear);
2266 wpabuf_free(pc);
2267
2268 return msg;
2269 fail:
2270 wpabuf_free(msg);
2271 msg = NULL;
2272 goto out;
2273 }
2274
2275
2276 struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication * auth,const u8 * attr_start,size_t attr_len)2277 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2278 size_t attr_len)
2279 {
2280 const u8 *wrapped_data, *e_nonce, *config_attr;
2281 u16 wrapped_data_len, e_nonce_len, config_attr_len;
2282 u8 *unwrapped = NULL;
2283 size_t unwrapped_len = 0;
2284 struct wpabuf *resp = NULL;
2285 struct json_token *root = NULL, *token;
2286 enum dpp_netrole netrole;
2287 struct wpabuf *cert_req = NULL;
2288 #ifdef CONFIG_DPP3
2289 const u8 *i_proto;
2290 u16 i_proto_len;
2291 #endif /* CONFIG_DPP3 */
2292
2293 #ifdef CONFIG_TESTING_OPTIONS
2294 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2295 wpa_printf(MSG_INFO,
2296 "DPP: TESTING - stop at Config Request");
2297 return NULL;
2298 }
2299 #endif /* CONFIG_TESTING_OPTIONS */
2300
2301 if (dpp_check_attrs(attr_start, attr_len) < 0) {
2302 dpp_auth_fail(auth, "Invalid attribute in config request");
2303 return NULL;
2304 }
2305
2306 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2307 &wrapped_data_len);
2308 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2309 dpp_auth_fail(auth,
2310 "Missing or invalid required Wrapped Data attribute");
2311 return NULL;
2312 }
2313
2314 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2315 wrapped_data, wrapped_data_len);
2316 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2317 unwrapped = os_malloc(unwrapped_len);
2318 if (!unwrapped)
2319 return NULL;
2320 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2321 wrapped_data, wrapped_data_len,
2322 0, NULL, NULL, unwrapped) < 0) {
2323 dpp_auth_fail(auth, "AES-SIV decryption failed");
2324 goto fail;
2325 }
2326 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2327 unwrapped, unwrapped_len);
2328
2329 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2330 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
2331 goto fail;
2332 }
2333
2334 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2335 DPP_ATTR_ENROLLEE_NONCE,
2336 &e_nonce_len);
2337 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
2338 dpp_auth_fail(auth,
2339 "Missing or invalid Enrollee Nonce attribute");
2340 goto fail;
2341 }
2342 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
2343 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
2344
2345 #ifdef CONFIG_DPP3
2346 i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2347 DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2348 if (i_proto && !auth->waiting_new_key) {
2349 dpp_auth_fail(auth,
2350 "Enrollee included a new protocol key even though one was not expected");
2351 goto fail;
2352 }
2353 if (i_proto) {
2354 struct crypto_ec_key *pe;
2355 u8 auth_i[DPP_MAX_HASH_LEN];
2356 const u8 *rx_auth_i;
2357 u16 rx_auth_i_len;
2358
2359 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2360 i_proto, i_proto_len);
2361
2362 pe = dpp_set_pubkey_point(auth->own_protocol_key,
2363 i_proto, i_proto_len);
2364 if (!pe) {
2365 dpp_auth_fail(auth,
2366 "Invalid Initiator Protocol Key (Pe)");
2367 goto fail;
2368 }
2369 dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2370 crypto_ec_key_deinit(auth->peer_protocol_key);
2371 auth->peer_protocol_key = pe;
2372 auth->new_key_received = true;
2373 auth->waiting_new_key = false;
2374
2375 if (dpp_derive_auth_i(auth, auth_i) < 0)
2376 goto fail;
2377
2378 rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2379 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2380 if (!rx_auth_i) {
2381 dpp_auth_fail(auth,
2382 "Missing Initiator Authentication Tag");
2383 goto fail;
2384 }
2385 if (rx_auth_i_len != auth->curve->hash_len ||
2386 os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2387 dpp_auth_fail(auth,
2388 "Mismatch in Initiator Authenticating Tag");
2389 wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2390 rx_auth_i, rx_auth_i_len);
2391 wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2392 auth_i, auth->curve->hash_len);
2393 goto fail;
2394 }
2395 }
2396 #endif /* CONFIG_DPP3 */
2397
2398 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2399 DPP_ATTR_CONFIG_ATTR_OBJ,
2400 &config_attr_len);
2401 if (!config_attr) {
2402 dpp_auth_fail(auth,
2403 "Missing or invalid Config Attributes attribute");
2404 goto fail;
2405 }
2406 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2407 config_attr, config_attr_len);
2408
2409 root = json_parse((const char *) config_attr, config_attr_len);
2410 if (!root) {
2411 dpp_auth_fail(auth, "Could not parse Config Attributes");
2412 goto fail;
2413 }
2414
2415 token = json_get_member(root, "name");
2416 if (!token || token->type != JSON_STRING) {
2417 dpp_auth_fail(auth, "No Config Attributes - name");
2418 goto fail;
2419 }
2420 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
2421 os_free(auth->e_name);
2422 auth->e_name = os_strdup(token->string);
2423
2424 token = json_get_member(root, "wi-fi_tech");
2425 if (!token || token->type != JSON_STRING) {
2426 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
2427 goto fail;
2428 }
2429 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2430 if (os_strcmp(token->string, "infra") != 0) {
2431 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2432 token->string);
2433 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
2434 goto fail;
2435 }
2436
2437 token = json_get_member(root, "netRole");
2438 if (!token || token->type != JSON_STRING) {
2439 dpp_auth_fail(auth, "No Config Attributes - netRole");
2440 goto fail;
2441 }
2442 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2443 if (os_strcmp(token->string, "sta") == 0) {
2444 netrole = DPP_NETROLE_STA;
2445 } else if (os_strcmp(token->string, "ap") == 0) {
2446 netrole = DPP_NETROLE_AP;
2447 } else if (os_strcmp(token->string, "configurator") == 0) {
2448 netrole = DPP_NETROLE_CONFIGURATOR;
2449 } else {
2450 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2451 token->string);
2452 dpp_auth_fail(auth, "Unsupported netRole");
2453 goto fail;
2454 }
2455 auth->e_netrole = netrole;
2456
2457 token = json_get_member(root, "mudurl");
2458 if (token && token->type == JSON_STRING) {
2459 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
2460 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2461 token->string);
2462 os_free(auth->e_mud_url);
2463 auth->e_mud_url = os_strdup(token->string);
2464 }
2465
2466 token = json_get_member(root, "bandSupport");
2467 auth->band_list_size = 0;
2468 if (token && token->type == JSON_ARRAY) {
2469 int *opclass = NULL;
2470 char txt[200], *pos, *end;
2471 int i, res;
2472
2473 memset(auth->band_list, 0, sizeof(auth->band_list));
2474 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2475 token = token->child;
2476 while (token) {
2477 if (token->type != JSON_NUMBER) {
2478 wpa_printf(MSG_DEBUG,
2479 "DPP: Invalid bandSupport array member type");
2480 } else {
2481 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2482 auth->band_list[auth->band_list_size++] = token->number;
2483 }
2484 wpa_printf(MSG_DEBUG,
2485 "DPP: Supported global operating class: %d",
2486 token->number);
2487 int_array_add_unique(&opclass, token->number);
2488 }
2489 token = token->sibling;
2490 }
2491
2492 txt[0] = '\0';
2493 pos = txt;
2494 end = txt + sizeof(txt);
2495 for (i = 0; opclass && opclass[i]; i++) {
2496 res = os_snprintf(pos, end - pos, "%s%d",
2497 pos == txt ? "" : ",", opclass[i]);
2498 if (os_snprintf_error(end - pos, res)) {
2499 *pos = '\0';
2500 break;
2501 }
2502 pos += res;
2503 }
2504 os_free(auth->e_band_support);
2505 auth->e_band_support = opclass;
2506 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2507 txt);
2508 }
2509
2510 #ifdef CONFIG_DPP2
2511 cert_req = json_get_member_base64(root, "pkcs10");
2512 if (cert_req) {
2513 char *txt;
2514 int id;
2515
2516 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2517 if (dpp_validate_csr(auth, cert_req) < 0) {
2518 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2519 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2520 goto cont;
2521 }
2522
2523 id = dpp_get_peer_bi_id(auth);
2524 if (id < 0)
2525 goto fail;
2526
2527 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2528 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2529 wpabuf_len(cert_req), NULL);
2530 if (!txt)
2531 goto fail;
2532
2533 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2534 id, txt);
2535 os_free(txt);
2536 auth->waiting_csr = false;
2537 auth->waiting_cert = true;
2538 goto fail;
2539 }
2540 cont:
2541 #endif /* CONFIG_DPP2 */
2542
2543 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2544 cert_req);
2545
2546 fail:
2547 wpabuf_free(cert_req);
2548 json_free(root);
2549 os_free(unwrapped);
2550 return resp;
2551 }
2552
2553
dpp_parse_cred_legacy(struct dpp_config_obj * conf,struct json_token * cred)2554 static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
2555 struct json_token *cred)
2556 {
2557 struct json_token *pass, *psk_hex;
2558
2559 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2560
2561 pass = json_get_member(cred, "pass");
2562 psk_hex = json_get_member(cred, "psk_hex");
2563
2564 if (pass && pass->type == JSON_STRING) {
2565 size_t len = os_strlen(pass->string);
2566
2567 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2568 pass->string, len);
2569 if (len < 8 || len > 63)
2570 return -1;
2571 os_strlcpy(conf->passphrase, pass->string,
2572 sizeof(conf->passphrase));
2573 } else if (psk_hex && psk_hex->type == JSON_STRING) {
2574 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
2575 wpa_printf(MSG_DEBUG,
2576 "DPP: Unexpected psk_hex with akm=sae");
2577 return -1;
2578 }
2579 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
2580 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
2581 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2582 return -1;
2583 }
2584 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
2585 conf->psk, PMK_LEN);
2586 conf->psk_set = 1;
2587 } else {
2588 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2589 return -1;
2590 }
2591
2592 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
2593 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2594 return -1;
2595 }
2596
2597 return 0;
2598 }
2599
2600
dpp_parse_jwk(struct json_token * jwk,const struct dpp_curve_params ** key_curve)2601 struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2602 const struct dpp_curve_params **key_curve)
2603 {
2604 struct json_token *token;
2605 const struct dpp_curve_params *curve;
2606 struct wpabuf *x = NULL, *y = NULL;
2607 struct crypto_ec_key *key = NULL;
2608
2609 token = json_get_member(jwk, "kty");
2610 if (!token || token->type != JSON_STRING) {
2611 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2612 goto fail;
2613 }
2614 if (os_strcmp(token->string, "EC") != 0) {
2615 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
2616 token->string);
2617 goto fail;
2618 }
2619
2620 token = json_get_member(jwk, "crv");
2621 if (!token || token->type != JSON_STRING) {
2622 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2623 goto fail;
2624 }
2625 curve = dpp_get_curve_jwk_crv(token->string);
2626 if (!curve) {
2627 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2628 token->string);
2629 goto fail;
2630 }
2631
2632 x = json_get_member_base64url(jwk, "x");
2633 if (!x) {
2634 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2635 goto fail;
2636 }
2637 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2638 if (wpabuf_len(x) != curve->prime_len) {
2639 wpa_printf(MSG_DEBUG,
2640 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2641 (unsigned int) wpabuf_len(x),
2642 (unsigned int) curve->prime_len, curve->name);
2643 goto fail;
2644 }
2645
2646 y = json_get_member_base64url(jwk, "y");
2647 if (!y) {
2648 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2649 goto fail;
2650 }
2651 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2652 if (wpabuf_len(y) != curve->prime_len) {
2653 wpa_printf(MSG_DEBUG,
2654 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2655 (unsigned int) wpabuf_len(y),
2656 (unsigned int) curve->prime_len, curve->name);
2657 goto fail;
2658 }
2659
2660 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2661 wpabuf_head(y), wpabuf_len(x));
2662 if (!key)
2663 goto fail;
2664
2665 *key_curve = curve;
2666
2667 fail:
2668 wpabuf_free(x);
2669 wpabuf_free(y);
2670
2671 return key;
2672 }
2673
2674
dpp_key_expired(const char * timestamp,os_time_t * expiry)2675 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2676 {
2677 struct os_time now;
2678 unsigned int year, month, day, hour, min, sec;
2679 os_time_t utime;
2680 const char *pos;
2681
2682 /* ISO 8601 date and time:
2683 * <date>T<time>
2684 * YYYY-MM-DDTHH:MM:SSZ
2685 * YYYY-MM-DDTHH:MM:SS+03:00
2686 */
2687 if (os_strlen(timestamp) < 19) {
2688 wpa_printf(MSG_DEBUG,
2689 "DPP: Too short timestamp - assume expired key");
2690 return 1;
2691 }
2692 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2693 &year, &month, &day, &hour, &min, &sec) != 6) {
2694 wpa_printf(MSG_DEBUG,
2695 "DPP: Failed to parse expiration day - assume expired key");
2696 return 1;
2697 }
2698
2699 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2700 wpa_printf(MSG_DEBUG,
2701 "DPP: Invalid date/time information - assume expired key");
2702 return 1;
2703 }
2704
2705 pos = timestamp + 19;
2706 if (*pos == 'Z' || *pos == '\0') {
2707 /* In UTC - no need to adjust */
2708 } else if (*pos == '-' || *pos == '+') {
2709 int items;
2710
2711 /* Adjust local time to UTC */
2712 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2713 if (items < 1) {
2714 wpa_printf(MSG_DEBUG,
2715 "DPP: Invalid time zone designator (%s) - assume expired key",
2716 pos);
2717 return 1;
2718 }
2719 if (*pos == '-')
2720 utime += 3600 * hour;
2721 if (*pos == '+')
2722 utime -= 3600 * hour;
2723 if (items > 1) {
2724 if (*pos == '-')
2725 utime += 60 * min;
2726 if (*pos == '+')
2727 utime -= 60 * min;
2728 }
2729 } else {
2730 wpa_printf(MSG_DEBUG,
2731 "DPP: Invalid time zone designator (%s) - assume expired key",
2732 pos);
2733 return 1;
2734 }
2735 if (expiry)
2736 *expiry = utime;
2737
2738 if (os_get_time(&now) < 0) {
2739 wpa_printf(MSG_DEBUG,
2740 "DPP: Cannot get current time - assume expired key");
2741 return 1;
2742 }
2743
2744 if (now.sec > utime) {
2745 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2746 utime, now.sec);
2747 return 1;
2748 }
2749
2750 return 0;
2751 }
2752
2753
dpp_parse_connector(struct dpp_authentication * auth,struct dpp_config_obj * conf,const unsigned char * payload,u16 payload_len)2754 static int dpp_parse_connector(struct dpp_authentication *auth,
2755 struct dpp_config_obj *conf,
2756 const unsigned char *payload,
2757 u16 payload_len)
2758 {
2759 struct json_token *root, *groups, *netkey, *token;
2760 int ret = -1;
2761 struct crypto_ec_key *key = NULL;
2762 const struct dpp_curve_params *curve;
2763 unsigned int rules = 0;
2764
2765 root = json_parse((const char *) payload, payload_len);
2766 if (!root) {
2767 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2768 goto fail;
2769 }
2770
2771 groups = json_get_member(root, "groups");
2772 if (!groups || groups->type != JSON_ARRAY) {
2773 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2774 goto skip_groups;
2775 }
2776 for (token = groups->child; token; token = token->sibling) {
2777 struct json_token *id, *role;
2778
2779 id = json_get_member(token, "groupId");
2780 if (!id || id->type != JSON_STRING) {
2781 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2782 goto fail;
2783 }
2784
2785 role = json_get_member(token, "netRole");
2786 if (!role || role->type != JSON_STRING) {
2787 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2788 goto fail;
2789 }
2790 wpa_printf(MSG_DEBUG,
2791 "DPP: connector group: groupId='%s' netRole='%s'",
2792 id->string, role->string);
2793 rules++;
2794 }
2795 skip_groups:
2796
2797 if (!rules) {
2798 wpa_printf(MSG_DEBUG,
2799 "DPP: Connector includes no groups");
2800 goto fail;
2801 }
2802
2803 token = json_get_member(root, "expiry");
2804 if (!token || token->type != JSON_STRING) {
2805 wpa_printf(MSG_DEBUG,
2806 "DPP: No expiry string found - connector does not expire");
2807 } else {
2808 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2809 if (dpp_key_expired(token->string,
2810 &auth->net_access_key_expiry)) {
2811 wpa_printf(MSG_DEBUG,
2812 "DPP: Connector (netAccessKey) has expired");
2813 goto fail;
2814 }
2815 }
2816
2817 netkey = json_get_member(root, "netAccessKey");
2818 if (!netkey || netkey->type != JSON_OBJECT) {
2819 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2820 goto fail;
2821 }
2822
2823 key = dpp_parse_jwk(netkey, &curve);
2824 if (!key)
2825 goto fail;
2826 dpp_debug_print_key("DPP: Received netAccessKey", key);
2827
2828 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
2829 wpa_printf(MSG_DEBUG,
2830 "DPP: netAccessKey in connector does not match own protocol key");
2831 #ifdef CONFIG_TESTING_OPTIONS
2832 if (auth->ignore_netaccesskey_mismatch) {
2833 wpa_printf(MSG_DEBUG,
2834 "DPP: TESTING - skip netAccessKey mismatch");
2835 } else {
2836 goto fail;
2837 }
2838 #else /* CONFIG_TESTING_OPTIONS */
2839 goto fail;
2840 #endif /* CONFIG_TESTING_OPTIONS */
2841 }
2842
2843 ret = 0;
2844 fail:
2845 crypto_ec_key_deinit(key);
2846 json_free(root);
2847 return ret;
2848 }
2849
2850
dpp_copy_csign(struct dpp_config_obj * conf,struct crypto_ec_key * csign)2851 static void dpp_copy_csign(struct dpp_config_obj *conf,
2852 struct crypto_ec_key *csign)
2853 {
2854 struct wpabuf *c_sign_key;
2855
2856 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2857 if (!c_sign_key)
2858 return;
2859
2860 wpabuf_free(conf->c_sign_key);
2861 conf->c_sign_key = c_sign_key;
2862 }
2863
2864
dpp_copy_ppkey(struct dpp_config_obj * conf,struct crypto_ec_key * ppkey)2865 static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2866 struct crypto_ec_key *ppkey)
2867 {
2868 struct wpabuf *pp_key;
2869
2870 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2871 if (!pp_key)
2872 return;
2873
2874 wpabuf_free(conf->pp_key);
2875 conf->pp_key = pp_key;
2876 }
2877
2878
dpp_copy_netaccesskey(struct dpp_authentication * auth,struct dpp_config_obj * conf)2879 static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2880 struct dpp_config_obj *conf)
2881 {
2882 struct wpabuf *net_access_key;
2883 struct crypto_ec_key *own_key;
2884
2885 own_key = auth->own_protocol_key;
2886 #ifdef CONFIG_DPP2
2887 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2888 auth->reconfig_old_protocol_key)
2889 own_key = auth->reconfig_old_protocol_key;
2890 #endif /* CONFIG_DPP2 */
2891
2892 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2893 if (!net_access_key)
2894 return;
2895
2896 wpabuf_free(auth->net_access_key);
2897 auth->net_access_key = net_access_key;
2898 }
2899
2900
dpp_parse_cred_dpp(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)2901 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
2902 struct dpp_config_obj *conf,
2903 struct json_token *cred)
2904 {
2905 struct dpp_signed_connector_info info;
2906 struct json_token *token, *csign, *ppkey;
2907 int ret = -1;
2908 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
2909 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
2910 const char *signed_connector;
2911
2912 os_memset(&info, 0, sizeof(info));
2913
2914 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
2915 wpa_printf(MSG_DEBUG,
2916 "DPP: Legacy credential included in Connector credential");
2917 if (dpp_parse_cred_legacy(conf, cred) < 0)
2918 return -1;
2919 }
2920
2921 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2922
2923 csign = json_get_member(cred, "csign");
2924 if (!csign || csign->type != JSON_OBJECT) {
2925 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2926 goto fail;
2927 }
2928
2929 csign_pub = dpp_parse_jwk(csign, &key_curve);
2930 if (!csign_pub) {
2931 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
2932 goto fail;
2933 }
2934 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
2935
2936 ppkey = json_get_member(cred, "ppKey");
2937 if (ppkey && ppkey->type == JSON_OBJECT) {
2938 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2939 if (!pp_pub) {
2940 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2941 goto fail;
2942 }
2943 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2944 if (key_curve != pp_curve) {
2945 wpa_printf(MSG_DEBUG,
2946 "DPP: C-sign-key and ppKey do not use the same curve");
2947 goto fail;
2948 }
2949 }
2950
2951 token = json_get_member(cred, "signedConnector");
2952 if (!token || token->type != JSON_STRING) {
2953 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
2954 goto fail;
2955 }
2956 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
2957 token->string, os_strlen(token->string));
2958 signed_connector = token->string;
2959
2960 if (os_strchr(signed_connector, '"') ||
2961 os_strchr(signed_connector, '\n')) {
2962 wpa_printf(MSG_DEBUG,
2963 "DPP: Unexpected character in signedConnector");
2964 goto fail;
2965 }
2966
2967 if (dpp_process_signed_connector(&info, csign_pub,
2968 signed_connector) != DPP_STATUS_OK)
2969 goto fail;
2970
2971 if (dpp_parse_connector(auth, conf,
2972 info.payload, info.payload_len) < 0) {
2973 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
2974 goto fail;
2975 }
2976
2977 os_free(conf->connector);
2978 conf->connector = os_strdup(signed_connector);
2979
2980 dpp_copy_csign(conf, csign_pub);
2981 if (pp_pub)
2982 dpp_copy_ppkey(conf, pp_pub);
2983 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
2984 dpp_copy_netaccesskey(auth, conf);
2985
2986 ret = 0;
2987 fail:
2988 crypto_ec_key_deinit(csign_pub);
2989 crypto_ec_key_deinit(pp_pub);
2990 os_free(info.payload);
2991 return ret;
2992 }
2993
2994
2995 #ifdef CONFIG_DPP2
dpp_parse_cred_dot1x(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)2996 static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2997 struct dpp_config_obj *conf,
2998 struct json_token *cred)
2999 {
3000 struct json_token *ent, *name;
3001
3002 ent = json_get_member(cred, "entCreds");
3003 if (!ent || ent->type != JSON_OBJECT) {
3004 dpp_auth_fail(auth, "No entCreds in JSON");
3005 return -1;
3006 }
3007
3008 conf->certbag = json_get_member_base64(ent, "certBag");
3009 if (!conf->certbag) {
3010 dpp_auth_fail(auth, "No certBag in JSON");
3011 return -1;
3012 }
3013 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
3014 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
3015 if (!conf->certs) {
3016 dpp_auth_fail(auth, "No certificates in certBag");
3017 return -1;
3018 }
3019
3020 conf->cacert = json_get_member_base64(ent, "caCert");
3021 if (conf->cacert)
3022 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3023 conf->cacert);
3024
3025 name = json_get_member(ent, "trustedEapServerName");
3026 if (name &&
3027 (name->type != JSON_STRING ||
3028 has_ctrl_char((const u8 *) name->string,
3029 os_strlen(name->string)))) {
3030 dpp_auth_fail(auth,
3031 "Invalid trustedEapServerName type in JSON");
3032 return -1;
3033 }
3034 if (name && name->string) {
3035 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3036 name->string);
3037 conf->server_name = os_strdup(name->string);
3038 if (!conf->server_name)
3039 return -1;
3040 }
3041
3042 return 0;
3043 }
3044 #endif /* CONFIG_DPP2 */
3045
3046
dpp_akm_str(enum dpp_akm akm)3047 const char * dpp_akm_str(enum dpp_akm akm)
3048 {
3049 switch (akm) {
3050 case DPP_AKM_DPP:
3051 return "dpp";
3052 case DPP_AKM_PSK:
3053 return "psk";
3054 case DPP_AKM_SAE:
3055 return "sae";
3056 case DPP_AKM_PSK_SAE:
3057 return "psk+sae";
3058 case DPP_AKM_SAE_DPP:
3059 return "dpp+sae";
3060 case DPP_AKM_PSK_SAE_DPP:
3061 return "dpp+psk+sae";
3062 case DPP_AKM_DOT1X:
3063 return "dot1x";
3064 default:
3065 return "??";
3066 }
3067 }
3068
3069
dpp_akm_selector_str(enum dpp_akm akm)3070 const char * dpp_akm_selector_str(enum dpp_akm akm)
3071 {
3072 switch (akm) {
3073 case DPP_AKM_DPP:
3074 return "506F9A02";
3075 case DPP_AKM_PSK:
3076 return "000FAC02+000FAC06";
3077 case DPP_AKM_SAE:
3078 return "000FAC08";
3079 case DPP_AKM_PSK_SAE:
3080 return "000FAC02+000FAC06+000FAC08";
3081 case DPP_AKM_SAE_DPP:
3082 return "506F9A02+000FAC08";
3083 case DPP_AKM_PSK_SAE_DPP:
3084 return "506F9A02+000FAC08+000FAC02+000FAC06";
3085 case DPP_AKM_DOT1X:
3086 return "000FAC01+000FAC05";
3087 default:
3088 return "??";
3089 }
3090 }
3091
3092
dpp_akm_from_str(const char * akm)3093 static enum dpp_akm dpp_akm_from_str(const char *akm)
3094 {
3095 const char *pos;
3096 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
3097
3098 if (os_strcmp(akm, "psk") == 0)
3099 return DPP_AKM_PSK;
3100 if (os_strcmp(akm, "sae") == 0)
3101 return DPP_AKM_SAE;
3102 if (os_strcmp(akm, "psk+sae") == 0)
3103 return DPP_AKM_PSK_SAE;
3104 if (os_strcmp(akm, "dpp") == 0)
3105 return DPP_AKM_DPP;
3106 if (os_strcmp(akm, "dpp+sae") == 0)
3107 return DPP_AKM_SAE_DPP;
3108 if (os_strcmp(akm, "dpp+psk+sae") == 0)
3109 return DPP_AKM_PSK_SAE_DPP;
3110 if (os_strcmp(akm, "dot1x") == 0)
3111 return DPP_AKM_DOT1X;
3112
3113 pos = akm;
3114 while (*pos) {
3115 if (os_strlen(pos) < 8)
3116 break;
3117 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3118 dpp = 1;
3119 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3120 psk = 1;
3121 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3122 psk = 1;
3123 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3124 sae = 1;
3125 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3126 dot1x = 1;
3127 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3128 dot1x = 1;
3129 pos += 8;
3130 if (*pos != '+')
3131 break;
3132 pos++;
3133 }
3134
3135 if (dpp && psk && sae)
3136 return DPP_AKM_PSK_SAE_DPP;
3137 if (dpp && sae)
3138 return DPP_AKM_SAE_DPP;
3139 if (dpp)
3140 return DPP_AKM_DPP;
3141 if (psk && sae)
3142 return DPP_AKM_PSK_SAE;
3143 if (sae)
3144 return DPP_AKM_SAE;
3145 if (psk)
3146 return DPP_AKM_PSK;
3147 if (dot1x)
3148 return DPP_AKM_DOT1X;
3149
3150 return DPP_AKM_UNKNOWN;
3151 }
3152
3153
dpp_parse_conf_obj(struct dpp_authentication * auth,const u8 * conf_obj,u16 conf_obj_len)3154 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3155 const u8 *conf_obj, u16 conf_obj_len)
3156 {
3157 int ret = -1;
3158 struct json_token *root, *token, *discovery, *cred;
3159 struct dpp_config_obj *conf;
3160 struct wpabuf *ssid64 = NULL;
3161 int legacy;
3162
3163 root = json_parse((const char *) conf_obj, conf_obj_len);
3164 if (!root)
3165 return -1;
3166 if (root->type != JSON_OBJECT) {
3167 dpp_auth_fail(auth, "JSON root is not an object");
3168 goto fail;
3169 }
3170
3171 token = json_get_member(root, "wi-fi_tech");
3172 if (!token || token->type != JSON_STRING) {
3173 dpp_auth_fail(auth, "No wi-fi_tech string value found");
3174 goto fail;
3175 }
3176 if (os_strcmp(token->string, "infra") != 0) {
3177 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3178 token->string);
3179 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
3180 goto fail;
3181 }
3182
3183 discovery = json_get_member(root, "discovery");
3184 if (!discovery || discovery->type != JSON_OBJECT) {
3185 dpp_auth_fail(auth, "No discovery object in JSON");
3186 goto fail;
3187 }
3188
3189 ssid64 = json_get_member_base64url(discovery, "ssid64");
3190 if (ssid64) {
3191 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3192 wpabuf_head(ssid64), wpabuf_len(ssid64));
3193 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3194 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3195 goto fail;
3196 }
3197 } else {
3198 token = json_get_member(discovery, "ssid");
3199 if (!token || token->type != JSON_STRING) {
3200 dpp_auth_fail(auth,
3201 "No discovery::ssid string value found");
3202 goto fail;
3203 }
3204 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3205 token->string, os_strlen(token->string));
3206 if (os_strlen(token->string) > SSID_MAX_LEN) {
3207 dpp_auth_fail(auth,
3208 "Too long discovery::ssid string value");
3209 goto fail;
3210 }
3211 }
3212
3213 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3214 wpa_printf(MSG_DEBUG,
3215 "DPP: No room for this many Config Objects - ignore this one");
3216 ret = 0;
3217 goto fail;
3218 }
3219 conf = &auth->conf_obj[auth->num_conf_obj++];
3220
3221 if (ssid64) {
3222 conf->ssid_len = wpabuf_len(ssid64);
3223 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3224 } else {
3225 conf->ssid_len = os_strlen(token->string);
3226 os_memcpy(conf->ssid, token->string, conf->ssid_len);
3227 }
3228
3229 token = json_get_member(discovery, "ssid_charset");
3230 if (token && token->type == JSON_NUMBER) {
3231 conf->ssid_charset = token->number;
3232 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3233 conf->ssid_charset);
3234 }
3235
3236 cred = json_get_member(root, "cred");
3237 if (!cred || cred->type != JSON_OBJECT) {
3238 dpp_auth_fail(auth, "No cred object in JSON");
3239 goto fail;
3240 }
3241
3242 token = json_get_member(cred, "akm");
3243 if (!token || token->type != JSON_STRING) {
3244 dpp_auth_fail(auth, "No cred::akm string value found");
3245 goto fail;
3246 }
3247 conf->akm = dpp_akm_from_str(token->string);
3248
3249 legacy = dpp_akm_legacy(conf->akm);
3250 if (legacy && auth->peer_version >= 2) {
3251 struct json_token *csign, *s_conn;
3252
3253 csign = json_get_member(cred, "csign");
3254 s_conn = json_get_member(cred, "signedConnector");
3255 if (csign && csign->type == JSON_OBJECT &&
3256 s_conn && s_conn->type == JSON_STRING)
3257 legacy = 0;
3258 }
3259 if (legacy) {
3260 if (dpp_parse_cred_legacy(conf, cred) < 0)
3261 goto fail;
3262 } else if (dpp_akm_dpp(conf->akm) ||
3263 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
3264 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
3265 goto fail;
3266 #ifdef CONFIG_DPP2
3267 } else if (conf->akm == DPP_AKM_DOT1X) {
3268 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3269 dpp_parse_cred_dpp(auth, conf, cred) < 0)
3270 goto fail;
3271 #endif /* CONFIG_DPP2 */
3272 } else {
3273 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3274 token->string);
3275 dpp_auth_fail(auth, "Unsupported akm");
3276 goto fail;
3277 }
3278
3279 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3280 ret = 0;
3281 fail:
3282 wpabuf_free(ssid64);
3283 json_free(root);
3284 return ret;
3285 }
3286
3287
3288 #ifdef CONFIG_DPP2
dpp_get_csr_attrs(const u8 * attrs,size_t attrs_len,size_t * len)3289 static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3290 {
3291 const u8 *b64;
3292 u16 b64_len;
3293
3294 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3295 if (!b64)
3296 return NULL;
3297 return base64_decode((const char *) b64, b64_len, len);
3298 }
3299 #endif /* CONFIG_DPP2 */
3300
3301
dpp_conf_resp_rx(struct dpp_authentication * auth,const struct wpabuf * resp)3302 int dpp_conf_resp_rx(struct dpp_authentication *auth,
3303 const struct wpabuf *resp)
3304 {
3305 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3306 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
3307 const u8 *env_data;
3308 u16 env_data_len;
3309 const u8 *addr[1];
3310 size_t len[1];
3311 u8 *unwrapped = NULL;
3312 size_t unwrapped_len = 0;
3313 int ret = -1;
3314
3315 auth->conf_resp_status = 255;
3316
3317 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
3318 dpp_auth_fail(auth, "Invalid attribute in config response");
3319 return -1;
3320 }
3321
3322 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3323 DPP_ATTR_WRAPPED_DATA,
3324 &wrapped_data_len);
3325 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3326 dpp_auth_fail(auth,
3327 "Missing or invalid required Wrapped Data attribute");
3328 return -1;
3329 }
3330
3331 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3332 wrapped_data, wrapped_data_len);
3333 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3334 unwrapped = os_malloc(unwrapped_len);
3335 if (!unwrapped)
3336 return -1;
3337
3338 addr[0] = wpabuf_head(resp);
3339 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3340 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3341
3342 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3343 wrapped_data, wrapped_data_len,
3344 1, addr, len, unwrapped) < 0) {
3345 dpp_auth_fail(auth, "AES-SIV decryption failed");
3346 goto fail;
3347 }
3348 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3349 unwrapped, unwrapped_len);
3350
3351 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3352 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3353 goto fail;
3354 }
3355
3356 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3357 DPP_ATTR_ENROLLEE_NONCE,
3358 &e_nonce_len);
3359 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3360 dpp_auth_fail(auth,
3361 "Missing or invalid Enrollee Nonce attribute");
3362 goto fail;
3363 }
3364 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3365 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3366 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3367 goto fail;
3368 }
3369
3370 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3371 DPP_ATTR_STATUS, &status_len);
3372 if (!status || status_len < 1) {
3373 dpp_auth_fail(auth,
3374 "Missing or invalid required DPP Status attribute");
3375 goto fail;
3376 }
3377 auth->conf_resp_status = status[0];
3378 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3379 #ifdef CONFIG_DPP2
3380 if (status[0] == DPP_STATUS_CSR_NEEDED) {
3381 u8 *csrattrs;
3382 size_t csrattrs_len;
3383
3384 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3385
3386 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3387 &csrattrs_len);
3388 if (!csrattrs) {
3389 dpp_auth_fail(auth,
3390 "Missing or invalid CSR Attributes Request attribute");
3391 goto fail;
3392 }
3393 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3394 os_free(auth->csrattrs);
3395 auth->csrattrs = csrattrs;
3396 auth->csrattrs_len = csrattrs_len;
3397 ret = -2;
3398 goto fail;
3399 }
3400 #endif /* CONFIG_DPP2 */
3401 #ifdef CONFIG_DPP3
3402 if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3403 const u8 *fcgroup, *r_proto;
3404 u16 fcgroup_len, r_proto_len;
3405 u16 group;
3406 const struct dpp_curve_params *curve;
3407 struct crypto_ec_key *new_pe;
3408 struct crypto_ec_key *pc;
3409
3410 fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3411 DPP_ATTR_FINITE_CYCLIC_GROUP,
3412 &fcgroup_len);
3413 if (!fcgroup || fcgroup_len != 2) {
3414 dpp_auth_fail(auth,
3415 "Missing or invalid required Finite Cyclic Group attribute");
3416 goto fail;
3417 }
3418 group = WPA_GET_LE16(fcgroup);
3419
3420 wpa_printf(MSG_DEBUG,
3421 "DPP: Configurator requested a new protocol key from group %u",
3422 group);
3423 curve = dpp_get_curve_ike_group(group);
3424 if (!curve) {
3425 dpp_auth_fail(auth,
3426 "Unsupported group for new protocol key");
3427 goto fail;
3428 }
3429
3430 new_pe = dpp_gen_keypair(curve);
3431 if (!new_pe) {
3432 dpp_auth_fail(auth,
3433 "Failed to generate a new protocol key");
3434 goto fail;
3435 }
3436
3437 crypto_ec_key_deinit(auth->own_protocol_key);
3438 auth->own_protocol_key = new_pe;
3439 auth->new_curve = curve;
3440
3441 r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3442 DPP_ATTR_R_PROTOCOL_KEY,
3443 &r_proto_len);
3444 if (!r_proto) {
3445 dpp_auth_fail(auth,
3446 "Missing required Responder Protocol Key attribute (Pc)");
3447 goto fail;
3448 }
3449 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3450 r_proto, r_proto_len);
3451
3452 pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3453 if (!pc) {
3454 dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3455 goto fail;
3456 }
3457 dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3458
3459 crypto_ec_key_deinit(auth->peer_protocol_key);
3460 auth->peer_protocol_key = pc;
3461
3462 auth->waiting_new_key = true;
3463 ret = -3;
3464 goto fail;
3465 }
3466 #endif /* CONFIG_DPP3 */
3467 if (status[0] != DPP_STATUS_OK) {
3468 dpp_auth_fail(auth, "Configurator rejected configuration");
3469 goto fail;
3470 }
3471
3472 env_data = dpp_get_attr(unwrapped, unwrapped_len,
3473 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3474 #ifdef CONFIG_DPP2
3475 if (env_data &&
3476 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3477 goto fail;
3478 #endif /* CONFIG_DPP2 */
3479
3480 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3481 &conf_obj_len);
3482 if (!conf_obj && !env_data) {
3483 dpp_auth_fail(auth,
3484 "Missing required Configuration Object attribute");
3485 goto fail;
3486 }
3487 while (conf_obj) {
3488 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3489 conf_obj, conf_obj_len);
3490 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3491 goto fail;
3492 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3493 DPP_ATTR_CONFIG_OBJ,
3494 &conf_obj_len);
3495 }
3496
3497 #ifdef CONFIG_DPP2
3498 status = dpp_get_attr(unwrapped, unwrapped_len,
3499 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3500 if (status) {
3501 wpa_printf(MSG_DEBUG,
3502 "DPP: Configurator requested connection status result");
3503 auth->conn_status_requested = 1;
3504 }
3505 #endif /* CONFIG_DPP2 */
3506
3507 ret = 0;
3508
3509 fail:
3510 os_free(unwrapped);
3511 return ret;
3512 }
3513
3514
3515 #ifdef CONFIG_DPP2
3516
dpp_conf_result_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)3517 enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3518 const u8 *hdr,
3519 const u8 *attr_start, size_t attr_len)
3520 {
3521 const u8 *wrapped_data, *status, *e_nonce;
3522 u16 wrapped_data_len, status_len, e_nonce_len;
3523 const u8 *addr[2];
3524 size_t len[2];
3525 u8 *unwrapped = NULL;
3526 size_t unwrapped_len = 0;
3527 enum dpp_status_error ret = 256;
3528
3529 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3530 &wrapped_data_len);
3531 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3532 dpp_auth_fail(auth,
3533 "Missing or invalid required Wrapped Data attribute");
3534 goto fail;
3535 }
3536 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3537 wrapped_data, wrapped_data_len);
3538
3539 attr_len = wrapped_data - 4 - attr_start;
3540
3541 addr[0] = hdr;
3542 len[0] = DPP_HDR_LEN;
3543 addr[1] = attr_start;
3544 len[1] = attr_len;
3545 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3546 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3547 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3548 wrapped_data, wrapped_data_len);
3549 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3550 unwrapped = os_malloc(unwrapped_len);
3551 if (!unwrapped)
3552 goto fail;
3553 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3554 wrapped_data, wrapped_data_len,
3555 2, addr, len, unwrapped) < 0) {
3556 dpp_auth_fail(auth, "AES-SIV decryption failed");
3557 goto fail;
3558 }
3559 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3560 unwrapped, unwrapped_len);
3561
3562 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3563 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3564 goto fail;
3565 }
3566
3567 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3568 DPP_ATTR_ENROLLEE_NONCE,
3569 &e_nonce_len);
3570 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3571 dpp_auth_fail(auth,
3572 "Missing or invalid Enrollee Nonce attribute");
3573 goto fail;
3574 }
3575 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3576 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3577 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3578 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3579 auth->e_nonce, e_nonce_len);
3580 goto fail;
3581 }
3582
3583 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3584 &status_len);
3585 if (!status || status_len < 1) {
3586 dpp_auth_fail(auth,
3587 "Missing or invalid required DPP Status attribute");
3588 goto fail;
3589 }
3590 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3591 ret = status[0];
3592
3593 fail:
3594 bin_clear_free(unwrapped, unwrapped_len);
3595 return ret;
3596 }
3597
3598
dpp_build_conf_result(struct dpp_authentication * auth,enum dpp_status_error status)3599 struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3600 enum dpp_status_error status)
3601 {
3602 struct wpabuf *msg, *clear;
3603 size_t nonce_len, clear_len, attr_len;
3604 const u8 *addr[2];
3605 size_t len[2];
3606 u8 *wrapped;
3607
3608 nonce_len = auth->curve->nonce_len;
3609 clear_len = 5 + 4 + nonce_len;
3610 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3611 clear = wpabuf_alloc(clear_len);
3612 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3613 if (!clear || !msg)
3614 goto fail;
3615
3616 /* DPP Status */
3617 dpp_build_attr_status(clear, status);
3618
3619 /* E-nonce */
3620 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3621 wpabuf_put_le16(clear, nonce_len);
3622 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3623
3624 /* OUI, OUI type, Crypto Suite, DPP frame type */
3625 addr[0] = wpabuf_head_u8(msg) + 2;
3626 len[0] = 3 + 1 + 1 + 1;
3627 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3628
3629 /* Attributes before Wrapped Data (none) */
3630 addr[1] = wpabuf_put(msg, 0);
3631 len[1] = 0;
3632 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3633
3634 /* Wrapped Data */
3635 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3636 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3637 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3638
3639 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3640 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3641 wpabuf_head(clear), wpabuf_len(clear),
3642 2, addr, len, wrapped) < 0)
3643 goto fail;
3644
3645 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3646 wpabuf_free(clear);
3647 return msg;
3648 fail:
3649 wpabuf_free(clear);
3650 wpabuf_free(msg);
3651 return NULL;
3652 }
3653
3654
valid_channel_list(const char * val)3655 static int valid_channel_list(const char *val)
3656 {
3657 while (*val) {
3658 if (!((*val >= '0' && *val <= '9') ||
3659 *val == '/' || *val == ','))
3660 return 0;
3661 val++;
3662 }
3663
3664 return 1;
3665 }
3666
3667
dpp_conn_status_result_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,u8 * ssid,size_t * ssid_len,char ** channel_list)3668 enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3669 const u8 *hdr,
3670 const u8 *attr_start,
3671 size_t attr_len,
3672 u8 *ssid, size_t *ssid_len,
3673 char **channel_list)
3674 {
3675 const u8 *wrapped_data, *status, *e_nonce;
3676 u16 wrapped_data_len, status_len, e_nonce_len;
3677 const u8 *addr[2];
3678 size_t len[2];
3679 u8 *unwrapped = NULL;
3680 size_t unwrapped_len = 0;
3681 enum dpp_status_error ret = 256;
3682 struct json_token *root = NULL, *token;
3683 struct wpabuf *ssid64;
3684
3685 *ssid_len = 0;
3686 *channel_list = NULL;
3687
3688 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3689 &wrapped_data_len);
3690 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3691 dpp_auth_fail(auth,
3692 "Missing or invalid required Wrapped Data attribute");
3693 goto fail;
3694 }
3695 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3696 wrapped_data, wrapped_data_len);
3697
3698 attr_len = wrapped_data - 4 - attr_start;
3699
3700 addr[0] = hdr;
3701 len[0] = DPP_HDR_LEN;
3702 addr[1] = attr_start;
3703 len[1] = attr_len;
3704 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3705 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3706 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3707 wrapped_data, wrapped_data_len);
3708 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3709 unwrapped = os_malloc(unwrapped_len);
3710 if (!unwrapped)
3711 goto fail;
3712 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3713 wrapped_data, wrapped_data_len,
3714 2, addr, len, unwrapped) < 0) {
3715 dpp_auth_fail(auth, "AES-SIV decryption failed");
3716 goto fail;
3717 }
3718 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3719 unwrapped, unwrapped_len);
3720
3721 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3722 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3723 goto fail;
3724 }
3725
3726 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3727 DPP_ATTR_ENROLLEE_NONCE,
3728 &e_nonce_len);
3729 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3730 dpp_auth_fail(auth,
3731 "Missing or invalid Enrollee Nonce attribute");
3732 goto fail;
3733 }
3734 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3735 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3736 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3737 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3738 auth->e_nonce, e_nonce_len);
3739 goto fail;
3740 }
3741
3742 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3743 &status_len);
3744 if (!status) {
3745 dpp_auth_fail(auth,
3746 "Missing required DPP Connection Status attribute");
3747 goto fail;
3748 }
3749 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3750 status, status_len);
3751
3752 root = json_parse((const char *) status, status_len);
3753 if (!root) {
3754 dpp_auth_fail(auth, "Could not parse connStatus");
3755 goto fail;
3756 }
3757
3758 ssid64 = json_get_member_base64url(root, "ssid64");
3759 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3760 *ssid_len = wpabuf_len(ssid64);
3761 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
3762 }
3763 wpabuf_free(ssid64);
3764
3765 token = json_get_member(root, "channelList");
3766 if (token && token->type == JSON_STRING &&
3767 valid_channel_list(token->string))
3768 *channel_list = os_strdup(token->string);
3769
3770 token = json_get_member(root, "result");
3771 if (!token || token->type != JSON_NUMBER) {
3772 dpp_auth_fail(auth, "No connStatus - result");
3773 goto fail;
3774 }
3775 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3776 ret = token->number;
3777
3778 fail:
3779 json_free(root);
3780 bin_clear_free(unwrapped, unwrapped_len);
3781 return ret;
3782 }
3783
3784
dpp_build_conn_status(enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)3785 struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3786 const u8 *ssid, size_t ssid_len,
3787 const char *channel_list)
3788 {
3789 struct wpabuf *json;
3790
3791 json = wpabuf_alloc(1000);
3792 if (!json)
3793 return NULL;
3794 json_start_object(json, NULL);
3795 json_add_int(json, "result", result);
3796 if (ssid) {
3797 json_value_sep(json);
3798 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3799 wpabuf_free(json);
3800 return NULL;
3801 }
3802 }
3803 if (channel_list) {
3804 json_value_sep(json);
3805 json_add_string(json, "channelList", channel_list);
3806 }
3807 json_end_object(json);
3808 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3809 wpabuf_head(json), wpabuf_len(json));
3810
3811 return json;
3812 }
3813
3814
dpp_build_conn_status_result(struct dpp_authentication * auth,enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)3815 struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3816 enum dpp_status_error result,
3817 const u8 *ssid, size_t ssid_len,
3818 const char *channel_list)
3819 {
3820 struct wpabuf *msg = NULL, *clear = NULL, *json;
3821 size_t nonce_len, clear_len, attr_len;
3822 const u8 *addr[2];
3823 size_t len[2];
3824 u8 *wrapped;
3825
3826 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
3827 if (!json)
3828 return NULL;
3829
3830 nonce_len = auth->curve->nonce_len;
3831 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3832 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3833 clear = wpabuf_alloc(clear_len);
3834 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3835 if (!clear || !msg)
3836 goto fail;
3837
3838 /* E-nonce */
3839 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3840 wpabuf_put_le16(clear, nonce_len);
3841 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3842
3843 /* DPP Connection Status */
3844 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3845 wpabuf_put_le16(clear, wpabuf_len(json));
3846 wpabuf_put_buf(clear, json);
3847
3848 /* OUI, OUI type, Crypto Suite, DPP frame type */
3849 addr[0] = wpabuf_head_u8(msg) + 2;
3850 len[0] = 3 + 1 + 1 + 1;
3851 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3852
3853 /* Attributes before Wrapped Data (none) */
3854 addr[1] = wpabuf_put(msg, 0);
3855 len[1] = 0;
3856 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3857
3858 /* Wrapped Data */
3859 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3860 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3861 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3862
3863 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3864 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3865 wpabuf_head(clear), wpabuf_len(clear),
3866 2, addr, len, wrapped) < 0)
3867 goto fail;
3868
3869 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3870 msg);
3871 wpabuf_free(json);
3872 wpabuf_free(clear);
3873 return msg;
3874 fail:
3875 wpabuf_free(json);
3876 wpabuf_free(clear);
3877 wpabuf_free(msg);
3878 return NULL;
3879 }
3880
3881 #endif /* CONFIG_DPP2 */
3882
3883
dpp_configurator_free(struct dpp_configurator * conf)3884 void dpp_configurator_free(struct dpp_configurator *conf)
3885 {
3886 if (!conf)
3887 return;
3888 crypto_ec_key_deinit(conf->csign);
3889 os_free(conf->kid);
3890 os_free(conf->connector);
3891 crypto_ec_key_deinit(conf->connector_key);
3892 crypto_ec_key_deinit(conf->pp_key);
3893 os_free(conf);
3894 }
3895
3896
dpp_configurator_get_key(const struct dpp_configurator * conf,char * buf,size_t buflen)3897 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3898 size_t buflen)
3899 {
3900 struct wpabuf *key;
3901 int ret = -1;
3902
3903 if (!conf->csign)
3904 return -1;
3905
3906 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3907 if (!key)
3908 return -1;
3909
3910 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
3911
3912 wpabuf_clear_free(key);
3913 return ret;
3914 }
3915
3916
dpp_configurator_gen_kid(struct dpp_configurator * conf)3917 static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3918 {
3919 struct wpabuf *csign_pub = NULL;
3920 const u8 *addr[1];
3921 size_t len[1];
3922 int res;
3923
3924 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
3925 if (!csign_pub) {
3926 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3927 return -1;
3928 }
3929
3930 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
3931 addr[0] = wpabuf_head(csign_pub);
3932 len[0] = wpabuf_len(csign_pub);
3933 res = sha256_vector(1, addr, len, conf->kid_hash);
3934 wpabuf_free(csign_pub);
3935 if (res < 0) {
3936 wpa_printf(MSG_DEBUG,
3937 "DPP: Failed to derive kid for C-sign-key");
3938 return -1;
3939 }
3940
3941 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3942 NULL);
3943 return conf->kid ? 0 : -1;
3944 }
3945
3946
3947 static struct dpp_configurator *
dpp_keygen_configurator(const char * curve,const u8 * privkey,size_t privkey_len,const u8 * pp_key,size_t pp_key_len)3948 dpp_keygen_configurator(const char *curve, const u8 *privkey,
3949 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
3950 {
3951 struct dpp_configurator *conf;
3952
3953 conf = os_zalloc(sizeof(*conf));
3954 if (!conf)
3955 return NULL;
3956
3957 conf->curve = dpp_get_curve_name(curve);
3958 if (!conf->curve) {
3959 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3960 os_free(conf);
3961 return NULL;
3962 }
3963
3964 if (privkey)
3965 conf->csign = dpp_set_keypair(&conf->curve, privkey,
3966 privkey_len);
3967 else
3968 conf->csign = dpp_gen_keypair(conf->curve);
3969 if (pp_key)
3970 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3971 pp_key_len);
3972 else
3973 conf->pp_key = dpp_gen_keypair(conf->curve);
3974 if (!conf->csign || !conf->pp_key)
3975 goto fail;
3976 conf->own = 1;
3977
3978 if (dpp_configurator_gen_kid(conf) < 0)
3979 goto fail;
3980 return conf;
3981 fail:
3982 dpp_configurator_free(conf);
3983 return NULL;
3984 }
3985
3986
dpp_configurator_own_config(struct dpp_authentication * auth,const char * curve,int ap)3987 int dpp_configurator_own_config(struct dpp_authentication *auth,
3988 const char *curve, int ap)
3989 {
3990 struct wpabuf *conf_obj;
3991 int ret = -1;
3992
3993 if (!auth->conf) {
3994 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
3995 return -1;
3996 }
3997
3998 auth->curve = dpp_get_curve_name(curve);
3999 if (!auth->curve) {
4000 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
4001 return -1;
4002 }
4003
4004 wpa_printf(MSG_DEBUG,
4005 "DPP: Building own configuration/connector with curve %s",
4006 auth->curve->name);
4007
4008 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4009 if (!auth->own_protocol_key)
4010 return -1;
4011 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
4012 auth->peer_protocol_key = auth->own_protocol_key;
4013 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
4014
4015 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
4016 if (!conf_obj) {
4017 wpabuf_free(auth->conf_obj[0].c_sign_key);
4018 auth->conf_obj[0].c_sign_key = NULL;
4019 goto fail;
4020 }
4021 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4022 wpabuf_len(conf_obj));
4023 fail:
4024 wpabuf_free(conf_obj);
4025 auth->peer_protocol_key = NULL;
4026 return ret;
4027 }
4028
4029
dpp_compatible_netrole(const char * role1,const char * role2)4030 static int dpp_compatible_netrole(const char *role1, const char *role2)
4031 {
4032 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4033 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4034 }
4035
4036
dpp_connector_compatible_group(struct json_token * root,const char * group_id,const char * net_role,bool reconfig)4037 static int dpp_connector_compatible_group(struct json_token *root,
4038 const char *group_id,
4039 const char *net_role,
4040 bool reconfig)
4041 {
4042 struct json_token *groups, *token;
4043
4044 groups = json_get_member(root, "groups");
4045 if (!groups || groups->type != JSON_ARRAY)
4046 return 0;
4047
4048 for (token = groups->child; token; token = token->sibling) {
4049 struct json_token *id, *role;
4050
4051 id = json_get_member(token, "groupId");
4052 if (!id || id->type != JSON_STRING)
4053 continue;
4054
4055 role = json_get_member(token, "netRole");
4056 if (!role || role->type != JSON_STRING)
4057 continue;
4058
4059 if (os_strcmp(id->string, "*") != 0 &&
4060 os_strcmp(group_id, "*") != 0 &&
4061 os_strcmp(id->string, group_id) != 0)
4062 continue;
4063
4064 if (reconfig && os_strcmp(net_role, "configurator") == 0)
4065 return 1;
4066 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
4067 return 1;
4068 }
4069
4070 return 0;
4071 }
4072
4073
dpp_connector_match_groups(struct json_token * own_root,struct json_token * peer_root,bool reconfig)4074 int dpp_connector_match_groups(struct json_token *own_root,
4075 struct json_token *peer_root, bool reconfig)
4076 {
4077 struct json_token *groups, *token;
4078
4079 groups = json_get_member(peer_root, "groups");
4080 if (!groups || groups->type != JSON_ARRAY) {
4081 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4082 return 0;
4083 }
4084
4085 for (token = groups->child; token; token = token->sibling) {
4086 struct json_token *id, *role;
4087
4088 id = json_get_member(token, "groupId");
4089 if (!id || id->type != JSON_STRING) {
4090 wpa_printf(MSG_DEBUG,
4091 "DPP: Missing peer groupId string");
4092 continue;
4093 }
4094
4095 role = json_get_member(token, "netRole");
4096 if (!role || role->type != JSON_STRING) {
4097 wpa_printf(MSG_DEBUG,
4098 "DPP: Missing peer groups::netRole string");
4099 continue;
4100 }
4101 wpa_printf(MSG_DEBUG,
4102 "DPP: peer connector group: groupId='%s' netRole='%s'",
4103 id->string, role->string);
4104 if (dpp_connector_compatible_group(own_root, id->string,
4105 role->string, reconfig)) {
4106 wpa_printf(MSG_DEBUG,
4107 "DPP: Compatible group/netRole in own connector");
4108 return 1;
4109 }
4110 }
4111
4112 return 0;
4113 }
4114
4115
dpp_parse_own_connector(const char * own_connector)4116 struct json_token * dpp_parse_own_connector(const char *own_connector)
4117 {
4118 unsigned char *own_conn;
4119 size_t own_conn_len;
4120 const char *pos, *end;
4121 struct json_token *own_root;
4122
4123 pos = os_strchr(own_connector, '.');
4124 if (!pos) {
4125 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4126 return NULL;
4127 }
4128 pos++;
4129 end = os_strchr(pos, '.');
4130 if (!end) {
4131 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4132 return NULL;
4133 }
4134 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4135 if (!own_conn) {
4136 wpa_printf(MSG_DEBUG,
4137 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4138 return NULL;
4139 }
4140
4141 own_root = json_parse((const char *) own_conn, own_conn_len);
4142 os_free(own_conn);
4143 if (!own_root)
4144 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4145
4146 return own_root;
4147 }
4148
4149
4150 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,u8 * peer_key_hash)4151 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4152 const u8 *net_access_key, size_t net_access_key_len,
4153 const u8 *csign_key, size_t csign_key_len,
4154 const u8 *peer_connector, size_t peer_connector_len,
4155 os_time_t *expiry, u8 *peer_key_hash)
4156 {
4157 struct json_token *root = NULL, *netkey, *token;
4158 struct json_token *own_root = NULL;
4159 enum dpp_status_error ret = 255, res;
4160 struct crypto_ec_key *own_key = NULL;
4161 struct wpabuf *own_key_pub = NULL;
4162 const struct dpp_curve_params *curve, *own_curve;
4163 struct dpp_signed_connector_info info;
4164 size_t Nx_len;
4165 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4166
4167 os_memset(intro, 0, sizeof(*intro));
4168 os_memset(&info, 0, sizeof(info));
4169 if (expiry)
4170 *expiry = 0;
4171
4172 own_key = dpp_set_keypair(&own_curve, net_access_key,
4173 net_access_key_len);
4174 if (!own_key) {
4175 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4176 goto fail;
4177 }
4178
4179 own_root = dpp_parse_own_connector(own_connector);
4180 if (!own_root)
4181 goto fail;
4182
4183 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4184 peer_connector, peer_connector_len);
4185 if (res != DPP_STATUS_OK) {
4186 ret = res;
4187 goto fail;
4188 }
4189
4190 root = json_parse((const char *) info.payload, info.payload_len);
4191 if (!root) {
4192 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4193 ret = DPP_STATUS_INVALID_CONNECTOR;
4194 goto fail;
4195 }
4196
4197 if (!dpp_connector_match_groups(own_root, root, false)) {
4198 wpa_printf(MSG_DEBUG,
4199 "DPP: Peer connector does not include compatible group netrole with own connector");
4200 ret = DPP_STATUS_NO_MATCH;
4201 goto fail;
4202 }
4203
4204 token = json_get_member(root, "expiry");
4205 if (!token || token->type != JSON_STRING) {
4206 wpa_printf(MSG_DEBUG,
4207 "DPP: No expiry string found - connector does not expire");
4208 } else {
4209 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4210 if (dpp_key_expired(token->string, expiry)) {
4211 wpa_printf(MSG_DEBUG,
4212 "DPP: Connector (netAccessKey) has expired");
4213 ret = DPP_STATUS_INVALID_CONNECTOR;
4214 goto fail;
4215 }
4216 }
4217
4218 #ifdef CONFIG_DPP3
4219 token = json_get_member(root, "version");
4220 if (token && token->type == JSON_NUMBER) {
4221 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4222 intro->peer_version = token->number;
4223 }
4224 #endif /* CONFIG_DPP3 */
4225
4226 netkey = json_get_member(root, "netAccessKey");
4227 if (!netkey || netkey->type != JSON_OBJECT) {
4228 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4229 ret = DPP_STATUS_INVALID_CONNECTOR;
4230 goto fail;
4231 }
4232
4233 intro->peer_key = dpp_parse_jwk(netkey, &curve);
4234 if (!intro->peer_key) {
4235 ret = DPP_STATUS_INVALID_CONNECTOR;
4236 goto fail;
4237 }
4238 dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
4239
4240 if (own_curve != curve) {
4241 wpa_printf(MSG_DEBUG,
4242 "DPP: Mismatching netAccessKey curves (%s != %s)",
4243 own_curve->name, curve->name);
4244 ret = DPP_STATUS_INVALID_CONNECTOR;
4245 goto fail;
4246 }
4247
4248 /* ECDH: N = nk * PK */
4249 if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
4250 goto fail;
4251
4252 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4253 Nx, Nx_len);
4254
4255 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4256 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4257 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4258 goto fail;
4259 }
4260 intro->pmk_len = curve->hash_len;
4261
4262 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4263 if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4264 0) {
4265 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4266 goto fail;
4267 }
4268
4269 #ifdef CONFIG_DPP3
4270 if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4271 &intro->aead_id) < 0) {
4272 wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4273 curve->ike_group);
4274 goto fail;
4275 }
4276 #endif /* CONFIG_DPP3 */
4277
4278 if (peer_key_hash)
4279 dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
4280
4281 ret = DPP_STATUS_OK;
4282 fail:
4283 if (ret != DPP_STATUS_OK)
4284 dpp_peer_intro_deinit(intro);
4285 os_memset(Nx, 0, sizeof(Nx));
4286 os_free(info.payload);
4287 crypto_ec_key_deinit(own_key);
4288 wpabuf_free(own_key_pub);
4289 json_free(root);
4290 json_free(own_root);
4291 return ret;
4292 }
4293
4294
dpp_peer_intro_deinit(struct dpp_introduction * intro)4295 void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4296 {
4297 if (!intro)
4298 return;
4299
4300 crypto_ec_key_deinit(intro->peer_key);
4301 os_memset(intro, 0, sizeof(*intro));
4302 }
4303
4304
4305 #ifdef CONFIG_DPP3
dpp_get_connector_version(const char * connector)4306 int dpp_get_connector_version(const char *connector)
4307 {
4308 struct json_token *root, *token;
4309 int ver = -1;
4310
4311 root = dpp_parse_own_connector(connector);
4312 if (!root)
4313 return -1;
4314
4315 token = json_get_member(root, "version");
4316 if (token && token->type == JSON_NUMBER)
4317 ver = token->number;
4318
4319 json_free(root);
4320 return ver;
4321 }
4322 #endif /* CONFIG_DPP3 */
4323
4324
dpp_next_id(struct dpp_global * dpp)4325 unsigned int dpp_next_id(struct dpp_global *dpp)
4326 {
4327 struct dpp_bootstrap_info *bi;
4328 unsigned int max_id = 0;
4329
4330 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4331 if (bi->id > max_id)
4332 max_id = bi->id;
4333 }
4334 return max_id + 1;
4335 }
4336
4337
dpp_bootstrap_del(struct dpp_global * dpp,unsigned int id)4338 static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4339 {
4340 struct dpp_bootstrap_info *bi, *tmp;
4341 int found = 0;
4342
4343 if (!dpp)
4344 return -1;
4345
4346 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4347 struct dpp_bootstrap_info, list) {
4348 if (id && bi->id != id)
4349 continue;
4350 found = 1;
4351 #ifdef CONFIG_DPP2
4352 if (dpp->remove_bi)
4353 dpp->remove_bi(dpp->cb_ctx, bi);
4354 #endif /* CONFIG_DPP2 */
4355 dl_list_del(&bi->list);
4356 dpp_bootstrap_info_free(bi);
4357 }
4358
4359 if (id == 0)
4360 return 0; /* flush succeeds regardless of entries found */
4361 return found ? 0 : -1;
4362 }
4363
4364
dpp_add_qr_code(struct dpp_global * dpp,const char * uri)4365 struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4366 const char *uri)
4367 {
4368 struct dpp_bootstrap_info *bi;
4369
4370 if (!dpp)
4371 return NULL;
4372
4373 bi = dpp_parse_uri(uri);
4374 if (!bi)
4375 return NULL;
4376
4377 bi->type = DPP_BOOTSTRAP_QR_CODE;
4378 bi->id = dpp_next_id(dpp);
4379 dl_list_add(&dpp->bootstrap, &bi->list);
4380 return bi;
4381 }
4382
4383
dpp_add_nfc_uri(struct dpp_global * dpp,const char * uri)4384 struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4385 const char *uri)
4386 {
4387 struct dpp_bootstrap_info *bi;
4388
4389 if (!dpp)
4390 return NULL;
4391
4392 bi = dpp_parse_uri(uri);
4393 if (!bi)
4394 return NULL;
4395
4396 bi->type = DPP_BOOTSTRAP_NFC_URI;
4397 bi->id = dpp_next_id(dpp);
4398 dl_list_add(&dpp->bootstrap, &bi->list);
4399 return bi;
4400 }
4401
4402
dpp_parse_supported_curves_list(struct dpp_bootstrap_info * bi,char * txt)4403 static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4404 char *txt)
4405 {
4406 char *token, *context = NULL;
4407 u8 curves = 0;
4408
4409 if (!txt)
4410 return 0;
4411
4412 while ((token = str_token(txt, ":", &context))) {
4413 if (os_strcmp(token, "P-256") == 0) {
4414 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4415 } else if (os_strcmp(token, "P-384") == 0) {
4416 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4417 } else if (os_strcmp(token, "P-521") == 0) {
4418 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4419 } else if (os_strcmp(token, "BP-256") == 0) {
4420 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4421 } else if (os_strcmp(token, "BP-384") == 0) {
4422 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4423 } else if (os_strcmp(token, "BP-512") == 0) {
4424 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4425 } else {
4426 wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4427 token);
4428 return -1;
4429 }
4430 }
4431 bi->supported_curves = curves;
4432
4433 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4434 bi->supported_curves);
4435
4436 return 0;
4437 }
4438
4439
dpp_bootstrap_gen(struct dpp_global * dpp,const char * cmd)4440 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4441 {
4442 char *mac = NULL, *info = NULL, *curve = NULL;
4443 char *key = NULL, *supported_curves = NULL, *host = NULL;
4444 u8 *privkey = NULL;
4445 size_t privkey_len = 0;
4446 int ret = -1;
4447 struct dpp_bootstrap_info *bi;
4448
4449 if (!dpp)
4450 return -1;
4451
4452 bi = os_zalloc(sizeof(*bi));
4453 if (!bi)
4454 goto fail;
4455
4456 if (os_strstr(cmd, "type=qrcode"))
4457 bi->type = DPP_BOOTSTRAP_QR_CODE;
4458 else if (os_strstr(cmd, "type=pkex"))
4459 bi->type = DPP_BOOTSTRAP_PKEX;
4460 else if (os_strstr(cmd, "type=nfc-uri"))
4461 bi->type = DPP_BOOTSTRAP_NFC_URI;
4462 else
4463 goto fail;
4464
4465 bi->chan = get_param(cmd, " chan=");
4466 mac = get_param(cmd, " mac=");
4467 info = get_param(cmd, " info=");
4468 curve = get_param(cmd, " curve=");
4469 key = get_param(cmd, " key=");
4470 supported_curves = get_param(cmd, " supported_curves=");
4471 host = get_param(cmd, " host=");
4472
4473 if (key) {
4474 privkey_len = os_strlen(key) / 2;
4475 privkey = os_malloc(privkey_len);
4476 if (!privkey ||
4477 hexstr2bin(key, privkey, privkey_len) < 0)
4478 goto fail;
4479 }
4480
4481 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4482 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4483 dpp_parse_uri_mac(bi, mac) < 0 ||
4484 dpp_parse_uri_info(bi, info) < 0 ||
4485 dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
4486 dpp_parse_uri_host(bi, host) < 0 ||
4487 dpp_gen_uri(bi) < 0)
4488 goto fail;
4489
4490 bi->id = dpp_next_id(dpp);
4491 dl_list_add(&dpp->bootstrap, &bi->list);
4492 ret = bi->id;
4493 bi = NULL;
4494 fail:
4495 os_free(curve);
4496 os_free(mac);
4497 os_free(info);
4498 str_clear_free(key);
4499 os_free(supported_curves);
4500 os_free(host);
4501 bin_clear_free(privkey, privkey_len);
4502 dpp_bootstrap_info_free(bi);
4503 return ret;
4504 }
4505
4506
4507 struct dpp_bootstrap_info *
dpp_bootstrap_get_id(struct dpp_global * dpp,unsigned int id)4508 dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4509 {
4510 struct dpp_bootstrap_info *bi;
4511
4512 if (!dpp)
4513 return NULL;
4514
4515 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4516 if (bi->id == id)
4517 return bi;
4518 }
4519 return NULL;
4520 }
4521
4522
dpp_bootstrap_remove(struct dpp_global * dpp,const char * id)4523 int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4524 {
4525 unsigned int id_val;
4526
4527 if (os_strcmp(id, "*") == 0) {
4528 id_val = 0;
4529 } else {
4530 id_val = atoi(id);
4531 if (id_val == 0)
4532 return -1;
4533 }
4534
4535 return dpp_bootstrap_del(dpp, id_val);
4536 }
4537
4538
dpp_bootstrap_get_uri(struct dpp_global * dpp,unsigned int id)4539 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4540 {
4541 struct dpp_bootstrap_info *bi;
4542
4543 bi = dpp_bootstrap_get_id(dpp, id);
4544 if (!bi)
4545 return NULL;
4546 return bi->uri;
4547 }
4548
4549
dpp_bootstrap_info(struct dpp_global * dpp,int id,char * reply,int reply_size)4550 int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4551 char *reply, int reply_size)
4552 {
4553 struct dpp_bootstrap_info *bi;
4554 char pkhash[2 * SHA256_MAC_LEN + 1];
4555 char supp_curves[100];
4556 char host[100];
4557 int ret;
4558
4559 bi = dpp_bootstrap_get_id(dpp, id);
4560 if (!bi)
4561 return -1;
4562 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4563 SHA256_MAC_LEN);
4564
4565 supp_curves[0] = '\0';
4566 if (bi->supported_curves) {
4567 size_t i;
4568 char *pos = supp_curves;
4569 char *end = &supp_curves[sizeof(supp_curves)];
4570 const char *curve[6] = { "P-256", "P-384", "P-521",
4571 "BP-256", "BP-384", "BP-512" };
4572
4573 ret = os_snprintf(pos, end - pos, "supp_curves=");
4574 if (os_snprintf_error(end - pos, ret))
4575 return -1;
4576 pos += ret;
4577
4578 for (i = 0; i < ARRAY_SIZE(curve); i++) {
4579 if (!(bi->supported_curves & BIT(i)))
4580 continue;
4581 ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4582 if (os_snprintf_error(end - pos, ret))
4583 return -1;
4584 pos += ret;
4585 }
4586
4587 if (pos[-1] == ':')
4588 pos[-1] = '\n';
4589 else
4590 supp_curves[0] = '\0';
4591 }
4592
4593 host[0] = '\0';
4594 if (bi->host) {
4595 char buf[100];
4596
4597 ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4598 hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4599 bi->port);
4600 if (os_snprintf_error(sizeof(host), ret))
4601 return -1;
4602 }
4603
4604 return os_snprintf(reply, reply_size, "type=%s\n"
4605 "mac_addr=" MACSTR "\n"
4606 "info=%s\n"
4607 "num_freq=%u\n"
4608 "use_freq=%u\n"
4609 "curve=%s\n"
4610 "pkhash=%s\n"
4611 "version=%d\n%s%s",
4612 dpp_bootstrap_type_txt(bi->type),
4613 MAC2STR(bi->mac_addr),
4614 bi->info ? bi->info : "",
4615 bi->num_freq,
4616 bi->num_freq == 1 ? bi->freq[0] : 0,
4617 bi->curve->name,
4618 pkhash,
4619 bi->version,
4620 supp_curves,
4621 host);
4622 }
4623
4624
dpp_bootstrap_set(struct dpp_global * dpp,int id,const char * params)4625 int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4626 {
4627 struct dpp_bootstrap_info *bi;
4628
4629 bi = dpp_bootstrap_get_id(dpp, id);
4630 if (!bi)
4631 return -1;
4632
4633 str_clear_free(bi->configurator_params);
4634
4635 if (params) {
4636 bi->configurator_params = os_strdup(params);
4637 return bi->configurator_params ? 0 : -1;
4638 }
4639
4640 bi->configurator_params = NULL;
4641 return 0;
4642 }
4643
4644
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)4645 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4646 const u8 *r_bootstrap,
4647 struct dpp_bootstrap_info **own_bi,
4648 struct dpp_bootstrap_info **peer_bi)
4649 {
4650 struct dpp_bootstrap_info *bi;
4651
4652 *own_bi = NULL;
4653 *peer_bi = NULL;
4654 if (!dpp)
4655 return;
4656
4657 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4658 if (!*own_bi && bi->own &&
4659 os_memcmp(bi->pubkey_hash, r_bootstrap,
4660 SHA256_MAC_LEN) == 0) {
4661 wpa_printf(MSG_DEBUG,
4662 "DPP: Found matching own bootstrapping information");
4663 *own_bi = bi;
4664 }
4665
4666 if (!*peer_bi && !bi->own &&
4667 os_memcmp(bi->pubkey_hash, i_bootstrap,
4668 SHA256_MAC_LEN) == 0) {
4669 wpa_printf(MSG_DEBUG,
4670 "DPP: Found matching peer bootstrapping information");
4671 *peer_bi = bi;
4672 }
4673
4674 if (*own_bi && *peer_bi)
4675 break;
4676 }
4677 }
4678
4679
4680 #ifdef CONFIG_DPP2
dpp_bootstrap_find_chirp(struct dpp_global * dpp,const u8 * hash)4681 struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4682 const u8 *hash)
4683 {
4684 struct dpp_bootstrap_info *bi;
4685
4686 if (!dpp)
4687 return NULL;
4688
4689 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4690 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4691 SHA256_MAC_LEN) == 0)
4692 return bi;
4693 }
4694
4695 return NULL;
4696 }
4697 #endif /* CONFIG_DPP2 */
4698
4699
dpp_nfc_update_bi_channel(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4700 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4701 struct dpp_bootstrap_info *peer_bi)
4702 {
4703 unsigned int i, freq = 0;
4704 enum hostapd_hw_mode mode;
4705 u8 op_class, channel;
4706 char chan[20];
4707
4708 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
4709 return 0; /* no channel preference/constraint */
4710
4711 for (i = 0; i < peer_bi->num_freq; i++) {
4712 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
4713 freq_included(own_bi->freq, own_bi->num_freq,
4714 peer_bi->freq[i])) {
4715 freq = peer_bi->freq[i];
4716 break;
4717 }
4718 }
4719 if (!freq) {
4720 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4721 return -1;
4722 }
4723
4724 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4725 if (mode == NUM_HOSTAPD_MODES) {
4726 wpa_printf(MSG_DEBUG,
4727 "DPP: Could not determine operating class or channel number for %u MHz",
4728 freq);
4729 }
4730
4731 wpa_printf(MSG_DEBUG,
4732 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4733 freq, op_class, channel);
4734 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4735 os_free(own_bi->chan);
4736 own_bi->chan = os_strdup(chan);
4737 own_bi->freq[0] = freq;
4738 own_bi->num_freq = 1;
4739 os_free(peer_bi->chan);
4740 peer_bi->chan = os_strdup(chan);
4741 peer_bi->freq[0] = freq;
4742 peer_bi->num_freq = 1;
4743
4744 return dpp_gen_uri(own_bi);
4745 }
4746
4747
dpp_nfc_update_bi_key(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4748 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4749 struct dpp_bootstrap_info *peer_bi)
4750 {
4751 if (peer_bi->curve == own_bi->curve)
4752 return 0;
4753
4754 wpa_printf(MSG_DEBUG,
4755 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4756
4757 crypto_ec_key_deinit(own_bi->pubkey);
4758 own_bi->pubkey = NULL;
4759
4760 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4761 dpp_gen_uri(own_bi) < 0)
4762 goto fail;
4763
4764 return 0;
4765 fail:
4766 dl_list_del(&own_bi->list);
4767 dpp_bootstrap_info_free(own_bi);
4768 return -1;
4769 }
4770
4771
dpp_nfc_update_bi(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4772 int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4773 struct dpp_bootstrap_info *peer_bi)
4774 {
4775 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4776 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4777 return -1;
4778 return 0;
4779 }
4780
4781
dpp_next_configurator_id(struct dpp_global * dpp)4782 static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4783 {
4784 struct dpp_configurator *conf;
4785 unsigned int max_id = 0;
4786
4787 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4788 list) {
4789 if (conf->id > max_id)
4790 max_id = conf->id;
4791 }
4792 return max_id + 1;
4793 }
4794
4795
dpp_configurator_add(struct dpp_global * dpp,const char * cmd)4796 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4797 {
4798 char *curve;
4799 char *key = NULL, *ppkey = NULL;
4800 u8 *privkey = NULL, *pp_key = NULL;
4801 size_t privkey_len = 0, pp_key_len = 0;
4802 int ret = -1;
4803 struct dpp_configurator *conf = NULL;
4804 const struct dpp_curve_params *net_access_key_curve = NULL;
4805
4806 curve = get_param(cmd, " net_access_key_curve=");
4807 if (curve) {
4808 net_access_key_curve = dpp_get_curve_name(curve);
4809 if (!net_access_key_curve) {
4810 wpa_printf(MSG_DEBUG,
4811 "DPP: Unsupported net_access_key_curve: %s",
4812 curve);
4813 goto fail;
4814 }
4815 os_free(curve);
4816 }
4817
4818 curve = get_param(cmd, " curve=");
4819 key = get_param(cmd, " key=");
4820 ppkey = get_param(cmd, " ppkey=");
4821
4822 if (key) {
4823 privkey_len = os_strlen(key) / 2;
4824 privkey = os_malloc(privkey_len);
4825 if (!privkey ||
4826 hexstr2bin(key, privkey, privkey_len) < 0)
4827 goto fail;
4828 }
4829
4830 if (ppkey) {
4831 pp_key_len = os_strlen(ppkey) / 2;
4832 pp_key = os_malloc(pp_key_len);
4833 if (!pp_key ||
4834 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4835 goto fail;
4836 }
4837
4838 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4839 pp_key, pp_key_len);
4840 if (!conf)
4841 goto fail;
4842
4843 conf->net_access_key_curve = net_access_key_curve;
4844 conf->id = dpp_next_configurator_id(dpp);
4845 dl_list_add(&dpp->configurator, &conf->list);
4846 ret = conf->id;
4847 conf = NULL;
4848 fail:
4849 os_free(curve);
4850 str_clear_free(key);
4851 str_clear_free(ppkey);
4852 bin_clear_free(privkey, privkey_len);
4853 bin_clear_free(pp_key, pp_key_len);
4854 dpp_configurator_free(conf);
4855 return ret;
4856 }
4857
4858
dpp_configurator_set(struct dpp_global * dpp,const char * cmd)4859 int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4860 {
4861 unsigned int id;
4862 struct dpp_configurator *conf;
4863 char *curve;
4864
4865 id = atoi(cmd);
4866 conf = dpp_configurator_get_id(dpp, id);
4867 if (!conf)
4868 return -1;
4869
4870 curve = get_param(cmd, " net_access_key_curve=");
4871 if (curve) {
4872 const struct dpp_curve_params *net_access_key_curve;
4873
4874 net_access_key_curve = dpp_get_curve_name(curve);
4875 os_free(curve);
4876 if (!net_access_key_curve)
4877 return -1;
4878 conf->net_access_key_curve = net_access_key_curve;
4879 }
4880
4881 return 0;
4882 }
4883
4884
dpp_configurator_del(struct dpp_global * dpp,unsigned int id)4885 static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4886 {
4887 struct dpp_configurator *conf, *tmp;
4888 int found = 0;
4889
4890 if (!dpp)
4891 return -1;
4892
4893 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4894 struct dpp_configurator, list) {
4895 if (id && conf->id != id)
4896 continue;
4897 found = 1;
4898 dl_list_del(&conf->list);
4899 dpp_configurator_free(conf);
4900 }
4901
4902 if (id == 0)
4903 return 0; /* flush succeeds regardless of entries found */
4904 return found ? 0 : -1;
4905 }
4906
4907
dpp_configurator_remove(struct dpp_global * dpp,const char * id)4908 int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4909 {
4910 unsigned int id_val;
4911
4912 if (os_strcmp(id, "*") == 0) {
4913 id_val = 0;
4914 } else {
4915 id_val = atoi(id);
4916 if (id_val == 0)
4917 return -1;
4918 }
4919
4920 return dpp_configurator_del(dpp, id_val);
4921 }
4922
4923
dpp_configurator_get_key_id(struct dpp_global * dpp,unsigned int id,char * buf,size_t buflen)4924 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4925 char *buf, size_t buflen)
4926 {
4927 struct dpp_configurator *conf;
4928
4929 conf = dpp_configurator_get_id(dpp, id);
4930 if (!conf)
4931 return -1;
4932
4933 return dpp_configurator_get_key(conf, buf, buflen);
4934 }
4935
4936
4937 #ifdef CONFIG_DPP2
4938
dpp_configurator_from_backup(struct dpp_global * dpp,struct dpp_asymmetric_key * key)4939 int dpp_configurator_from_backup(struct dpp_global *dpp,
4940 struct dpp_asymmetric_key *key)
4941 {
4942 struct dpp_configurator *conf;
4943 const struct dpp_curve_params *curve, *curve_pp;
4944
4945 if (!key->csign || !key->pp_key)
4946 return -1;
4947
4948 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
4949 if (!curve) {
4950 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4951 return -1;
4952 }
4953
4954 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
4955 if (!curve_pp) {
4956 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
4957 return -1;
4958 }
4959
4960 if (curve != curve_pp) {
4961 wpa_printf(MSG_INFO,
4962 "DPP: Mismatch in c-sign-key and ppKey groups");
4963 return -1;
4964 }
4965
4966 conf = os_zalloc(sizeof(*conf));
4967 if (!conf)
4968 return -1;
4969 conf->curve = curve;
4970 conf->csign = key->csign;
4971 key->csign = NULL;
4972 conf->pp_key = key->pp_key;
4973 key->pp_key = NULL;
4974 conf->own = 1;
4975 if (dpp_configurator_gen_kid(conf) < 0) {
4976 dpp_configurator_free(conf);
4977 return -1;
4978 }
4979
4980 conf->id = dpp_next_configurator_id(dpp);
4981 dl_list_add(&dpp->configurator, &conf->list);
4982 return conf->id;
4983 }
4984
4985
dpp_configurator_find_kid(struct dpp_global * dpp,const u8 * kid)4986 struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4987 const u8 *kid)
4988 {
4989 struct dpp_configurator *conf;
4990
4991 if (!dpp)
4992 return NULL;
4993
4994 dl_list_for_each(conf, &dpp->configurator,
4995 struct dpp_configurator, list) {
4996 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4997 return conf;
4998 }
4999 return NULL;
5000 }
5001
5002 #endif /* CONFIG_DPP2 */
5003
5004
dpp_global_init(struct dpp_global_config * config)5005 struct dpp_global * dpp_global_init(struct dpp_global_config *config)
5006 {
5007 struct dpp_global *dpp;
5008
5009 dpp = os_zalloc(sizeof(*dpp));
5010 if (!dpp)
5011 return NULL;
5012 #ifdef CONFIG_DPP2
5013 dpp->cb_ctx = config->cb_ctx;
5014 dpp->remove_bi = config->remove_bi;
5015 #endif /* CONFIG_DPP2 */
5016
5017 dl_list_init(&dpp->bootstrap);
5018 dl_list_init(&dpp->configurator);
5019 #ifdef CONFIG_DPP2
5020 dl_list_init(&dpp->controllers);
5021 dl_list_init(&dpp->tcp_init);
5022 dpp->relay_sock = -1;
5023 #endif /* CONFIG_DPP2 */
5024
5025 return dpp;
5026 }
5027
5028
dpp_global_clear(struct dpp_global * dpp)5029 void dpp_global_clear(struct dpp_global *dpp)
5030 {
5031 if (!dpp)
5032 return;
5033
5034 dpp_bootstrap_del(dpp, 0);
5035 dpp_configurator_del(dpp, 0);
5036 #ifdef CONFIG_DPP2
5037 dpp_tcp_init_flush(dpp);
5038 dpp_relay_flush_controllers(dpp);
5039 dpp_controller_stop(dpp);
5040 #endif /* CONFIG_DPP2 */
5041 }
5042
5043
dpp_global_deinit(struct dpp_global * dpp)5044 void dpp_global_deinit(struct dpp_global *dpp)
5045 {
5046 dpp_global_clear(dpp);
5047 os_free(dpp);
5048 }
5049
5050
dpp_notify_auth_success(struct dpp_authentication * auth,int initiator)5051 void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
5052 {
5053 u8 hash[SHA256_MAC_LEN];
5054 char hex[SHA256_MAC_LEN * 2 + 1];
5055
5056 if (auth->peer_protocol_key) {
5057 dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
5058 wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
5059 } else {
5060 hex[0] = '\0';
5061 }
5062 wpa_msg(auth->msg_ctx, MSG_INFO,
5063 DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d",
5064 initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1,
5065 auth->peer_bi ? (int) auth->peer_bi->id : -1);
5066 }
5067
5068
5069 #ifdef CONFIG_DPP2
5070
dpp_build_presence_announcement(struct dpp_bootstrap_info * bi)5071 struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5072 {
5073 struct wpabuf *msg;
5074
5075 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5076
5077 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5078 if (!msg)
5079 return NULL;
5080
5081 /* Responder Bootstrapping Key Hash */
5082 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5083 wpa_hexdump_buf(MSG_DEBUG,
5084 "DPP: Presence Announcement frame attributes", msg);
5085 return msg;
5086 }
5087
5088
dpp_notify_chirp_received(void * msg_ctx,int id,const u8 * src,unsigned int freq,const u8 * hash)5089 void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5090 unsigned int freq, const u8 *hash)
5091 {
5092 char hex[SHA256_MAC_LEN * 2 + 1];
5093
5094 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5095 wpa_msg(msg_ctx, MSG_INFO,
5096 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5097 id, MAC2STR(src), freq, hex);
5098 }
5099
5100 #endif /* CONFIG_DPP2 */
5101
5102
5103 #ifdef CONFIG_DPP3
5104
dpp_build_pb_announcement(struct dpp_bootstrap_info * bi)5105 struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5106 {
5107 struct wpabuf *msg;
5108 const u8 *r_hash = bi->pubkey_hash_chirp;
5109 #ifdef CONFIG_TESTING_OPTIONS
5110 u8 test_hash[SHA256_MAC_LEN];
5111 #endif /* CONFIG_TESTING_OPTIONS */
5112
5113 wpa_printf(MSG_DEBUG,
5114 "DPP: Build Push Button Presence Announcement frame");
5115
5116 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5117 4 + SHA256_MAC_LEN);
5118 if (!msg)
5119 return NULL;
5120
5121 #ifdef CONFIG_TESTING_OPTIONS
5122 if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5123 wpa_printf(MSG_INFO,
5124 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5125 os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5126 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5127 r_hash = test_hash;
5128 }
5129 #endif /* CONFIG_TESTING_OPTIONS */
5130
5131 /* Responder Bootstrapping Key Hash */
5132 dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5133 wpa_hexdump_buf(MSG_DEBUG,
5134 "DPP: Push Button Presence Announcement frame attributes",
5135 msg);
5136 return msg;
5137 }
5138
5139
dpp_build_pb_announcement_resp(struct dpp_bootstrap_info * bi,const u8 * e_hash,const u8 * c_nonce,size_t c_nonce_len)5140 struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5141 const u8 *e_hash,
5142 const u8 *c_nonce,
5143 size_t c_nonce_len)
5144 {
5145 struct wpabuf *msg;
5146 const u8 *i_hash = bi->pubkey_hash_chirp;
5147 #ifdef CONFIG_TESTING_OPTIONS
5148 u8 test_hash[SHA256_MAC_LEN];
5149 #endif /* CONFIG_TESTING_OPTIONS */
5150
5151 wpa_printf(MSG_DEBUG,
5152 "DPP: Build Push Button Presence Announcement Response frame");
5153
5154 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5155 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5156 if (!msg)
5157 return NULL;
5158
5159 #ifdef CONFIG_TESTING_OPTIONS
5160 if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5161 wpa_printf(MSG_INFO,
5162 "DPP: TESTING - invalid I-Bootstrap Key Hash");
5163 os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5164 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5165 i_hash = test_hash;
5166 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5167 wpa_printf(MSG_INFO,
5168 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5169 os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5170 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5171 e_hash = test_hash;
5172 }
5173 #endif /* CONFIG_TESTING_OPTIONS */
5174
5175 /* Initiator Bootstrapping Key Hash */
5176 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5177 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5178 wpabuf_put_le16(msg, SHA256_MAC_LEN);
5179 wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5180
5181 /* Responder Bootstrapping Key Hash */
5182 dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5183
5184 /* Configurator Nonce */
5185 wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5186 wpabuf_put_le16(msg, c_nonce_len);
5187 wpabuf_put_data(msg, c_nonce, c_nonce_len);
5188
5189 wpa_hexdump_buf(MSG_DEBUG,
5190 "DPP: Push Button Presence Announcement Response frame attributes",
5191 msg);
5192 return msg;
5193 }
5194
5195 #endif /* CONFIG_DPP3 */
5196