blob: 22998abb3d4b037e09e2a3c5ac954c0ad7633d89 [file] [log] [blame]
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001/*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
Hai Shalomfdcde762020-04-02 11:19:20 -07004 * Copyright (c) 2018-2020, The Linux Foundation
Hai Shaloma20dcd72022-02-04 13:43:00 -08005 * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07006 *
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"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070012
13#include "utils/common.h"
14#include "utils/base64.h"
15#include "utils/json.h"
Sunil8cd6f4d2022-06-28 18:40:46 +000016#include "utils/ip_addr.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "common/ieee802_11_common.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070018#include "common/wpa_ctrl.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070019#include "common/gas.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070020#include "eap_common/eap_defs.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070021#include "crypto/crypto.h"
22#include "crypto/random.h"
23#include "crypto/aes.h"
24#include "crypto/aes_siv.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070025#include "drivers/driver.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070026#include "dpp.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070027#include "dpp_i.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070028
29
Roshan Pius3a1667e2018-07-03 15:17:14 -070030#ifdef CONFIG_TESTING_OPTIONS
Hai Shaloma20dcd72022-02-04 13:43:00 -080031#ifdef CONFIG_DPP3
32int dpp_version_override = 3;
33#elif defined(CONFIG_DPP2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070034int dpp_version_override = 2;
35#else
36int dpp_version_override = 1;
37#endif
Roshan Pius3a1667e2018-07-03 15:17:14 -070038enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
Roshan Pius3a1667e2018-07-03 15:17:14 -070039#endif /* CONFIG_TESTING_OPTIONS */
40
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070041
Hai Shalom4fbc08f2020-05-18 12:37:00 -070042void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
Roshan Pius3a1667e2018-07-03 15:17:14 -070043{
44 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
45}
46
47
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070048struct 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
66const 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
Hai Shalomc3565922019-10-28 11:58:20 -070089static 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
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700117int dpp_check_attrs(const u8 *buf, size_t len)
118{
119 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700120 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700121
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 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700138 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;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700145 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
159void 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);
Hai Shalomfdcde762020-04-02 11:19:20 -0700165 os_free(info->chan);
Sunil8cd6f4d2022-06-28 18:40:46 +0000166 os_free(info->host);
Hai Shalomfdcde762020-04-02 11:19:20 -0700167 os_free(info->pk);
Hai Shaloma20dcd72022-02-04 13:43:00 -0800168 crypto_ec_key_deinit(info->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -0700169 str_clear_free(info->configurator_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700170 os_free(info);
171}
172
173
174const 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";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800181 case DPP_BOOTSTRAP_NFC_URI:
182 return "NFC-URI";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700183 }
184 return "??";
185}
186
187
188static 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
201static 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
208int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
209 const char *chan_list)
210{
Hai Shalom81f62d82019-07-22 12:10:00 -0700211 const char *pos = chan_list, *pos2;
212 int opclass = -1, channel, freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700213
214 while (pos && *pos && *pos != ';') {
Hai Shalom81f62d82019-07-22 12:10:00 -0700215 pos2 = pos;
216 while (*pos2 >= '0' && *pos2 <= '9')
217 pos2++;
218 if (*pos2 == '/') {
219 opclass = atoi(pos);
220 pos = pos2 + 1;
221 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700222 if (opclass <= 0)
223 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700224 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);
Hai Shalom899fcc72020-10-19 14:38:18 -0700233 bi->channels_listed = true;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700234 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;
255fail:
256 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
257 return -1;
258}
259
260
261int 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
277int 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
Sunil Ravi876a49b2025-02-03 19:18:32 +0000302static int dpp_parse_uri_version(struct dpp_bootstrap_info *bi,
303 const char *version)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700304{
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700305#ifdef CONFIG_DPP2
306 if (!version || DPP_VERSION < 2)
307 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700308
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700309 if (*version == '1')
310 bi->version = 1;
311 else if (*version == '2')
312 bi->version = 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800313 else if (*version == '3')
314 bi->version = 3;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700315 else
316 wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700317
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700318 wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
319#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700320
321 return 0;
322}
323
324
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700325static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
326{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700327 u8 *data;
328 size_t data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700329 int res;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700330 const char *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700331
332 end = os_strchr(info, ';');
333 if (!end)
334 return -1;
335
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800336 data = base64_decode(info, end - info, &data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700337 if (!data) {
338 wpa_printf(MSG_DEBUG,
339 "DPP: Invalid base64 encoding on URI public-key");
340 return -1;
341 }
342 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
343 data, data_len);
344
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700345 res = dpp_get_subject_public_key(bi, data, data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700346 os_free(data);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700347 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700348}
349
350
Sunil Ravia04bd252022-05-02 22:54:18 -0700351static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
352 const char *txt)
353{
354 int val;
355
356 if (!txt)
357 return 0;
358
359 val = hex2num(txt[0]);
360 if (val < 0)
361 return -1;
362 bi->supported_curves = val;
363
364 val = hex2num(txt[1]);
365 if (val > 0)
366 bi->supported_curves |= val << 4;
367
368 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
369 bi->supported_curves);
370
371 return 0;
372}
373
374
Sunil8cd6f4d2022-06-28 18:40:46 +0000375static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
376{
377 const char *end;
378 char *port;
379 struct hostapd_ip_addr addr;
380 char buf[100], *pos;
381
382 if (!txt)
383 return 0;
384
385 end = os_strchr(txt, ';');
386 if (!end)
387 end = txt + os_strlen(txt);
388 if (end - txt > (int) sizeof(buf) - 1)
389 return -1;
390 os_memcpy(buf, txt, end - txt);
391 buf[end - txt] = '\0';
392
393 bi->port = DPP_TCP_PORT;
394
395 pos = buf;
396 if (*pos == '[') {
397 pos = &buf[1];
398 port = os_strchr(pos, ']');
399 if (!port)
400 return -1;
401 *port++ = '\0';
402 if (*port == ':')
403 bi->port = atoi(port + 1);
404 }
405
406 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
407 if (buf[0] != '[') {
408 port = os_strrchr(pos, ':');
409 if (port) {
410 *port++ = '\0';
411 bi->port = atoi(port);
412 }
413 }
414 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
415 wpa_printf(MSG_INFO,
416 "DPP: Invalid IP address in URI host entry: %s",
417 pos);
418 return -1;
419 }
420 }
421 os_free(bi->host);
422 bi->host = os_memdup(&addr, sizeof(addr));
423 if (!bi->host)
424 return -1;
425
426 wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
427 hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
428
429 return 0;
430}
431
432
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700433static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
434{
435 const char *pos = uri;
436 const char *end;
437 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +0000438 const char *version = NULL, *supported_curves = NULL, *host = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700439 struct dpp_bootstrap_info *bi;
440
441 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
442
443 if (os_strncmp(pos, "DPP:", 4) != 0) {
444 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
445 return NULL;
446 }
447 pos += 4;
448
449 for (;;) {
450 end = os_strchr(pos, ';');
451 if (!end)
452 break;
453
454 if (end == pos) {
455 /* Handle terminating ";;" and ignore unexpected ";"
456 * for parsing robustness. */
457 pos++;
458 continue;
459 }
460
461 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
462 chan_list = pos + 2;
463 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
464 mac = pos + 2;
465 else if (pos[0] == 'I' && pos[1] == ':' && !info)
466 info = pos + 2;
467 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
468 pk = pos + 2;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700469 else if (pos[0] == 'V' && pos[1] == ':' && !version)
470 version = pos + 2;
Sunil Ravia04bd252022-05-02 22:54:18 -0700471 else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
472 supported_curves = pos + 2;
Sunil8cd6f4d2022-06-28 18:40:46 +0000473 else if (pos[0] == 'H' && pos[1] == ':' && !host)
474 host = pos + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700475 else
476 wpa_hexdump_ascii(MSG_DEBUG,
477 "DPP: Ignore unrecognized URI parameter",
478 pos, end - pos);
479 pos = end + 1;
480 }
481
482 if (!pk) {
483 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
484 return NULL;
485 }
486
487 bi = os_zalloc(sizeof(*bi));
488 if (!bi)
489 return NULL;
490
491 if (dpp_clone_uri(bi, uri) < 0 ||
492 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
493 dpp_parse_uri_mac(bi, mac) < 0 ||
494 dpp_parse_uri_info(bi, info) < 0 ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700495 dpp_parse_uri_version(bi, version) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -0700496 dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +0000497 dpp_parse_uri_host(bi, host) < 0 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700498 dpp_parse_uri_pk(bi, pk) < 0) {
499 dpp_bootstrap_info_free(bi);
500 bi = NULL;
501 }
502
503 return bi;
504}
505
506
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700507void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700508{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700509 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
510 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
511 wpabuf_put_le16(msg, 1);
512 wpabuf_put_u8(msg, status);
513}
514
515
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700516void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700517{
518 if (hash) {
519 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
520 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
521 wpabuf_put_le16(msg, SHA256_MAC_LEN);
522 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
523 }
524}
525
526
Roshan Pius3a1667e2018-07-03 15:17:14 -0700527static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
528 u16 num_modes, unsigned int freq)
529{
530 u16 m;
531 int c, flag;
532
533 if (!own_modes || !num_modes)
534 return 1;
535
536 for (m = 0; m < num_modes; m++) {
537 for (c = 0; c < own_modes[m].num_channels; c++) {
538 if ((unsigned int) own_modes[m].channels[c].freq !=
539 freq)
540 continue;
541 flag = own_modes[m].channels[c].flag;
542 if (!(flag & (HOSTAPD_CHAN_DISABLED |
543 HOSTAPD_CHAN_NO_IR |
544 HOSTAPD_CHAN_RADAR)))
545 return 1;
546 }
547 }
548
549 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
550 return 0;
551}
552
553
554static int freq_included(const unsigned int freqs[], unsigned int num,
555 unsigned int freq)
556{
557 while (num > 0) {
558 if (freqs[--num] == freq)
559 return 1;
560 }
561 return 0;
562}
563
564
565static void freq_to_start(unsigned int freqs[], unsigned int num,
566 unsigned int freq)
567{
568 unsigned int i;
569
570 for (i = 0; i < num; i++) {
571 if (freqs[i] == freq)
572 break;
573 }
574 if (i == 0 || i >= num)
575 return;
576 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
577 freqs[0] = freq;
578}
579
580
581static int dpp_channel_intersect(struct dpp_authentication *auth,
582 struct hostapd_hw_modes *own_modes,
583 u16 num_modes)
584{
585 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
586 unsigned int i, freq;
587
588 for (i = 0; i < peer_bi->num_freq; i++) {
589 freq = peer_bi->freq[i];
590 if (freq_included(auth->freq, auth->num_freq, freq))
591 continue;
592 if (dpp_channel_ok_init(own_modes, num_modes, freq))
593 auth->freq[auth->num_freq++] = freq;
594 }
595 if (!auth->num_freq) {
596 wpa_printf(MSG_INFO,
597 "DPP: No available channels for initiating DPP Authentication");
598 return -1;
599 }
600 auth->curr_freq = auth->freq[0];
601 return 0;
602}
603
604
605static int dpp_channel_local_list(struct dpp_authentication *auth,
606 struct hostapd_hw_modes *own_modes,
607 u16 num_modes)
608{
609 u16 m;
610 int c, flag;
611 unsigned int freq;
612
613 auth->num_freq = 0;
614
615 if (!own_modes || !num_modes) {
616 auth->freq[0] = 2412;
617 auth->freq[1] = 2437;
618 auth->freq[2] = 2462;
619 auth->num_freq = 3;
620 return 0;
621 }
622
623 for (m = 0; m < num_modes; m++) {
624 for (c = 0; c < own_modes[m].num_channels; c++) {
625 freq = own_modes[m].channels[c].freq;
626 flag = own_modes[m].channels[c].flag;
627 if (flag & (HOSTAPD_CHAN_DISABLED |
628 HOSTAPD_CHAN_NO_IR |
629 HOSTAPD_CHAN_RADAR))
630 continue;
631 if (freq_included(auth->freq, auth->num_freq, freq))
632 continue;
633 auth->freq[auth->num_freq++] = freq;
634 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
635 m = num_modes;
636 break;
637 }
638 }
639 }
640
641 return auth->num_freq == 0 ? -1 : 0;
642}
643
644
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700645int dpp_prepare_channel_list(struct dpp_authentication *auth,
646 unsigned int neg_freq,
647 struct hostapd_hw_modes *own_modes, u16 num_modes)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700648{
649 int res;
650 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
651 unsigned int i;
652
Hai Shalomfdcde762020-04-02 11:19:20 -0700653 if (!own_modes) {
654 if (!neg_freq)
655 return -1;
656 auth->num_freq = 1;
657 auth->freq[0] = neg_freq;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700658 auth->curr_freq = neg_freq;
Hai Shalomfdcde762020-04-02 11:19:20 -0700659 return 0;
660 }
661
Roshan Pius3a1667e2018-07-03 15:17:14 -0700662 if (auth->peer_bi->num_freq > 0)
663 res = dpp_channel_intersect(auth, own_modes, num_modes);
664 else
665 res = dpp_channel_local_list(auth, own_modes, num_modes);
666 if (res < 0)
667 return res;
668
669 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
670 * likely channels first. */
671 freq_to_start(auth->freq, auth->num_freq, 2462);
672 freq_to_start(auth->freq, auth->num_freq, 2412);
673 freq_to_start(auth->freq, auth->num_freq, 2437);
674
675 auth->freq_idx = 0;
676 auth->curr_freq = auth->freq[0];
677
678 pos = freqs;
679 end = pos + sizeof(freqs);
680 for (i = 0; i < auth->num_freq; i++) {
681 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
682 if (os_snprintf_error(end - pos, res))
683 break;
684 pos += res;
685 }
686 *pos = '\0';
687 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
688 freqs);
689
690 return 0;
691}
692
693
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700694int dpp_gen_uri(struct dpp_bootstrap_info *bi)
Hai Shalomfdcde762020-04-02 11:19:20 -0700695{
696 char macstr[ETH_ALEN * 2 + 10];
697 size_t len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700698 char supp_curves[10];
Sunil8cd6f4d2022-06-28 18:40:46 +0000699 char host[100];
Hai Shalomfdcde762020-04-02 11:19:20 -0700700
701 len = 4; /* "DPP:" */
702 if (bi->chan)
703 len += 3 + os_strlen(bi->chan); /* C:...; */
704 if (is_zero_ether_addr(bi->mac_addr))
705 macstr[0] = '\0';
706 else
707 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
708 MAC2STR(bi->mac_addr));
709 len += os_strlen(macstr); /* M:...; */
710 if (bi->info)
711 len += 3 + os_strlen(bi->info); /* I:...; */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700712#ifdef CONFIG_DPP2
713 len += 4; /* V:2; */
714#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700715 len += 4 + os_strlen(bi->pk); /* K:...;; */
716
Sunil Ravia04bd252022-05-02 22:54:18 -0700717 if (bi->supported_curves) {
718 u8 val = bi->supported_curves;
719
720 if (val & 0xf0) {
721 val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
722 len += os_snprintf(supp_curves, sizeof(supp_curves),
723 "B:%02x;", val);
724 } else {
725 len += os_snprintf(supp_curves, sizeof(supp_curves),
726 "B:%x;", val);
727 }
728 } else {
729 supp_curves[0] = '\0';
730 }
731
Sunil8cd6f4d2022-06-28 18:40:46 +0000732 host[0] = '\0';
733 if (bi->host) {
734 char buf[100];
735 const char *addr;
736
737 addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
738 if (!addr)
739 return -1;
740 if (bi->port == DPP_TCP_PORT)
741 len += os_snprintf(host, sizeof(host), "H:%s;", addr);
742 else if (bi->host->af == AF_INET)
743 len += os_snprintf(host, sizeof(host), "H:%s:%u;",
744 addr, bi->port);
745 else
746 len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
747 addr, bi->port);
748 }
749
Hai Shalomfdcde762020-04-02 11:19:20 -0700750 os_free(bi->uri);
751 bi->uri = os_malloc(len + 1);
752 if (!bi->uri)
753 return -1;
Sunil8cd6f4d2022-06-28 18:40:46 +0000754 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
Hai Shalomfdcde762020-04-02 11:19:20 -0700755 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
756 bi->chan ? ";" : "",
757 macstr,
758 bi->info ? "I:" : "", bi->info ? bi->info : "",
759 bi->info ? ";" : "",
Hai Shaloma20dcd72022-02-04 13:43:00 -0800760 DPP_VERSION == 3 ? "V:3;" :
761 (DPP_VERSION == 2 ? "V:2;" : ""),
Sunil Ravia04bd252022-05-02 22:54:18 -0700762 supp_curves,
Sunil8cd6f4d2022-06-28 18:40:46 +0000763 host,
Hai Shalomfdcde762020-04-02 11:19:20 -0700764 bi->pk);
765 return 0;
766}
767
768
Hai Shalomfdcde762020-04-02 11:19:20 -0700769struct dpp_authentication *
770dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
771{
772 struct dpp_authentication *auth;
773
774 auth = os_zalloc(sizeof(*auth));
775 if (!auth)
776 return NULL;
777 auth->global = dpp;
778 auth->msg_ctx = msg_ctx;
779 auth->conf_resp_status = 255;
780 return auth;
781}
782
783
Hai Shalom021b0b52019-04-10 11:17:58 -0700784static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
785 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700786{
787 size_t nonce_len;
788 size_t json_len, clear_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700789 struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700790 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700791 size_t attr_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700792#ifdef CONFIG_DPP3
793 u8 auth_i[DPP_MAX_HASH_LEN];
794#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700795
796 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
797
798 nonce_len = auth->curve->nonce_len;
799 if (random_get_bytes(auth->e_nonce, nonce_len)) {
800 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
801 goto fail;
802 }
803 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
804 json_len = os_strlen(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700805 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700806
807 /* { E-nonce, configAttrib }ke */
808 clear_len = 4 + nonce_len + 4 + json_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700809#ifdef CONFIG_DPP3
810 if (auth->waiting_new_key) {
811 pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
812 if (!pe)
813 goto fail;
814 clear_len += 4 + wpabuf_len(pe);
815
816 if (dpp_derive_auth_i(auth, auth_i) < 0)
817 goto fail;
818 clear_len += 4 + auth->curve->hash_len;
819 }
820#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700821 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700822 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
823#ifdef CONFIG_TESTING_OPTIONS
824 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
825 attr_len += 5;
826#endif /* CONFIG_TESTING_OPTIONS */
827 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700828 if (!clear || !msg)
829 goto fail;
830
Roshan Pius3a1667e2018-07-03 15:17:14 -0700831#ifdef CONFIG_TESTING_OPTIONS
832 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
833 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
834 goto skip_e_nonce;
835 }
836 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
837 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
838 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
839 wpabuf_put_le16(clear, nonce_len - 1);
840 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
841 goto skip_e_nonce;
842 }
843 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
844 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
845 goto skip_wrapped_data;
846 }
847#endif /* CONFIG_TESTING_OPTIONS */
848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700849 /* E-nonce */
850 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
851 wpabuf_put_le16(clear, nonce_len);
852 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
853
Roshan Pius3a1667e2018-07-03 15:17:14 -0700854#ifdef CONFIG_TESTING_OPTIONS
855skip_e_nonce:
856 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
857 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
858 goto skip_conf_attr_obj;
859 }
860#endif /* CONFIG_TESTING_OPTIONS */
861
Sunil Ravia04bd252022-05-02 22:54:18 -0700862#ifdef CONFIG_DPP3
863 if (pe) {
864 wpa_printf(MSG_DEBUG, "DPP: Pe");
865 wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
866 wpabuf_put_le16(clear, wpabuf_len(pe));
867 wpabuf_put_buf(clear, pe);
868 }
869 if (auth->waiting_new_key) {
870 wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
871 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
872 wpabuf_put_le16(clear, auth->curve->hash_len);
873 wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
874 }
875#endif /* CONFIG_DPP3 */
876
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700877 /* configAttrib */
878 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
879 wpabuf_put_le16(clear, json_len);
880 wpabuf_put_data(clear, json, json_len);
881
Roshan Pius3a1667e2018-07-03 15:17:14 -0700882#ifdef CONFIG_TESTING_OPTIONS
883skip_conf_attr_obj:
884#endif /* CONFIG_TESTING_OPTIONS */
885
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700886 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
887 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
888 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
889
890 /* No AES-SIV AD */
891 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
892 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
893 wpabuf_head(clear), wpabuf_len(clear),
894 0, NULL, NULL, wrapped) < 0)
895 goto fail;
896 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
897 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
898
Roshan Pius3a1667e2018-07-03 15:17:14 -0700899#ifdef CONFIG_TESTING_OPTIONS
900 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
901 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
902 dpp_build_attr_status(msg, DPP_STATUS_OK);
903 }
904skip_wrapped_data:
905#endif /* CONFIG_TESTING_OPTIONS */
906
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700907 wpa_hexdump_buf(MSG_DEBUG,
908 "DPP: Configuration Request frame attributes", msg);
Sunil Ravia04bd252022-05-02 22:54:18 -0700909out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700910 wpabuf_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -0700911 wpabuf_free(pe);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700912 return msg;
913
914fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700915 wpabuf_free(msg);
Sunil Ravia04bd252022-05-02 22:54:18 -0700916 msg = NULL;
917 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700918}
919
920
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700921void dpp_write_adv_proto(struct wpabuf *buf)
Hai Shalom021b0b52019-04-10 11:17:58 -0700922{
923 /* Advertisement Protocol IE */
924 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
925 wpabuf_put_u8(buf, 8); /* Length */
926 wpabuf_put_u8(buf, 0x7f);
927 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
928 wpabuf_put_u8(buf, 5);
929 wpabuf_put_be24(buf, OUI_WFA);
930 wpabuf_put_u8(buf, DPP_OUI_TYPE);
931 wpabuf_put_u8(buf, 0x01);
932}
933
934
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700935void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
Hai Shalom021b0b52019-04-10 11:17:58 -0700936{
937 /* GAS Query */
938 wpabuf_put_le16(buf, wpabuf_len(query));
939 wpabuf_put_buf(buf, query);
940}
941
942
943struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
944 const char *json)
945{
946 struct wpabuf *buf, *conf_req;
947
948 conf_req = dpp_build_conf_req_attr(auth, json);
949 if (!conf_req) {
950 wpa_printf(MSG_DEBUG,
951 "DPP: No configuration request data available");
952 return NULL;
953 }
954
955 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
956 if (!buf) {
957 wpabuf_free(conf_req);
958 return NULL;
959 }
960
961 dpp_write_adv_proto(buf);
962 dpp_write_gas_query(buf, conf_req);
963 wpabuf_free(conf_req);
964 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
965
966 return buf;
967}
968
969
Hai Shalomc3565922019-10-28 11:58:20 -0700970struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800971 const char *name,
972 enum dpp_netrole netrole,
Sunil Ravi89eba102022-09-13 21:04:37 -0700973 const char *mud_url, int *opclasses,
974 const char *extra_name,
975 const char *extra_value)
Hai Shalomc3565922019-10-28 11:58:20 -0700976{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800977 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -0700978 const char *tech = "infra";
979 const char *dpp_name;
Sunil Ravia04bd252022-05-02 22:54:18 -0700980 struct wpabuf *buf = NULL, *json = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700981 char *csr = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700982
983#ifdef CONFIG_TESTING_OPTIONS
984 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
985 static const char *bogus_tech = "knfra";
986
987 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
988 tech = bogus_tech;
989 }
990#endif /* CONFIG_TESTING_OPTIONS */
991
992 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800993 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -0700994
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800995 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -0700996 if (mud_url && mud_url[0])
997 len += 10 + os_strlen(mud_url);
Sunil Ravi89eba102022-09-13 21:04:37 -0700998 if (extra_name && extra_value && extra_name[0] && extra_value[0])
999 len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
Hai Shalom899fcc72020-10-19 14:38:18 -07001000#ifdef CONFIG_DPP2
1001 if (auth->csr) {
1002 size_t csr_len;
1003
1004 csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1005 wpabuf_len(auth->csr), &csr_len);
1006 if (!csr)
Sunil Ravia04bd252022-05-02 22:54:18 -07001007 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07001008 len += 30 + csr_len;
1009 }
1010#endif /* CONFIG_DPP2 */
Hai Shalomc3565922019-10-28 11:58:20 -07001011 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001012 if (!json)
Sunil Ravia04bd252022-05-02 22:54:18 -07001013 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001014
1015 json_start_object(json, NULL);
Sunil Ravia04bd252022-05-02 22:54:18 -07001016 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1017 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001018 json_value_sep(json);
1019 json_add_string(json, "wi-fi_tech", tech);
1020 json_value_sep(json);
1021 json_add_string(json, "netRole", dpp_netrole_str(netrole));
1022 if (mud_url && mud_url[0]) {
1023 json_value_sep(json);
1024 json_add_string(json, "mudurl", mud_url);
1025 }
Hai Shalomc3565922019-10-28 11:58:20 -07001026 if (opclasses) {
1027 int i;
1028
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001029 json_value_sep(json);
1030 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -07001031 for (i = 0; opclasses[i]; i++)
1032 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001033 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001034 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001035 if (csr) {
1036 json_value_sep(json);
1037 json_add_string(json, "pkcs10", csr);
1038 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00001039#ifdef CONFIG_DPP3
1040 json_value_sep(json);
1041 json_add_int(json, "capabilities", DPP_ENROLLEE_CAPAB_SAE_PW_ID);
1042#endif /* CONFIG_DPP3 */
Sunil Ravi89eba102022-09-13 21:04:37 -07001043 if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1044 json_value_sep(json);
1045 wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1046 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001047 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001048
1049 buf = dpp_build_conf_req(auth, wpabuf_head(json));
Sunil Ravia04bd252022-05-02 22:54:18 -07001050fail:
Hai Shalomc3565922019-10-28 11:58:20 -07001051 wpabuf_free(json);
Hai Shalom899fcc72020-10-19 14:38:18 -07001052 os_free(csr);
Hai Shalomc3565922019-10-28 11:58:20 -07001053
1054 return buf;
1055}
1056
1057
Hai Shalom021b0b52019-04-10 11:17:58 -07001058static int bin_str_eq(const char *val, size_t len, const char *cmp)
1059{
1060 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1061}
1062
1063
1064struct dpp_configuration * dpp_configuration_alloc(const char *type)
1065{
1066 struct dpp_configuration *conf;
1067 const char *end;
1068 size_t len;
1069
1070 conf = os_zalloc(sizeof(*conf));
1071 if (!conf)
1072 goto fail;
1073
1074 end = os_strchr(type, ' ');
1075 if (end)
1076 len = end - type;
1077 else
1078 len = os_strlen(type);
1079
1080 if (bin_str_eq(type, len, "psk"))
1081 conf->akm = DPP_AKM_PSK;
1082 else if (bin_str_eq(type, len, "sae"))
1083 conf->akm = DPP_AKM_SAE;
1084 else if (bin_str_eq(type, len, "psk-sae") ||
1085 bin_str_eq(type, len, "psk+sae"))
1086 conf->akm = DPP_AKM_PSK_SAE;
1087 else if (bin_str_eq(type, len, "sae-dpp") ||
1088 bin_str_eq(type, len, "dpp+sae"))
1089 conf->akm = DPP_AKM_SAE_DPP;
1090 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1091 bin_str_eq(type, len, "dpp+psk+sae"))
1092 conf->akm = DPP_AKM_PSK_SAE_DPP;
1093 else if (bin_str_eq(type, len, "dpp"))
1094 conf->akm = DPP_AKM_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07001095 else if (bin_str_eq(type, len, "dot1x"))
1096 conf->akm = DPP_AKM_DOT1X;
Hai Shalom021b0b52019-04-10 11:17:58 -07001097 else
1098 goto fail;
1099
1100 return conf;
1101fail:
1102 dpp_configuration_free(conf);
1103 return NULL;
1104}
1105
1106
1107int dpp_akm_psk(enum dpp_akm akm)
1108{
1109 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1110 akm == DPP_AKM_PSK_SAE_DPP;
1111}
1112
1113
1114int dpp_akm_sae(enum dpp_akm akm)
1115{
1116 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1117 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1118}
1119
1120
1121int dpp_akm_legacy(enum dpp_akm akm)
1122{
1123 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1124 akm == DPP_AKM_SAE;
1125}
1126
1127
1128int dpp_akm_dpp(enum dpp_akm akm)
1129{
1130 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1131 akm == DPP_AKM_PSK_SAE_DPP;
1132}
1133
1134
1135int dpp_akm_ver2(enum dpp_akm akm)
1136{
1137 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1138}
1139
1140
1141int dpp_configuration_valid(const struct dpp_configuration *conf)
1142{
1143 if (conf->ssid_len == 0)
1144 return 0;
1145 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1146 return 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001147 if (dpp_akm_psk(conf->akm) && conf->passphrase) {
1148 size_t len = os_strlen(conf->passphrase);
1149
1150 if (len > 63 || len < 8)
1151 return 0;
1152 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001153 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1154 return 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001155#ifdef CONFIG_DPP3
1156 if (conf->idpass && (!conf->passphrase || !dpp_akm_sae(conf->akm)))
1157 return 0;
1158#endif /* CONFIG_DPP3 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001159 return 1;
1160}
1161
1162
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001163void dpp_configuration_free(struct dpp_configuration *conf)
1164{
1165 if (!conf)
1166 return;
1167 str_clear_free(conf->passphrase);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001168#ifdef CONFIG_DPP3
1169 os_free(conf->idpass);
1170#endif /* CONFIG_DPP3 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07001171 os_free(conf->group_id);
Hai Shalom899fcc72020-10-19 14:38:18 -07001172 os_free(conf->csrattrs);
Sunil Ravi89eba102022-09-13 21:04:37 -07001173 os_free(conf->extra_name);
1174 os_free(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001175 bin_clear_free(conf, sizeof(*conf));
1176}
1177
1178
Hai Shalomc3565922019-10-28 11:58:20 -07001179static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1180 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07001181{
1182 const char *pos, *end;
1183 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1184 struct dpp_configuration *conf = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001185 size_t len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001186
1187 pos = os_strstr(cmd, " conf=sta-");
1188 if (pos) {
1189 conf_sta = dpp_configuration_alloc(pos + 10);
1190 if (!conf_sta)
1191 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001192 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07001193 conf = conf_sta;
1194 }
1195
1196 pos = os_strstr(cmd, " conf=ap-");
1197 if (pos) {
1198 conf_ap = dpp_configuration_alloc(pos + 9);
1199 if (!conf_ap)
1200 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001201 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07001202 conf = conf_ap;
1203 }
1204
Hai Shalomfdcde762020-04-02 11:19:20 -07001205 pos = os_strstr(cmd, " conf=configurator");
1206 if (pos)
1207 auth->provision_configurator = 1;
1208
Hai Shalom021b0b52019-04-10 11:17:58 -07001209 if (!conf)
1210 return 0;
1211
1212 pos = os_strstr(cmd, " ssid=");
1213 if (pos) {
1214 pos += 6;
1215 end = os_strchr(pos, ' ');
1216 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1217 conf->ssid_len /= 2;
1218 if (conf->ssid_len > sizeof(conf->ssid) ||
1219 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1220 goto fail;
1221 } else {
1222#ifdef CONFIG_TESTING_OPTIONS
1223 /* use a default SSID for legacy testing reasons */
1224 os_memcpy(conf->ssid, "test", 4);
1225 conf->ssid_len = 4;
1226#else /* CONFIG_TESTING_OPTIONS */
1227 goto fail;
1228#endif /* CONFIG_TESTING_OPTIONS */
1229 }
1230
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001231 pos = os_strstr(cmd, " ssid_charset=");
1232 if (pos) {
1233 if (conf_ap) {
1234 wpa_printf(MSG_INFO,
1235 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1236 goto fail;
1237 }
1238 conf->ssid_charset = atoi(pos + 14);
1239 }
1240
Hai Shalom021b0b52019-04-10 11:17:58 -07001241 pos = os_strstr(cmd, " pass=");
1242 if (pos) {
1243 size_t pass_len;
1244
1245 pos += 6;
1246 end = os_strchr(pos, ' ');
1247 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1248 pass_len /= 2;
Hai Shalom021b0b52019-04-10 11:17:58 -07001249 conf->passphrase = os_zalloc(pass_len + 1);
1250 if (!conf->passphrase ||
1251 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1252 goto fail;
1253 }
1254
Sunil Ravic0f5d412024-09-11 22:12:49 +00001255#ifdef CONFIG_DPP3
1256 pos = os_strstr(cmd, " idpass=");
1257 if (pos) {
1258 size_t idpass_len;
1259
1260 pos += 8;
1261 end = os_strchr(pos, ' ');
1262 idpass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1263 idpass_len /= 2;
1264 conf->idpass = os_zalloc(idpass_len + 1);
1265 if (!conf->idpass ||
1266 hexstr2bin(pos, (u8 *) conf->idpass, idpass_len) < 0)
1267 goto fail;
1268 }
1269#endif /* CONFIG_DPP3 */
1270
Hai Shalom021b0b52019-04-10 11:17:58 -07001271 pos = os_strstr(cmd, " psk=");
1272 if (pos) {
1273 pos += 5;
1274 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1275 goto fail;
1276 conf->psk_set = 1;
1277 }
1278
1279 pos = os_strstr(cmd, " group_id=");
1280 if (pos) {
1281 size_t group_id_len;
1282
1283 pos += 10;
1284 end = os_strchr(pos, ' ');
1285 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1286 conf->group_id = os_malloc(group_id_len + 1);
1287 if (!conf->group_id)
1288 goto fail;
1289 os_memcpy(conf->group_id, pos, group_id_len);
1290 conf->group_id[group_id_len] = '\0';
1291 }
1292
1293 pos = os_strstr(cmd, " expiry=");
1294 if (pos) {
1295 long int val;
1296
1297 pos += 8;
1298 val = strtol(pos, NULL, 0);
1299 if (val <= 0)
1300 goto fail;
1301 conf->netaccesskey_expiry = val;
1302 }
1303
Hai Shalom899fcc72020-10-19 14:38:18 -07001304 pos = os_strstr(cmd, " csrattrs=");
1305 if (pos) {
1306 pos += 10;
1307 end = os_strchr(pos, ' ');
1308 len = end ? (size_t) (end - pos) : os_strlen(pos);
1309 conf->csrattrs = os_zalloc(len + 1);
1310 if (!conf->csrattrs)
1311 goto fail;
1312 os_memcpy(conf->csrattrs, pos, len);
1313 }
1314
Sunil Ravi89eba102022-09-13 21:04:37 -07001315 pos = os_strstr(cmd, " conf_extra_name=");
1316 if (pos) {
1317 pos += 17;
1318 end = os_strchr(pos, ' ');
1319 len = end ? (size_t) (end - pos) : os_strlen(pos);
1320 conf->extra_name = os_zalloc(len + 1);
1321 if (!conf->extra_name)
1322 goto fail;
1323 os_memcpy(conf->extra_name, pos, len);
1324 }
1325
1326 pos = os_strstr(cmd, " conf_extra_value=");
1327 if (pos) {
1328 pos += 18;
1329 end = os_strchr(pos, ' ');
1330 len = end ? (size_t) (end - pos) : os_strlen(pos);
1331 len /= 2;
1332 conf->extra_value = os_zalloc(len + 1);
1333 if (!conf->extra_value ||
1334 hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1335 goto fail;
1336 }
1337
Hai Shalom021b0b52019-04-10 11:17:58 -07001338 if (!dpp_configuration_valid(conf))
1339 goto fail;
1340
Hai Shalomc3565922019-10-28 11:58:20 -07001341 if (idx == 0) {
1342 auth->conf_sta = conf_sta;
1343 auth->conf_ap = conf_ap;
1344 } else if (idx == 1) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001345 if (!auth->conf_sta)
1346 auth->conf_sta = conf_sta;
1347 else
1348 auth->conf2_sta = conf_sta;
1349 if (!auth->conf_ap)
1350 auth->conf_ap = conf_ap;
1351 else
1352 auth->conf2_ap = conf_ap;
Hai Shalomc3565922019-10-28 11:58:20 -07001353 } else {
1354 goto fail;
1355 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001356 return 0;
1357
1358fail:
1359 dpp_configuration_free(conf_sta);
1360 dpp_configuration_free(conf_ap);
1361 return -1;
1362}
1363
1364
Hai Shalomc3565922019-10-28 11:58:20 -07001365static int dpp_configuration_parse(struct dpp_authentication *auth,
1366 const char *cmd)
1367{
1368 const char *pos;
1369 char *tmp;
1370 size_t len;
1371 int res;
1372
1373 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1374 if (!pos)
1375 return dpp_configuration_parse_helper(auth, cmd, 0);
1376
1377 len = pos - cmd;
1378 tmp = os_malloc(len + 1);
1379 if (!tmp)
1380 goto fail;
1381 os_memcpy(tmp, cmd, len);
1382 tmp[len] = '\0';
Sunil Raviaf8751c2023-03-29 11:35:17 -07001383 res = dpp_configuration_parse_helper(auth, tmp, 0);
Hai Shalomc3565922019-10-28 11:58:20 -07001384 str_clear_free(tmp);
1385 if (res)
1386 goto fail;
1387 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1388 if (res)
1389 goto fail;
1390 return 0;
1391fail:
1392 dpp_configuration_free(auth->conf_sta);
1393 dpp_configuration_free(auth->conf2_sta);
1394 dpp_configuration_free(auth->conf_ap);
1395 dpp_configuration_free(auth->conf2_ap);
1396 return -1;
1397}
1398
1399
Hai Shalom021b0b52019-04-10 11:17:58 -07001400static struct dpp_configurator *
1401dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1402{
1403 struct dpp_configurator *conf;
1404
1405 if (!dpp)
1406 return NULL;
1407
1408 dl_list_for_each(conf, &dpp->configurator,
1409 struct dpp_configurator, list) {
1410 if (conf->id == id)
1411 return conf;
1412 }
1413 return NULL;
1414}
1415
1416
Hai Shalomfdcde762020-04-02 11:19:20 -07001417int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07001418{
1419 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07001420 char *tmp = NULL;
1421 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07001422
Hai Shalomfdcde762020-04-02 11:19:20 -07001423 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07001424 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07001425 auth->configurator_set = 1;
1426
1427 if (cmd[0] != ' ') {
1428 size_t len;
1429
1430 len = os_strlen(cmd);
1431 tmp = os_malloc(len + 2);
1432 if (!tmp)
1433 goto fail;
1434 tmp[0] = ' ';
1435 os_memcpy(tmp + 1, cmd, len + 1);
1436 cmd = tmp;
1437 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001438
1439 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1440
Hai Shaloma20dcd72022-02-04 13:43:00 -08001441 if (os_strstr(cmd, " conf=query")) {
1442 auth->configurator_set = 0;
1443 auth->use_config_query = true;
1444 ret = 0;
1445 goto fail;
1446 }
1447
Hai Shalom021b0b52019-04-10 11:17:58 -07001448 pos = os_strstr(cmd, " configurator=");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001449 if (!auth->conf && pos) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001450 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07001451 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07001452 if (!auth->conf) {
1453 wpa_printf(MSG_INFO,
1454 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07001455 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001456 }
1457 }
1458
Hai Shalomc3565922019-10-28 11:58:20 -07001459 pos = os_strstr(cmd, " conn_status=");
1460 if (pos) {
1461 pos += 13;
1462 auth->send_conn_status = atoi(pos);
1463 }
1464
1465 pos = os_strstr(cmd, " akm_use_selector=");
1466 if (pos) {
1467 pos += 18;
1468 auth->akm_use_selector = atoi(pos);
1469 }
1470
Hai Shalom021b0b52019-04-10 11:17:58 -07001471 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001472 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07001473 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07001474 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001475 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001476 ret = 0;
1477fail:
1478 os_free(tmp);
1479 return ret;
1480}
1481
1482
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001483void dpp_auth_deinit(struct dpp_authentication *auth)
1484{
Hai Shalomc3565922019-10-28 11:58:20 -07001485 unsigned int i;
1486
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001487 if (!auth)
1488 return;
1489 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07001490 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001491 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001492 dpp_configuration_free(auth->conf2_sta);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001493 crypto_ec_key_deinit(auth->own_protocol_key);
1494 crypto_ec_key_deinit(auth->peer_protocol_key);
1495 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001496 wpabuf_free(auth->req_msg);
1497 wpabuf_free(auth->resp_msg);
1498 wpabuf_free(auth->conf_req);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001499 wpabuf_free(auth->reconfig_req_msg);
1500 wpabuf_free(auth->reconfig_resp_msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001501 for (i = 0; i < auth->num_conf_obj; i++) {
1502 struct dpp_config_obj *conf = &auth->conf_obj[i];
1503
1504 os_free(conf->connector);
1505 wpabuf_free(conf->c_sign_key);
Hai Shalom899fcc72020-10-19 14:38:18 -07001506 wpabuf_free(conf->certbag);
1507 wpabuf_free(conf->certs);
1508 wpabuf_free(conf->cacert);
1509 os_free(conf->server_name);
1510 wpabuf_free(conf->pp_key);
Hai Shalomc3565922019-10-28 11:58:20 -07001511 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001512#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -07001513 dpp_free_asymmetric_key(auth->conf_key_pkg);
Hai Shalom899fcc72020-10-19 14:38:18 -07001514 os_free(auth->csrattrs);
1515 wpabuf_free(auth->csr);
1516 wpabuf_free(auth->priv_key);
1517 wpabuf_free(auth->cacert);
1518 wpabuf_free(auth->certbag);
1519 os_free(auth->trusted_eap_server_name);
1520 wpabuf_free(auth->conf_resp_tcp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001521#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001522 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001523 dpp_bootstrap_info_free(auth->tmp_own_bi);
Hai Shalom899fcc72020-10-19 14:38:18 -07001524 if (auth->tmp_peer_bi) {
1525 dl_list_del(&auth->tmp_peer_bi->list);
1526 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1527 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001528 os_free(auth->e_name);
1529 os_free(auth->e_mud_url);
1530 os_free(auth->e_band_support);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001531#ifdef CONFIG_TESTING_OPTIONS
1532 os_free(auth->config_obj_override);
1533 os_free(auth->discovery_override);
1534 os_free(auth->groups_override);
1535#endif /* CONFIG_TESTING_OPTIONS */
1536 bin_clear_free(auth, sizeof(*auth));
1537}
1538
1539
1540static struct wpabuf *
1541dpp_build_conf_start(struct dpp_authentication *auth,
1542 struct dpp_configuration *conf, size_t tailroom)
1543{
1544 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001545
1546#ifdef CONFIG_TESTING_OPTIONS
1547 if (auth->discovery_override)
1548 tailroom += os_strlen(auth->discovery_override);
1549#endif /* CONFIG_TESTING_OPTIONS */
1550
1551 buf = wpabuf_alloc(200 + tailroom);
1552 if (!buf)
1553 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001554 json_start_object(buf, NULL);
1555 json_add_string(buf, "wi-fi_tech", "infra");
1556 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001557#ifdef CONFIG_TESTING_OPTIONS
1558 if (auth->discovery_override) {
1559 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1560 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001561 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001562 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001563 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001564 return buf;
1565 }
1566#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001567 json_start_object(buf, "discovery");
1568 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1569 json_add_string_escape(buf, "ssid", conf->ssid,
1570 conf->ssid_len) < 0) ||
1571 ((conf->ssid_charset && auth->peer_version >= 2) &&
1572 json_add_base64url(buf, "ssid64", conf->ssid,
1573 conf->ssid_len) < 0)) {
1574 wpabuf_free(buf);
1575 return NULL;
1576 }
1577 if (conf->ssid_charset > 0) {
1578 json_value_sep(buf);
1579 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1580 }
1581 json_end_object(buf);
1582 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001583
1584 return buf;
1585}
1586
1587
Hai Shaloma20dcd72022-02-04 13:43:00 -08001588int dpp_build_jwk(struct wpabuf *buf, const char *name,
1589 struct crypto_ec_key *key, const char *kid,
1590 const struct dpp_curve_params *curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001591{
1592 struct wpabuf *pub;
1593 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001594 int ret = -1;
1595
Hai Shaloma20dcd72022-02-04 13:43:00 -08001596 pub = crypto_ec_key_get_pubkey_point(key, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001597 if (!pub)
1598 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001599
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001600 json_start_object(buf, name);
1601 json_add_string(buf, "kty", "EC");
1602 json_value_sep(buf);
1603 json_add_string(buf, "crv", curve->jwk_crv);
1604 json_value_sep(buf);
1605 pos = wpabuf_head(pub);
1606 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1607 goto fail;
1608 json_value_sep(buf);
1609 pos += curve->prime_len;
1610 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1611 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001612 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001613 json_value_sep(buf);
1614 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001615 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001616 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001617 ret = 0;
1618fail:
1619 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001620 return ret;
1621}
1622
1623
Hai Shalom021b0b52019-04-10 11:17:58 -07001624static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1625 struct dpp_configuration *conf)
1626{
1627 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001628 json_add_string_escape(buf, "pass", conf->passphrase,
1629 os_strlen(conf->passphrase));
Sunil Ravic0f5d412024-09-11 22:12:49 +00001630#ifdef CONFIG_DPP3
1631 if (conf->idpass) {
1632 json_value_sep(buf);
1633 json_add_string_escape(buf, "idpass", conf->idpass,
1634 os_strlen(conf->idpass));
1635 }
1636#endif /* CONFIG_DPP3 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001637 } else if (conf->psk_set) {
1638 char psk[2 * sizeof(conf->psk) + 1];
1639
1640 wpa_snprintf_hex(psk, sizeof(psk),
1641 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001642 json_add_string(buf, "psk_hex", psk);
1643 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07001644 }
1645}
1646
1647
Hai Shaloma20dcd72022-02-04 13:43:00 -08001648const char * dpp_netrole_str(enum dpp_netrole netrole)
Hai Shalomc3565922019-10-28 11:58:20 -07001649{
1650 switch (netrole) {
1651 case DPP_NETROLE_STA:
1652 return "sta";
1653 case DPP_NETROLE_AP:
1654 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001655 case DPP_NETROLE_CONFIGURATOR:
1656 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07001657 default:
1658 return "??";
1659 }
1660}
1661
1662
Sunil Ravi89eba102022-09-13 21:04:37 -07001663static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1664{
1665 enum dpp_bootstrap_supported_curves idx;
1666
1667 if (!bi || !bi->supported_curves)
1668 return true; /* no support indication available */
1669
1670 if (os_strcmp(curve, "prime256v1") == 0)
1671 idx = DPP_BOOTSTRAP_CURVE_P_256;
1672 else if (os_strcmp(curve, "secp384r1") == 0)
1673 idx = DPP_BOOTSTRAP_CURVE_P_384;
1674 else if (os_strcmp(curve, "secp521r1") == 0)
1675 idx = DPP_BOOTSTRAP_CURVE_P_521;
1676 else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1677 idx = DPP_BOOTSTRAP_CURVE_BP_256;
1678 else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1679 idx = DPP_BOOTSTRAP_CURVE_BP_384;
1680 else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1681 idx = DPP_BOOTSTRAP_CURVE_BP_512;
1682 else
1683 return true;
1684
1685 return bi->supported_curves & BIT(idx);
1686}
1687
1688
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001689static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001690dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001691 struct dpp_configuration *conf)
1692{
1693 struct wpabuf *buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001694 char *signed_conn = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001695 size_t tailroom;
Sunil Ravia04bd252022-05-02 22:54:18 -07001696 const struct dpp_curve_params *curve; /* C-sign-key curve */
1697 const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001698 struct wpabuf *dppcon = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001699 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07001700 int incl_legacy;
1701 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07001702 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001703
1704 if (!auth->conf) {
1705 wpa_printf(MSG_INFO,
1706 "DPP: No configurator specified - cannot generate DPP config object");
1707 goto fail;
1708 }
1709 curve = auth->conf->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001710 if (dpp_akm_dpp(conf->akm) &&
1711 !dpp_supports_curve(curve->name, auth->peer_bi)) {
1712 wpa_printf(MSG_DEBUG,
1713 "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1714 curve->name);
1715 goto fail;
1716 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001717 if (auth->new_curve && auth->new_key_received)
1718 nak_curve = auth->new_curve;
1719 else
1720 nak_curve = auth->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001721 if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1722 wpa_printf(MSG_DEBUG,
1723 "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1724 nak_curve->name);
1725 goto fail;
1726 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001727
Hai Shalom021b0b52019-04-10 11:17:58 -07001728 akm = conf->akm;
1729 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1730 wpa_printf(MSG_DEBUG,
1731 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1732 akm = DPP_AKM_DPP;
1733 }
1734
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001735#ifdef CONFIG_TESTING_OPTIONS
1736 if (auth->groups_override)
1737 extra_len += os_strlen(auth->groups_override);
1738#endif /* CONFIG_TESTING_OPTIONS */
1739
Hai Shalomce48b4a2018-09-05 11:41:35 -07001740 if (conf->group_id)
1741 extra_len += os_strlen(conf->group_id);
1742
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001743 /* Connector (JSON dppCon object) */
Sunil Ravia04bd252022-05-02 22:54:18 -07001744 dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001745 if (!dppcon)
1746 goto fail;
1747#ifdef CONFIG_TESTING_OPTIONS
1748 if (auth->groups_override) {
1749 wpabuf_put_u8(dppcon, '{');
1750 if (auth->groups_override) {
1751 wpa_printf(MSG_DEBUG,
1752 "DPP: TESTING - groups override: '%s'",
1753 auth->groups_override);
1754 wpabuf_put_str(dppcon, "\"groups\":");
1755 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001756 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001757 }
1758 goto skip_groups;
1759 }
1760#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001761 json_start_object(dppcon, NULL);
1762 json_start_array(dppcon, "groups");
1763 json_start_object(dppcon, NULL);
1764 json_add_string(dppcon, "groupId",
1765 conf->group_id ? conf->group_id : "*");
1766 json_value_sep(dppcon);
1767 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1768 json_end_object(dppcon);
1769 json_end_array(dppcon);
1770 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001771#ifdef CONFIG_TESTING_OPTIONS
1772skip_groups:
1773#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravia04bd252022-05-02 22:54:18 -07001774 if (!auth->peer_protocol_key) {
1775 wpa_printf(MSG_DEBUG,
1776 "DPP: No peer protocol key available to build netAccessKey JWK");
1777 goto fail;
1778 }
1779#ifdef CONFIG_DPP3
1780 if (auth->conf->net_access_key_curve &&
1781 auth->curve != auth->conf->net_access_key_curve &&
1782 !auth->new_key_received) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001783 if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1784 auth->peer_bi)) {
1785 wpa_printf(MSG_DEBUG,
1786 "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1787 auth->conf->net_access_key_curve->name);
1788 goto fail;
1789 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001790 wpa_printf(MSG_DEBUG,
1791 "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1792 auth->curve->name,
1793 auth->conf->net_access_key_curve->name,
1794 auth->waiting_new_key ?
1795 "the required key not received" :
1796 "request a new key");
1797 if (auth->waiting_new_key)
1798 auth->waiting_new_key = false; /* failed */
1799 else
1800 auth->waiting_new_key = true;
1801 goto fail;
1802 }
1803#endif /* CONFIG_DPP3 */
1804 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1805 nak_curve) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001806 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1807 goto fail;
1808 }
1809 if (conf->netaccesskey_expiry) {
1810 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001811 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001812
1813 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1814 wpa_printf(MSG_DEBUG,
1815 "DPP: Failed to generate expiry string");
1816 goto fail;
1817 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001818 os_snprintf(expiry, sizeof(expiry),
1819 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1820 tm.year, tm.month, tm.day,
1821 tm.hour, tm.min, tm.sec);
1822 json_value_sep(dppcon);
1823 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001824 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001825#ifdef CONFIG_DPP3
1826 json_value_sep(dppcon);
1827 json_add_int(dppcon, "version", auth->peer_version);
1828#endif /* CONFIG_DPP3 */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001829 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001830 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1831 (const char *) wpabuf_head(dppcon));
1832
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001833 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1834 if (!signed_conn)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001835 goto fail;
1836
Hai Shalom021b0b52019-04-10 11:17:58 -07001837 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001838 tailroom = 1000;
1839 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001840 tailroom += os_strlen(signed_conn);
Hai Shalom021b0b52019-04-10 11:17:58 -07001841 if (incl_legacy)
1842 tailroom += 1000;
Hai Shalom899fcc72020-10-19 14:38:18 -07001843 if (akm == DPP_AKM_DOT1X) {
1844 if (auth->certbag)
1845 tailroom += 2 * wpabuf_len(auth->certbag);
1846 if (auth->cacert)
1847 tailroom += 2 * wpabuf_len(auth->cacert);
1848 if (auth->trusted_eap_server_name)
1849 tailroom += os_strlen(auth->trusted_eap_server_name);
1850 tailroom += 1000;
1851 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001852 if (conf->extra_name && conf->extra_value)
1853 tailroom += 10 + os_strlen(conf->extra_name) +
1854 os_strlen(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001855 buf = dpp_build_conf_start(auth, conf, tailroom);
1856 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001857 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001858
Hai Shalomc3565922019-10-28 11:58:20 -07001859 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1860 akm_str = dpp_akm_selector_str(akm);
1861 else
1862 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001863 json_start_object(buf, "cred");
1864 json_add_string(buf, "akm", akm_str);
1865 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001866 if (incl_legacy) {
1867 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001868 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001869 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001870 if (akm == DPP_AKM_DOT1X) {
1871 json_start_object(buf, "entCreds");
1872 if (!auth->certbag)
1873 goto fail;
1874 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1875 wpabuf_len(auth->certbag));
1876 if (auth->cacert) {
1877 json_value_sep(buf);
1878 json_add_base64(buf, "caCert",
1879 wpabuf_head(auth->cacert),
1880 wpabuf_len(auth->cacert));
1881 }
1882 if (auth->trusted_eap_server_name) {
1883 json_value_sep(buf);
1884 json_add_string(buf, "trustedEapServerName",
1885 auth->trusted_eap_server_name);
1886 }
1887 json_value_sep(buf);
1888 json_start_array(buf, "eapMethods");
1889 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1890 json_end_array(buf);
1891 json_end_object(buf);
1892 json_value_sep(buf);
1893 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001894 wpabuf_put_str(buf, "\"signedConnector\":\"");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001895 wpabuf_put_str(buf, signed_conn);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001896 wpabuf_put_str(buf, "\"");
1897 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001898 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1899 curve) < 0) {
1900 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1901 goto fail;
1902 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001903#ifdef CONFIG_DPP2
1904 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1905 json_value_sep(buf);
1906 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1907 curve) < 0) {
1908 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1909 goto fail;
1910 }
1911 }
1912#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001913
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001914 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001915 if (conf->extra_name && conf->extra_value) {
1916 json_value_sep(buf);
1917 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1918 conf->extra_value);
1919 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001920 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001921
1922 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1923 wpabuf_head(buf), wpabuf_len(buf));
1924
Sunil Ravia04bd252022-05-02 22:54:18 -07001925#ifdef CONFIG_DPP3
1926 if (!auth->conf->net_access_key_curve) {
1927 /* All netAccessKey values used in the network will have to be
1928 * from the same curve for network introduction to work, so
1929 * hardcode the first used netAccessKey curve for consecutive
1930 * operations if there was no explicit configuration of which
1931 * curve to use. */
1932 wpa_printf(MSG_DEBUG,
1933 "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1934 nak_curve->name);
1935 auth->conf->net_access_key_curve = nak_curve;
1936 }
1937#endif /* CONFIG_DPP3 */
1938
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001939out:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001940 os_free(signed_conn);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001941 wpabuf_free(dppcon);
1942 return buf;
1943fail:
1944 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1945 wpabuf_free(buf);
1946 buf = NULL;
1947 goto out;
1948}
1949
1950
1951static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001952dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001953 struct dpp_configuration *conf)
1954{
1955 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001956 const char *akm_str;
Sunil Ravi89eba102022-09-13 21:04:37 -07001957 size_t len = 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001958
Sunil Ravic0f5d412024-09-11 22:12:49 +00001959
1960#ifdef CONFIG_DPP3
1961 if (conf->idpass &&
1962 !(auth->enrollee_capabilities & DPP_ENROLLEE_CAPAB_SAE_PW_ID)) {
1963 wpa_printf(MSG_DEBUG,
1964 "DPP: Enrollee does not support SAE Password Identifier - cannot generate config object");
1965 return NULL;
1966 }
1967#endif /* CONFIG_DPP3 */
1968
Sunil Ravi89eba102022-09-13 21:04:37 -07001969 if (conf->extra_name && conf->extra_value)
1970 len += 10 + os_strlen(conf->extra_name) +
1971 os_strlen(conf->extra_value);
1972 buf = dpp_build_conf_start(auth, conf, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001973 if (!buf)
1974 return NULL;
1975
Hai Shalomc3565922019-10-28 11:58:20 -07001976 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1977 akm_str = dpp_akm_selector_str(conf->akm);
1978 else
1979 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001980 json_start_object(buf, "cred");
1981 json_add_string(buf, "akm", akm_str);
1982 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001983 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001984 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001985 if (conf->extra_name && conf->extra_value) {
1986 json_value_sep(buf);
1987 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1988 conf->extra_value);
1989 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001990 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001991
1992 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1993 wpabuf_head(buf), wpabuf_len(buf));
1994
1995 return buf;
1996}
1997
1998
Hai Shaloma20dcd72022-02-04 13:43:00 -08001999static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
2000{
2001 struct dpp_bootstrap_info *bi;
2002
2003 if (auth->peer_bi)
2004 return auth->peer_bi->id;
2005 if (auth->tmp_peer_bi)
2006 return auth->tmp_peer_bi->id;
2007
2008 bi = os_zalloc(sizeof(*bi));
2009 if (!bi)
2010 return -1;
2011 bi->id = dpp_next_id(auth->global);
2012 dl_list_add(&auth->global->bootstrap, &bi->list);
2013 auth->tmp_peer_bi = bi;
2014 return bi->id;
2015}
2016
2017
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002018static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002019dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
Hai Shalom899fcc72020-10-19 14:38:18 -07002020 int idx, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002021{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002022 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002023
2024#ifdef CONFIG_TESTING_OPTIONS
2025 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07002026 if (idx != 0)
2027 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002028 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
2029 return wpabuf_alloc_copy(auth->config_obj_override,
2030 os_strlen(auth->config_obj_override));
2031 }
2032#endif /* CONFIG_TESTING_OPTIONS */
2033
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002034 if (idx == 0) {
2035 if (netrole == DPP_NETROLE_STA)
2036 conf = auth->conf_sta;
2037 else if (netrole == DPP_NETROLE_AP)
2038 conf = auth->conf_ap;
2039 } else if (idx == 1) {
2040 if (netrole == DPP_NETROLE_STA)
2041 conf = auth->conf2_sta;
2042 else if (netrole == DPP_NETROLE_AP)
2043 conf = auth->conf2_ap;
2044 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002045 if (!conf) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002046 if (idx == 0) {
2047 if (auth->use_config_query) {
2048 wpa_printf(MSG_DEBUG,
2049 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
2050 dpp_netrole_str(netrole));
2051 auth->waiting_config = true;
2052 dpp_get_peer_bi_id(auth);
2053 return NULL;
2054 }
Hai Shalomc3565922019-10-28 11:58:20 -07002055 wpa_printf(MSG_DEBUG,
2056 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002057 dpp_netrole_str(netrole));
Hai Shaloma20dcd72022-02-04 13:43:00 -08002058 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002059 return NULL;
2060 }
2061
Hai Shalom899fcc72020-10-19 14:38:18 -07002062 if (conf->akm == DPP_AKM_DOT1X) {
2063 if (!auth->conf) {
2064 wpa_printf(MSG_DEBUG,
2065 "DPP: No Configurator data available");
2066 return NULL;
2067 }
2068 if (!cert_req && !auth->certbag) {
2069 wpa_printf(MSG_DEBUG,
2070 "DPP: No certificate data available for dot1x configuration");
2071 return NULL;
2072 }
2073 return dpp_build_conf_obj_dpp(auth, conf);
2074 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002075 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07002076 return dpp_build_conf_obj_dpp(auth, conf);
2077 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002078}
2079
2080
Hai Shalom899fcc72020-10-19 14:38:18 -07002081struct wpabuf *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002082dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Hai Shalom899fcc72020-10-19 14:38:18 -07002083 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002084{
Sunil Ravia04bd252022-05-02 22:54:18 -07002085 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002086 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002087 struct wpabuf *clear = NULL, *msg = NULL;
2088 u8 *wrapped;
2089 const u8 *addr[1];
2090 size_t len[1];
2091 enum dpp_status_error status;
2092
Hai Shalom899fcc72020-10-19 14:38:18 -07002093 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2094 status = auth->force_conf_resp_status;
2095 goto forced_status;
2096 }
2097
Hai Shalomfdcde762020-04-02 11:19:20 -07002098 if (netrole == DPP_NETROLE_CONFIGURATOR) {
2099#ifdef CONFIG_DPP2
2100 env_data = dpp_build_enveloped_data(auth);
2101#endif /* CONFIG_DPP2 */
2102 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002103 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002104 if (conf) {
2105 wpa_hexdump_ascii(MSG_DEBUG,
2106 "DPP: configurationObject JSON",
2107 wpabuf_head(conf), wpabuf_len(conf));
Hai Shalom899fcc72020-10-19 14:38:18 -07002108 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002109 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002110 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002111
Hai Shaloma20dcd72022-02-04 13:43:00 -08002112 if (!conf && auth->waiting_config)
2113 return NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002114 if (conf || env_data)
2115 status = DPP_STATUS_OK;
2116 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2117 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2118 status = DPP_STATUS_CSR_NEEDED;
Sunil Ravia04bd252022-05-02 22:54:18 -07002119#ifdef CONFIG_DPP3
2120 else if (auth->waiting_new_key)
2121 status = DPP_STATUS_NEW_KEY_NEEDED;
2122#endif /* CONFIG_DPP3 */
Hai Shalom899fcc72020-10-19 14:38:18 -07002123 else
2124 status = DPP_STATUS_CONFIGURE_FAILURE;
2125forced_status:
Hai Shalom021b0b52019-04-10 11:17:58 -07002126 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002127
Hai Shalomc3565922019-10-28 11:58:20 -07002128 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002129 clear_len = 4 + e_nonce_len;
2130 if (conf)
2131 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07002132 if (conf2)
2133 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07002134 if (env_data)
2135 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002136 if (auth->peer_version >= 2 && auth->send_conn_status &&
2137 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07002138 clear_len += 4;
Hai Shalom899fcc72020-10-19 14:38:18 -07002139 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2140 auth->conf_sta->csrattrs)
2141 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
Sunil Ravia04bd252022-05-02 22:54:18 -07002142#ifdef CONFIG_DPP3
2143 if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2144 struct crypto_ec_key *new_pc;
2145
2146 clear_len += 6; /* Finite Cyclic Group attribute */
2147
2148 wpa_printf(MSG_DEBUG,
2149 "DPP: Generate a new own protocol key for the curve %s",
2150 auth->conf->net_access_key_curve->name);
2151 new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2152 if (!new_pc) {
2153 wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2154 return NULL;
2155 }
2156 pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2157 if (!pc) {
2158 crypto_ec_key_deinit(new_pc);
2159 return NULL;
2160 }
2161 crypto_ec_key_deinit(auth->own_protocol_key);
2162 auth->own_protocol_key = new_pc;
2163 auth->new_curve = auth->conf->net_access_key_curve;
2164 clear_len += 4 + wpabuf_len(pc);
2165 }
2166#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002167 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002168 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2169#ifdef CONFIG_TESTING_OPTIONS
2170 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2171 attr_len += 5;
2172#endif /* CONFIG_TESTING_OPTIONS */
2173 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002174 if (!clear || !msg)
2175 goto fail;
2176
Roshan Pius3a1667e2018-07-03 15:17:14 -07002177#ifdef CONFIG_TESTING_OPTIONS
2178 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2179 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2180 goto skip_e_nonce;
2181 }
2182 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2183 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2184 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2185 wpabuf_put_le16(clear, e_nonce_len);
2186 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2187 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2188 goto skip_e_nonce;
2189 }
2190 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2191 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2192 goto skip_wrapped_data;
2193 }
2194#endif /* CONFIG_TESTING_OPTIONS */
2195
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002196 /* E-nonce */
2197 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2198 wpabuf_put_le16(clear, e_nonce_len);
2199 wpabuf_put_data(clear, e_nonce, e_nonce_len);
2200
Roshan Pius3a1667e2018-07-03 15:17:14 -07002201#ifdef CONFIG_TESTING_OPTIONS
2202skip_e_nonce:
2203 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2204 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2205 goto skip_config_obj;
2206 }
2207#endif /* CONFIG_TESTING_OPTIONS */
2208
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002209 if (conf) {
2210 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2211 wpabuf_put_le16(clear, wpabuf_len(conf));
2212 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002213 }
Hai Shalomc3565922019-10-28 11:58:20 -07002214 if (auth->peer_version >= 2 && conf2) {
2215 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2216 wpabuf_put_le16(clear, wpabuf_len(conf2));
2217 wpabuf_put_buf(clear, conf2);
2218 } else if (conf2) {
2219 wpa_printf(MSG_DEBUG,
2220 "DPP: Second Config Object available, but peer does not support more than one");
2221 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002222 if (env_data) {
2223 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2224 wpabuf_put_le16(clear, wpabuf_len(env_data));
2225 wpabuf_put_buf(clear, env_data);
2226 }
Hai Shalomc3565922019-10-28 11:58:20 -07002227
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002228 if (auth->peer_version >= 2 && auth->send_conn_status &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002229 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002230 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2231 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2232 wpabuf_put_le16(clear, 0);
2233 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002234
Hai Shalom899fcc72020-10-19 14:38:18 -07002235 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2236 auth->conf_sta->csrattrs) {
2237 auth->waiting_csr = true;
2238 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2239 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2240 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2241 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2242 }
2243
Sunil Ravia04bd252022-05-02 22:54:18 -07002244#ifdef CONFIG_DPP3
2245 if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2246 auth->conf->net_access_key_curve) {
2247 u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2248
2249 /* Finite Cyclic Group attribute */
2250 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2251 ike_group);
2252 wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2253 wpabuf_put_le16(clear, 2);
2254 wpabuf_put_le16(clear, ike_group);
2255
2256 if (pc) {
2257 wpa_printf(MSG_DEBUG, "DPP: Pc");
2258 wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2259 wpabuf_put_le16(clear, wpabuf_len(pc));
2260 wpabuf_put_buf(clear, pc);
2261 }
2262 }
2263#endif /* CONFIG_DPP3 */
2264
Roshan Pius3a1667e2018-07-03 15:17:14 -07002265#ifdef CONFIG_TESTING_OPTIONS
2266skip_config_obj:
2267 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2268 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2269 goto skip_status;
2270 }
2271 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2272 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2273 status = 255;
2274 }
2275#endif /* CONFIG_TESTING_OPTIONS */
2276
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002277 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002278 dpp_build_attr_status(msg, status);
2279
2280#ifdef CONFIG_TESTING_OPTIONS
2281skip_status:
2282#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002283
2284 addr[0] = wpabuf_head(msg);
2285 len[0] = wpabuf_len(msg);
2286 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2287
2288 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2289 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2290 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2291
2292 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2293 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2294 wpabuf_head(clear), wpabuf_len(clear),
2295 1, addr, len, wrapped) < 0)
2296 goto fail;
2297 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2298 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002299
2300#ifdef CONFIG_TESTING_OPTIONS
2301 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2302 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2303 dpp_build_attr_status(msg, DPP_STATUS_OK);
2304 }
2305skip_wrapped_data:
2306#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002307
2308 wpa_hexdump_buf(MSG_DEBUG,
2309 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002310out:
Hai Shalomfdcde762020-04-02 11:19:20 -07002311 wpabuf_clear_free(conf);
2312 wpabuf_clear_free(conf2);
2313 wpabuf_clear_free(env_data);
2314 wpabuf_clear_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -07002315 wpabuf_free(pc);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002316
2317 return msg;
2318fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002319 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002320 msg = NULL;
2321 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002322}
2323
2324
2325struct wpabuf *
2326dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2327 size_t attr_len)
2328{
2329 const u8 *wrapped_data, *e_nonce, *config_attr;
2330 u16 wrapped_data_len, e_nonce_len, config_attr_len;
2331 u8 *unwrapped = NULL;
2332 size_t unwrapped_len = 0;
2333 struct wpabuf *resp = NULL;
2334 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002335 enum dpp_netrole netrole;
Hai Shalom899fcc72020-10-19 14:38:18 -07002336 struct wpabuf *cert_req = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07002337#ifdef CONFIG_DPP3
2338 const u8 *i_proto;
2339 u16 i_proto_len;
2340#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002341
Roshan Pius3a1667e2018-07-03 15:17:14 -07002342#ifdef CONFIG_TESTING_OPTIONS
2343 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2344 wpa_printf(MSG_INFO,
2345 "DPP: TESTING - stop at Config Request");
2346 return NULL;
2347 }
2348#endif /* CONFIG_TESTING_OPTIONS */
2349
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002350 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002351 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002352 return NULL;
2353 }
2354
2355 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2356 &wrapped_data_len);
2357 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002358 dpp_auth_fail(auth,
2359 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002360 return NULL;
2361 }
2362
2363 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2364 wrapped_data, wrapped_data_len);
2365 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2366 unwrapped = os_malloc(unwrapped_len);
2367 if (!unwrapped)
2368 return NULL;
2369 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2370 wrapped_data, wrapped_data_len,
2371 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002372 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002373 goto fail;
2374 }
2375 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2376 unwrapped, unwrapped_len);
2377
2378 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002379 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002380 goto fail;
2381 }
2382
2383 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2384 DPP_ATTR_ENROLLEE_NONCE,
2385 &e_nonce_len);
2386 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002387 dpp_auth_fail(auth,
2388 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002389 goto fail;
2390 }
2391 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07002392 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002393
Sunil Ravia04bd252022-05-02 22:54:18 -07002394#ifdef CONFIG_DPP3
2395 i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2396 DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2397 if (i_proto && !auth->waiting_new_key) {
2398 dpp_auth_fail(auth,
2399 "Enrollee included a new protocol key even though one was not expected");
2400 goto fail;
2401 }
2402 if (i_proto) {
2403 struct crypto_ec_key *pe;
2404 u8 auth_i[DPP_MAX_HASH_LEN];
2405 const u8 *rx_auth_i;
2406 u16 rx_auth_i_len;
2407
2408 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2409 i_proto, i_proto_len);
2410
2411 pe = dpp_set_pubkey_point(auth->own_protocol_key,
2412 i_proto, i_proto_len);
2413 if (!pe) {
2414 dpp_auth_fail(auth,
2415 "Invalid Initiator Protocol Key (Pe)");
2416 goto fail;
2417 }
2418 dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2419 crypto_ec_key_deinit(auth->peer_protocol_key);
2420 auth->peer_protocol_key = pe;
2421 auth->new_key_received = true;
2422 auth->waiting_new_key = false;
2423
2424 if (dpp_derive_auth_i(auth, auth_i) < 0)
2425 goto fail;
2426
2427 rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2428 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2429 if (!rx_auth_i) {
2430 dpp_auth_fail(auth,
2431 "Missing Initiator Authentication Tag");
2432 goto fail;
2433 }
2434 if (rx_auth_i_len != auth->curve->hash_len ||
2435 os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2436 dpp_auth_fail(auth,
2437 "Mismatch in Initiator Authenticating Tag");
2438 wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2439 rx_auth_i, rx_auth_i_len);
2440 wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2441 auth_i, auth->curve->hash_len);
2442 goto fail;
2443 }
2444 }
2445#endif /* CONFIG_DPP3 */
2446
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002447 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2448 DPP_ATTR_CONFIG_ATTR_OBJ,
2449 &config_attr_len);
2450 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002451 dpp_auth_fail(auth,
2452 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002453 goto fail;
2454 }
2455 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2456 config_attr, config_attr_len);
2457
2458 root = json_parse((const char *) config_attr, config_attr_len);
2459 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002460 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002461 goto fail;
2462 }
2463
2464 token = json_get_member(root, "name");
2465 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002466 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002467 goto fail;
2468 }
2469 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002470 os_free(auth->e_name);
2471 auth->e_name = os_strdup(token->string);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002472
2473 token = json_get_member(root, "wi-fi_tech");
2474 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002475 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002476 goto fail;
2477 }
2478 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2479 if (os_strcmp(token->string, "infra") != 0) {
2480 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2481 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002482 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002483 goto fail;
2484 }
2485
2486 token = json_get_member(root, "netRole");
2487 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002488 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002489 goto fail;
2490 }
2491 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2492 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002493 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002494 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002495 netrole = DPP_NETROLE_AP;
2496 } else if (os_strcmp(token->string, "configurator") == 0) {
2497 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002498 } else {
2499 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2500 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002501 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002502 goto fail;
2503 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002504 auth->e_netrole = netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002505
Hai Shalomc3565922019-10-28 11:58:20 -07002506 token = json_get_member(root, "mudurl");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002507 if (token && token->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002508 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002509 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2510 token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002511 os_free(auth->e_mud_url);
2512 auth->e_mud_url = os_strdup(token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002513 }
Hai Shalomc3565922019-10-28 11:58:20 -07002514
2515 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08002516 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002517 if (token && token->type == JSON_ARRAY) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002518 int *opclass = NULL;
2519 char txt[200], *pos, *end;
2520 int i, res;
2521
Hai Shalom06768112019-12-04 15:49:43 -08002522 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07002523 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2524 token = token->child;
2525 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08002526 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07002527 wpa_printf(MSG_DEBUG,
2528 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08002529 } else {
2530 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2531 auth->band_list[auth->band_list_size++] = token->number;
2532 }
Hai Shalomc3565922019-10-28 11:58:20 -07002533 wpa_printf(MSG_DEBUG,
2534 "DPP: Supported global operating class: %d",
2535 token->number);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002536 int_array_add_unique(&opclass, token->number);
Hai Shalom06768112019-12-04 15:49:43 -08002537 }
Hai Shalomc3565922019-10-28 11:58:20 -07002538 token = token->sibling;
2539 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002540
2541 txt[0] = '\0';
2542 pos = txt;
2543 end = txt + sizeof(txt);
2544 for (i = 0; opclass && opclass[i]; i++) {
2545 res = os_snprintf(pos, end - pos, "%s%d",
2546 pos == txt ? "" : ",", opclass[i]);
2547 if (os_snprintf_error(end - pos, res)) {
2548 *pos = '\0';
2549 break;
2550 }
2551 pos += res;
2552 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002553 os_free(auth->e_band_support);
2554 auth->e_band_support = opclass;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002555 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2556 txt);
Hai Shalomc3565922019-10-28 11:58:20 -07002557 }
2558
Hai Shalom899fcc72020-10-19 14:38:18 -07002559#ifdef CONFIG_DPP2
2560 cert_req = json_get_member_base64(root, "pkcs10");
2561 if (cert_req) {
2562 char *txt;
2563 int id;
2564
2565 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2566 if (dpp_validate_csr(auth, cert_req) < 0) {
2567 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2568 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2569 goto cont;
2570 }
2571
Hai Shaloma20dcd72022-02-04 13:43:00 -08002572 id = dpp_get_peer_bi_id(auth);
2573 if (id < 0)
2574 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002575
2576 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2577 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2578 wpabuf_len(cert_req), NULL);
2579 if (!txt)
2580 goto fail;
2581
2582 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2583 id, txt);
2584 os_free(txt);
2585 auth->waiting_csr = false;
2586 auth->waiting_cert = true;
2587 goto fail;
2588 }
2589cont:
2590#endif /* CONFIG_DPP2 */
2591
Sunil Ravic0f5d412024-09-11 22:12:49 +00002592#ifdef CONFIG_DPP3
2593 token = json_get_member(root, "capabilities");
2594 if (token && token->type == JSON_NUMBER) {
2595 wpa_printf(MSG_DEBUG, "DPP: capabilities = 0x%x",
2596 token->number);
2597 wpa_msg(auth->msg_ctx, MSG_INFO,
2598 DPP_EVENT_ENROLLEE_CAPABILITY "%d",
2599 token->number);
2600 auth->enrollee_capabilities = token->number;
2601 }
2602#endif /* CONFIG_DPP3 */
2603
Hai Shalom899fcc72020-10-19 14:38:18 -07002604 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2605 cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002606
2607fail:
Hai Shalom899fcc72020-10-19 14:38:18 -07002608 wpabuf_free(cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002609 json_free(root);
2610 os_free(unwrapped);
2611 return resp;
2612}
2613
2614
Hai Shalomc3565922019-10-28 11:58:20 -07002615static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002616 struct json_token *cred)
2617{
2618 struct json_token *pass, *psk_hex;
2619
2620 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2621
2622 pass = json_get_member(cred, "pass");
2623 psk_hex = json_get_member(cred, "psk_hex");
2624
2625 if (pass && pass->type == JSON_STRING) {
2626 size_t len = os_strlen(pass->string);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002627#ifdef CONFIG_DPP3
2628 struct json_token *saepi = json_get_member(cred, "idpass");
2629#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002630
2631 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2632 pass->string, len);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002633 if (dpp_akm_psk(conf->akm) && (len < 8 || len > 63)) {
2634 wpa_printf(MSG_DEBUG,
2635 "DPP: Unexpected pass length %zu for a config object that includes PSK",
2636 len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002637 return -1;
Sunil Ravic0f5d412024-09-11 22:12:49 +00002638 }
Hai Shalomc3565922019-10-28 11:58:20 -07002639 os_strlcpy(conf->passphrase, pass->string,
2640 sizeof(conf->passphrase));
Sunil Ravic0f5d412024-09-11 22:12:49 +00002641#ifdef CONFIG_DPP3
2642 if (saepi && saepi->type == JSON_STRING)
2643 os_strlcpy(conf->password_id, saepi->string,
2644 sizeof(conf->password_id));
2645#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002646 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002647 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002648 wpa_printf(MSG_DEBUG,
2649 "DPP: Unexpected psk_hex with akm=sae");
2650 return -1;
2651 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002652 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07002653 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002654 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2655 return -1;
2656 }
2657 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07002658 conf->psk, PMK_LEN);
2659 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002660 } else {
2661 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2662 return -1;
2663 }
2664
Hai Shalomc3565922019-10-28 11:58:20 -07002665 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002666 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2667 return -1;
2668 }
2669
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002670 return 0;
2671}
2672
2673
Hai Shaloma20dcd72022-02-04 13:43:00 -08002674struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2675 const struct dpp_curve_params **key_curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002676{
2677 struct json_token *token;
2678 const struct dpp_curve_params *curve;
2679 struct wpabuf *x = NULL, *y = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002680 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002681
2682 token = json_get_member(jwk, "kty");
2683 if (!token || token->type != JSON_STRING) {
2684 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2685 goto fail;
2686 }
2687 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002688 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002689 token->string);
2690 goto fail;
2691 }
2692
2693 token = json_get_member(jwk, "crv");
2694 if (!token || token->type != JSON_STRING) {
2695 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2696 goto fail;
2697 }
2698 curve = dpp_get_curve_jwk_crv(token->string);
2699 if (!curve) {
2700 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2701 token->string);
2702 goto fail;
2703 }
2704
2705 x = json_get_member_base64url(jwk, "x");
2706 if (!x) {
2707 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2708 goto fail;
2709 }
2710 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2711 if (wpabuf_len(x) != curve->prime_len) {
2712 wpa_printf(MSG_DEBUG,
2713 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2714 (unsigned int) wpabuf_len(x),
2715 (unsigned int) curve->prime_len, curve->name);
2716 goto fail;
2717 }
2718
2719 y = json_get_member_base64url(jwk, "y");
2720 if (!y) {
2721 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2722 goto fail;
2723 }
2724 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2725 if (wpabuf_len(y) != curve->prime_len) {
2726 wpa_printf(MSG_DEBUG,
2727 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2728 (unsigned int) wpabuf_len(y),
2729 (unsigned int) curve->prime_len, curve->name);
2730 goto fail;
2731 }
2732
Hai Shaloma20dcd72022-02-04 13:43:00 -08002733 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2734 wpabuf_head(y), wpabuf_len(x));
2735 if (!key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002736 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002737
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002738 *key_curve = curve;
2739
2740fail:
2741 wpabuf_free(x);
2742 wpabuf_free(y);
2743
Hai Shaloma20dcd72022-02-04 13:43:00 -08002744 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002745}
2746
2747
2748int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2749{
2750 struct os_time now;
2751 unsigned int year, month, day, hour, min, sec;
2752 os_time_t utime;
2753 const char *pos;
2754
2755 /* ISO 8601 date and time:
2756 * <date>T<time>
2757 * YYYY-MM-DDTHH:MM:SSZ
2758 * YYYY-MM-DDTHH:MM:SS+03:00
2759 */
2760 if (os_strlen(timestamp) < 19) {
2761 wpa_printf(MSG_DEBUG,
2762 "DPP: Too short timestamp - assume expired key");
2763 return 1;
2764 }
2765 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2766 &year, &month, &day, &hour, &min, &sec) != 6) {
2767 wpa_printf(MSG_DEBUG,
2768 "DPP: Failed to parse expiration day - assume expired key");
2769 return 1;
2770 }
2771
2772 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2773 wpa_printf(MSG_DEBUG,
2774 "DPP: Invalid date/time information - assume expired key");
2775 return 1;
2776 }
2777
2778 pos = timestamp + 19;
2779 if (*pos == 'Z' || *pos == '\0') {
2780 /* In UTC - no need to adjust */
2781 } else if (*pos == '-' || *pos == '+') {
2782 int items;
2783
2784 /* Adjust local time to UTC */
2785 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2786 if (items < 1) {
2787 wpa_printf(MSG_DEBUG,
2788 "DPP: Invalid time zone designator (%s) - assume expired key",
2789 pos);
2790 return 1;
2791 }
2792 if (*pos == '-')
2793 utime += 3600 * hour;
2794 if (*pos == '+')
2795 utime -= 3600 * hour;
2796 if (items > 1) {
2797 if (*pos == '-')
2798 utime += 60 * min;
2799 if (*pos == '+')
2800 utime -= 60 * min;
2801 }
2802 } else {
2803 wpa_printf(MSG_DEBUG,
2804 "DPP: Invalid time zone designator (%s) - assume expired key",
2805 pos);
2806 return 1;
2807 }
2808 if (expiry)
2809 *expiry = utime;
2810
2811 if (os_get_time(&now) < 0) {
2812 wpa_printf(MSG_DEBUG,
2813 "DPP: Cannot get current time - assume expired key");
2814 return 1;
2815 }
2816
2817 if (now.sec > utime) {
2818 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2819 utime, now.sec);
2820 return 1;
2821 }
2822
2823 return 0;
2824}
2825
2826
2827static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002828 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002829 const unsigned char *payload,
2830 u16 payload_len)
2831{
2832 struct json_token *root, *groups, *netkey, *token;
2833 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002834 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002835 const struct dpp_curve_params *curve;
2836 unsigned int rules = 0;
2837
2838 root = json_parse((const char *) payload, payload_len);
2839 if (!root) {
2840 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2841 goto fail;
2842 }
2843
2844 groups = json_get_member(root, "groups");
2845 if (!groups || groups->type != JSON_ARRAY) {
2846 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2847 goto skip_groups;
2848 }
2849 for (token = groups->child; token; token = token->sibling) {
2850 struct json_token *id, *role;
2851
2852 id = json_get_member(token, "groupId");
2853 if (!id || id->type != JSON_STRING) {
2854 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2855 goto fail;
2856 }
2857
2858 role = json_get_member(token, "netRole");
2859 if (!role || role->type != JSON_STRING) {
2860 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2861 goto fail;
2862 }
2863 wpa_printf(MSG_DEBUG,
2864 "DPP: connector group: groupId='%s' netRole='%s'",
2865 id->string, role->string);
2866 rules++;
2867 }
2868skip_groups:
2869
2870 if (!rules) {
2871 wpa_printf(MSG_DEBUG,
2872 "DPP: Connector includes no groups");
2873 goto fail;
2874 }
2875
2876 token = json_get_member(root, "expiry");
2877 if (!token || token->type != JSON_STRING) {
2878 wpa_printf(MSG_DEBUG,
2879 "DPP: No expiry string found - connector does not expire");
2880 } else {
2881 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2882 if (dpp_key_expired(token->string,
2883 &auth->net_access_key_expiry)) {
2884 wpa_printf(MSG_DEBUG,
2885 "DPP: Connector (netAccessKey) has expired");
2886 goto fail;
2887 }
2888 }
2889
2890 netkey = json_get_member(root, "netAccessKey");
2891 if (!netkey || netkey->type != JSON_OBJECT) {
2892 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2893 goto fail;
2894 }
2895
2896 key = dpp_parse_jwk(netkey, &curve);
2897 if (!key)
2898 goto fail;
2899 dpp_debug_print_key("DPP: Received netAccessKey", key);
2900
Hai Shaloma20dcd72022-02-04 13:43:00 -08002901 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002902 wpa_printf(MSG_DEBUG,
2903 "DPP: netAccessKey in connector does not match own protocol key");
2904#ifdef CONFIG_TESTING_OPTIONS
2905 if (auth->ignore_netaccesskey_mismatch) {
2906 wpa_printf(MSG_DEBUG,
2907 "DPP: TESTING - skip netAccessKey mismatch");
2908 } else {
2909 goto fail;
2910 }
2911#else /* CONFIG_TESTING_OPTIONS */
2912 goto fail;
2913#endif /* CONFIG_TESTING_OPTIONS */
2914 }
2915
2916 ret = 0;
2917fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002918 crypto_ec_key_deinit(key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002919 json_free(root);
2920 return ret;
2921}
2922
2923
Hai Shaloma20dcd72022-02-04 13:43:00 -08002924static void dpp_copy_csign(struct dpp_config_obj *conf,
2925 struct crypto_ec_key *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002926{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002927 struct wpabuf *c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002928
Hai Shaloma20dcd72022-02-04 13:43:00 -08002929 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2930 if (!c_sign_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002931 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002932
Hai Shalomc3565922019-10-28 11:58:20 -07002933 wpabuf_free(conf->c_sign_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002934 conf->c_sign_key = c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002935}
2936
2937
Hai Shaloma20dcd72022-02-04 13:43:00 -08002938static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2939 struct crypto_ec_key *ppkey)
Hai Shalom899fcc72020-10-19 14:38:18 -07002940{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002941 struct wpabuf *pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002942
Hai Shaloma20dcd72022-02-04 13:43:00 -08002943 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2944 if (!pp_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002945 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002946
Hai Shalom899fcc72020-10-19 14:38:18 -07002947 wpabuf_free(conf->pp_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002948 conf->pp_key = pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002949}
2950
2951
Hai Shalomc3565922019-10-28 11:58:20 -07002952static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2953 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002954{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002955 struct wpabuf *net_access_key;
2956 struct crypto_ec_key *own_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002957
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002958 own_key = auth->own_protocol_key;
2959#ifdef CONFIG_DPP2
2960 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2961 auth->reconfig_old_protocol_key)
2962 own_key = auth->reconfig_old_protocol_key;
2963#endif /* CONFIG_DPP2 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002964
2965 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2966 if (!net_access_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002967 return;
2968
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002969 wpabuf_free(auth->net_access_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002970 auth->net_access_key = net_access_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002971}
2972
2973
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002974static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002975 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002976 struct json_token *cred)
2977{
2978 struct dpp_signed_connector_info info;
Hai Shalom899fcc72020-10-19 14:38:18 -07002979 struct json_token *token, *csign, *ppkey;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002980 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002981 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002982 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002983 const char *signed_connector;
2984
2985 os_memset(&info, 0, sizeof(info));
2986
Hai Shalomc3565922019-10-28 11:58:20 -07002987 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002988 wpa_printf(MSG_DEBUG,
2989 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07002990 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07002991 return -1;
2992 }
2993
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002994 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2995
2996 csign = json_get_member(cred, "csign");
2997 if (!csign || csign->type != JSON_OBJECT) {
2998 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2999 goto fail;
3000 }
3001
3002 csign_pub = dpp_parse_jwk(csign, &key_curve);
3003 if (!csign_pub) {
3004 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
3005 goto fail;
3006 }
3007 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
3008
Hai Shalom899fcc72020-10-19 14:38:18 -07003009 ppkey = json_get_member(cred, "ppKey");
3010 if (ppkey && ppkey->type == JSON_OBJECT) {
3011 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
3012 if (!pp_pub) {
3013 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
3014 goto fail;
3015 }
3016 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
3017 if (key_curve != pp_curve) {
3018 wpa_printf(MSG_DEBUG,
3019 "DPP: C-sign-key and ppKey do not use the same curve");
3020 goto fail;
3021 }
3022 }
3023
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003024 token = json_get_member(cred, "signedConnector");
3025 if (!token || token->type != JSON_STRING) {
3026 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
3027 goto fail;
3028 }
3029 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
3030 token->string, os_strlen(token->string));
3031 signed_connector = token->string;
3032
3033 if (os_strchr(signed_connector, '"') ||
3034 os_strchr(signed_connector, '\n')) {
3035 wpa_printf(MSG_DEBUG,
3036 "DPP: Unexpected character in signedConnector");
3037 goto fail;
3038 }
3039
3040 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003041 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003042 goto fail;
3043
Hai Shalomc3565922019-10-28 11:58:20 -07003044 if (dpp_parse_connector(auth, conf,
3045 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003046 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
3047 goto fail;
3048 }
3049
Hai Shalomc3565922019-10-28 11:58:20 -07003050 os_free(conf->connector);
3051 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003052
Hai Shalomc3565922019-10-28 11:58:20 -07003053 dpp_copy_csign(conf, csign_pub);
Hai Shalom899fcc72020-10-19 14:38:18 -07003054 if (pp_pub)
3055 dpp_copy_ppkey(conf, pp_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07003056 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07003057 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003058
3059 ret = 0;
3060fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08003061 crypto_ec_key_deinit(csign_pub);
3062 crypto_ec_key_deinit(pp_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003063 os_free(info.payload);
3064 return ret;
3065}
3066
3067
Hai Shalom899fcc72020-10-19 14:38:18 -07003068#ifdef CONFIG_DPP2
3069static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
3070 struct dpp_config_obj *conf,
3071 struct json_token *cred)
3072{
3073 struct json_token *ent, *name;
3074
3075 ent = json_get_member(cred, "entCreds");
3076 if (!ent || ent->type != JSON_OBJECT) {
3077 dpp_auth_fail(auth, "No entCreds in JSON");
3078 return -1;
3079 }
3080
3081 conf->certbag = json_get_member_base64(ent, "certBag");
3082 if (!conf->certbag) {
3083 dpp_auth_fail(auth, "No certBag in JSON");
3084 return -1;
3085 }
3086 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003087 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
Hai Shalom899fcc72020-10-19 14:38:18 -07003088 if (!conf->certs) {
3089 dpp_auth_fail(auth, "No certificates in certBag");
3090 return -1;
3091 }
3092
3093 conf->cacert = json_get_member_base64(ent, "caCert");
3094 if (conf->cacert)
3095 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3096 conf->cacert);
3097
3098 name = json_get_member(ent, "trustedEapServerName");
3099 if (name &&
3100 (name->type != JSON_STRING ||
3101 has_ctrl_char((const u8 *) name->string,
3102 os_strlen(name->string)))) {
3103 dpp_auth_fail(auth,
3104 "Invalid trustedEapServerName type in JSON");
3105 return -1;
3106 }
3107 if (name && name->string) {
3108 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3109 name->string);
3110 conf->server_name = os_strdup(name->string);
3111 if (!conf->server_name)
3112 return -1;
3113 }
3114
3115 return 0;
3116}
3117#endif /* CONFIG_DPP2 */
3118
3119
Roshan Pius3a1667e2018-07-03 15:17:14 -07003120const char * dpp_akm_str(enum dpp_akm akm)
3121{
3122 switch (akm) {
3123 case DPP_AKM_DPP:
3124 return "dpp";
3125 case DPP_AKM_PSK:
3126 return "psk";
3127 case DPP_AKM_SAE:
3128 return "sae";
3129 case DPP_AKM_PSK_SAE:
3130 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07003131 case DPP_AKM_SAE_DPP:
3132 return "dpp+sae";
3133 case DPP_AKM_PSK_SAE_DPP:
3134 return "dpp+psk+sae";
Hai Shalom899fcc72020-10-19 14:38:18 -07003135 case DPP_AKM_DOT1X:
3136 return "dot1x";
Roshan Pius3a1667e2018-07-03 15:17:14 -07003137 default:
3138 return "??";
3139 }
3140}
3141
3142
Hai Shalomc3565922019-10-28 11:58:20 -07003143const char * dpp_akm_selector_str(enum dpp_akm akm)
3144{
3145 switch (akm) {
3146 case DPP_AKM_DPP:
3147 return "506F9A02";
3148 case DPP_AKM_PSK:
3149 return "000FAC02+000FAC06";
3150 case DPP_AKM_SAE:
3151 return "000FAC08";
3152 case DPP_AKM_PSK_SAE:
3153 return "000FAC02+000FAC06+000FAC08";
3154 case DPP_AKM_SAE_DPP:
3155 return "506F9A02+000FAC08";
3156 case DPP_AKM_PSK_SAE_DPP:
3157 return "506F9A02+000FAC08+000FAC02+000FAC06";
Hai Shalom899fcc72020-10-19 14:38:18 -07003158 case DPP_AKM_DOT1X:
3159 return "000FAC01+000FAC05";
Hai Shalomc3565922019-10-28 11:58:20 -07003160 default:
3161 return "??";
3162 }
3163}
3164
3165
Roshan Pius3a1667e2018-07-03 15:17:14 -07003166static enum dpp_akm dpp_akm_from_str(const char *akm)
3167{
Hai Shalomc3565922019-10-28 11:58:20 -07003168 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07003169 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07003170
Roshan Pius3a1667e2018-07-03 15:17:14 -07003171 if (os_strcmp(akm, "psk") == 0)
3172 return DPP_AKM_PSK;
3173 if (os_strcmp(akm, "sae") == 0)
3174 return DPP_AKM_SAE;
3175 if (os_strcmp(akm, "psk+sae") == 0)
3176 return DPP_AKM_PSK_SAE;
3177 if (os_strcmp(akm, "dpp") == 0)
3178 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07003179 if (os_strcmp(akm, "dpp+sae") == 0)
3180 return DPP_AKM_SAE_DPP;
3181 if (os_strcmp(akm, "dpp+psk+sae") == 0)
3182 return DPP_AKM_PSK_SAE_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07003183 if (os_strcmp(akm, "dot1x") == 0)
3184 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003185
3186 pos = akm;
3187 while (*pos) {
3188 if (os_strlen(pos) < 8)
3189 break;
3190 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3191 dpp = 1;
3192 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3193 psk = 1;
3194 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3195 psk = 1;
3196 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3197 sae = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07003198 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3199 dot1x = 1;
3200 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3201 dot1x = 1;
Hai Shalomc3565922019-10-28 11:58:20 -07003202 pos += 8;
3203 if (*pos != '+')
3204 break;
3205 pos++;
3206 }
3207
3208 if (dpp && psk && sae)
3209 return DPP_AKM_PSK_SAE_DPP;
3210 if (dpp && sae)
3211 return DPP_AKM_SAE_DPP;
3212 if (dpp)
3213 return DPP_AKM_DPP;
3214 if (psk && sae)
3215 return DPP_AKM_PSK_SAE;
3216 if (sae)
3217 return DPP_AKM_SAE;
3218 if (psk)
3219 return DPP_AKM_PSK;
Hai Shalom899fcc72020-10-19 14:38:18 -07003220 if (dot1x)
3221 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003222
Roshan Pius3a1667e2018-07-03 15:17:14 -07003223 return DPP_AKM_UNKNOWN;
3224}
3225
3226
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003227static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3228 const u8 *conf_obj, u16 conf_obj_len)
3229{
3230 int ret = -1;
3231 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07003232 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003233 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003234 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003235
3236 root = json_parse((const char *) conf_obj, conf_obj_len);
3237 if (!root)
3238 return -1;
3239 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003240 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003241 goto fail;
3242 }
3243
3244 token = json_get_member(root, "wi-fi_tech");
3245 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003246 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003247 goto fail;
3248 }
3249 if (os_strcmp(token->string, "infra") != 0) {
3250 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3251 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003252 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003253 goto fail;
3254 }
3255
3256 discovery = json_get_member(root, "discovery");
3257 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003258 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003259 goto fail;
3260 }
3261
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003262 ssid64 = json_get_member_base64url(discovery, "ssid64");
3263 if (ssid64) {
3264 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3265 wpabuf_head(ssid64), wpabuf_len(ssid64));
3266 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3267 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3268 goto fail;
3269 }
3270 } else {
3271 token = json_get_member(discovery, "ssid");
3272 if (!token || token->type != JSON_STRING) {
3273 dpp_auth_fail(auth,
3274 "No discovery::ssid string value found");
3275 goto fail;
3276 }
3277 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3278 token->string, os_strlen(token->string));
3279 if (os_strlen(token->string) > SSID_MAX_LEN) {
3280 dpp_auth_fail(auth,
3281 "Too long discovery::ssid string value");
3282 goto fail;
3283 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003284 }
Hai Shalomc3565922019-10-28 11:58:20 -07003285
3286 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3287 wpa_printf(MSG_DEBUG,
3288 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003289 ret = 0;
3290 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003291 }
3292 conf = &auth->conf_obj[auth->num_conf_obj++];
3293
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003294 if (ssid64) {
3295 conf->ssid_len = wpabuf_len(ssid64);
3296 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3297 } else {
3298 conf->ssid_len = os_strlen(token->string);
3299 os_memcpy(conf->ssid, token->string, conf->ssid_len);
3300 }
3301
3302 token = json_get_member(discovery, "ssid_charset");
3303 if (token && token->type == JSON_NUMBER) {
3304 conf->ssid_charset = token->number;
3305 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3306 conf->ssid_charset);
3307 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003308
3309 cred = json_get_member(root, "cred");
3310 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003311 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003312 goto fail;
3313 }
3314
3315 token = json_get_member(cred, "akm");
3316 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003317 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003318 goto fail;
3319 }
Hai Shalomc3565922019-10-28 11:58:20 -07003320 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003321
Hai Shalomfdcde762020-04-02 11:19:20 -07003322 legacy = dpp_akm_legacy(conf->akm);
3323 if (legacy && auth->peer_version >= 2) {
3324 struct json_token *csign, *s_conn;
3325
3326 csign = json_get_member(cred, "csign");
3327 s_conn = json_get_member(cred, "signedConnector");
3328 if (csign && csign->type == JSON_OBJECT &&
3329 s_conn && s_conn->type == JSON_STRING)
3330 legacy = 0;
3331 }
3332 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07003333 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003334 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003335 } else if (dpp_akm_dpp(conf->akm) ||
3336 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07003337 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003338 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07003339#ifdef CONFIG_DPP2
3340 } else if (conf->akm == DPP_AKM_DOT1X) {
3341 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3342 dpp_parse_cred_dpp(auth, conf, cred) < 0)
3343 goto fail;
3344#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003345 } else {
3346 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3347 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003348 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003349 goto fail;
3350 }
3351
3352 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3353 ret = 0;
3354fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003355 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003356 json_free(root);
3357 return ret;
3358}
3359
3360
Hai Shalom899fcc72020-10-19 14:38:18 -07003361#ifdef CONFIG_DPP2
3362static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3363{
3364 const u8 *b64;
3365 u16 b64_len;
3366
3367 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3368 if (!b64)
3369 return NULL;
3370 return base64_decode((const char *) b64, b64_len, len);
3371}
3372#endif /* CONFIG_DPP2 */
3373
3374
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003375int dpp_conf_resp_rx(struct dpp_authentication *auth,
3376 const struct wpabuf *resp)
3377{
3378 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3379 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07003380 const u8 *env_data;
3381 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003382 const u8 *addr[1];
3383 size_t len[1];
3384 u8 *unwrapped = NULL;
3385 size_t unwrapped_len = 0;
3386 int ret = -1;
3387
Hai Shalom021b0b52019-04-10 11:17:58 -07003388 auth->conf_resp_status = 255;
3389
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003390 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003391 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003392 return -1;
3393 }
3394
3395 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3396 DPP_ATTR_WRAPPED_DATA,
3397 &wrapped_data_len);
3398 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003399 dpp_auth_fail(auth,
3400 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003401 return -1;
3402 }
3403
3404 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3405 wrapped_data, wrapped_data_len);
3406 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3407 unwrapped = os_malloc(unwrapped_len);
3408 if (!unwrapped)
3409 return -1;
3410
3411 addr[0] = wpabuf_head(resp);
3412 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3413 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3414
3415 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3416 wrapped_data, wrapped_data_len,
3417 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003418 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003419 goto fail;
3420 }
3421 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3422 unwrapped, unwrapped_len);
3423
3424 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003425 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003426 goto fail;
3427 }
3428
3429 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3430 DPP_ATTR_ENROLLEE_NONCE,
3431 &e_nonce_len);
3432 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003433 dpp_auth_fail(auth,
3434 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003435 goto fail;
3436 }
3437 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3438 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003439 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003440 goto fail;
3441 }
3442
3443 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3444 DPP_ATTR_STATUS, &status_len);
3445 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003446 dpp_auth_fail(auth,
3447 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003448 goto fail;
3449 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003450 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003451 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Hai Shalom899fcc72020-10-19 14:38:18 -07003452#ifdef CONFIG_DPP2
3453 if (status[0] == DPP_STATUS_CSR_NEEDED) {
3454 u8 *csrattrs;
3455 size_t csrattrs_len;
3456
3457 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3458
3459 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3460 &csrattrs_len);
3461 if (!csrattrs) {
3462 dpp_auth_fail(auth,
3463 "Missing or invalid CSR Attributes Request attribute");
3464 goto fail;
3465 }
3466 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3467 os_free(auth->csrattrs);
3468 auth->csrattrs = csrattrs;
3469 auth->csrattrs_len = csrattrs_len;
3470 ret = -2;
3471 goto fail;
3472 }
3473#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07003474#ifdef CONFIG_DPP3
3475 if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3476 const u8 *fcgroup, *r_proto;
3477 u16 fcgroup_len, r_proto_len;
3478 u16 group;
3479 const struct dpp_curve_params *curve;
3480 struct crypto_ec_key *new_pe;
3481 struct crypto_ec_key *pc;
3482
3483 fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3484 DPP_ATTR_FINITE_CYCLIC_GROUP,
3485 &fcgroup_len);
3486 if (!fcgroup || fcgroup_len != 2) {
3487 dpp_auth_fail(auth,
3488 "Missing or invalid required Finite Cyclic Group attribute");
3489 goto fail;
3490 }
3491 group = WPA_GET_LE16(fcgroup);
3492
3493 wpa_printf(MSG_DEBUG,
3494 "DPP: Configurator requested a new protocol key from group %u",
3495 group);
3496 curve = dpp_get_curve_ike_group(group);
3497 if (!curve) {
3498 dpp_auth_fail(auth,
3499 "Unsupported group for new protocol key");
3500 goto fail;
3501 }
3502
3503 new_pe = dpp_gen_keypair(curve);
3504 if (!new_pe) {
3505 dpp_auth_fail(auth,
3506 "Failed to generate a new protocol key");
3507 goto fail;
3508 }
3509
3510 crypto_ec_key_deinit(auth->own_protocol_key);
3511 auth->own_protocol_key = new_pe;
3512 auth->new_curve = curve;
3513
3514 r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3515 DPP_ATTR_R_PROTOCOL_KEY,
3516 &r_proto_len);
3517 if (!r_proto) {
3518 dpp_auth_fail(auth,
3519 "Missing required Responder Protocol Key attribute (Pc)");
3520 goto fail;
3521 }
3522 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3523 r_proto, r_proto_len);
3524
3525 pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3526 if (!pc) {
3527 dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3528 goto fail;
3529 }
3530 dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3531
3532 crypto_ec_key_deinit(auth->peer_protocol_key);
3533 auth->peer_protocol_key = pc;
3534
3535 auth->waiting_new_key = true;
3536 ret = -3;
3537 goto fail;
3538 }
3539#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003540 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003541 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003542 goto fail;
3543 }
3544
Hai Shalomfdcde762020-04-02 11:19:20 -07003545 env_data = dpp_get_attr(unwrapped, unwrapped_len,
3546 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3547#ifdef CONFIG_DPP2
3548 if (env_data &&
3549 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3550 goto fail;
3551#endif /* CONFIG_DPP2 */
3552
Hai Shalomc3565922019-10-28 11:58:20 -07003553 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3554 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003555 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003556 dpp_auth_fail(auth,
3557 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003558 goto fail;
3559 }
Hai Shalomc3565922019-10-28 11:58:20 -07003560 while (conf_obj) {
3561 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3562 conf_obj, conf_obj_len);
3563 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3564 goto fail;
3565 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3566 DPP_ATTR_CONFIG_OBJ,
3567 &conf_obj_len);
3568 }
3569
3570#ifdef CONFIG_DPP2
3571 status = dpp_get_attr(unwrapped, unwrapped_len,
3572 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3573 if (status) {
3574 wpa_printf(MSG_DEBUG,
3575 "DPP: Configurator requested connection status result");
3576 auth->conn_status_requested = 1;
3577 }
3578#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003579
3580 ret = 0;
3581
3582fail:
3583 os_free(unwrapped);
3584 return ret;
3585}
3586
3587
Hai Shalom021b0b52019-04-10 11:17:58 -07003588#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07003589
Hai Shalom021b0b52019-04-10 11:17:58 -07003590enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3591 const u8 *hdr,
3592 const u8 *attr_start, size_t attr_len)
3593{
3594 const u8 *wrapped_data, *status, *e_nonce;
3595 u16 wrapped_data_len, status_len, e_nonce_len;
3596 const u8 *addr[2];
3597 size_t len[2];
3598 u8 *unwrapped = NULL;
3599 size_t unwrapped_len = 0;
3600 enum dpp_status_error ret = 256;
3601
3602 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3603 &wrapped_data_len);
3604 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3605 dpp_auth_fail(auth,
3606 "Missing or invalid required Wrapped Data attribute");
3607 goto fail;
3608 }
3609 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3610 wrapped_data, wrapped_data_len);
3611
3612 attr_len = wrapped_data - 4 - attr_start;
3613
3614 addr[0] = hdr;
3615 len[0] = DPP_HDR_LEN;
3616 addr[1] = attr_start;
3617 len[1] = attr_len;
3618 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3619 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3620 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3621 wrapped_data, wrapped_data_len);
3622 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3623 unwrapped = os_malloc(unwrapped_len);
3624 if (!unwrapped)
3625 goto fail;
3626 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3627 wrapped_data, wrapped_data_len,
3628 2, addr, len, unwrapped) < 0) {
3629 dpp_auth_fail(auth, "AES-SIV decryption failed");
3630 goto fail;
3631 }
3632 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3633 unwrapped, unwrapped_len);
3634
3635 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3636 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3637 goto fail;
3638 }
3639
3640 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3641 DPP_ATTR_ENROLLEE_NONCE,
3642 &e_nonce_len);
3643 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3644 dpp_auth_fail(auth,
3645 "Missing or invalid Enrollee Nonce attribute");
3646 goto fail;
3647 }
3648 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3649 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3650 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3651 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3652 auth->e_nonce, e_nonce_len);
3653 goto fail;
3654 }
3655
3656 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3657 &status_len);
3658 if (!status || status_len < 1) {
3659 dpp_auth_fail(auth,
3660 "Missing or invalid required DPP Status attribute");
3661 goto fail;
3662 }
3663 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3664 ret = status[0];
3665
3666fail:
3667 bin_clear_free(unwrapped, unwrapped_len);
3668 return ret;
3669}
Hai Shalom021b0b52019-04-10 11:17:58 -07003670
3671
3672struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3673 enum dpp_status_error status)
3674{
3675 struct wpabuf *msg, *clear;
3676 size_t nonce_len, clear_len, attr_len;
3677 const u8 *addr[2];
3678 size_t len[2];
3679 u8 *wrapped;
3680
3681 nonce_len = auth->curve->nonce_len;
3682 clear_len = 5 + 4 + nonce_len;
3683 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3684 clear = wpabuf_alloc(clear_len);
3685 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3686 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003687 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07003688
3689 /* DPP Status */
3690 dpp_build_attr_status(clear, status);
3691
3692 /* E-nonce */
3693 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3694 wpabuf_put_le16(clear, nonce_len);
3695 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3696
3697 /* OUI, OUI type, Crypto Suite, DPP frame type */
3698 addr[0] = wpabuf_head_u8(msg) + 2;
3699 len[0] = 3 + 1 + 1 + 1;
3700 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3701
3702 /* Attributes before Wrapped Data (none) */
3703 addr[1] = wpabuf_put(msg, 0);
3704 len[1] = 0;
3705 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3706
3707 /* Wrapped Data */
3708 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3709 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3710 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3711
3712 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3713 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3714 wpabuf_head(clear), wpabuf_len(clear),
3715 2, addr, len, wrapped) < 0)
3716 goto fail;
3717
3718 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3719 wpabuf_free(clear);
3720 return msg;
3721fail:
3722 wpabuf_free(clear);
3723 wpabuf_free(msg);
3724 return NULL;
3725}
3726
3727
Hai Shalomc3565922019-10-28 11:58:20 -07003728static int valid_channel_list(const char *val)
3729{
3730 while (*val) {
3731 if (!((*val >= '0' && *val <= '9') ||
3732 *val == '/' || *val == ','))
3733 return 0;
3734 val++;
3735 }
3736
3737 return 1;
3738}
3739
3740
3741enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3742 const u8 *hdr,
3743 const u8 *attr_start,
3744 size_t attr_len,
3745 u8 *ssid, size_t *ssid_len,
3746 char **channel_list)
3747{
3748 const u8 *wrapped_data, *status, *e_nonce;
3749 u16 wrapped_data_len, status_len, e_nonce_len;
3750 const u8 *addr[2];
3751 size_t len[2];
3752 u8 *unwrapped = NULL;
3753 size_t unwrapped_len = 0;
3754 enum dpp_status_error ret = 256;
3755 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003756 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07003757
3758 *ssid_len = 0;
3759 *channel_list = NULL;
3760
3761 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3762 &wrapped_data_len);
3763 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3764 dpp_auth_fail(auth,
3765 "Missing or invalid required Wrapped Data attribute");
3766 goto fail;
3767 }
3768 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3769 wrapped_data, wrapped_data_len);
3770
3771 attr_len = wrapped_data - 4 - attr_start;
3772
3773 addr[0] = hdr;
3774 len[0] = DPP_HDR_LEN;
3775 addr[1] = attr_start;
3776 len[1] = attr_len;
3777 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3778 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3779 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3780 wrapped_data, wrapped_data_len);
3781 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3782 unwrapped = os_malloc(unwrapped_len);
3783 if (!unwrapped)
3784 goto fail;
3785 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3786 wrapped_data, wrapped_data_len,
3787 2, addr, len, unwrapped) < 0) {
3788 dpp_auth_fail(auth, "AES-SIV decryption failed");
3789 goto fail;
3790 }
3791 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3792 unwrapped, unwrapped_len);
3793
3794 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3795 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3796 goto fail;
3797 }
3798
3799 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3800 DPP_ATTR_ENROLLEE_NONCE,
3801 &e_nonce_len);
3802 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3803 dpp_auth_fail(auth,
3804 "Missing or invalid Enrollee Nonce attribute");
3805 goto fail;
3806 }
3807 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3808 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3809 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3810 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3811 auth->e_nonce, e_nonce_len);
3812 goto fail;
3813 }
3814
3815 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3816 &status_len);
3817 if (!status) {
3818 dpp_auth_fail(auth,
3819 "Missing required DPP Connection Status attribute");
3820 goto fail;
3821 }
3822 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3823 status, status_len);
3824
3825 root = json_parse((const char *) status, status_len);
3826 if (!root) {
3827 dpp_auth_fail(auth, "Could not parse connStatus");
3828 goto fail;
3829 }
3830
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003831 ssid64 = json_get_member_base64url(root, "ssid64");
3832 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3833 *ssid_len = wpabuf_len(ssid64);
3834 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07003835 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003836 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07003837
3838 token = json_get_member(root, "channelList");
3839 if (token && token->type == JSON_STRING &&
3840 valid_channel_list(token->string))
3841 *channel_list = os_strdup(token->string);
3842
3843 token = json_get_member(root, "result");
3844 if (!token || token->type != JSON_NUMBER) {
3845 dpp_auth_fail(auth, "No connStatus - result");
3846 goto fail;
3847 }
3848 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3849 ret = token->number;
3850
3851fail:
3852 json_free(root);
3853 bin_clear_free(unwrapped, unwrapped_len);
3854 return ret;
3855}
3856
3857
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003858struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3859 const u8 *ssid, size_t ssid_len,
3860 const char *channel_list)
3861{
3862 struct wpabuf *json;
3863
3864 json = wpabuf_alloc(1000);
3865 if (!json)
3866 return NULL;
3867 json_start_object(json, NULL);
3868 json_add_int(json, "result", result);
3869 if (ssid) {
3870 json_value_sep(json);
3871 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3872 wpabuf_free(json);
3873 return NULL;
3874 }
3875 }
3876 if (channel_list) {
3877 json_value_sep(json);
3878 json_add_string(json, "channelList", channel_list);
3879 }
3880 json_end_object(json);
3881 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3882 wpabuf_head(json), wpabuf_len(json));
3883
3884 return json;
3885}
3886
3887
Hai Shalomc3565922019-10-28 11:58:20 -07003888struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3889 enum dpp_status_error result,
3890 const u8 *ssid, size_t ssid_len,
3891 const char *channel_list)
3892{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003893 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07003894 size_t nonce_len, clear_len, attr_len;
3895 const u8 *addr[2];
3896 size_t len[2];
3897 u8 *wrapped;
3898
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003899 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
Hai Shalomc3565922019-10-28 11:58:20 -07003900 if (!json)
3901 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003902
3903 nonce_len = auth->curve->nonce_len;
3904 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3905 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3906 clear = wpabuf_alloc(clear_len);
3907 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3908 if (!clear || !msg)
3909 goto fail;
3910
3911 /* E-nonce */
3912 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3913 wpabuf_put_le16(clear, nonce_len);
3914 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3915
3916 /* DPP Connection Status */
3917 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3918 wpabuf_put_le16(clear, wpabuf_len(json));
3919 wpabuf_put_buf(clear, json);
3920
3921 /* OUI, OUI type, Crypto Suite, DPP frame type */
3922 addr[0] = wpabuf_head_u8(msg) + 2;
3923 len[0] = 3 + 1 + 1 + 1;
3924 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3925
3926 /* Attributes before Wrapped Data (none) */
3927 addr[1] = wpabuf_put(msg, 0);
3928 len[1] = 0;
3929 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3930
3931 /* Wrapped Data */
3932 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3933 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3934 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3935
3936 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3937 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3938 wpabuf_head(clear), wpabuf_len(clear),
3939 2, addr, len, wrapped) < 0)
3940 goto fail;
3941
3942 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3943 msg);
3944 wpabuf_free(json);
3945 wpabuf_free(clear);
3946 return msg;
3947fail:
3948 wpabuf_free(json);
3949 wpabuf_free(clear);
3950 wpabuf_free(msg);
3951 return NULL;
3952}
3953
3954#endif /* CONFIG_DPP2 */
3955
3956
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003957void dpp_configurator_free(struct dpp_configurator *conf)
3958{
3959 if (!conf)
3960 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003961 crypto_ec_key_deinit(conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003962 os_free(conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003963 os_free(conf->connector);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003964 crypto_ec_key_deinit(conf->connector_key);
3965 crypto_ec_key_deinit(conf->pp_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003966 os_free(conf);
3967}
3968
3969
Roshan Pius3a1667e2018-07-03 15:17:14 -07003970int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3971 size_t buflen)
3972{
Hai Shaloma20dcd72022-02-04 13:43:00 -08003973 struct wpabuf *key;
3974 int ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003975
3976 if (!conf->csign)
3977 return -1;
3978
Hai Shaloma20dcd72022-02-04 13:43:00 -08003979 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3980 if (!key)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003981 return -1;
3982
Hai Shaloma20dcd72022-02-04 13:43:00 -08003983 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003984
Hai Shaloma20dcd72022-02-04 13:43:00 -08003985 wpabuf_clear_free(key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003986 return ret;
3987}
3988
3989
Hai Shalomfdcde762020-04-02 11:19:20 -07003990static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3991{
3992 struct wpabuf *csign_pub = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003993 const u8 *addr[1];
3994 size_t len[1];
3995 int res;
3996
Hai Shaloma20dcd72022-02-04 13:43:00 -08003997 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
Hai Shalomfdcde762020-04-02 11:19:20 -07003998 if (!csign_pub) {
3999 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
4000 return -1;
4001 }
4002
4003 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
4004 addr[0] = wpabuf_head(csign_pub);
4005 len[0] = wpabuf_len(csign_pub);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004006 res = sha256_vector(1, addr, len, conf->kid_hash);
Hai Shalomfdcde762020-04-02 11:19:20 -07004007 wpabuf_free(csign_pub);
4008 if (res < 0) {
4009 wpa_printf(MSG_DEBUG,
4010 "DPP: Failed to derive kid for C-sign-key");
4011 return -1;
4012 }
4013
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004014 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
4015 NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07004016 return conf->kid ? 0 : -1;
4017}
4018
4019
Hai Shalom899fcc72020-10-19 14:38:18 -07004020static struct dpp_configurator *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004021dpp_keygen_configurator(const char *curve, const u8 *privkey,
Hai Shalom899fcc72020-10-19 14:38:18 -07004022 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004023{
4024 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004025
4026 conf = os_zalloc(sizeof(*conf));
4027 if (!conf)
4028 return NULL;
4029
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004030 conf->curve = dpp_get_curve_name(curve);
4031 if (!conf->curve) {
4032 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
4033 os_free(conf);
4034 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004035 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004036
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004037 if (privkey)
4038 conf->csign = dpp_set_keypair(&conf->curve, privkey,
4039 privkey_len);
4040 else
4041 conf->csign = dpp_gen_keypair(conf->curve);
Hai Shalom899fcc72020-10-19 14:38:18 -07004042 if (pp_key)
4043 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
4044 pp_key_len);
4045 else
4046 conf->pp_key = dpp_gen_keypair(conf->curve);
4047 if (!conf->csign || !conf->pp_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004048 goto fail;
4049 conf->own = 1;
4050
Hai Shalomfdcde762020-04-02 11:19:20 -07004051 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004052 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004053 return conf;
4054fail:
4055 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07004056 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004057}
4058
4059
4060int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004061 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004062{
4063 struct wpabuf *conf_obj;
4064 int ret = -1;
4065
4066 if (!auth->conf) {
4067 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
4068 return -1;
4069 }
4070
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004071 auth->curve = dpp_get_curve_name(curve);
4072 if (!auth->curve) {
4073 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
4074 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004075 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004076
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004077 wpa_printf(MSG_DEBUG,
4078 "DPP: Building own configuration/connector with curve %s",
4079 auth->curve->name);
4080
4081 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4082 if (!auth->own_protocol_key)
4083 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07004084 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004085 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07004086 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004087
Hai Shalom899fcc72020-10-19 14:38:18 -07004088 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004089 if (!conf_obj) {
4090 wpabuf_free(auth->conf_obj[0].c_sign_key);
4091 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004092 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004093 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004094 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4095 wpabuf_len(conf_obj));
4096fail:
4097 wpabuf_free(conf_obj);
4098 auth->peer_protocol_key = NULL;
4099 return ret;
4100}
4101
4102
4103static int dpp_compatible_netrole(const char *role1, const char *role2)
4104{
4105 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4106 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4107}
4108
4109
4110static int dpp_connector_compatible_group(struct json_token *root,
4111 const char *group_id,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004112 const char *net_role,
4113 bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004114{
4115 struct json_token *groups, *token;
4116
4117 groups = json_get_member(root, "groups");
4118 if (!groups || groups->type != JSON_ARRAY)
4119 return 0;
4120
4121 for (token = groups->child; token; token = token->sibling) {
4122 struct json_token *id, *role;
4123
4124 id = json_get_member(token, "groupId");
4125 if (!id || id->type != JSON_STRING)
4126 continue;
4127
4128 role = json_get_member(token, "netRole");
4129 if (!role || role->type != JSON_STRING)
4130 continue;
4131
4132 if (os_strcmp(id->string, "*") != 0 &&
4133 os_strcmp(group_id, "*") != 0 &&
4134 os_strcmp(id->string, group_id) != 0)
4135 continue;
4136
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004137 if (reconfig && os_strcmp(net_role, "configurator") == 0)
4138 return 1;
4139 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004140 return 1;
4141 }
4142
4143 return 0;
4144}
4145
4146
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004147int dpp_connector_match_groups(struct json_token *own_root,
4148 struct json_token *peer_root, bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004149{
4150 struct json_token *groups, *token;
4151
4152 groups = json_get_member(peer_root, "groups");
4153 if (!groups || groups->type != JSON_ARRAY) {
4154 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4155 return 0;
4156 }
4157
4158 for (token = groups->child; token; token = token->sibling) {
4159 struct json_token *id, *role;
4160
4161 id = json_get_member(token, "groupId");
4162 if (!id || id->type != JSON_STRING) {
4163 wpa_printf(MSG_DEBUG,
4164 "DPP: Missing peer groupId string");
4165 continue;
4166 }
4167
4168 role = json_get_member(token, "netRole");
4169 if (!role || role->type != JSON_STRING) {
4170 wpa_printf(MSG_DEBUG,
4171 "DPP: Missing peer groups::netRole string");
4172 continue;
4173 }
4174 wpa_printf(MSG_DEBUG,
4175 "DPP: peer connector group: groupId='%s' netRole='%s'",
4176 id->string, role->string);
4177 if (dpp_connector_compatible_group(own_root, id->string,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004178 role->string, reconfig)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004179 wpa_printf(MSG_DEBUG,
4180 "DPP: Compatible group/netRole in own connector");
4181 return 1;
4182 }
4183 }
4184
4185 return 0;
4186}
4187
4188
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004189struct json_token * dpp_parse_own_connector(const char *own_connector)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004190{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004191 unsigned char *own_conn;
4192 size_t own_conn_len;
4193 const char *pos, *end;
4194 struct json_token *own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004195
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004196 pos = os_strchr(own_connector, '.');
4197 if (!pos) {
4198 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4199 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004200 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004201 pos++;
4202 end = os_strchr(pos, '.');
4203 if (!end) {
4204 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4205 return NULL;
4206 }
4207 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4208 if (!own_conn) {
4209 wpa_printf(MSG_DEBUG,
4210 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4211 return NULL;
4212 }
4213
4214 own_root = json_parse((const char *) own_conn, own_conn_len);
4215 os_free(own_conn);
4216 if (!own_root)
4217 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4218
4219 return own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004220}
4221
4222
Roshan Pius3a1667e2018-07-03 15:17:14 -07004223enum dpp_status_error
4224dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4225 const u8 *net_access_key, size_t net_access_key_len,
4226 const u8 *csign_key, size_t csign_key_len,
4227 const u8 *peer_connector, size_t peer_connector_len,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00004228 os_time_t *expiry, u8 *peer_key_hash)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004229{
4230 struct json_token *root = NULL, *netkey, *token;
4231 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004232 enum dpp_status_error ret = 255, res;
Sunil Ravi89eba102022-09-13 21:04:37 -07004233 struct crypto_ec_key *own_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004234 struct wpabuf *own_key_pub = NULL;
4235 const struct dpp_curve_params *curve, *own_curve;
4236 struct dpp_signed_connector_info info;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004237 size_t Nx_len;
4238 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4239
4240 os_memset(intro, 0, sizeof(*intro));
4241 os_memset(&info, 0, sizeof(info));
4242 if (expiry)
4243 *expiry = 0;
4244
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004245 own_key = dpp_set_keypair(&own_curve, net_access_key,
4246 net_access_key_len);
4247 if (!own_key) {
4248 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4249 goto fail;
4250 }
4251
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004252 own_root = dpp_parse_own_connector(own_connector);
4253 if (!own_root)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004254 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004255
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004256 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4257 peer_connector, peer_connector_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004258 if (res != DPP_STATUS_OK) {
4259 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004260 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004261 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004262
4263 root = json_parse((const char *) info.payload, info.payload_len);
4264 if (!root) {
4265 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004266 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004267 goto fail;
4268 }
4269
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004270 if (!dpp_connector_match_groups(own_root, root, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004271 wpa_printf(MSG_DEBUG,
4272 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004273 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004274 goto fail;
4275 }
4276
4277 token = json_get_member(root, "expiry");
4278 if (!token || token->type != JSON_STRING) {
4279 wpa_printf(MSG_DEBUG,
4280 "DPP: No expiry string found - connector does not expire");
4281 } else {
4282 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4283 if (dpp_key_expired(token->string, expiry)) {
4284 wpa_printf(MSG_DEBUG,
4285 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004286 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004287 goto fail;
4288 }
4289 }
4290
Hai Shaloma20dcd72022-02-04 13:43:00 -08004291#ifdef CONFIG_DPP3
4292 token = json_get_member(root, "version");
4293 if (token && token->type == JSON_NUMBER) {
4294 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4295 intro->peer_version = token->number;
4296 }
4297#endif /* CONFIG_DPP3 */
4298
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004299 netkey = json_get_member(root, "netAccessKey");
4300 if (!netkey || netkey->type != JSON_OBJECT) {
4301 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004302 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004303 goto fail;
4304 }
4305
Sunil Ravi89eba102022-09-13 21:04:37 -07004306 intro->peer_key = dpp_parse_jwk(netkey, &curve);
4307 if (!intro->peer_key) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004308 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004309 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004310 }
Sunil Ravi89eba102022-09-13 21:04:37 -07004311 dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004312
4313 if (own_curve != curve) {
4314 wpa_printf(MSG_DEBUG,
4315 "DPP: Mismatching netAccessKey curves (%s != %s)",
4316 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004317 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004318 goto fail;
4319 }
4320
4321 /* ECDH: N = nk * PK */
Sunil Ravi89eba102022-09-13 21:04:37 -07004322 if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004323 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004324
4325 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4326 Nx, Nx_len);
4327
4328 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4329 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4330 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4331 goto fail;
4332 }
4333 intro->pmk_len = curve->hash_len;
4334
4335 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
Sunil Ravi89eba102022-09-13 21:04:37 -07004336 if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4337 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004338 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4339 goto fail;
4340 }
4341
Sunil Ravi89eba102022-09-13 21:04:37 -07004342#ifdef CONFIG_DPP3
4343 if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4344 &intro->aead_id) < 0) {
4345 wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4346 curve->ike_group);
4347 goto fail;
4348 }
4349#endif /* CONFIG_DPP3 */
4350
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00004351 if (peer_key_hash)
4352 dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
4353
Roshan Pius3a1667e2018-07-03 15:17:14 -07004354 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004355fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07004356 if (ret != DPP_STATUS_OK)
Sunil Ravi89eba102022-09-13 21:04:37 -07004357 dpp_peer_intro_deinit(intro);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004358 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004359 os_free(info.payload);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004360 crypto_ec_key_deinit(own_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004361 wpabuf_free(own_key_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004362 json_free(root);
4363 json_free(own_root);
4364 return ret;
4365}
4366
4367
Sunil Ravi89eba102022-09-13 21:04:37 -07004368void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4369{
4370 if (!intro)
4371 return;
4372
4373 crypto_ec_key_deinit(intro->peer_key);
4374 os_memset(intro, 0, sizeof(*intro));
4375}
4376
4377
Hai Shaloma20dcd72022-02-04 13:43:00 -08004378#ifdef CONFIG_DPP3
4379int dpp_get_connector_version(const char *connector)
4380{
4381 struct json_token *root, *token;
4382 int ver = -1;
4383
4384 root = dpp_parse_own_connector(connector);
4385 if (!root)
4386 return -1;
4387
4388 token = json_get_member(root, "version");
4389 if (token && token->type == JSON_NUMBER)
4390 ver = token->number;
4391
4392 json_free(root);
4393 return ver;
4394}
4395#endif /* CONFIG_DPP3 */
4396
4397
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004398unsigned int dpp_next_id(struct dpp_global *dpp)
Hai Shalom021b0b52019-04-10 11:17:58 -07004399{
4400 struct dpp_bootstrap_info *bi;
4401 unsigned int max_id = 0;
4402
4403 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4404 if (bi->id > max_id)
4405 max_id = bi->id;
4406 }
4407 return max_id + 1;
4408}
4409
4410
4411static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4412{
4413 struct dpp_bootstrap_info *bi, *tmp;
4414 int found = 0;
4415
4416 if (!dpp)
4417 return -1;
4418
4419 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4420 struct dpp_bootstrap_info, list) {
4421 if (id && bi->id != id)
4422 continue;
4423 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07004424#ifdef CONFIG_DPP2
4425 if (dpp->remove_bi)
4426 dpp->remove_bi(dpp->cb_ctx, bi);
4427#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004428 dl_list_del(&bi->list);
4429 dpp_bootstrap_info_free(bi);
4430 }
4431
4432 if (id == 0)
4433 return 0; /* flush succeeds regardless of entries found */
4434 return found ? 0 : -1;
4435}
4436
4437
4438struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4439 const char *uri)
4440{
4441 struct dpp_bootstrap_info *bi;
4442
4443 if (!dpp)
4444 return NULL;
4445
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004446 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -07004447 if (!bi)
4448 return NULL;
4449
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004450 bi->type = DPP_BOOTSTRAP_QR_CODE;
4451 bi->id = dpp_next_id(dpp);
4452 dl_list_add(&dpp->bootstrap, &bi->list);
4453 return bi;
4454}
4455
4456
4457struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4458 const char *uri)
4459{
4460 struct dpp_bootstrap_info *bi;
4461
4462 if (!dpp)
4463 return NULL;
4464
4465 bi = dpp_parse_uri(uri);
4466 if (!bi)
4467 return NULL;
4468
4469 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004470 bi->id = dpp_next_id(dpp);
4471 dl_list_add(&dpp->bootstrap, &bi->list);
4472 return bi;
4473}
4474
4475
Sunil Ravia04bd252022-05-02 22:54:18 -07004476static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4477 char *txt)
4478{
4479 char *token, *context = NULL;
4480 u8 curves = 0;
4481
4482 if (!txt)
4483 return 0;
4484
4485 while ((token = str_token(txt, ":", &context))) {
4486 if (os_strcmp(token, "P-256") == 0) {
4487 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4488 } else if (os_strcmp(token, "P-384") == 0) {
4489 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4490 } else if (os_strcmp(token, "P-521") == 0) {
4491 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4492 } else if (os_strcmp(token, "BP-256") == 0) {
4493 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4494 } else if (os_strcmp(token, "BP-384") == 0) {
4495 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4496 } else if (os_strcmp(token, "BP-512") == 0) {
4497 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4498 } else {
4499 wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4500 token);
4501 return -1;
4502 }
4503 }
4504 bi->supported_curves = curves;
4505
4506 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4507 bi->supported_curves);
4508
4509 return 0;
4510}
4511
4512
Hai Shalom021b0b52019-04-10 11:17:58 -07004513int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4514{
Hai Shalomfdcde762020-04-02 11:19:20 -07004515 char *mac = NULL, *info = NULL, *curve = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00004516 char *key = NULL, *supported_curves = NULL, *host = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07004517 u8 *privkey = NULL;
4518 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004519 int ret = -1;
4520 struct dpp_bootstrap_info *bi;
4521
4522 if (!dpp)
4523 return -1;
4524
4525 bi = os_zalloc(sizeof(*bi));
4526 if (!bi)
4527 goto fail;
4528
4529 if (os_strstr(cmd, "type=qrcode"))
4530 bi->type = DPP_BOOTSTRAP_QR_CODE;
4531 else if (os_strstr(cmd, "type=pkex"))
4532 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004533 else if (os_strstr(cmd, "type=nfc-uri"))
4534 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004535 else
4536 goto fail;
4537
Hai Shalomfdcde762020-04-02 11:19:20 -07004538 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004539 mac = get_param(cmd, " mac=");
4540 info = get_param(cmd, " info=");
4541 curve = get_param(cmd, " curve=");
4542 key = get_param(cmd, " key=");
Sunil Ravia04bd252022-05-02 22:54:18 -07004543 supported_curves = get_param(cmd, " supported_curves=");
Sunil8cd6f4d2022-06-28 18:40:46 +00004544 host = get_param(cmd, " host=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004545
4546 if (key) {
4547 privkey_len = os_strlen(key) / 2;
4548 privkey = os_malloc(privkey_len);
4549 if (!privkey ||
4550 hexstr2bin(key, privkey, privkey_len) < 0)
4551 goto fail;
4552 }
4553
Hai Shalomfdcde762020-04-02 11:19:20 -07004554 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4555 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4556 dpp_parse_uri_mac(bi, mac) < 0 ||
4557 dpp_parse_uri_info(bi, info) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -07004558 dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +00004559 dpp_parse_uri_host(bi, host) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004560 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07004561 goto fail;
4562
Hai Shalom021b0b52019-04-10 11:17:58 -07004563 bi->id = dpp_next_id(dpp);
4564 dl_list_add(&dpp->bootstrap, &bi->list);
4565 ret = bi->id;
4566 bi = NULL;
4567fail:
4568 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -07004569 os_free(mac);
4570 os_free(info);
4571 str_clear_free(key);
Sunil Ravia04bd252022-05-02 22:54:18 -07004572 os_free(supported_curves);
Sunil8cd6f4d2022-06-28 18:40:46 +00004573 os_free(host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004574 bin_clear_free(privkey, privkey_len);
4575 dpp_bootstrap_info_free(bi);
4576 return ret;
4577}
4578
4579
4580struct dpp_bootstrap_info *
4581dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4582{
4583 struct dpp_bootstrap_info *bi;
4584
4585 if (!dpp)
4586 return NULL;
4587
4588 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4589 if (bi->id == id)
4590 return bi;
4591 }
4592 return NULL;
4593}
4594
4595
4596int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4597{
4598 unsigned int id_val;
4599
4600 if (os_strcmp(id, "*") == 0) {
4601 id_val = 0;
4602 } else {
4603 id_val = atoi(id);
4604 if (id_val == 0)
4605 return -1;
4606 }
4607
4608 return dpp_bootstrap_del(dpp, id_val);
4609}
4610
4611
Hai Shalom021b0b52019-04-10 11:17:58 -07004612const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4613{
4614 struct dpp_bootstrap_info *bi;
4615
4616 bi = dpp_bootstrap_get_id(dpp, id);
4617 if (!bi)
4618 return NULL;
4619 return bi->uri;
4620}
4621
4622
4623int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4624 char *reply, int reply_size)
4625{
4626 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004627 char pkhash[2 * SHA256_MAC_LEN + 1];
Sunil Ravia04bd252022-05-02 22:54:18 -07004628 char supp_curves[100];
Sunil8cd6f4d2022-06-28 18:40:46 +00004629 char host[100];
4630 int ret;
Hai Shalom021b0b52019-04-10 11:17:58 -07004631
4632 bi = dpp_bootstrap_get_id(dpp, id);
4633 if (!bi)
4634 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07004635 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4636 SHA256_MAC_LEN);
Sunil Ravia04bd252022-05-02 22:54:18 -07004637
4638 supp_curves[0] = '\0';
4639 if (bi->supported_curves) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004640 size_t i;
4641 char *pos = supp_curves;
4642 char *end = &supp_curves[sizeof(supp_curves)];
4643 const char *curve[6] = { "P-256", "P-384", "P-521",
4644 "BP-256", "BP-384", "BP-512" };
4645
4646 ret = os_snprintf(pos, end - pos, "supp_curves=");
4647 if (os_snprintf_error(end - pos, ret))
4648 return -1;
4649 pos += ret;
4650
4651 for (i = 0; i < ARRAY_SIZE(curve); i++) {
4652 if (!(bi->supported_curves & BIT(i)))
4653 continue;
4654 ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4655 if (os_snprintf_error(end - pos, ret))
4656 return -1;
4657 pos += ret;
4658 }
4659
4660 if (pos[-1] == ':')
4661 pos[-1] = '\n';
4662 else
4663 supp_curves[0] = '\0';
4664 }
4665
Sunil8cd6f4d2022-06-28 18:40:46 +00004666 host[0] = '\0';
4667 if (bi->host) {
4668 char buf[100];
4669
4670 ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4671 hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4672 bi->port);
4673 if (os_snprintf_error(sizeof(host), ret))
4674 return -1;
4675 }
4676
Hai Shalom021b0b52019-04-10 11:17:58 -07004677 return os_snprintf(reply, reply_size, "type=%s\n"
4678 "mac_addr=" MACSTR "\n"
4679 "info=%s\n"
4680 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -07004681 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07004682 "curve=%s\n"
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004683 "pkhash=%s\n"
Sunil8cd6f4d2022-06-28 18:40:46 +00004684 "version=%d\n%s%s",
Hai Shalom021b0b52019-04-10 11:17:58 -07004685 dpp_bootstrap_type_txt(bi->type),
4686 MAC2STR(bi->mac_addr),
4687 bi->info ? bi->info : "",
4688 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07004689 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -07004690 bi->curve->name,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004691 pkhash,
Sunil Ravia04bd252022-05-02 22:54:18 -07004692 bi->version,
Sunil8cd6f4d2022-06-28 18:40:46 +00004693 supp_curves,
4694 host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004695}
4696
4697
Hai Shalomfdcde762020-04-02 11:19:20 -07004698int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4699{
4700 struct dpp_bootstrap_info *bi;
4701
4702 bi = dpp_bootstrap_get_id(dpp, id);
4703 if (!bi)
4704 return -1;
4705
4706 str_clear_free(bi->configurator_params);
4707
4708 if (params) {
4709 bi->configurator_params = os_strdup(params);
4710 return bi->configurator_params ? 0 : -1;
4711 }
4712
4713 bi->configurator_params = NULL;
4714 return 0;
4715}
4716
4717
Hai Shalom021b0b52019-04-10 11:17:58 -07004718void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4719 const u8 *r_bootstrap,
4720 struct dpp_bootstrap_info **own_bi,
4721 struct dpp_bootstrap_info **peer_bi)
4722{
4723 struct dpp_bootstrap_info *bi;
4724
4725 *own_bi = NULL;
4726 *peer_bi = NULL;
4727 if (!dpp)
4728 return;
4729
4730 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4731 if (!*own_bi && bi->own &&
4732 os_memcmp(bi->pubkey_hash, r_bootstrap,
4733 SHA256_MAC_LEN) == 0) {
4734 wpa_printf(MSG_DEBUG,
4735 "DPP: Found matching own bootstrapping information");
4736 *own_bi = bi;
4737 }
4738
4739 if (!*peer_bi && !bi->own &&
4740 os_memcmp(bi->pubkey_hash, i_bootstrap,
4741 SHA256_MAC_LEN) == 0) {
4742 wpa_printf(MSG_DEBUG,
4743 "DPP: Found matching peer bootstrapping information");
4744 *peer_bi = bi;
4745 }
4746
4747 if (*own_bi && *peer_bi)
4748 break;
4749 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004750}
Hai Shalom021b0b52019-04-10 11:17:58 -07004751
Hai Shalomfdcde762020-04-02 11:19:20 -07004752
4753#ifdef CONFIG_DPP2
4754struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4755 const u8 *hash)
4756{
4757 struct dpp_bootstrap_info *bi;
4758
4759 if (!dpp)
4760 return NULL;
4761
4762 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4763 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4764 SHA256_MAC_LEN) == 0)
4765 return bi;
4766 }
4767
4768 return NULL;
4769}
4770#endif /* CONFIG_DPP2 */
4771
4772
4773static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4774 struct dpp_bootstrap_info *peer_bi)
4775{
4776 unsigned int i, freq = 0;
4777 enum hostapd_hw_mode mode;
4778 u8 op_class, channel;
4779 char chan[20];
4780
Hai Shalom899fcc72020-10-19 14:38:18 -07004781 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
Hai Shalomfdcde762020-04-02 11:19:20 -07004782 return 0; /* no channel preference/constraint */
4783
4784 for (i = 0; i < peer_bi->num_freq; i++) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004785 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004786 freq_included(own_bi->freq, own_bi->num_freq,
4787 peer_bi->freq[i])) {
4788 freq = peer_bi->freq[i];
4789 break;
4790 }
4791 }
4792 if (!freq) {
4793 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4794 return -1;
4795 }
4796
4797 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4798 if (mode == NUM_HOSTAPD_MODES) {
4799 wpa_printf(MSG_DEBUG,
4800 "DPP: Could not determine operating class or channel number for %u MHz",
4801 freq);
4802 }
4803
4804 wpa_printf(MSG_DEBUG,
4805 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4806 freq, op_class, channel);
4807 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4808 os_free(own_bi->chan);
4809 own_bi->chan = os_strdup(chan);
4810 own_bi->freq[0] = freq;
4811 own_bi->num_freq = 1;
4812 os_free(peer_bi->chan);
4813 peer_bi->chan = os_strdup(chan);
4814 peer_bi->freq[0] = freq;
4815 peer_bi->num_freq = 1;
4816
4817 return dpp_gen_uri(own_bi);
4818}
4819
4820
4821static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4822 struct dpp_bootstrap_info *peer_bi)
4823{
4824 if (peer_bi->curve == own_bi->curve)
4825 return 0;
4826
4827 wpa_printf(MSG_DEBUG,
4828 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4829
Hai Shaloma20dcd72022-02-04 13:43:00 -08004830 crypto_ec_key_deinit(own_bi->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -07004831 own_bi->pubkey = NULL;
4832
4833 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4834 dpp_gen_uri(own_bi) < 0)
4835 goto fail;
4836
4837 return 0;
4838fail:
4839 dl_list_del(&own_bi->list);
4840 dpp_bootstrap_info_free(own_bi);
4841 return -1;
4842}
4843
4844
4845int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4846 struct dpp_bootstrap_info *peer_bi)
4847{
4848 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4849 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4850 return -1;
4851 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004852}
4853
4854
4855static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4856{
4857 struct dpp_configurator *conf;
4858 unsigned int max_id = 0;
4859
4860 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4861 list) {
4862 if (conf->id > max_id)
4863 max_id = conf->id;
4864 }
4865 return max_id + 1;
4866}
4867
4868
4869int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4870{
Sunil Ravia04bd252022-05-02 22:54:18 -07004871 char *curve;
Hai Shalom899fcc72020-10-19 14:38:18 -07004872 char *key = NULL, *ppkey = NULL;
4873 u8 *privkey = NULL, *pp_key = NULL;
4874 size_t privkey_len = 0, pp_key_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004875 int ret = -1;
4876 struct dpp_configurator *conf = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07004877 const struct dpp_curve_params *net_access_key_curve = NULL;
4878
4879 curve = get_param(cmd, " net_access_key_curve=");
4880 if (curve) {
4881 net_access_key_curve = dpp_get_curve_name(curve);
4882 if (!net_access_key_curve) {
4883 wpa_printf(MSG_DEBUG,
4884 "DPP: Unsupported net_access_key_curve: %s",
4885 curve);
4886 goto fail;
4887 }
4888 os_free(curve);
4889 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004890
4891 curve = get_param(cmd, " curve=");
4892 key = get_param(cmd, " key=");
Hai Shalom899fcc72020-10-19 14:38:18 -07004893 ppkey = get_param(cmd, " ppkey=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004894
4895 if (key) {
4896 privkey_len = os_strlen(key) / 2;
4897 privkey = os_malloc(privkey_len);
4898 if (!privkey ||
4899 hexstr2bin(key, privkey, privkey_len) < 0)
4900 goto fail;
4901 }
4902
Hai Shalom899fcc72020-10-19 14:38:18 -07004903 if (ppkey) {
Hai Shalom60840252021-02-19 19:02:11 -08004904 pp_key_len = os_strlen(ppkey) / 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07004905 pp_key = os_malloc(pp_key_len);
4906 if (!pp_key ||
4907 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4908 goto fail;
4909 }
4910
4911 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4912 pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004913 if (!conf)
4914 goto fail;
4915
Sunil Ravia04bd252022-05-02 22:54:18 -07004916 conf->net_access_key_curve = net_access_key_curve;
Hai Shalom021b0b52019-04-10 11:17:58 -07004917 conf->id = dpp_next_configurator_id(dpp);
4918 dl_list_add(&dpp->configurator, &conf->list);
4919 ret = conf->id;
4920 conf = NULL;
4921fail:
4922 os_free(curve);
4923 str_clear_free(key);
Hai Shalom899fcc72020-10-19 14:38:18 -07004924 str_clear_free(ppkey);
Hai Shalom021b0b52019-04-10 11:17:58 -07004925 bin_clear_free(privkey, privkey_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004926 bin_clear_free(pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004927 dpp_configurator_free(conf);
4928 return ret;
4929}
4930
4931
Sunil Ravia04bd252022-05-02 22:54:18 -07004932int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4933{
4934 unsigned int id;
4935 struct dpp_configurator *conf;
4936 char *curve;
4937
4938 id = atoi(cmd);
4939 conf = dpp_configurator_get_id(dpp, id);
4940 if (!conf)
4941 return -1;
4942
4943 curve = get_param(cmd, " net_access_key_curve=");
4944 if (curve) {
4945 const struct dpp_curve_params *net_access_key_curve;
4946
4947 net_access_key_curve = dpp_get_curve_name(curve);
4948 os_free(curve);
4949 if (!net_access_key_curve)
4950 return -1;
4951 conf->net_access_key_curve = net_access_key_curve;
4952 }
4953
4954 return 0;
4955}
4956
4957
Hai Shalom021b0b52019-04-10 11:17:58 -07004958static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4959{
4960 struct dpp_configurator *conf, *tmp;
4961 int found = 0;
4962
4963 if (!dpp)
4964 return -1;
4965
4966 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4967 struct dpp_configurator, list) {
4968 if (id && conf->id != id)
4969 continue;
4970 found = 1;
4971 dl_list_del(&conf->list);
4972 dpp_configurator_free(conf);
4973 }
4974
4975 if (id == 0)
4976 return 0; /* flush succeeds regardless of entries found */
4977 return found ? 0 : -1;
4978}
4979
4980
4981int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4982{
4983 unsigned int id_val;
4984
4985 if (os_strcmp(id, "*") == 0) {
4986 id_val = 0;
4987 } else {
4988 id_val = atoi(id);
4989 if (id_val == 0)
4990 return -1;
4991 }
4992
4993 return dpp_configurator_del(dpp, id_val);
4994}
4995
4996
4997int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4998 char *buf, size_t buflen)
4999{
5000 struct dpp_configurator *conf;
5001
5002 conf = dpp_configurator_get_id(dpp, id);
5003 if (!conf)
5004 return -1;
5005
5006 return dpp_configurator_get_key(conf, buf, buflen);
5007}
5008
5009
Hai Shalom81f62d82019-07-22 12:10:00 -07005010#ifdef CONFIG_DPP2
5011
Hai Shalomfdcde762020-04-02 11:19:20 -07005012int dpp_configurator_from_backup(struct dpp_global *dpp,
5013 struct dpp_asymmetric_key *key)
5014{
5015 struct dpp_configurator *conf;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005016 const struct dpp_curve_params *curve, *curve_pp;
Hai Shalomfdcde762020-04-02 11:19:20 -07005017
Hai Shalom899fcc72020-10-19 14:38:18 -07005018 if (!key->csign || !key->pp_key)
Hai Shalomfdcde762020-04-02 11:19:20 -07005019 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005020
5021 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
Hai Shalomfdcde762020-04-02 11:19:20 -07005022 if (!curve) {
5023 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
5024 return -1;
5025 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08005026
5027 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
5028 if (!curve_pp) {
5029 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
Hai Shalom899fcc72020-10-19 14:38:18 -07005030 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005031 }
5032
5033 if (curve != curve_pp) {
Hai Shalom899fcc72020-10-19 14:38:18 -07005034 wpa_printf(MSG_INFO,
5035 "DPP: Mismatch in c-sign-key and ppKey groups");
5036 return -1;
5037 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005038
5039 conf = os_zalloc(sizeof(*conf));
5040 if (!conf)
5041 return -1;
5042 conf->curve = curve;
5043 conf->csign = key->csign;
5044 key->csign = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07005045 conf->pp_key = key->pp_key;
5046 key->pp_key = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07005047 conf->own = 1;
5048 if (dpp_configurator_gen_kid(conf) < 0) {
5049 dpp_configurator_free(conf);
5050 return -1;
5051 }
5052
5053 conf->id = dpp_next_configurator_id(dpp);
5054 dl_list_add(&dpp->configurator, &conf->list);
5055 return conf->id;
5056}
5057
5058
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005059struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
5060 const u8 *kid)
Hai Shalom81f62d82019-07-22 12:10:00 -07005061{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005062 struct dpp_configurator *conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07005063
5064 if (!dpp)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005065 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005066
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005067 dl_list_for_each(conf, &dpp->configurator,
5068 struct dpp_configurator, list) {
5069 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
5070 return conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07005071 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005072 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005073}
5074
5075#endif /* CONFIG_DPP2 */
5076
5077
5078struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07005079{
5080 struct dpp_global *dpp;
5081
5082 dpp = os_zalloc(sizeof(*dpp));
5083 if (!dpp)
5084 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005085#ifdef CONFIG_DPP2
5086 dpp->cb_ctx = config->cb_ctx;
Hai Shalomfdcde762020-04-02 11:19:20 -07005087 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07005088#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005089
5090 dl_list_init(&dpp->bootstrap);
5091 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07005092#ifdef CONFIG_DPP2
5093 dl_list_init(&dpp->controllers);
5094 dl_list_init(&dpp->tcp_init);
Sunil Ravi89eba102022-09-13 21:04:37 -07005095 dpp->relay_sock = -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07005096#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005097
5098 return dpp;
5099}
5100
5101
5102void dpp_global_clear(struct dpp_global *dpp)
5103{
5104 if (!dpp)
5105 return;
5106
5107 dpp_bootstrap_del(dpp, 0);
5108 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07005109#ifdef CONFIG_DPP2
5110 dpp_tcp_init_flush(dpp);
5111 dpp_relay_flush_controllers(dpp);
5112 dpp_controller_stop(dpp);
5113#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005114}
5115
5116
5117void dpp_global_deinit(struct dpp_global *dpp)
5118{
5119 dpp_global_clear(dpp);
5120 os_free(dpp);
5121}
Hai Shalom81f62d82019-07-22 12:10:00 -07005122
5123
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00005124void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
5125{
5126 u8 hash[SHA256_MAC_LEN];
5127 char hex[SHA256_MAC_LEN * 2 + 1];
5128
5129 if (auth->peer_protocol_key) {
5130 dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
5131 wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
5132 } else {
5133 hex[0] = '\0';
5134 }
5135 wpa_msg(auth->msg_ctx, MSG_INFO,
5136 DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d",
5137 initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1,
5138 auth->peer_bi ? (int) auth->peer_bi->id : -1);
5139}
5140
5141
Hai Shalom81f62d82019-07-22 12:10:00 -07005142#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07005143
Hai Shalomfdcde762020-04-02 11:19:20 -07005144struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5145{
5146 struct wpabuf *msg;
5147
5148 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5149
5150 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5151 if (!msg)
5152 return NULL;
5153
5154 /* Responder Bootstrapping Key Hash */
5155 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5156 wpa_hexdump_buf(MSG_DEBUG,
5157 "DPP: Presence Announcement frame attributes", msg);
5158 return msg;
5159}
Hai Shalom899fcc72020-10-19 14:38:18 -07005160
5161
5162void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5163 unsigned int freq, const u8 *hash)
5164{
5165 char hex[SHA256_MAC_LEN * 2 + 1];
5166
5167 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5168 wpa_msg(msg_ctx, MSG_INFO,
5169 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5170 id, MAC2STR(src), freq, hex);
5171}
5172
Hai Shalom81f62d82019-07-22 12:10:00 -07005173#endif /* CONFIG_DPP2 */
Sunil Ravi89eba102022-09-13 21:04:37 -07005174
5175
5176#ifdef CONFIG_DPP3
5177
5178struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5179{
5180 struct wpabuf *msg;
5181 const u8 *r_hash = bi->pubkey_hash_chirp;
5182#ifdef CONFIG_TESTING_OPTIONS
5183 u8 test_hash[SHA256_MAC_LEN];
5184#endif /* CONFIG_TESTING_OPTIONS */
5185
5186 wpa_printf(MSG_DEBUG,
5187 "DPP: Build Push Button Presence Announcement frame");
5188
5189 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5190 4 + SHA256_MAC_LEN);
5191 if (!msg)
5192 return NULL;
5193
5194#ifdef CONFIG_TESTING_OPTIONS
5195 if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5196 wpa_printf(MSG_INFO,
5197 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5198 os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5199 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5200 r_hash = test_hash;
5201 }
5202#endif /* CONFIG_TESTING_OPTIONS */
5203
5204 /* Responder Bootstrapping Key Hash */
5205 dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5206 wpa_hexdump_buf(MSG_DEBUG,
5207 "DPP: Push Button Presence Announcement frame attributes",
5208 msg);
5209 return msg;
5210}
5211
5212
5213struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5214 const u8 *e_hash,
5215 const u8 *c_nonce,
5216 size_t c_nonce_len)
5217{
5218 struct wpabuf *msg;
5219 const u8 *i_hash = bi->pubkey_hash_chirp;
5220#ifdef CONFIG_TESTING_OPTIONS
5221 u8 test_hash[SHA256_MAC_LEN];
5222#endif /* CONFIG_TESTING_OPTIONS */
5223
5224 wpa_printf(MSG_DEBUG,
5225 "DPP: Build Push Button Presence Announcement Response frame");
5226
5227 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5228 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5229 if (!msg)
5230 return NULL;
5231
5232#ifdef CONFIG_TESTING_OPTIONS
5233 if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5234 wpa_printf(MSG_INFO,
5235 "DPP: TESTING - invalid I-Bootstrap Key Hash");
5236 os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5237 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5238 i_hash = test_hash;
5239 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5240 wpa_printf(MSG_INFO,
5241 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5242 os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5243 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5244 e_hash = test_hash;
5245 }
5246#endif /* CONFIG_TESTING_OPTIONS */
5247
5248 /* Initiator Bootstrapping Key Hash */
5249 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5250 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5251 wpabuf_put_le16(msg, SHA256_MAC_LEN);
5252 wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5253
5254 /* Responder Bootstrapping Key Hash */
5255 dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5256
5257 /* Configurator Nonce */
5258 wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5259 wpabuf_put_le16(msg, c_nonce_len);
5260 wpabuf_put_data(msg, c_nonce, c_nonce_len);
5261
5262 wpa_hexdump_buf(MSG_DEBUG,
5263 "DPP: Push Button Presence Announcement Response frame attributes",
5264 msg);
5265 return msg;
5266}
5267
5268#endif /* CONFIG_DPP3 */