blob: 46f2551eb8b6e979df14a5cd5f632a09ac12b1f4 [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
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700302int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700303{
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700304#ifdef CONFIG_DPP2
305 if (!version || DPP_VERSION < 2)
306 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700307
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700308 if (*version == '1')
309 bi->version = 1;
310 else if (*version == '2')
311 bi->version = 2;
Hai Shaloma20dcd72022-02-04 13:43:00 -0800312 else if (*version == '3')
313 bi->version = 3;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700314 else
315 wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700316
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700317 wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
318#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700319
320 return 0;
321}
322
323
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700324static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
325{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700326 u8 *data;
327 size_t data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700328 int res;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700329 const char *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700330
331 end = os_strchr(info, ';');
332 if (!end)
333 return -1;
334
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800335 data = base64_decode(info, end - info, &data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700336 if (!data) {
337 wpa_printf(MSG_DEBUG,
338 "DPP: Invalid base64 encoding on URI public-key");
339 return -1;
340 }
341 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
342 data, data_len);
343
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700344 res = dpp_get_subject_public_key(bi, data, data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700345 os_free(data);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700346 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700347}
348
349
Sunil Ravia04bd252022-05-02 22:54:18 -0700350static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
351 const char *txt)
352{
353 int val;
354
355 if (!txt)
356 return 0;
357
358 val = hex2num(txt[0]);
359 if (val < 0)
360 return -1;
361 bi->supported_curves = val;
362
363 val = hex2num(txt[1]);
364 if (val > 0)
365 bi->supported_curves |= val << 4;
366
367 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
368 bi->supported_curves);
369
370 return 0;
371}
372
373
Sunil8cd6f4d2022-06-28 18:40:46 +0000374static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
375{
376 const char *end;
377 char *port;
378 struct hostapd_ip_addr addr;
379 char buf[100], *pos;
380
381 if (!txt)
382 return 0;
383
384 end = os_strchr(txt, ';');
385 if (!end)
386 end = txt + os_strlen(txt);
387 if (end - txt > (int) sizeof(buf) - 1)
388 return -1;
389 os_memcpy(buf, txt, end - txt);
390 buf[end - txt] = '\0';
391
392 bi->port = DPP_TCP_PORT;
393
394 pos = buf;
395 if (*pos == '[') {
396 pos = &buf[1];
397 port = os_strchr(pos, ']');
398 if (!port)
399 return -1;
400 *port++ = '\0';
401 if (*port == ':')
402 bi->port = atoi(port + 1);
403 }
404
405 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
406 if (buf[0] != '[') {
407 port = os_strrchr(pos, ':');
408 if (port) {
409 *port++ = '\0';
410 bi->port = atoi(port);
411 }
412 }
413 if (hostapd_parse_ip_addr(pos, &addr) < 0) {
414 wpa_printf(MSG_INFO,
415 "DPP: Invalid IP address in URI host entry: %s",
416 pos);
417 return -1;
418 }
419 }
420 os_free(bi->host);
421 bi->host = os_memdup(&addr, sizeof(addr));
422 if (!bi->host)
423 return -1;
424
425 wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
426 hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
427
428 return 0;
429}
430
431
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700432static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
433{
434 const char *pos = uri;
435 const char *end;
436 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +0000437 const char *version = NULL, *supported_curves = NULL, *host = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700438 struct dpp_bootstrap_info *bi;
439
440 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
441
442 if (os_strncmp(pos, "DPP:", 4) != 0) {
443 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
444 return NULL;
445 }
446 pos += 4;
447
448 for (;;) {
449 end = os_strchr(pos, ';');
450 if (!end)
451 break;
452
453 if (end == pos) {
454 /* Handle terminating ";;" and ignore unexpected ";"
455 * for parsing robustness. */
456 pos++;
457 continue;
458 }
459
460 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
461 chan_list = pos + 2;
462 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
463 mac = pos + 2;
464 else if (pos[0] == 'I' && pos[1] == ':' && !info)
465 info = pos + 2;
466 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
467 pk = pos + 2;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700468 else if (pos[0] == 'V' && pos[1] == ':' && !version)
469 version = pos + 2;
Sunil Ravia04bd252022-05-02 22:54:18 -0700470 else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
471 supported_curves = pos + 2;
Sunil8cd6f4d2022-06-28 18:40:46 +0000472 else if (pos[0] == 'H' && pos[1] == ':' && !host)
473 host = pos + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700474 else
475 wpa_hexdump_ascii(MSG_DEBUG,
476 "DPP: Ignore unrecognized URI parameter",
477 pos, end - pos);
478 pos = end + 1;
479 }
480
481 if (!pk) {
482 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
483 return NULL;
484 }
485
486 bi = os_zalloc(sizeof(*bi));
487 if (!bi)
488 return NULL;
489
490 if (dpp_clone_uri(bi, uri) < 0 ||
491 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
492 dpp_parse_uri_mac(bi, mac) < 0 ||
493 dpp_parse_uri_info(bi, info) < 0 ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700494 dpp_parse_uri_version(bi, version) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -0700495 dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +0000496 dpp_parse_uri_host(bi, host) < 0 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700497 dpp_parse_uri_pk(bi, pk) < 0) {
498 dpp_bootstrap_info_free(bi);
499 bi = NULL;
500 }
501
502 return bi;
503}
504
505
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700506void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700507{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700508 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
509 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
510 wpabuf_put_le16(msg, 1);
511 wpabuf_put_u8(msg, status);
512}
513
514
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700515void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700516{
517 if (hash) {
518 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
519 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
520 wpabuf_put_le16(msg, SHA256_MAC_LEN);
521 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
522 }
523}
524
525
Roshan Pius3a1667e2018-07-03 15:17:14 -0700526static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
527 u16 num_modes, unsigned int freq)
528{
529 u16 m;
530 int c, flag;
531
532 if (!own_modes || !num_modes)
533 return 1;
534
535 for (m = 0; m < num_modes; m++) {
536 for (c = 0; c < own_modes[m].num_channels; c++) {
537 if ((unsigned int) own_modes[m].channels[c].freq !=
538 freq)
539 continue;
540 flag = own_modes[m].channels[c].flag;
541 if (!(flag & (HOSTAPD_CHAN_DISABLED |
542 HOSTAPD_CHAN_NO_IR |
543 HOSTAPD_CHAN_RADAR)))
544 return 1;
545 }
546 }
547
548 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
549 return 0;
550}
551
552
553static int freq_included(const unsigned int freqs[], unsigned int num,
554 unsigned int freq)
555{
556 while (num > 0) {
557 if (freqs[--num] == freq)
558 return 1;
559 }
560 return 0;
561}
562
563
564static void freq_to_start(unsigned int freqs[], unsigned int num,
565 unsigned int freq)
566{
567 unsigned int i;
568
569 for (i = 0; i < num; i++) {
570 if (freqs[i] == freq)
571 break;
572 }
573 if (i == 0 || i >= num)
574 return;
575 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
576 freqs[0] = freq;
577}
578
579
580static int dpp_channel_intersect(struct dpp_authentication *auth,
581 struct hostapd_hw_modes *own_modes,
582 u16 num_modes)
583{
584 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
585 unsigned int i, freq;
586
587 for (i = 0; i < peer_bi->num_freq; i++) {
588 freq = peer_bi->freq[i];
589 if (freq_included(auth->freq, auth->num_freq, freq))
590 continue;
591 if (dpp_channel_ok_init(own_modes, num_modes, freq))
592 auth->freq[auth->num_freq++] = freq;
593 }
594 if (!auth->num_freq) {
595 wpa_printf(MSG_INFO,
596 "DPP: No available channels for initiating DPP Authentication");
597 return -1;
598 }
599 auth->curr_freq = auth->freq[0];
600 return 0;
601}
602
603
604static int dpp_channel_local_list(struct dpp_authentication *auth,
605 struct hostapd_hw_modes *own_modes,
606 u16 num_modes)
607{
608 u16 m;
609 int c, flag;
610 unsigned int freq;
611
612 auth->num_freq = 0;
613
614 if (!own_modes || !num_modes) {
615 auth->freq[0] = 2412;
616 auth->freq[1] = 2437;
617 auth->freq[2] = 2462;
618 auth->num_freq = 3;
619 return 0;
620 }
621
622 for (m = 0; m < num_modes; m++) {
623 for (c = 0; c < own_modes[m].num_channels; c++) {
624 freq = own_modes[m].channels[c].freq;
625 flag = own_modes[m].channels[c].flag;
626 if (flag & (HOSTAPD_CHAN_DISABLED |
627 HOSTAPD_CHAN_NO_IR |
628 HOSTAPD_CHAN_RADAR))
629 continue;
630 if (freq_included(auth->freq, auth->num_freq, freq))
631 continue;
632 auth->freq[auth->num_freq++] = freq;
633 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
634 m = num_modes;
635 break;
636 }
637 }
638 }
639
640 return auth->num_freq == 0 ? -1 : 0;
641}
642
643
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700644int dpp_prepare_channel_list(struct dpp_authentication *auth,
645 unsigned int neg_freq,
646 struct hostapd_hw_modes *own_modes, u16 num_modes)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700647{
648 int res;
649 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
650 unsigned int i;
651
Hai Shalomfdcde762020-04-02 11:19:20 -0700652 if (!own_modes) {
653 if (!neg_freq)
654 return -1;
655 auth->num_freq = 1;
656 auth->freq[0] = neg_freq;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700657 auth->curr_freq = neg_freq;
Hai Shalomfdcde762020-04-02 11:19:20 -0700658 return 0;
659 }
660
Roshan Pius3a1667e2018-07-03 15:17:14 -0700661 if (auth->peer_bi->num_freq > 0)
662 res = dpp_channel_intersect(auth, own_modes, num_modes);
663 else
664 res = dpp_channel_local_list(auth, own_modes, num_modes);
665 if (res < 0)
666 return res;
667
668 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
669 * likely channels first. */
670 freq_to_start(auth->freq, auth->num_freq, 2462);
671 freq_to_start(auth->freq, auth->num_freq, 2412);
672 freq_to_start(auth->freq, auth->num_freq, 2437);
673
674 auth->freq_idx = 0;
675 auth->curr_freq = auth->freq[0];
676
677 pos = freqs;
678 end = pos + sizeof(freqs);
679 for (i = 0; i < auth->num_freq; i++) {
680 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
681 if (os_snprintf_error(end - pos, res))
682 break;
683 pos += res;
684 }
685 *pos = '\0';
686 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
687 freqs);
688
689 return 0;
690}
691
692
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700693int dpp_gen_uri(struct dpp_bootstrap_info *bi)
Hai Shalomfdcde762020-04-02 11:19:20 -0700694{
695 char macstr[ETH_ALEN * 2 + 10];
696 size_t len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700697 char supp_curves[10];
Sunil8cd6f4d2022-06-28 18:40:46 +0000698 char host[100];
Hai Shalomfdcde762020-04-02 11:19:20 -0700699
700 len = 4; /* "DPP:" */
701 if (bi->chan)
702 len += 3 + os_strlen(bi->chan); /* C:...; */
703 if (is_zero_ether_addr(bi->mac_addr))
704 macstr[0] = '\0';
705 else
706 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
707 MAC2STR(bi->mac_addr));
708 len += os_strlen(macstr); /* M:...; */
709 if (bi->info)
710 len += 3 + os_strlen(bi->info); /* I:...; */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700711#ifdef CONFIG_DPP2
712 len += 4; /* V:2; */
713#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700714 len += 4 + os_strlen(bi->pk); /* K:...;; */
715
Sunil Ravia04bd252022-05-02 22:54:18 -0700716 if (bi->supported_curves) {
717 u8 val = bi->supported_curves;
718
719 if (val & 0xf0) {
720 val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
721 len += os_snprintf(supp_curves, sizeof(supp_curves),
722 "B:%02x;", val);
723 } else {
724 len += os_snprintf(supp_curves, sizeof(supp_curves),
725 "B:%x;", val);
726 }
727 } else {
728 supp_curves[0] = '\0';
729 }
730
Sunil8cd6f4d2022-06-28 18:40:46 +0000731 host[0] = '\0';
732 if (bi->host) {
733 char buf[100];
734 const char *addr;
735
736 addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
737 if (!addr)
738 return -1;
739 if (bi->port == DPP_TCP_PORT)
740 len += os_snprintf(host, sizeof(host), "H:%s;", addr);
741 else if (bi->host->af == AF_INET)
742 len += os_snprintf(host, sizeof(host), "H:%s:%u;",
743 addr, bi->port);
744 else
745 len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
746 addr, bi->port);
747 }
748
Hai Shalomfdcde762020-04-02 11:19:20 -0700749 os_free(bi->uri);
750 bi->uri = os_malloc(len + 1);
751 if (!bi->uri)
752 return -1;
Sunil8cd6f4d2022-06-28 18:40:46 +0000753 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 -0700754 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
755 bi->chan ? ";" : "",
756 macstr,
757 bi->info ? "I:" : "", bi->info ? bi->info : "",
758 bi->info ? ";" : "",
Hai Shaloma20dcd72022-02-04 13:43:00 -0800759 DPP_VERSION == 3 ? "V:3;" :
760 (DPP_VERSION == 2 ? "V:2;" : ""),
Sunil Ravia04bd252022-05-02 22:54:18 -0700761 supp_curves,
Sunil8cd6f4d2022-06-28 18:40:46 +0000762 host,
Hai Shalomfdcde762020-04-02 11:19:20 -0700763 bi->pk);
764 return 0;
765}
766
767
Hai Shalomfdcde762020-04-02 11:19:20 -0700768struct dpp_authentication *
769dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
770{
771 struct dpp_authentication *auth;
772
773 auth = os_zalloc(sizeof(*auth));
774 if (!auth)
775 return NULL;
776 auth->global = dpp;
777 auth->msg_ctx = msg_ctx;
778 auth->conf_resp_status = 255;
779 return auth;
780}
781
782
Hai Shalom021b0b52019-04-10 11:17:58 -0700783static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
784 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700785{
786 size_t nonce_len;
787 size_t json_len, clear_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700788 struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700789 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700790 size_t attr_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700791#ifdef CONFIG_DPP3
792 u8 auth_i[DPP_MAX_HASH_LEN];
793#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700794
795 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
796
797 nonce_len = auth->curve->nonce_len;
798 if (random_get_bytes(auth->e_nonce, nonce_len)) {
799 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
800 goto fail;
801 }
802 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
803 json_len = os_strlen(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700804 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700805
806 /* { E-nonce, configAttrib }ke */
807 clear_len = 4 + nonce_len + 4 + json_len;
Sunil Ravia04bd252022-05-02 22:54:18 -0700808#ifdef CONFIG_DPP3
809 if (auth->waiting_new_key) {
810 pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
811 if (!pe)
812 goto fail;
813 clear_len += 4 + wpabuf_len(pe);
814
815 if (dpp_derive_auth_i(auth, auth_i) < 0)
816 goto fail;
817 clear_len += 4 + auth->curve->hash_len;
818 }
819#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700820 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700821 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
822#ifdef CONFIG_TESTING_OPTIONS
823 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
824 attr_len += 5;
825#endif /* CONFIG_TESTING_OPTIONS */
826 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700827 if (!clear || !msg)
828 goto fail;
829
Roshan Pius3a1667e2018-07-03 15:17:14 -0700830#ifdef CONFIG_TESTING_OPTIONS
831 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
832 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
833 goto skip_e_nonce;
834 }
835 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
836 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
837 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
838 wpabuf_put_le16(clear, nonce_len - 1);
839 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
840 goto skip_e_nonce;
841 }
842 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
843 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
844 goto skip_wrapped_data;
845 }
846#endif /* CONFIG_TESTING_OPTIONS */
847
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700848 /* E-nonce */
849 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
850 wpabuf_put_le16(clear, nonce_len);
851 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
852
Roshan Pius3a1667e2018-07-03 15:17:14 -0700853#ifdef CONFIG_TESTING_OPTIONS
854skip_e_nonce:
855 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
856 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
857 goto skip_conf_attr_obj;
858 }
859#endif /* CONFIG_TESTING_OPTIONS */
860
Sunil Ravia04bd252022-05-02 22:54:18 -0700861#ifdef CONFIG_DPP3
862 if (pe) {
863 wpa_printf(MSG_DEBUG, "DPP: Pe");
864 wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
865 wpabuf_put_le16(clear, wpabuf_len(pe));
866 wpabuf_put_buf(clear, pe);
867 }
868 if (auth->waiting_new_key) {
869 wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
870 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
871 wpabuf_put_le16(clear, auth->curve->hash_len);
872 wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
873 }
874#endif /* CONFIG_DPP3 */
875
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700876 /* configAttrib */
877 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
878 wpabuf_put_le16(clear, json_len);
879 wpabuf_put_data(clear, json, json_len);
880
Roshan Pius3a1667e2018-07-03 15:17:14 -0700881#ifdef CONFIG_TESTING_OPTIONS
882skip_conf_attr_obj:
883#endif /* CONFIG_TESTING_OPTIONS */
884
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700885 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
886 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
887 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
888
889 /* No AES-SIV AD */
890 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
891 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
892 wpabuf_head(clear), wpabuf_len(clear),
893 0, NULL, NULL, wrapped) < 0)
894 goto fail;
895 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
896 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
897
Roshan Pius3a1667e2018-07-03 15:17:14 -0700898#ifdef CONFIG_TESTING_OPTIONS
899 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
900 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
901 dpp_build_attr_status(msg, DPP_STATUS_OK);
902 }
903skip_wrapped_data:
904#endif /* CONFIG_TESTING_OPTIONS */
905
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700906 wpa_hexdump_buf(MSG_DEBUG,
907 "DPP: Configuration Request frame attributes", msg);
Sunil Ravia04bd252022-05-02 22:54:18 -0700908out:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700909 wpabuf_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -0700910 wpabuf_free(pe);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700911 return msg;
912
913fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700914 wpabuf_free(msg);
Sunil Ravia04bd252022-05-02 22:54:18 -0700915 msg = NULL;
916 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700917}
918
919
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700920void dpp_write_adv_proto(struct wpabuf *buf)
Hai Shalom021b0b52019-04-10 11:17:58 -0700921{
922 /* Advertisement Protocol IE */
923 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
924 wpabuf_put_u8(buf, 8); /* Length */
925 wpabuf_put_u8(buf, 0x7f);
926 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
927 wpabuf_put_u8(buf, 5);
928 wpabuf_put_be24(buf, OUI_WFA);
929 wpabuf_put_u8(buf, DPP_OUI_TYPE);
930 wpabuf_put_u8(buf, 0x01);
931}
932
933
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700934void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
Hai Shalom021b0b52019-04-10 11:17:58 -0700935{
936 /* GAS Query */
937 wpabuf_put_le16(buf, wpabuf_len(query));
938 wpabuf_put_buf(buf, query);
939}
940
941
942struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
943 const char *json)
944{
945 struct wpabuf *buf, *conf_req;
946
947 conf_req = dpp_build_conf_req_attr(auth, json);
948 if (!conf_req) {
949 wpa_printf(MSG_DEBUG,
950 "DPP: No configuration request data available");
951 return NULL;
952 }
953
954 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
955 if (!buf) {
956 wpabuf_free(conf_req);
957 return NULL;
958 }
959
960 dpp_write_adv_proto(buf);
961 dpp_write_gas_query(buf, conf_req);
962 wpabuf_free(conf_req);
963 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
964
965 return buf;
966}
967
968
Hai Shalomc3565922019-10-28 11:58:20 -0700969struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800970 const char *name,
971 enum dpp_netrole netrole,
Sunil Ravi89eba102022-09-13 21:04:37 -0700972 const char *mud_url, int *opclasses,
973 const char *extra_name,
974 const char *extra_value)
Hai Shalomc3565922019-10-28 11:58:20 -0700975{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800976 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -0700977 const char *tech = "infra";
978 const char *dpp_name;
Sunil Ravia04bd252022-05-02 22:54:18 -0700979 struct wpabuf *buf = NULL, *json = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700980 char *csr = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700981
982#ifdef CONFIG_TESTING_OPTIONS
983 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
984 static const char *bogus_tech = "knfra";
985
986 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
987 tech = bogus_tech;
988 }
989#endif /* CONFIG_TESTING_OPTIONS */
990
991 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800992 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -0700993
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800994 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -0700995 if (mud_url && mud_url[0])
996 len += 10 + os_strlen(mud_url);
Sunil Ravi89eba102022-09-13 21:04:37 -0700997 if (extra_name && extra_value && extra_name[0] && extra_value[0])
998 len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
Hai Shalom899fcc72020-10-19 14:38:18 -0700999#ifdef CONFIG_DPP2
1000 if (auth->csr) {
1001 size_t csr_len;
1002
1003 csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1004 wpabuf_len(auth->csr), &csr_len);
1005 if (!csr)
Sunil Ravia04bd252022-05-02 22:54:18 -07001006 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07001007 len += 30 + csr_len;
1008 }
1009#endif /* CONFIG_DPP2 */
Hai Shalomc3565922019-10-28 11:58:20 -07001010 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001011 if (!json)
Sunil Ravia04bd252022-05-02 22:54:18 -07001012 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001013
1014 json_start_object(json, NULL);
Sunil Ravia04bd252022-05-02 22:54:18 -07001015 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1016 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001017 json_value_sep(json);
1018 json_add_string(json, "wi-fi_tech", tech);
1019 json_value_sep(json);
1020 json_add_string(json, "netRole", dpp_netrole_str(netrole));
1021 if (mud_url && mud_url[0]) {
1022 json_value_sep(json);
1023 json_add_string(json, "mudurl", mud_url);
1024 }
Hai Shalomc3565922019-10-28 11:58:20 -07001025 if (opclasses) {
1026 int i;
1027
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001028 json_value_sep(json);
1029 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -07001030 for (i = 0; opclasses[i]; i++)
1031 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001032 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001033 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001034 if (csr) {
1035 json_value_sep(json);
1036 json_add_string(json, "pkcs10", csr);
1037 }
Sunil Ravic0f5d412024-09-11 22:12:49 +00001038#ifdef CONFIG_DPP3
1039 json_value_sep(json);
1040 json_add_int(json, "capabilities", DPP_ENROLLEE_CAPAB_SAE_PW_ID);
1041#endif /* CONFIG_DPP3 */
Sunil Ravi89eba102022-09-13 21:04:37 -07001042 if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1043 json_value_sep(json);
1044 wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1045 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001046 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001047
1048 buf = dpp_build_conf_req(auth, wpabuf_head(json));
Sunil Ravia04bd252022-05-02 22:54:18 -07001049fail:
Hai Shalomc3565922019-10-28 11:58:20 -07001050 wpabuf_free(json);
Hai Shalom899fcc72020-10-19 14:38:18 -07001051 os_free(csr);
Hai Shalomc3565922019-10-28 11:58:20 -07001052
1053 return buf;
1054}
1055
1056
Hai Shalom021b0b52019-04-10 11:17:58 -07001057static int bin_str_eq(const char *val, size_t len, const char *cmp)
1058{
1059 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1060}
1061
1062
1063struct dpp_configuration * dpp_configuration_alloc(const char *type)
1064{
1065 struct dpp_configuration *conf;
1066 const char *end;
1067 size_t len;
1068
1069 conf = os_zalloc(sizeof(*conf));
1070 if (!conf)
1071 goto fail;
1072
1073 end = os_strchr(type, ' ');
1074 if (end)
1075 len = end - type;
1076 else
1077 len = os_strlen(type);
1078
1079 if (bin_str_eq(type, len, "psk"))
1080 conf->akm = DPP_AKM_PSK;
1081 else if (bin_str_eq(type, len, "sae"))
1082 conf->akm = DPP_AKM_SAE;
1083 else if (bin_str_eq(type, len, "psk-sae") ||
1084 bin_str_eq(type, len, "psk+sae"))
1085 conf->akm = DPP_AKM_PSK_SAE;
1086 else if (bin_str_eq(type, len, "sae-dpp") ||
1087 bin_str_eq(type, len, "dpp+sae"))
1088 conf->akm = DPP_AKM_SAE_DPP;
1089 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1090 bin_str_eq(type, len, "dpp+psk+sae"))
1091 conf->akm = DPP_AKM_PSK_SAE_DPP;
1092 else if (bin_str_eq(type, len, "dpp"))
1093 conf->akm = DPP_AKM_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07001094 else if (bin_str_eq(type, len, "dot1x"))
1095 conf->akm = DPP_AKM_DOT1X;
Hai Shalom021b0b52019-04-10 11:17:58 -07001096 else
1097 goto fail;
1098
1099 return conf;
1100fail:
1101 dpp_configuration_free(conf);
1102 return NULL;
1103}
1104
1105
1106int dpp_akm_psk(enum dpp_akm akm)
1107{
1108 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1109 akm == DPP_AKM_PSK_SAE_DPP;
1110}
1111
1112
1113int dpp_akm_sae(enum dpp_akm akm)
1114{
1115 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1116 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1117}
1118
1119
1120int dpp_akm_legacy(enum dpp_akm akm)
1121{
1122 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1123 akm == DPP_AKM_SAE;
1124}
1125
1126
1127int dpp_akm_dpp(enum dpp_akm akm)
1128{
1129 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1130 akm == DPP_AKM_PSK_SAE_DPP;
1131}
1132
1133
1134int dpp_akm_ver2(enum dpp_akm akm)
1135{
1136 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1137}
1138
1139
1140int dpp_configuration_valid(const struct dpp_configuration *conf)
1141{
1142 if (conf->ssid_len == 0)
1143 return 0;
1144 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1145 return 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001146 if (dpp_akm_psk(conf->akm) && conf->passphrase) {
1147 size_t len = os_strlen(conf->passphrase);
1148
1149 if (len > 63 || len < 8)
1150 return 0;
1151 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001152 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1153 return 0;
Sunil Ravic0f5d412024-09-11 22:12:49 +00001154#ifdef CONFIG_DPP3
1155 if (conf->idpass && (!conf->passphrase || !dpp_akm_sae(conf->akm)))
1156 return 0;
1157#endif /* CONFIG_DPP3 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001158 return 1;
1159}
1160
1161
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001162void dpp_configuration_free(struct dpp_configuration *conf)
1163{
1164 if (!conf)
1165 return;
1166 str_clear_free(conf->passphrase);
Sunil Ravic0f5d412024-09-11 22:12:49 +00001167#ifdef CONFIG_DPP3
1168 os_free(conf->idpass);
1169#endif /* CONFIG_DPP3 */
Hai Shalomce48b4a2018-09-05 11:41:35 -07001170 os_free(conf->group_id);
Hai Shalom899fcc72020-10-19 14:38:18 -07001171 os_free(conf->csrattrs);
Sunil Ravi89eba102022-09-13 21:04:37 -07001172 os_free(conf->extra_name);
1173 os_free(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001174 bin_clear_free(conf, sizeof(*conf));
1175}
1176
1177
Hai Shalomc3565922019-10-28 11:58:20 -07001178static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1179 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07001180{
1181 const char *pos, *end;
1182 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1183 struct dpp_configuration *conf = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001184 size_t len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001185
1186 pos = os_strstr(cmd, " conf=sta-");
1187 if (pos) {
1188 conf_sta = dpp_configuration_alloc(pos + 10);
1189 if (!conf_sta)
1190 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001191 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07001192 conf = conf_sta;
1193 }
1194
1195 pos = os_strstr(cmd, " conf=ap-");
1196 if (pos) {
1197 conf_ap = dpp_configuration_alloc(pos + 9);
1198 if (!conf_ap)
1199 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001200 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07001201 conf = conf_ap;
1202 }
1203
Hai Shalomfdcde762020-04-02 11:19:20 -07001204 pos = os_strstr(cmd, " conf=configurator");
1205 if (pos)
1206 auth->provision_configurator = 1;
1207
Hai Shalom021b0b52019-04-10 11:17:58 -07001208 if (!conf)
1209 return 0;
1210
1211 pos = os_strstr(cmd, " ssid=");
1212 if (pos) {
1213 pos += 6;
1214 end = os_strchr(pos, ' ');
1215 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1216 conf->ssid_len /= 2;
1217 if (conf->ssid_len > sizeof(conf->ssid) ||
1218 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1219 goto fail;
1220 } else {
1221#ifdef CONFIG_TESTING_OPTIONS
1222 /* use a default SSID for legacy testing reasons */
1223 os_memcpy(conf->ssid, "test", 4);
1224 conf->ssid_len = 4;
1225#else /* CONFIG_TESTING_OPTIONS */
1226 goto fail;
1227#endif /* CONFIG_TESTING_OPTIONS */
1228 }
1229
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001230 pos = os_strstr(cmd, " ssid_charset=");
1231 if (pos) {
1232 if (conf_ap) {
1233 wpa_printf(MSG_INFO,
1234 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1235 goto fail;
1236 }
1237 conf->ssid_charset = atoi(pos + 14);
1238 }
1239
Hai Shalom021b0b52019-04-10 11:17:58 -07001240 pos = os_strstr(cmd, " pass=");
1241 if (pos) {
1242 size_t pass_len;
1243
1244 pos += 6;
1245 end = os_strchr(pos, ' ');
1246 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1247 pass_len /= 2;
Hai Shalom021b0b52019-04-10 11:17:58 -07001248 conf->passphrase = os_zalloc(pass_len + 1);
1249 if (!conf->passphrase ||
1250 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1251 goto fail;
1252 }
1253
Sunil Ravic0f5d412024-09-11 22:12:49 +00001254#ifdef CONFIG_DPP3
1255 pos = os_strstr(cmd, " idpass=");
1256 if (pos) {
1257 size_t idpass_len;
1258
1259 pos += 8;
1260 end = os_strchr(pos, ' ');
1261 idpass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1262 idpass_len /= 2;
1263 conf->idpass = os_zalloc(idpass_len + 1);
1264 if (!conf->idpass ||
1265 hexstr2bin(pos, (u8 *) conf->idpass, idpass_len) < 0)
1266 goto fail;
1267 }
1268#endif /* CONFIG_DPP3 */
1269
Hai Shalom021b0b52019-04-10 11:17:58 -07001270 pos = os_strstr(cmd, " psk=");
1271 if (pos) {
1272 pos += 5;
1273 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1274 goto fail;
1275 conf->psk_set = 1;
1276 }
1277
1278 pos = os_strstr(cmd, " group_id=");
1279 if (pos) {
1280 size_t group_id_len;
1281
1282 pos += 10;
1283 end = os_strchr(pos, ' ');
1284 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1285 conf->group_id = os_malloc(group_id_len + 1);
1286 if (!conf->group_id)
1287 goto fail;
1288 os_memcpy(conf->group_id, pos, group_id_len);
1289 conf->group_id[group_id_len] = '\0';
1290 }
1291
1292 pos = os_strstr(cmd, " expiry=");
1293 if (pos) {
1294 long int val;
1295
1296 pos += 8;
1297 val = strtol(pos, NULL, 0);
1298 if (val <= 0)
1299 goto fail;
1300 conf->netaccesskey_expiry = val;
1301 }
1302
Hai Shalom899fcc72020-10-19 14:38:18 -07001303 pos = os_strstr(cmd, " csrattrs=");
1304 if (pos) {
1305 pos += 10;
1306 end = os_strchr(pos, ' ');
1307 len = end ? (size_t) (end - pos) : os_strlen(pos);
1308 conf->csrattrs = os_zalloc(len + 1);
1309 if (!conf->csrattrs)
1310 goto fail;
1311 os_memcpy(conf->csrattrs, pos, len);
1312 }
1313
Sunil Ravi89eba102022-09-13 21:04:37 -07001314 pos = os_strstr(cmd, " conf_extra_name=");
1315 if (pos) {
1316 pos += 17;
1317 end = os_strchr(pos, ' ');
1318 len = end ? (size_t) (end - pos) : os_strlen(pos);
1319 conf->extra_name = os_zalloc(len + 1);
1320 if (!conf->extra_name)
1321 goto fail;
1322 os_memcpy(conf->extra_name, pos, len);
1323 }
1324
1325 pos = os_strstr(cmd, " conf_extra_value=");
1326 if (pos) {
1327 pos += 18;
1328 end = os_strchr(pos, ' ');
1329 len = end ? (size_t) (end - pos) : os_strlen(pos);
1330 len /= 2;
1331 conf->extra_value = os_zalloc(len + 1);
1332 if (!conf->extra_value ||
1333 hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1334 goto fail;
1335 }
1336
Hai Shalom021b0b52019-04-10 11:17:58 -07001337 if (!dpp_configuration_valid(conf))
1338 goto fail;
1339
Hai Shalomc3565922019-10-28 11:58:20 -07001340 if (idx == 0) {
1341 auth->conf_sta = conf_sta;
1342 auth->conf_ap = conf_ap;
1343 } else if (idx == 1) {
Sunil Raviaf8751c2023-03-29 11:35:17 -07001344 if (!auth->conf_sta)
1345 auth->conf_sta = conf_sta;
1346 else
1347 auth->conf2_sta = conf_sta;
1348 if (!auth->conf_ap)
1349 auth->conf_ap = conf_ap;
1350 else
1351 auth->conf2_ap = conf_ap;
Hai Shalomc3565922019-10-28 11:58:20 -07001352 } else {
1353 goto fail;
1354 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001355 return 0;
1356
1357fail:
1358 dpp_configuration_free(conf_sta);
1359 dpp_configuration_free(conf_ap);
1360 return -1;
1361}
1362
1363
Hai Shalomc3565922019-10-28 11:58:20 -07001364static int dpp_configuration_parse(struct dpp_authentication *auth,
1365 const char *cmd)
1366{
1367 const char *pos;
1368 char *tmp;
1369 size_t len;
1370 int res;
1371
1372 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1373 if (!pos)
1374 return dpp_configuration_parse_helper(auth, cmd, 0);
1375
1376 len = pos - cmd;
1377 tmp = os_malloc(len + 1);
1378 if (!tmp)
1379 goto fail;
1380 os_memcpy(tmp, cmd, len);
1381 tmp[len] = '\0';
Sunil Raviaf8751c2023-03-29 11:35:17 -07001382 res = dpp_configuration_parse_helper(auth, tmp, 0);
Hai Shalomc3565922019-10-28 11:58:20 -07001383 str_clear_free(tmp);
1384 if (res)
1385 goto fail;
1386 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1387 if (res)
1388 goto fail;
1389 return 0;
1390fail:
1391 dpp_configuration_free(auth->conf_sta);
1392 dpp_configuration_free(auth->conf2_sta);
1393 dpp_configuration_free(auth->conf_ap);
1394 dpp_configuration_free(auth->conf2_ap);
1395 return -1;
1396}
1397
1398
Hai Shalom021b0b52019-04-10 11:17:58 -07001399static struct dpp_configurator *
1400dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1401{
1402 struct dpp_configurator *conf;
1403
1404 if (!dpp)
1405 return NULL;
1406
1407 dl_list_for_each(conf, &dpp->configurator,
1408 struct dpp_configurator, list) {
1409 if (conf->id == id)
1410 return conf;
1411 }
1412 return NULL;
1413}
1414
1415
Hai Shalomfdcde762020-04-02 11:19:20 -07001416int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07001417{
1418 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07001419 char *tmp = NULL;
1420 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07001421
Hai Shalomfdcde762020-04-02 11:19:20 -07001422 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07001423 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07001424 auth->configurator_set = 1;
1425
1426 if (cmd[0] != ' ') {
1427 size_t len;
1428
1429 len = os_strlen(cmd);
1430 tmp = os_malloc(len + 2);
1431 if (!tmp)
1432 goto fail;
1433 tmp[0] = ' ';
1434 os_memcpy(tmp + 1, cmd, len + 1);
1435 cmd = tmp;
1436 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001437
1438 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1439
Hai Shaloma20dcd72022-02-04 13:43:00 -08001440 if (os_strstr(cmd, " conf=query")) {
1441 auth->configurator_set = 0;
1442 auth->use_config_query = true;
1443 ret = 0;
1444 goto fail;
1445 }
1446
Hai Shalom021b0b52019-04-10 11:17:58 -07001447 pos = os_strstr(cmd, " configurator=");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001448 if (!auth->conf && pos) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001449 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07001450 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07001451 if (!auth->conf) {
1452 wpa_printf(MSG_INFO,
1453 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07001454 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001455 }
1456 }
1457
Hai Shalomc3565922019-10-28 11:58:20 -07001458 pos = os_strstr(cmd, " conn_status=");
1459 if (pos) {
1460 pos += 13;
1461 auth->send_conn_status = atoi(pos);
1462 }
1463
1464 pos = os_strstr(cmd, " akm_use_selector=");
1465 if (pos) {
1466 pos += 18;
1467 auth->akm_use_selector = atoi(pos);
1468 }
1469
Hai Shalom021b0b52019-04-10 11:17:58 -07001470 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001471 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07001472 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07001473 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001474 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001475 ret = 0;
1476fail:
1477 os_free(tmp);
1478 return ret;
1479}
1480
1481
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001482void dpp_auth_deinit(struct dpp_authentication *auth)
1483{
Hai Shalomc3565922019-10-28 11:58:20 -07001484 unsigned int i;
1485
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001486 if (!auth)
1487 return;
1488 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07001489 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001490 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001491 dpp_configuration_free(auth->conf2_sta);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001492 crypto_ec_key_deinit(auth->own_protocol_key);
1493 crypto_ec_key_deinit(auth->peer_protocol_key);
1494 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001495 wpabuf_free(auth->req_msg);
1496 wpabuf_free(auth->resp_msg);
1497 wpabuf_free(auth->conf_req);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001498 wpabuf_free(auth->reconfig_req_msg);
1499 wpabuf_free(auth->reconfig_resp_msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001500 for (i = 0; i < auth->num_conf_obj; i++) {
1501 struct dpp_config_obj *conf = &auth->conf_obj[i];
1502
1503 os_free(conf->connector);
1504 wpabuf_free(conf->c_sign_key);
Hai Shalom899fcc72020-10-19 14:38:18 -07001505 wpabuf_free(conf->certbag);
1506 wpabuf_free(conf->certs);
1507 wpabuf_free(conf->cacert);
1508 os_free(conf->server_name);
1509 wpabuf_free(conf->pp_key);
Hai Shalomc3565922019-10-28 11:58:20 -07001510 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001511#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -07001512 dpp_free_asymmetric_key(auth->conf_key_pkg);
Hai Shalom899fcc72020-10-19 14:38:18 -07001513 os_free(auth->csrattrs);
1514 wpabuf_free(auth->csr);
1515 wpabuf_free(auth->priv_key);
1516 wpabuf_free(auth->cacert);
1517 wpabuf_free(auth->certbag);
1518 os_free(auth->trusted_eap_server_name);
1519 wpabuf_free(auth->conf_resp_tcp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001520#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001521 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001522 dpp_bootstrap_info_free(auth->tmp_own_bi);
Hai Shalom899fcc72020-10-19 14:38:18 -07001523 if (auth->tmp_peer_bi) {
1524 dl_list_del(&auth->tmp_peer_bi->list);
1525 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1526 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001527 os_free(auth->e_name);
1528 os_free(auth->e_mud_url);
1529 os_free(auth->e_band_support);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001530#ifdef CONFIG_TESTING_OPTIONS
1531 os_free(auth->config_obj_override);
1532 os_free(auth->discovery_override);
1533 os_free(auth->groups_override);
1534#endif /* CONFIG_TESTING_OPTIONS */
1535 bin_clear_free(auth, sizeof(*auth));
1536}
1537
1538
1539static struct wpabuf *
1540dpp_build_conf_start(struct dpp_authentication *auth,
1541 struct dpp_configuration *conf, size_t tailroom)
1542{
1543 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001544
1545#ifdef CONFIG_TESTING_OPTIONS
1546 if (auth->discovery_override)
1547 tailroom += os_strlen(auth->discovery_override);
1548#endif /* CONFIG_TESTING_OPTIONS */
1549
1550 buf = wpabuf_alloc(200 + tailroom);
1551 if (!buf)
1552 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001553 json_start_object(buf, NULL);
1554 json_add_string(buf, "wi-fi_tech", "infra");
1555 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001556#ifdef CONFIG_TESTING_OPTIONS
1557 if (auth->discovery_override) {
1558 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1559 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001560 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001561 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001562 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001563 return buf;
1564 }
1565#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001566 json_start_object(buf, "discovery");
1567 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1568 json_add_string_escape(buf, "ssid", conf->ssid,
1569 conf->ssid_len) < 0) ||
1570 ((conf->ssid_charset && auth->peer_version >= 2) &&
1571 json_add_base64url(buf, "ssid64", conf->ssid,
1572 conf->ssid_len) < 0)) {
1573 wpabuf_free(buf);
1574 return NULL;
1575 }
1576 if (conf->ssid_charset > 0) {
1577 json_value_sep(buf);
1578 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1579 }
1580 json_end_object(buf);
1581 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001582
1583 return buf;
1584}
1585
1586
Hai Shaloma20dcd72022-02-04 13:43:00 -08001587int dpp_build_jwk(struct wpabuf *buf, const char *name,
1588 struct crypto_ec_key *key, const char *kid,
1589 const struct dpp_curve_params *curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001590{
1591 struct wpabuf *pub;
1592 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001593 int ret = -1;
1594
Hai Shaloma20dcd72022-02-04 13:43:00 -08001595 pub = crypto_ec_key_get_pubkey_point(key, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001596 if (!pub)
1597 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001598
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001599 json_start_object(buf, name);
1600 json_add_string(buf, "kty", "EC");
1601 json_value_sep(buf);
1602 json_add_string(buf, "crv", curve->jwk_crv);
1603 json_value_sep(buf);
1604 pos = wpabuf_head(pub);
1605 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1606 goto fail;
1607 json_value_sep(buf);
1608 pos += curve->prime_len;
1609 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1610 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001611 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001612 json_value_sep(buf);
1613 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001614 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001615 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001616 ret = 0;
1617fail:
1618 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001619 return ret;
1620}
1621
1622
Hai Shalom021b0b52019-04-10 11:17:58 -07001623static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1624 struct dpp_configuration *conf)
1625{
1626 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001627 json_add_string_escape(buf, "pass", conf->passphrase,
1628 os_strlen(conf->passphrase));
Sunil Ravic0f5d412024-09-11 22:12:49 +00001629#ifdef CONFIG_DPP3
1630 if (conf->idpass) {
1631 json_value_sep(buf);
1632 json_add_string_escape(buf, "idpass", conf->idpass,
1633 os_strlen(conf->idpass));
1634 }
1635#endif /* CONFIG_DPP3 */
Hai Shalom021b0b52019-04-10 11:17:58 -07001636 } else if (conf->psk_set) {
1637 char psk[2 * sizeof(conf->psk) + 1];
1638
1639 wpa_snprintf_hex(psk, sizeof(psk),
1640 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001641 json_add_string(buf, "psk_hex", psk);
1642 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07001643 }
1644}
1645
1646
Hai Shaloma20dcd72022-02-04 13:43:00 -08001647const char * dpp_netrole_str(enum dpp_netrole netrole)
Hai Shalomc3565922019-10-28 11:58:20 -07001648{
1649 switch (netrole) {
1650 case DPP_NETROLE_STA:
1651 return "sta";
1652 case DPP_NETROLE_AP:
1653 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001654 case DPP_NETROLE_CONFIGURATOR:
1655 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07001656 default:
1657 return "??";
1658 }
1659}
1660
1661
Sunil Ravi89eba102022-09-13 21:04:37 -07001662static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1663{
1664 enum dpp_bootstrap_supported_curves idx;
1665
1666 if (!bi || !bi->supported_curves)
1667 return true; /* no support indication available */
1668
1669 if (os_strcmp(curve, "prime256v1") == 0)
1670 idx = DPP_BOOTSTRAP_CURVE_P_256;
1671 else if (os_strcmp(curve, "secp384r1") == 0)
1672 idx = DPP_BOOTSTRAP_CURVE_P_384;
1673 else if (os_strcmp(curve, "secp521r1") == 0)
1674 idx = DPP_BOOTSTRAP_CURVE_P_521;
1675 else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1676 idx = DPP_BOOTSTRAP_CURVE_BP_256;
1677 else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1678 idx = DPP_BOOTSTRAP_CURVE_BP_384;
1679 else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1680 idx = DPP_BOOTSTRAP_CURVE_BP_512;
1681 else
1682 return true;
1683
1684 return bi->supported_curves & BIT(idx);
1685}
1686
1687
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001688static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001689dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001690 struct dpp_configuration *conf)
1691{
1692 struct wpabuf *buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001693 char *signed_conn = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001694 size_t tailroom;
Sunil Ravia04bd252022-05-02 22:54:18 -07001695 const struct dpp_curve_params *curve; /* C-sign-key curve */
1696 const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001697 struct wpabuf *dppcon = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001698 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07001699 int incl_legacy;
1700 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07001701 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001702
1703 if (!auth->conf) {
1704 wpa_printf(MSG_INFO,
1705 "DPP: No configurator specified - cannot generate DPP config object");
1706 goto fail;
1707 }
1708 curve = auth->conf->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001709 if (dpp_akm_dpp(conf->akm) &&
1710 !dpp_supports_curve(curve->name, auth->peer_bi)) {
1711 wpa_printf(MSG_DEBUG,
1712 "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1713 curve->name);
1714 goto fail;
1715 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001716 if (auth->new_curve && auth->new_key_received)
1717 nak_curve = auth->new_curve;
1718 else
1719 nak_curve = auth->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001720 if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1721 wpa_printf(MSG_DEBUG,
1722 "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1723 nak_curve->name);
1724 goto fail;
1725 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001726
Hai Shalom021b0b52019-04-10 11:17:58 -07001727 akm = conf->akm;
1728 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1729 wpa_printf(MSG_DEBUG,
1730 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1731 akm = DPP_AKM_DPP;
1732 }
1733
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001734#ifdef CONFIG_TESTING_OPTIONS
1735 if (auth->groups_override)
1736 extra_len += os_strlen(auth->groups_override);
1737#endif /* CONFIG_TESTING_OPTIONS */
1738
Hai Shalomce48b4a2018-09-05 11:41:35 -07001739 if (conf->group_id)
1740 extra_len += os_strlen(conf->group_id);
1741
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001742 /* Connector (JSON dppCon object) */
Sunil Ravia04bd252022-05-02 22:54:18 -07001743 dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001744 if (!dppcon)
1745 goto fail;
1746#ifdef CONFIG_TESTING_OPTIONS
1747 if (auth->groups_override) {
1748 wpabuf_put_u8(dppcon, '{');
1749 if (auth->groups_override) {
1750 wpa_printf(MSG_DEBUG,
1751 "DPP: TESTING - groups override: '%s'",
1752 auth->groups_override);
1753 wpabuf_put_str(dppcon, "\"groups\":");
1754 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001755 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001756 }
1757 goto skip_groups;
1758 }
1759#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001760 json_start_object(dppcon, NULL);
1761 json_start_array(dppcon, "groups");
1762 json_start_object(dppcon, NULL);
1763 json_add_string(dppcon, "groupId",
1764 conf->group_id ? conf->group_id : "*");
1765 json_value_sep(dppcon);
1766 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1767 json_end_object(dppcon);
1768 json_end_array(dppcon);
1769 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001770#ifdef CONFIG_TESTING_OPTIONS
1771skip_groups:
1772#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravia04bd252022-05-02 22:54:18 -07001773 if (!auth->peer_protocol_key) {
1774 wpa_printf(MSG_DEBUG,
1775 "DPP: No peer protocol key available to build netAccessKey JWK");
1776 goto fail;
1777 }
1778#ifdef CONFIG_DPP3
1779 if (auth->conf->net_access_key_curve &&
1780 auth->curve != auth->conf->net_access_key_curve &&
1781 !auth->new_key_received) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001782 if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1783 auth->peer_bi)) {
1784 wpa_printf(MSG_DEBUG,
1785 "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1786 auth->conf->net_access_key_curve->name);
1787 goto fail;
1788 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001789 wpa_printf(MSG_DEBUG,
1790 "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1791 auth->curve->name,
1792 auth->conf->net_access_key_curve->name,
1793 auth->waiting_new_key ?
1794 "the required key not received" :
1795 "request a new key");
1796 if (auth->waiting_new_key)
1797 auth->waiting_new_key = false; /* failed */
1798 else
1799 auth->waiting_new_key = true;
1800 goto fail;
1801 }
1802#endif /* CONFIG_DPP3 */
1803 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1804 nak_curve) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001805 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1806 goto fail;
1807 }
1808 if (conf->netaccesskey_expiry) {
1809 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001810 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001811
1812 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1813 wpa_printf(MSG_DEBUG,
1814 "DPP: Failed to generate expiry string");
1815 goto fail;
1816 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001817 os_snprintf(expiry, sizeof(expiry),
1818 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1819 tm.year, tm.month, tm.day,
1820 tm.hour, tm.min, tm.sec);
1821 json_value_sep(dppcon);
1822 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001823 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001824#ifdef CONFIG_DPP3
1825 json_value_sep(dppcon);
1826 json_add_int(dppcon, "version", auth->peer_version);
1827#endif /* CONFIG_DPP3 */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001828 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001829 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1830 (const char *) wpabuf_head(dppcon));
1831
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001832 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1833 if (!signed_conn)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001834 goto fail;
1835
Hai Shalom021b0b52019-04-10 11:17:58 -07001836 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001837 tailroom = 1000;
1838 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001839 tailroom += os_strlen(signed_conn);
Hai Shalom021b0b52019-04-10 11:17:58 -07001840 if (incl_legacy)
1841 tailroom += 1000;
Hai Shalom899fcc72020-10-19 14:38:18 -07001842 if (akm == DPP_AKM_DOT1X) {
1843 if (auth->certbag)
1844 tailroom += 2 * wpabuf_len(auth->certbag);
1845 if (auth->cacert)
1846 tailroom += 2 * wpabuf_len(auth->cacert);
1847 if (auth->trusted_eap_server_name)
1848 tailroom += os_strlen(auth->trusted_eap_server_name);
1849 tailroom += 1000;
1850 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001851 if (conf->extra_name && conf->extra_value)
1852 tailroom += 10 + os_strlen(conf->extra_name) +
1853 os_strlen(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001854 buf = dpp_build_conf_start(auth, conf, tailroom);
1855 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001856 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001857
Hai Shalomc3565922019-10-28 11:58:20 -07001858 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1859 akm_str = dpp_akm_selector_str(akm);
1860 else
1861 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001862 json_start_object(buf, "cred");
1863 json_add_string(buf, "akm", akm_str);
1864 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001865 if (incl_legacy) {
1866 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001867 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001868 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001869 if (akm == DPP_AKM_DOT1X) {
1870 json_start_object(buf, "entCreds");
1871 if (!auth->certbag)
1872 goto fail;
1873 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1874 wpabuf_len(auth->certbag));
1875 if (auth->cacert) {
1876 json_value_sep(buf);
1877 json_add_base64(buf, "caCert",
1878 wpabuf_head(auth->cacert),
1879 wpabuf_len(auth->cacert));
1880 }
1881 if (auth->trusted_eap_server_name) {
1882 json_value_sep(buf);
1883 json_add_string(buf, "trustedEapServerName",
1884 auth->trusted_eap_server_name);
1885 }
1886 json_value_sep(buf);
1887 json_start_array(buf, "eapMethods");
1888 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1889 json_end_array(buf);
1890 json_end_object(buf);
1891 json_value_sep(buf);
1892 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001893 wpabuf_put_str(buf, "\"signedConnector\":\"");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001894 wpabuf_put_str(buf, signed_conn);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001895 wpabuf_put_str(buf, "\"");
1896 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001897 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1898 curve) < 0) {
1899 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1900 goto fail;
1901 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001902#ifdef CONFIG_DPP2
1903 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1904 json_value_sep(buf);
1905 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1906 curve) < 0) {
1907 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1908 goto fail;
1909 }
1910 }
1911#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001912
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001913 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001914 if (conf->extra_name && conf->extra_value) {
1915 json_value_sep(buf);
1916 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1917 conf->extra_value);
1918 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001919 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001920
1921 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1922 wpabuf_head(buf), wpabuf_len(buf));
1923
Sunil Ravia04bd252022-05-02 22:54:18 -07001924#ifdef CONFIG_DPP3
1925 if (!auth->conf->net_access_key_curve) {
1926 /* All netAccessKey values used in the network will have to be
1927 * from the same curve for network introduction to work, so
1928 * hardcode the first used netAccessKey curve for consecutive
1929 * operations if there was no explicit configuration of which
1930 * curve to use. */
1931 wpa_printf(MSG_DEBUG,
1932 "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1933 nak_curve->name);
1934 auth->conf->net_access_key_curve = nak_curve;
1935 }
1936#endif /* CONFIG_DPP3 */
1937
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001938out:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001939 os_free(signed_conn);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001940 wpabuf_free(dppcon);
1941 return buf;
1942fail:
1943 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1944 wpabuf_free(buf);
1945 buf = NULL;
1946 goto out;
1947}
1948
1949
1950static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001951dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001952 struct dpp_configuration *conf)
1953{
1954 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001955 const char *akm_str;
Sunil Ravi89eba102022-09-13 21:04:37 -07001956 size_t len = 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001957
Sunil Ravic0f5d412024-09-11 22:12:49 +00001958
1959#ifdef CONFIG_DPP3
1960 if (conf->idpass &&
1961 !(auth->enrollee_capabilities & DPP_ENROLLEE_CAPAB_SAE_PW_ID)) {
1962 wpa_printf(MSG_DEBUG,
1963 "DPP: Enrollee does not support SAE Password Identifier - cannot generate config object");
1964 return NULL;
1965 }
1966#endif /* CONFIG_DPP3 */
1967
Sunil Ravi89eba102022-09-13 21:04:37 -07001968 if (conf->extra_name && conf->extra_value)
1969 len += 10 + os_strlen(conf->extra_name) +
1970 os_strlen(conf->extra_value);
1971 buf = dpp_build_conf_start(auth, conf, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001972 if (!buf)
1973 return NULL;
1974
Hai Shalomc3565922019-10-28 11:58:20 -07001975 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1976 akm_str = dpp_akm_selector_str(conf->akm);
1977 else
1978 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001979 json_start_object(buf, "cred");
1980 json_add_string(buf, "akm", akm_str);
1981 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001982 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001983 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001984 if (conf->extra_name && conf->extra_value) {
1985 json_value_sep(buf);
1986 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1987 conf->extra_value);
1988 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001989 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001990
1991 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1992 wpabuf_head(buf), wpabuf_len(buf));
1993
1994 return buf;
1995}
1996
1997
Hai Shaloma20dcd72022-02-04 13:43:00 -08001998static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1999{
2000 struct dpp_bootstrap_info *bi;
2001
2002 if (auth->peer_bi)
2003 return auth->peer_bi->id;
2004 if (auth->tmp_peer_bi)
2005 return auth->tmp_peer_bi->id;
2006
2007 bi = os_zalloc(sizeof(*bi));
2008 if (!bi)
2009 return -1;
2010 bi->id = dpp_next_id(auth->global);
2011 dl_list_add(&auth->global->bootstrap, &bi->list);
2012 auth->tmp_peer_bi = bi;
2013 return bi->id;
2014}
2015
2016
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002017static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002018dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
Hai Shalom899fcc72020-10-19 14:38:18 -07002019 int idx, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002020{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002021 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002022
2023#ifdef CONFIG_TESTING_OPTIONS
2024 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07002025 if (idx != 0)
2026 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002027 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
2028 return wpabuf_alloc_copy(auth->config_obj_override,
2029 os_strlen(auth->config_obj_override));
2030 }
2031#endif /* CONFIG_TESTING_OPTIONS */
2032
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002033 if (idx == 0) {
2034 if (netrole == DPP_NETROLE_STA)
2035 conf = auth->conf_sta;
2036 else if (netrole == DPP_NETROLE_AP)
2037 conf = auth->conf_ap;
2038 } else if (idx == 1) {
2039 if (netrole == DPP_NETROLE_STA)
2040 conf = auth->conf2_sta;
2041 else if (netrole == DPP_NETROLE_AP)
2042 conf = auth->conf2_ap;
2043 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002044 if (!conf) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08002045 if (idx == 0) {
2046 if (auth->use_config_query) {
2047 wpa_printf(MSG_DEBUG,
2048 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
2049 dpp_netrole_str(netrole));
2050 auth->waiting_config = true;
2051 dpp_get_peer_bi_id(auth);
2052 return NULL;
2053 }
Hai Shalomc3565922019-10-28 11:58:20 -07002054 wpa_printf(MSG_DEBUG,
2055 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002056 dpp_netrole_str(netrole));
Hai Shaloma20dcd72022-02-04 13:43:00 -08002057 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002058 return NULL;
2059 }
2060
Hai Shalom899fcc72020-10-19 14:38:18 -07002061 if (conf->akm == DPP_AKM_DOT1X) {
2062 if (!auth->conf) {
2063 wpa_printf(MSG_DEBUG,
2064 "DPP: No Configurator data available");
2065 return NULL;
2066 }
2067 if (!cert_req && !auth->certbag) {
2068 wpa_printf(MSG_DEBUG,
2069 "DPP: No certificate data available for dot1x configuration");
2070 return NULL;
2071 }
2072 return dpp_build_conf_obj_dpp(auth, conf);
2073 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002074 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07002075 return dpp_build_conf_obj_dpp(auth, conf);
2076 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002077}
2078
2079
Hai Shalom899fcc72020-10-19 14:38:18 -07002080struct wpabuf *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002081dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Hai Shalom899fcc72020-10-19 14:38:18 -07002082 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002083{
Sunil Ravia04bd252022-05-02 22:54:18 -07002084 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002085 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002086 struct wpabuf *clear = NULL, *msg = NULL;
2087 u8 *wrapped;
2088 const u8 *addr[1];
2089 size_t len[1];
2090 enum dpp_status_error status;
2091
Hai Shalom899fcc72020-10-19 14:38:18 -07002092 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2093 status = auth->force_conf_resp_status;
2094 goto forced_status;
2095 }
2096
Hai Shalomfdcde762020-04-02 11:19:20 -07002097 if (netrole == DPP_NETROLE_CONFIGURATOR) {
2098#ifdef CONFIG_DPP2
2099 env_data = dpp_build_enveloped_data(auth);
2100#endif /* CONFIG_DPP2 */
2101 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002102 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002103 if (conf) {
2104 wpa_hexdump_ascii(MSG_DEBUG,
2105 "DPP: configurationObject JSON",
2106 wpabuf_head(conf), wpabuf_len(conf));
Hai Shalom899fcc72020-10-19 14:38:18 -07002107 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002108 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002109 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002110
Hai Shaloma20dcd72022-02-04 13:43:00 -08002111 if (!conf && auth->waiting_config)
2112 return NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002113 if (conf || env_data)
2114 status = DPP_STATUS_OK;
2115 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2116 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2117 status = DPP_STATUS_CSR_NEEDED;
Sunil Ravia04bd252022-05-02 22:54:18 -07002118#ifdef CONFIG_DPP3
2119 else if (auth->waiting_new_key)
2120 status = DPP_STATUS_NEW_KEY_NEEDED;
2121#endif /* CONFIG_DPP3 */
Hai Shalom899fcc72020-10-19 14:38:18 -07002122 else
2123 status = DPP_STATUS_CONFIGURE_FAILURE;
2124forced_status:
Hai Shalom021b0b52019-04-10 11:17:58 -07002125 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002126
Hai Shalomc3565922019-10-28 11:58:20 -07002127 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002128 clear_len = 4 + e_nonce_len;
2129 if (conf)
2130 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07002131 if (conf2)
2132 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07002133 if (env_data)
2134 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002135 if (auth->peer_version >= 2 && auth->send_conn_status &&
2136 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07002137 clear_len += 4;
Hai Shalom899fcc72020-10-19 14:38:18 -07002138 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2139 auth->conf_sta->csrattrs)
2140 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
Sunil Ravia04bd252022-05-02 22:54:18 -07002141#ifdef CONFIG_DPP3
2142 if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2143 struct crypto_ec_key *new_pc;
2144
2145 clear_len += 6; /* Finite Cyclic Group attribute */
2146
2147 wpa_printf(MSG_DEBUG,
2148 "DPP: Generate a new own protocol key for the curve %s",
2149 auth->conf->net_access_key_curve->name);
2150 new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2151 if (!new_pc) {
2152 wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2153 return NULL;
2154 }
2155 pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2156 if (!pc) {
2157 crypto_ec_key_deinit(new_pc);
2158 return NULL;
2159 }
2160 crypto_ec_key_deinit(auth->own_protocol_key);
2161 auth->own_protocol_key = new_pc;
2162 auth->new_curve = auth->conf->net_access_key_curve;
2163 clear_len += 4 + wpabuf_len(pc);
2164 }
2165#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002166 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002167 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2168#ifdef CONFIG_TESTING_OPTIONS
2169 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2170 attr_len += 5;
2171#endif /* CONFIG_TESTING_OPTIONS */
2172 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002173 if (!clear || !msg)
2174 goto fail;
2175
Roshan Pius3a1667e2018-07-03 15:17:14 -07002176#ifdef CONFIG_TESTING_OPTIONS
2177 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2178 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2179 goto skip_e_nonce;
2180 }
2181 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2182 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2183 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2184 wpabuf_put_le16(clear, e_nonce_len);
2185 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2186 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2187 goto skip_e_nonce;
2188 }
2189 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2190 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2191 goto skip_wrapped_data;
2192 }
2193#endif /* CONFIG_TESTING_OPTIONS */
2194
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002195 /* E-nonce */
2196 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2197 wpabuf_put_le16(clear, e_nonce_len);
2198 wpabuf_put_data(clear, e_nonce, e_nonce_len);
2199
Roshan Pius3a1667e2018-07-03 15:17:14 -07002200#ifdef CONFIG_TESTING_OPTIONS
2201skip_e_nonce:
2202 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2203 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2204 goto skip_config_obj;
2205 }
2206#endif /* CONFIG_TESTING_OPTIONS */
2207
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002208 if (conf) {
2209 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2210 wpabuf_put_le16(clear, wpabuf_len(conf));
2211 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002212 }
Hai Shalomc3565922019-10-28 11:58:20 -07002213 if (auth->peer_version >= 2 && conf2) {
2214 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2215 wpabuf_put_le16(clear, wpabuf_len(conf2));
2216 wpabuf_put_buf(clear, conf2);
2217 } else if (conf2) {
2218 wpa_printf(MSG_DEBUG,
2219 "DPP: Second Config Object available, but peer does not support more than one");
2220 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002221 if (env_data) {
2222 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2223 wpabuf_put_le16(clear, wpabuf_len(env_data));
2224 wpabuf_put_buf(clear, env_data);
2225 }
Hai Shalomc3565922019-10-28 11:58:20 -07002226
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002227 if (auth->peer_version >= 2 && auth->send_conn_status &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002228 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002229 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2230 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2231 wpabuf_put_le16(clear, 0);
2232 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002233
Hai Shalom899fcc72020-10-19 14:38:18 -07002234 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2235 auth->conf_sta->csrattrs) {
2236 auth->waiting_csr = true;
2237 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2238 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2239 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2240 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2241 }
2242
Sunil Ravia04bd252022-05-02 22:54:18 -07002243#ifdef CONFIG_DPP3
2244 if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2245 auth->conf->net_access_key_curve) {
2246 u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2247
2248 /* Finite Cyclic Group attribute */
2249 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2250 ike_group);
2251 wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2252 wpabuf_put_le16(clear, 2);
2253 wpabuf_put_le16(clear, ike_group);
2254
2255 if (pc) {
2256 wpa_printf(MSG_DEBUG, "DPP: Pc");
2257 wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2258 wpabuf_put_le16(clear, wpabuf_len(pc));
2259 wpabuf_put_buf(clear, pc);
2260 }
2261 }
2262#endif /* CONFIG_DPP3 */
2263
Roshan Pius3a1667e2018-07-03 15:17:14 -07002264#ifdef CONFIG_TESTING_OPTIONS
2265skip_config_obj:
2266 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2267 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2268 goto skip_status;
2269 }
2270 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2271 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2272 status = 255;
2273 }
2274#endif /* CONFIG_TESTING_OPTIONS */
2275
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002276 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002277 dpp_build_attr_status(msg, status);
2278
2279#ifdef CONFIG_TESTING_OPTIONS
2280skip_status:
2281#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002282
2283 addr[0] = wpabuf_head(msg);
2284 len[0] = wpabuf_len(msg);
2285 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2286
2287 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2288 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2289 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2290
2291 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2292 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2293 wpabuf_head(clear), wpabuf_len(clear),
2294 1, addr, len, wrapped) < 0)
2295 goto fail;
2296 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2297 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002298
2299#ifdef CONFIG_TESTING_OPTIONS
2300 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2301 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2302 dpp_build_attr_status(msg, DPP_STATUS_OK);
2303 }
2304skip_wrapped_data:
2305#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002306
2307 wpa_hexdump_buf(MSG_DEBUG,
2308 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002309out:
Hai Shalomfdcde762020-04-02 11:19:20 -07002310 wpabuf_clear_free(conf);
2311 wpabuf_clear_free(conf2);
2312 wpabuf_clear_free(env_data);
2313 wpabuf_clear_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -07002314 wpabuf_free(pc);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002315
2316 return msg;
2317fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002318 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002319 msg = NULL;
2320 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002321}
2322
2323
2324struct wpabuf *
2325dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2326 size_t attr_len)
2327{
2328 const u8 *wrapped_data, *e_nonce, *config_attr;
2329 u16 wrapped_data_len, e_nonce_len, config_attr_len;
2330 u8 *unwrapped = NULL;
2331 size_t unwrapped_len = 0;
2332 struct wpabuf *resp = NULL;
2333 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002334 enum dpp_netrole netrole;
Hai Shalom899fcc72020-10-19 14:38:18 -07002335 struct wpabuf *cert_req = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07002336#ifdef CONFIG_DPP3
2337 const u8 *i_proto;
2338 u16 i_proto_len;
2339#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002340
Roshan Pius3a1667e2018-07-03 15:17:14 -07002341#ifdef CONFIG_TESTING_OPTIONS
2342 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2343 wpa_printf(MSG_INFO,
2344 "DPP: TESTING - stop at Config Request");
2345 return NULL;
2346 }
2347#endif /* CONFIG_TESTING_OPTIONS */
2348
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002349 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002350 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002351 return NULL;
2352 }
2353
2354 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2355 &wrapped_data_len);
2356 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002357 dpp_auth_fail(auth,
2358 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002359 return NULL;
2360 }
2361
2362 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2363 wrapped_data, wrapped_data_len);
2364 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2365 unwrapped = os_malloc(unwrapped_len);
2366 if (!unwrapped)
2367 return NULL;
2368 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2369 wrapped_data, wrapped_data_len,
2370 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002371 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002372 goto fail;
2373 }
2374 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2375 unwrapped, unwrapped_len);
2376
2377 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002378 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002379 goto fail;
2380 }
2381
2382 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2383 DPP_ATTR_ENROLLEE_NONCE,
2384 &e_nonce_len);
2385 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002386 dpp_auth_fail(auth,
2387 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002388 goto fail;
2389 }
2390 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07002391 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002392
Sunil Ravia04bd252022-05-02 22:54:18 -07002393#ifdef CONFIG_DPP3
2394 i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2395 DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2396 if (i_proto && !auth->waiting_new_key) {
2397 dpp_auth_fail(auth,
2398 "Enrollee included a new protocol key even though one was not expected");
2399 goto fail;
2400 }
2401 if (i_proto) {
2402 struct crypto_ec_key *pe;
2403 u8 auth_i[DPP_MAX_HASH_LEN];
2404 const u8 *rx_auth_i;
2405 u16 rx_auth_i_len;
2406
2407 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2408 i_proto, i_proto_len);
2409
2410 pe = dpp_set_pubkey_point(auth->own_protocol_key,
2411 i_proto, i_proto_len);
2412 if (!pe) {
2413 dpp_auth_fail(auth,
2414 "Invalid Initiator Protocol Key (Pe)");
2415 goto fail;
2416 }
2417 dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2418 crypto_ec_key_deinit(auth->peer_protocol_key);
2419 auth->peer_protocol_key = pe;
2420 auth->new_key_received = true;
2421 auth->waiting_new_key = false;
2422
2423 if (dpp_derive_auth_i(auth, auth_i) < 0)
2424 goto fail;
2425
2426 rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2427 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2428 if (!rx_auth_i) {
2429 dpp_auth_fail(auth,
2430 "Missing Initiator Authentication Tag");
2431 goto fail;
2432 }
2433 if (rx_auth_i_len != auth->curve->hash_len ||
2434 os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2435 dpp_auth_fail(auth,
2436 "Mismatch in Initiator Authenticating Tag");
2437 wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2438 rx_auth_i, rx_auth_i_len);
2439 wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2440 auth_i, auth->curve->hash_len);
2441 goto fail;
2442 }
2443 }
2444#endif /* CONFIG_DPP3 */
2445
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002446 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2447 DPP_ATTR_CONFIG_ATTR_OBJ,
2448 &config_attr_len);
2449 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002450 dpp_auth_fail(auth,
2451 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002452 goto fail;
2453 }
2454 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2455 config_attr, config_attr_len);
2456
2457 root = json_parse((const char *) config_attr, config_attr_len);
2458 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002459 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002460 goto fail;
2461 }
2462
2463 token = json_get_member(root, "name");
2464 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002465 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002466 goto fail;
2467 }
2468 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002469 os_free(auth->e_name);
2470 auth->e_name = os_strdup(token->string);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002471
2472 token = json_get_member(root, "wi-fi_tech");
2473 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002474 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002475 goto fail;
2476 }
2477 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2478 if (os_strcmp(token->string, "infra") != 0) {
2479 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2480 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002481 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002482 goto fail;
2483 }
2484
2485 token = json_get_member(root, "netRole");
2486 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002487 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002488 goto fail;
2489 }
2490 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2491 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002492 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002493 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002494 netrole = DPP_NETROLE_AP;
2495 } else if (os_strcmp(token->string, "configurator") == 0) {
2496 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002497 } else {
2498 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2499 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002500 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002501 goto fail;
2502 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002503 auth->e_netrole = netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002504
Hai Shalomc3565922019-10-28 11:58:20 -07002505 token = json_get_member(root, "mudurl");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002506 if (token && token->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002507 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002508 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2509 token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002510 os_free(auth->e_mud_url);
2511 auth->e_mud_url = os_strdup(token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002512 }
Hai Shalomc3565922019-10-28 11:58:20 -07002513
2514 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08002515 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002516 if (token && token->type == JSON_ARRAY) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002517 int *opclass = NULL;
2518 char txt[200], *pos, *end;
2519 int i, res;
2520
Hai Shalom06768112019-12-04 15:49:43 -08002521 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07002522 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2523 token = token->child;
2524 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08002525 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07002526 wpa_printf(MSG_DEBUG,
2527 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08002528 } else {
2529 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2530 auth->band_list[auth->band_list_size++] = token->number;
2531 }
Hai Shalomc3565922019-10-28 11:58:20 -07002532 wpa_printf(MSG_DEBUG,
2533 "DPP: Supported global operating class: %d",
2534 token->number);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002535 int_array_add_unique(&opclass, token->number);
Hai Shalom06768112019-12-04 15:49:43 -08002536 }
Hai Shalomc3565922019-10-28 11:58:20 -07002537 token = token->sibling;
2538 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002539
2540 txt[0] = '\0';
2541 pos = txt;
2542 end = txt + sizeof(txt);
2543 for (i = 0; opclass && opclass[i]; i++) {
2544 res = os_snprintf(pos, end - pos, "%s%d",
2545 pos == txt ? "" : ",", opclass[i]);
2546 if (os_snprintf_error(end - pos, res)) {
2547 *pos = '\0';
2548 break;
2549 }
2550 pos += res;
2551 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002552 os_free(auth->e_band_support);
2553 auth->e_band_support = opclass;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002554 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2555 txt);
Hai Shalomc3565922019-10-28 11:58:20 -07002556 }
2557
Hai Shalom899fcc72020-10-19 14:38:18 -07002558#ifdef CONFIG_DPP2
2559 cert_req = json_get_member_base64(root, "pkcs10");
2560 if (cert_req) {
2561 char *txt;
2562 int id;
2563
2564 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2565 if (dpp_validate_csr(auth, cert_req) < 0) {
2566 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2567 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2568 goto cont;
2569 }
2570
Hai Shaloma20dcd72022-02-04 13:43:00 -08002571 id = dpp_get_peer_bi_id(auth);
2572 if (id < 0)
2573 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002574
2575 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2576 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2577 wpabuf_len(cert_req), NULL);
2578 if (!txt)
2579 goto fail;
2580
2581 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2582 id, txt);
2583 os_free(txt);
2584 auth->waiting_csr = false;
2585 auth->waiting_cert = true;
2586 goto fail;
2587 }
2588cont:
2589#endif /* CONFIG_DPP2 */
2590
Sunil Ravic0f5d412024-09-11 22:12:49 +00002591#ifdef CONFIG_DPP3
2592 token = json_get_member(root, "capabilities");
2593 if (token && token->type == JSON_NUMBER) {
2594 wpa_printf(MSG_DEBUG, "DPP: capabilities = 0x%x",
2595 token->number);
2596 wpa_msg(auth->msg_ctx, MSG_INFO,
2597 DPP_EVENT_ENROLLEE_CAPABILITY "%d",
2598 token->number);
2599 auth->enrollee_capabilities = token->number;
2600 }
2601#endif /* CONFIG_DPP3 */
2602
Hai Shalom899fcc72020-10-19 14:38:18 -07002603 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2604 cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002605
2606fail:
Hai Shalom899fcc72020-10-19 14:38:18 -07002607 wpabuf_free(cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002608 json_free(root);
2609 os_free(unwrapped);
2610 return resp;
2611}
2612
2613
Hai Shalomc3565922019-10-28 11:58:20 -07002614static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002615 struct json_token *cred)
2616{
2617 struct json_token *pass, *psk_hex;
2618
2619 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2620
2621 pass = json_get_member(cred, "pass");
2622 psk_hex = json_get_member(cred, "psk_hex");
2623
2624 if (pass && pass->type == JSON_STRING) {
2625 size_t len = os_strlen(pass->string);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002626#ifdef CONFIG_DPP3
2627 struct json_token *saepi = json_get_member(cred, "idpass");
2628#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002629
2630 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2631 pass->string, len);
Sunil Ravic0f5d412024-09-11 22:12:49 +00002632 if (dpp_akm_psk(conf->akm) && (len < 8 || len > 63)) {
2633 wpa_printf(MSG_DEBUG,
2634 "DPP: Unexpected pass length %zu for a config object that includes PSK",
2635 len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002636 return -1;
Sunil Ravic0f5d412024-09-11 22:12:49 +00002637 }
Hai Shalomc3565922019-10-28 11:58:20 -07002638 os_strlcpy(conf->passphrase, pass->string,
2639 sizeof(conf->passphrase));
Sunil Ravic0f5d412024-09-11 22:12:49 +00002640#ifdef CONFIG_DPP3
2641 if (saepi && saepi->type == JSON_STRING)
2642 os_strlcpy(conf->password_id, saepi->string,
2643 sizeof(conf->password_id));
2644#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002645 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002646 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002647 wpa_printf(MSG_DEBUG,
2648 "DPP: Unexpected psk_hex with akm=sae");
2649 return -1;
2650 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002651 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07002652 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002653 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2654 return -1;
2655 }
2656 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07002657 conf->psk, PMK_LEN);
2658 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002659 } else {
2660 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2661 return -1;
2662 }
2663
Hai Shalomc3565922019-10-28 11:58:20 -07002664 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002665 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2666 return -1;
2667 }
2668
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002669 return 0;
2670}
2671
2672
Hai Shaloma20dcd72022-02-04 13:43:00 -08002673struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2674 const struct dpp_curve_params **key_curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002675{
2676 struct json_token *token;
2677 const struct dpp_curve_params *curve;
2678 struct wpabuf *x = NULL, *y = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002679 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002680
2681 token = json_get_member(jwk, "kty");
2682 if (!token || token->type != JSON_STRING) {
2683 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2684 goto fail;
2685 }
2686 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002687 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002688 token->string);
2689 goto fail;
2690 }
2691
2692 token = json_get_member(jwk, "crv");
2693 if (!token || token->type != JSON_STRING) {
2694 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2695 goto fail;
2696 }
2697 curve = dpp_get_curve_jwk_crv(token->string);
2698 if (!curve) {
2699 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2700 token->string);
2701 goto fail;
2702 }
2703
2704 x = json_get_member_base64url(jwk, "x");
2705 if (!x) {
2706 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2707 goto fail;
2708 }
2709 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2710 if (wpabuf_len(x) != curve->prime_len) {
2711 wpa_printf(MSG_DEBUG,
2712 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2713 (unsigned int) wpabuf_len(x),
2714 (unsigned int) curve->prime_len, curve->name);
2715 goto fail;
2716 }
2717
2718 y = json_get_member_base64url(jwk, "y");
2719 if (!y) {
2720 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2721 goto fail;
2722 }
2723 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2724 if (wpabuf_len(y) != curve->prime_len) {
2725 wpa_printf(MSG_DEBUG,
2726 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2727 (unsigned int) wpabuf_len(y),
2728 (unsigned int) curve->prime_len, curve->name);
2729 goto fail;
2730 }
2731
Hai Shaloma20dcd72022-02-04 13:43:00 -08002732 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2733 wpabuf_head(y), wpabuf_len(x));
2734 if (!key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002735 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002736
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002737 *key_curve = curve;
2738
2739fail:
2740 wpabuf_free(x);
2741 wpabuf_free(y);
2742
Hai Shaloma20dcd72022-02-04 13:43:00 -08002743 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002744}
2745
2746
2747int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2748{
2749 struct os_time now;
2750 unsigned int year, month, day, hour, min, sec;
2751 os_time_t utime;
2752 const char *pos;
2753
2754 /* ISO 8601 date and time:
2755 * <date>T<time>
2756 * YYYY-MM-DDTHH:MM:SSZ
2757 * YYYY-MM-DDTHH:MM:SS+03:00
2758 */
2759 if (os_strlen(timestamp) < 19) {
2760 wpa_printf(MSG_DEBUG,
2761 "DPP: Too short timestamp - assume expired key");
2762 return 1;
2763 }
2764 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2765 &year, &month, &day, &hour, &min, &sec) != 6) {
2766 wpa_printf(MSG_DEBUG,
2767 "DPP: Failed to parse expiration day - assume expired key");
2768 return 1;
2769 }
2770
2771 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2772 wpa_printf(MSG_DEBUG,
2773 "DPP: Invalid date/time information - assume expired key");
2774 return 1;
2775 }
2776
2777 pos = timestamp + 19;
2778 if (*pos == 'Z' || *pos == '\0') {
2779 /* In UTC - no need to adjust */
2780 } else if (*pos == '-' || *pos == '+') {
2781 int items;
2782
2783 /* Adjust local time to UTC */
2784 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2785 if (items < 1) {
2786 wpa_printf(MSG_DEBUG,
2787 "DPP: Invalid time zone designator (%s) - assume expired key",
2788 pos);
2789 return 1;
2790 }
2791 if (*pos == '-')
2792 utime += 3600 * hour;
2793 if (*pos == '+')
2794 utime -= 3600 * hour;
2795 if (items > 1) {
2796 if (*pos == '-')
2797 utime += 60 * min;
2798 if (*pos == '+')
2799 utime -= 60 * min;
2800 }
2801 } else {
2802 wpa_printf(MSG_DEBUG,
2803 "DPP: Invalid time zone designator (%s) - assume expired key",
2804 pos);
2805 return 1;
2806 }
2807 if (expiry)
2808 *expiry = utime;
2809
2810 if (os_get_time(&now) < 0) {
2811 wpa_printf(MSG_DEBUG,
2812 "DPP: Cannot get current time - assume expired key");
2813 return 1;
2814 }
2815
2816 if (now.sec > utime) {
2817 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2818 utime, now.sec);
2819 return 1;
2820 }
2821
2822 return 0;
2823}
2824
2825
2826static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002827 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002828 const unsigned char *payload,
2829 u16 payload_len)
2830{
2831 struct json_token *root, *groups, *netkey, *token;
2832 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002833 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002834 const struct dpp_curve_params *curve;
2835 unsigned int rules = 0;
2836
2837 root = json_parse((const char *) payload, payload_len);
2838 if (!root) {
2839 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2840 goto fail;
2841 }
2842
2843 groups = json_get_member(root, "groups");
2844 if (!groups || groups->type != JSON_ARRAY) {
2845 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2846 goto skip_groups;
2847 }
2848 for (token = groups->child; token; token = token->sibling) {
2849 struct json_token *id, *role;
2850
2851 id = json_get_member(token, "groupId");
2852 if (!id || id->type != JSON_STRING) {
2853 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2854 goto fail;
2855 }
2856
2857 role = json_get_member(token, "netRole");
2858 if (!role || role->type != JSON_STRING) {
2859 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2860 goto fail;
2861 }
2862 wpa_printf(MSG_DEBUG,
2863 "DPP: connector group: groupId='%s' netRole='%s'",
2864 id->string, role->string);
2865 rules++;
2866 }
2867skip_groups:
2868
2869 if (!rules) {
2870 wpa_printf(MSG_DEBUG,
2871 "DPP: Connector includes no groups");
2872 goto fail;
2873 }
2874
2875 token = json_get_member(root, "expiry");
2876 if (!token || token->type != JSON_STRING) {
2877 wpa_printf(MSG_DEBUG,
2878 "DPP: No expiry string found - connector does not expire");
2879 } else {
2880 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2881 if (dpp_key_expired(token->string,
2882 &auth->net_access_key_expiry)) {
2883 wpa_printf(MSG_DEBUG,
2884 "DPP: Connector (netAccessKey) has expired");
2885 goto fail;
2886 }
2887 }
2888
2889 netkey = json_get_member(root, "netAccessKey");
2890 if (!netkey || netkey->type != JSON_OBJECT) {
2891 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2892 goto fail;
2893 }
2894
2895 key = dpp_parse_jwk(netkey, &curve);
2896 if (!key)
2897 goto fail;
2898 dpp_debug_print_key("DPP: Received netAccessKey", key);
2899
Hai Shaloma20dcd72022-02-04 13:43:00 -08002900 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002901 wpa_printf(MSG_DEBUG,
2902 "DPP: netAccessKey in connector does not match own protocol key");
2903#ifdef CONFIG_TESTING_OPTIONS
2904 if (auth->ignore_netaccesskey_mismatch) {
2905 wpa_printf(MSG_DEBUG,
2906 "DPP: TESTING - skip netAccessKey mismatch");
2907 } else {
2908 goto fail;
2909 }
2910#else /* CONFIG_TESTING_OPTIONS */
2911 goto fail;
2912#endif /* CONFIG_TESTING_OPTIONS */
2913 }
2914
2915 ret = 0;
2916fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002917 crypto_ec_key_deinit(key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002918 json_free(root);
2919 return ret;
2920}
2921
2922
Hai Shaloma20dcd72022-02-04 13:43:00 -08002923static void dpp_copy_csign(struct dpp_config_obj *conf,
2924 struct crypto_ec_key *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002925{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002926 struct wpabuf *c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002927
Hai Shaloma20dcd72022-02-04 13:43:00 -08002928 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2929 if (!c_sign_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002930 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002931
Hai Shalomc3565922019-10-28 11:58:20 -07002932 wpabuf_free(conf->c_sign_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002933 conf->c_sign_key = c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002934}
2935
2936
Hai Shaloma20dcd72022-02-04 13:43:00 -08002937static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2938 struct crypto_ec_key *ppkey)
Hai Shalom899fcc72020-10-19 14:38:18 -07002939{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002940 struct wpabuf *pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002941
Hai Shaloma20dcd72022-02-04 13:43:00 -08002942 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2943 if (!pp_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002944 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002945
Hai Shalom899fcc72020-10-19 14:38:18 -07002946 wpabuf_free(conf->pp_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002947 conf->pp_key = pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002948}
2949
2950
Hai Shalomc3565922019-10-28 11:58:20 -07002951static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2952 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002953{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002954 struct wpabuf *net_access_key;
2955 struct crypto_ec_key *own_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002956
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002957 own_key = auth->own_protocol_key;
2958#ifdef CONFIG_DPP2
2959 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2960 auth->reconfig_old_protocol_key)
2961 own_key = auth->reconfig_old_protocol_key;
2962#endif /* CONFIG_DPP2 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002963
2964 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2965 if (!net_access_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002966 return;
2967
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002968 wpabuf_free(auth->net_access_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002969 auth->net_access_key = net_access_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002970}
2971
2972
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002973static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002974 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002975 struct json_token *cred)
2976{
2977 struct dpp_signed_connector_info info;
Hai Shalom899fcc72020-10-19 14:38:18 -07002978 struct json_token *token, *csign, *ppkey;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002979 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002980 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002981 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002982 const char *signed_connector;
2983
2984 os_memset(&info, 0, sizeof(info));
2985
Hai Shalomc3565922019-10-28 11:58:20 -07002986 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002987 wpa_printf(MSG_DEBUG,
2988 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07002989 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07002990 return -1;
2991 }
2992
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002993 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2994
2995 csign = json_get_member(cred, "csign");
2996 if (!csign || csign->type != JSON_OBJECT) {
2997 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2998 goto fail;
2999 }
3000
3001 csign_pub = dpp_parse_jwk(csign, &key_curve);
3002 if (!csign_pub) {
3003 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
3004 goto fail;
3005 }
3006 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
3007
Hai Shalom899fcc72020-10-19 14:38:18 -07003008 ppkey = json_get_member(cred, "ppKey");
3009 if (ppkey && ppkey->type == JSON_OBJECT) {
3010 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
3011 if (!pp_pub) {
3012 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
3013 goto fail;
3014 }
3015 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
3016 if (key_curve != pp_curve) {
3017 wpa_printf(MSG_DEBUG,
3018 "DPP: C-sign-key and ppKey do not use the same curve");
3019 goto fail;
3020 }
3021 }
3022
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003023 token = json_get_member(cred, "signedConnector");
3024 if (!token || token->type != JSON_STRING) {
3025 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
3026 goto fail;
3027 }
3028 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
3029 token->string, os_strlen(token->string));
3030 signed_connector = token->string;
3031
3032 if (os_strchr(signed_connector, '"') ||
3033 os_strchr(signed_connector, '\n')) {
3034 wpa_printf(MSG_DEBUG,
3035 "DPP: Unexpected character in signedConnector");
3036 goto fail;
3037 }
3038
3039 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003040 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003041 goto fail;
3042
Hai Shalomc3565922019-10-28 11:58:20 -07003043 if (dpp_parse_connector(auth, conf,
3044 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003045 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
3046 goto fail;
3047 }
3048
Hai Shalomc3565922019-10-28 11:58:20 -07003049 os_free(conf->connector);
3050 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003051
Hai Shalomc3565922019-10-28 11:58:20 -07003052 dpp_copy_csign(conf, csign_pub);
Hai Shalom899fcc72020-10-19 14:38:18 -07003053 if (pp_pub)
3054 dpp_copy_ppkey(conf, pp_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07003055 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07003056 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003057
3058 ret = 0;
3059fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08003060 crypto_ec_key_deinit(csign_pub);
3061 crypto_ec_key_deinit(pp_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003062 os_free(info.payload);
3063 return ret;
3064}
3065
3066
Hai Shalom899fcc72020-10-19 14:38:18 -07003067#ifdef CONFIG_DPP2
3068static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
3069 struct dpp_config_obj *conf,
3070 struct json_token *cred)
3071{
3072 struct json_token *ent, *name;
3073
3074 ent = json_get_member(cred, "entCreds");
3075 if (!ent || ent->type != JSON_OBJECT) {
3076 dpp_auth_fail(auth, "No entCreds in JSON");
3077 return -1;
3078 }
3079
3080 conf->certbag = json_get_member_base64(ent, "certBag");
3081 if (!conf->certbag) {
3082 dpp_auth_fail(auth, "No certBag in JSON");
3083 return -1;
3084 }
3085 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003086 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
Hai Shalom899fcc72020-10-19 14:38:18 -07003087 if (!conf->certs) {
3088 dpp_auth_fail(auth, "No certificates in certBag");
3089 return -1;
3090 }
3091
3092 conf->cacert = json_get_member_base64(ent, "caCert");
3093 if (conf->cacert)
3094 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3095 conf->cacert);
3096
3097 name = json_get_member(ent, "trustedEapServerName");
3098 if (name &&
3099 (name->type != JSON_STRING ||
3100 has_ctrl_char((const u8 *) name->string,
3101 os_strlen(name->string)))) {
3102 dpp_auth_fail(auth,
3103 "Invalid trustedEapServerName type in JSON");
3104 return -1;
3105 }
3106 if (name && name->string) {
3107 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3108 name->string);
3109 conf->server_name = os_strdup(name->string);
3110 if (!conf->server_name)
3111 return -1;
3112 }
3113
3114 return 0;
3115}
3116#endif /* CONFIG_DPP2 */
3117
3118
Roshan Pius3a1667e2018-07-03 15:17:14 -07003119const char * dpp_akm_str(enum dpp_akm akm)
3120{
3121 switch (akm) {
3122 case DPP_AKM_DPP:
3123 return "dpp";
3124 case DPP_AKM_PSK:
3125 return "psk";
3126 case DPP_AKM_SAE:
3127 return "sae";
3128 case DPP_AKM_PSK_SAE:
3129 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07003130 case DPP_AKM_SAE_DPP:
3131 return "dpp+sae";
3132 case DPP_AKM_PSK_SAE_DPP:
3133 return "dpp+psk+sae";
Hai Shalom899fcc72020-10-19 14:38:18 -07003134 case DPP_AKM_DOT1X:
3135 return "dot1x";
Roshan Pius3a1667e2018-07-03 15:17:14 -07003136 default:
3137 return "??";
3138 }
3139}
3140
3141
Hai Shalomc3565922019-10-28 11:58:20 -07003142const char * dpp_akm_selector_str(enum dpp_akm akm)
3143{
3144 switch (akm) {
3145 case DPP_AKM_DPP:
3146 return "506F9A02";
3147 case DPP_AKM_PSK:
3148 return "000FAC02+000FAC06";
3149 case DPP_AKM_SAE:
3150 return "000FAC08";
3151 case DPP_AKM_PSK_SAE:
3152 return "000FAC02+000FAC06+000FAC08";
3153 case DPP_AKM_SAE_DPP:
3154 return "506F9A02+000FAC08";
3155 case DPP_AKM_PSK_SAE_DPP:
3156 return "506F9A02+000FAC08+000FAC02+000FAC06";
Hai Shalom899fcc72020-10-19 14:38:18 -07003157 case DPP_AKM_DOT1X:
3158 return "000FAC01+000FAC05";
Hai Shalomc3565922019-10-28 11:58:20 -07003159 default:
3160 return "??";
3161 }
3162}
3163
3164
Roshan Pius3a1667e2018-07-03 15:17:14 -07003165static enum dpp_akm dpp_akm_from_str(const char *akm)
3166{
Hai Shalomc3565922019-10-28 11:58:20 -07003167 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07003168 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07003169
Roshan Pius3a1667e2018-07-03 15:17:14 -07003170 if (os_strcmp(akm, "psk") == 0)
3171 return DPP_AKM_PSK;
3172 if (os_strcmp(akm, "sae") == 0)
3173 return DPP_AKM_SAE;
3174 if (os_strcmp(akm, "psk+sae") == 0)
3175 return DPP_AKM_PSK_SAE;
3176 if (os_strcmp(akm, "dpp") == 0)
3177 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07003178 if (os_strcmp(akm, "dpp+sae") == 0)
3179 return DPP_AKM_SAE_DPP;
3180 if (os_strcmp(akm, "dpp+psk+sae") == 0)
3181 return DPP_AKM_PSK_SAE_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07003182 if (os_strcmp(akm, "dot1x") == 0)
3183 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003184
3185 pos = akm;
3186 while (*pos) {
3187 if (os_strlen(pos) < 8)
3188 break;
3189 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3190 dpp = 1;
3191 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3192 psk = 1;
3193 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3194 psk = 1;
3195 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3196 sae = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07003197 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3198 dot1x = 1;
3199 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3200 dot1x = 1;
Hai Shalomc3565922019-10-28 11:58:20 -07003201 pos += 8;
3202 if (*pos != '+')
3203 break;
3204 pos++;
3205 }
3206
3207 if (dpp && psk && sae)
3208 return DPP_AKM_PSK_SAE_DPP;
3209 if (dpp && sae)
3210 return DPP_AKM_SAE_DPP;
3211 if (dpp)
3212 return DPP_AKM_DPP;
3213 if (psk && sae)
3214 return DPP_AKM_PSK_SAE;
3215 if (sae)
3216 return DPP_AKM_SAE;
3217 if (psk)
3218 return DPP_AKM_PSK;
Hai Shalom899fcc72020-10-19 14:38:18 -07003219 if (dot1x)
3220 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003221
Roshan Pius3a1667e2018-07-03 15:17:14 -07003222 return DPP_AKM_UNKNOWN;
3223}
3224
3225
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003226static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3227 const u8 *conf_obj, u16 conf_obj_len)
3228{
3229 int ret = -1;
3230 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07003231 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003232 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003233 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003234
3235 root = json_parse((const char *) conf_obj, conf_obj_len);
3236 if (!root)
3237 return -1;
3238 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003239 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003240 goto fail;
3241 }
3242
3243 token = json_get_member(root, "wi-fi_tech");
3244 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003245 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003246 goto fail;
3247 }
3248 if (os_strcmp(token->string, "infra") != 0) {
3249 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3250 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003251 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003252 goto fail;
3253 }
3254
3255 discovery = json_get_member(root, "discovery");
3256 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003257 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003258 goto fail;
3259 }
3260
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003261 ssid64 = json_get_member_base64url(discovery, "ssid64");
3262 if (ssid64) {
3263 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3264 wpabuf_head(ssid64), wpabuf_len(ssid64));
3265 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3266 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3267 goto fail;
3268 }
3269 } else {
3270 token = json_get_member(discovery, "ssid");
3271 if (!token || token->type != JSON_STRING) {
3272 dpp_auth_fail(auth,
3273 "No discovery::ssid string value found");
3274 goto fail;
3275 }
3276 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3277 token->string, os_strlen(token->string));
3278 if (os_strlen(token->string) > SSID_MAX_LEN) {
3279 dpp_auth_fail(auth,
3280 "Too long discovery::ssid string value");
3281 goto fail;
3282 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003283 }
Hai Shalomc3565922019-10-28 11:58:20 -07003284
3285 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3286 wpa_printf(MSG_DEBUG,
3287 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003288 ret = 0;
3289 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003290 }
3291 conf = &auth->conf_obj[auth->num_conf_obj++];
3292
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003293 if (ssid64) {
3294 conf->ssid_len = wpabuf_len(ssid64);
3295 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3296 } else {
3297 conf->ssid_len = os_strlen(token->string);
3298 os_memcpy(conf->ssid, token->string, conf->ssid_len);
3299 }
3300
3301 token = json_get_member(discovery, "ssid_charset");
3302 if (token && token->type == JSON_NUMBER) {
3303 conf->ssid_charset = token->number;
3304 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3305 conf->ssid_charset);
3306 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003307
3308 cred = json_get_member(root, "cred");
3309 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003310 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003311 goto fail;
3312 }
3313
3314 token = json_get_member(cred, "akm");
3315 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003316 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003317 goto fail;
3318 }
Hai Shalomc3565922019-10-28 11:58:20 -07003319 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003320
Hai Shalomfdcde762020-04-02 11:19:20 -07003321 legacy = dpp_akm_legacy(conf->akm);
3322 if (legacy && auth->peer_version >= 2) {
3323 struct json_token *csign, *s_conn;
3324
3325 csign = json_get_member(cred, "csign");
3326 s_conn = json_get_member(cred, "signedConnector");
3327 if (csign && csign->type == JSON_OBJECT &&
3328 s_conn && s_conn->type == JSON_STRING)
3329 legacy = 0;
3330 }
3331 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07003332 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003333 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003334 } else if (dpp_akm_dpp(conf->akm) ||
3335 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07003336 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003337 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07003338#ifdef CONFIG_DPP2
3339 } else if (conf->akm == DPP_AKM_DOT1X) {
3340 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3341 dpp_parse_cred_dpp(auth, conf, cred) < 0)
3342 goto fail;
3343#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003344 } else {
3345 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3346 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003347 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003348 goto fail;
3349 }
3350
3351 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3352 ret = 0;
3353fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003354 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003355 json_free(root);
3356 return ret;
3357}
3358
3359
Hai Shalom899fcc72020-10-19 14:38:18 -07003360#ifdef CONFIG_DPP2
3361static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3362{
3363 const u8 *b64;
3364 u16 b64_len;
3365
3366 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3367 if (!b64)
3368 return NULL;
3369 return base64_decode((const char *) b64, b64_len, len);
3370}
3371#endif /* CONFIG_DPP2 */
3372
3373
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003374int dpp_conf_resp_rx(struct dpp_authentication *auth,
3375 const struct wpabuf *resp)
3376{
3377 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3378 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07003379 const u8 *env_data;
3380 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003381 const u8 *addr[1];
3382 size_t len[1];
3383 u8 *unwrapped = NULL;
3384 size_t unwrapped_len = 0;
3385 int ret = -1;
3386
Hai Shalom021b0b52019-04-10 11:17:58 -07003387 auth->conf_resp_status = 255;
3388
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003389 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003390 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003391 return -1;
3392 }
3393
3394 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3395 DPP_ATTR_WRAPPED_DATA,
3396 &wrapped_data_len);
3397 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003398 dpp_auth_fail(auth,
3399 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003400 return -1;
3401 }
3402
3403 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3404 wrapped_data, wrapped_data_len);
3405 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3406 unwrapped = os_malloc(unwrapped_len);
3407 if (!unwrapped)
3408 return -1;
3409
3410 addr[0] = wpabuf_head(resp);
3411 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3412 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3413
3414 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3415 wrapped_data, wrapped_data_len,
3416 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003417 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003418 goto fail;
3419 }
3420 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3421 unwrapped, unwrapped_len);
3422
3423 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003424 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003425 goto fail;
3426 }
3427
3428 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3429 DPP_ATTR_ENROLLEE_NONCE,
3430 &e_nonce_len);
3431 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003432 dpp_auth_fail(auth,
3433 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003434 goto fail;
3435 }
3436 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3437 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003438 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003439 goto fail;
3440 }
3441
3442 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3443 DPP_ATTR_STATUS, &status_len);
3444 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003445 dpp_auth_fail(auth,
3446 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003447 goto fail;
3448 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003449 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003450 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Hai Shalom899fcc72020-10-19 14:38:18 -07003451#ifdef CONFIG_DPP2
3452 if (status[0] == DPP_STATUS_CSR_NEEDED) {
3453 u8 *csrattrs;
3454 size_t csrattrs_len;
3455
3456 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3457
3458 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3459 &csrattrs_len);
3460 if (!csrattrs) {
3461 dpp_auth_fail(auth,
3462 "Missing or invalid CSR Attributes Request attribute");
3463 goto fail;
3464 }
3465 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3466 os_free(auth->csrattrs);
3467 auth->csrattrs = csrattrs;
3468 auth->csrattrs_len = csrattrs_len;
3469 ret = -2;
3470 goto fail;
3471 }
3472#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07003473#ifdef CONFIG_DPP3
3474 if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3475 const u8 *fcgroup, *r_proto;
3476 u16 fcgroup_len, r_proto_len;
3477 u16 group;
3478 const struct dpp_curve_params *curve;
3479 struct crypto_ec_key *new_pe;
3480 struct crypto_ec_key *pc;
3481
3482 fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3483 DPP_ATTR_FINITE_CYCLIC_GROUP,
3484 &fcgroup_len);
3485 if (!fcgroup || fcgroup_len != 2) {
3486 dpp_auth_fail(auth,
3487 "Missing or invalid required Finite Cyclic Group attribute");
3488 goto fail;
3489 }
3490 group = WPA_GET_LE16(fcgroup);
3491
3492 wpa_printf(MSG_DEBUG,
3493 "DPP: Configurator requested a new protocol key from group %u",
3494 group);
3495 curve = dpp_get_curve_ike_group(group);
3496 if (!curve) {
3497 dpp_auth_fail(auth,
3498 "Unsupported group for new protocol key");
3499 goto fail;
3500 }
3501
3502 new_pe = dpp_gen_keypair(curve);
3503 if (!new_pe) {
3504 dpp_auth_fail(auth,
3505 "Failed to generate a new protocol key");
3506 goto fail;
3507 }
3508
3509 crypto_ec_key_deinit(auth->own_protocol_key);
3510 auth->own_protocol_key = new_pe;
3511 auth->new_curve = curve;
3512
3513 r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3514 DPP_ATTR_R_PROTOCOL_KEY,
3515 &r_proto_len);
3516 if (!r_proto) {
3517 dpp_auth_fail(auth,
3518 "Missing required Responder Protocol Key attribute (Pc)");
3519 goto fail;
3520 }
3521 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3522 r_proto, r_proto_len);
3523
3524 pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3525 if (!pc) {
3526 dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3527 goto fail;
3528 }
3529 dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3530
3531 crypto_ec_key_deinit(auth->peer_protocol_key);
3532 auth->peer_protocol_key = pc;
3533
3534 auth->waiting_new_key = true;
3535 ret = -3;
3536 goto fail;
3537 }
3538#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003539 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003540 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003541 goto fail;
3542 }
3543
Hai Shalomfdcde762020-04-02 11:19:20 -07003544 env_data = dpp_get_attr(unwrapped, unwrapped_len,
3545 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3546#ifdef CONFIG_DPP2
3547 if (env_data &&
3548 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3549 goto fail;
3550#endif /* CONFIG_DPP2 */
3551
Hai Shalomc3565922019-10-28 11:58:20 -07003552 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3553 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003554 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003555 dpp_auth_fail(auth,
3556 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003557 goto fail;
3558 }
Hai Shalomc3565922019-10-28 11:58:20 -07003559 while (conf_obj) {
3560 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3561 conf_obj, conf_obj_len);
3562 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3563 goto fail;
3564 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3565 DPP_ATTR_CONFIG_OBJ,
3566 &conf_obj_len);
3567 }
3568
3569#ifdef CONFIG_DPP2
3570 status = dpp_get_attr(unwrapped, unwrapped_len,
3571 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3572 if (status) {
3573 wpa_printf(MSG_DEBUG,
3574 "DPP: Configurator requested connection status result");
3575 auth->conn_status_requested = 1;
3576 }
3577#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003578
3579 ret = 0;
3580
3581fail:
3582 os_free(unwrapped);
3583 return ret;
3584}
3585
3586
Hai Shalom021b0b52019-04-10 11:17:58 -07003587#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07003588
Hai Shalom021b0b52019-04-10 11:17:58 -07003589enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3590 const u8 *hdr,
3591 const u8 *attr_start, size_t attr_len)
3592{
3593 const u8 *wrapped_data, *status, *e_nonce;
3594 u16 wrapped_data_len, status_len, e_nonce_len;
3595 const u8 *addr[2];
3596 size_t len[2];
3597 u8 *unwrapped = NULL;
3598 size_t unwrapped_len = 0;
3599 enum dpp_status_error ret = 256;
3600
3601 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3602 &wrapped_data_len);
3603 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3604 dpp_auth_fail(auth,
3605 "Missing or invalid required Wrapped Data attribute");
3606 goto fail;
3607 }
3608 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3609 wrapped_data, wrapped_data_len);
3610
3611 attr_len = wrapped_data - 4 - attr_start;
3612
3613 addr[0] = hdr;
3614 len[0] = DPP_HDR_LEN;
3615 addr[1] = attr_start;
3616 len[1] = attr_len;
3617 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3618 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3619 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3620 wrapped_data, wrapped_data_len);
3621 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3622 unwrapped = os_malloc(unwrapped_len);
3623 if (!unwrapped)
3624 goto fail;
3625 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3626 wrapped_data, wrapped_data_len,
3627 2, addr, len, unwrapped) < 0) {
3628 dpp_auth_fail(auth, "AES-SIV decryption failed");
3629 goto fail;
3630 }
3631 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3632 unwrapped, unwrapped_len);
3633
3634 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3635 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3636 goto fail;
3637 }
3638
3639 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3640 DPP_ATTR_ENROLLEE_NONCE,
3641 &e_nonce_len);
3642 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3643 dpp_auth_fail(auth,
3644 "Missing or invalid Enrollee Nonce attribute");
3645 goto fail;
3646 }
3647 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3648 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3649 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3650 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3651 auth->e_nonce, e_nonce_len);
3652 goto fail;
3653 }
3654
3655 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3656 &status_len);
3657 if (!status || status_len < 1) {
3658 dpp_auth_fail(auth,
3659 "Missing or invalid required DPP Status attribute");
3660 goto fail;
3661 }
3662 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3663 ret = status[0];
3664
3665fail:
3666 bin_clear_free(unwrapped, unwrapped_len);
3667 return ret;
3668}
Hai Shalom021b0b52019-04-10 11:17:58 -07003669
3670
3671struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3672 enum dpp_status_error status)
3673{
3674 struct wpabuf *msg, *clear;
3675 size_t nonce_len, clear_len, attr_len;
3676 const u8 *addr[2];
3677 size_t len[2];
3678 u8 *wrapped;
3679
3680 nonce_len = auth->curve->nonce_len;
3681 clear_len = 5 + 4 + nonce_len;
3682 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3683 clear = wpabuf_alloc(clear_len);
3684 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3685 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003686 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07003687
3688 /* DPP Status */
3689 dpp_build_attr_status(clear, status);
3690
3691 /* E-nonce */
3692 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3693 wpabuf_put_le16(clear, nonce_len);
3694 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3695
3696 /* OUI, OUI type, Crypto Suite, DPP frame type */
3697 addr[0] = wpabuf_head_u8(msg) + 2;
3698 len[0] = 3 + 1 + 1 + 1;
3699 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3700
3701 /* Attributes before Wrapped Data (none) */
3702 addr[1] = wpabuf_put(msg, 0);
3703 len[1] = 0;
3704 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3705
3706 /* Wrapped Data */
3707 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3708 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3709 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3710
3711 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3712 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3713 wpabuf_head(clear), wpabuf_len(clear),
3714 2, addr, len, wrapped) < 0)
3715 goto fail;
3716
3717 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3718 wpabuf_free(clear);
3719 return msg;
3720fail:
3721 wpabuf_free(clear);
3722 wpabuf_free(msg);
3723 return NULL;
3724}
3725
3726
Hai Shalomc3565922019-10-28 11:58:20 -07003727static int valid_channel_list(const char *val)
3728{
3729 while (*val) {
3730 if (!((*val >= '0' && *val <= '9') ||
3731 *val == '/' || *val == ','))
3732 return 0;
3733 val++;
3734 }
3735
3736 return 1;
3737}
3738
3739
3740enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3741 const u8 *hdr,
3742 const u8 *attr_start,
3743 size_t attr_len,
3744 u8 *ssid, size_t *ssid_len,
3745 char **channel_list)
3746{
3747 const u8 *wrapped_data, *status, *e_nonce;
3748 u16 wrapped_data_len, status_len, e_nonce_len;
3749 const u8 *addr[2];
3750 size_t len[2];
3751 u8 *unwrapped = NULL;
3752 size_t unwrapped_len = 0;
3753 enum dpp_status_error ret = 256;
3754 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003755 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07003756
3757 *ssid_len = 0;
3758 *channel_list = NULL;
3759
3760 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3761 &wrapped_data_len);
3762 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3763 dpp_auth_fail(auth,
3764 "Missing or invalid required Wrapped Data attribute");
3765 goto fail;
3766 }
3767 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3768 wrapped_data, wrapped_data_len);
3769
3770 attr_len = wrapped_data - 4 - attr_start;
3771
3772 addr[0] = hdr;
3773 len[0] = DPP_HDR_LEN;
3774 addr[1] = attr_start;
3775 len[1] = attr_len;
3776 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3777 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3778 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3779 wrapped_data, wrapped_data_len);
3780 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3781 unwrapped = os_malloc(unwrapped_len);
3782 if (!unwrapped)
3783 goto fail;
3784 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3785 wrapped_data, wrapped_data_len,
3786 2, addr, len, unwrapped) < 0) {
3787 dpp_auth_fail(auth, "AES-SIV decryption failed");
3788 goto fail;
3789 }
3790 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3791 unwrapped, unwrapped_len);
3792
3793 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3794 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3795 goto fail;
3796 }
3797
3798 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3799 DPP_ATTR_ENROLLEE_NONCE,
3800 &e_nonce_len);
3801 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3802 dpp_auth_fail(auth,
3803 "Missing or invalid Enrollee Nonce attribute");
3804 goto fail;
3805 }
3806 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3807 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3808 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3809 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3810 auth->e_nonce, e_nonce_len);
3811 goto fail;
3812 }
3813
3814 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3815 &status_len);
3816 if (!status) {
3817 dpp_auth_fail(auth,
3818 "Missing required DPP Connection Status attribute");
3819 goto fail;
3820 }
3821 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3822 status, status_len);
3823
3824 root = json_parse((const char *) status, status_len);
3825 if (!root) {
3826 dpp_auth_fail(auth, "Could not parse connStatus");
3827 goto fail;
3828 }
3829
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003830 ssid64 = json_get_member_base64url(root, "ssid64");
3831 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3832 *ssid_len = wpabuf_len(ssid64);
3833 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07003834 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003835 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07003836
3837 token = json_get_member(root, "channelList");
3838 if (token && token->type == JSON_STRING &&
3839 valid_channel_list(token->string))
3840 *channel_list = os_strdup(token->string);
3841
3842 token = json_get_member(root, "result");
3843 if (!token || token->type != JSON_NUMBER) {
3844 dpp_auth_fail(auth, "No connStatus - result");
3845 goto fail;
3846 }
3847 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3848 ret = token->number;
3849
3850fail:
3851 json_free(root);
3852 bin_clear_free(unwrapped, unwrapped_len);
3853 return ret;
3854}
3855
3856
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003857struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3858 const u8 *ssid, size_t ssid_len,
3859 const char *channel_list)
3860{
3861 struct wpabuf *json;
3862
3863 json = wpabuf_alloc(1000);
3864 if (!json)
3865 return NULL;
3866 json_start_object(json, NULL);
3867 json_add_int(json, "result", result);
3868 if (ssid) {
3869 json_value_sep(json);
3870 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3871 wpabuf_free(json);
3872 return NULL;
3873 }
3874 }
3875 if (channel_list) {
3876 json_value_sep(json);
3877 json_add_string(json, "channelList", channel_list);
3878 }
3879 json_end_object(json);
3880 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3881 wpabuf_head(json), wpabuf_len(json));
3882
3883 return json;
3884}
3885
3886
Hai Shalomc3565922019-10-28 11:58:20 -07003887struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3888 enum dpp_status_error result,
3889 const u8 *ssid, size_t ssid_len,
3890 const char *channel_list)
3891{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003892 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07003893 size_t nonce_len, clear_len, attr_len;
3894 const u8 *addr[2];
3895 size_t len[2];
3896 u8 *wrapped;
3897
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003898 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
Hai Shalomc3565922019-10-28 11:58:20 -07003899 if (!json)
3900 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003901
3902 nonce_len = auth->curve->nonce_len;
3903 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3904 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3905 clear = wpabuf_alloc(clear_len);
3906 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3907 if (!clear || !msg)
3908 goto fail;
3909
3910 /* E-nonce */
3911 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3912 wpabuf_put_le16(clear, nonce_len);
3913 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3914
3915 /* DPP Connection Status */
3916 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3917 wpabuf_put_le16(clear, wpabuf_len(json));
3918 wpabuf_put_buf(clear, json);
3919
3920 /* OUI, OUI type, Crypto Suite, DPP frame type */
3921 addr[0] = wpabuf_head_u8(msg) + 2;
3922 len[0] = 3 + 1 + 1 + 1;
3923 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3924
3925 /* Attributes before Wrapped Data (none) */
3926 addr[1] = wpabuf_put(msg, 0);
3927 len[1] = 0;
3928 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3929
3930 /* Wrapped Data */
3931 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3932 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3933 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3934
3935 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3936 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3937 wpabuf_head(clear), wpabuf_len(clear),
3938 2, addr, len, wrapped) < 0)
3939 goto fail;
3940
3941 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3942 msg);
3943 wpabuf_free(json);
3944 wpabuf_free(clear);
3945 return msg;
3946fail:
3947 wpabuf_free(json);
3948 wpabuf_free(clear);
3949 wpabuf_free(msg);
3950 return NULL;
3951}
3952
3953#endif /* CONFIG_DPP2 */
3954
3955
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003956void dpp_configurator_free(struct dpp_configurator *conf)
3957{
3958 if (!conf)
3959 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003960 crypto_ec_key_deinit(conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003961 os_free(conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003962 os_free(conf->connector);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003963 crypto_ec_key_deinit(conf->connector_key);
3964 crypto_ec_key_deinit(conf->pp_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003965 os_free(conf);
3966}
3967
3968
Roshan Pius3a1667e2018-07-03 15:17:14 -07003969int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3970 size_t buflen)
3971{
Hai Shaloma20dcd72022-02-04 13:43:00 -08003972 struct wpabuf *key;
3973 int ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003974
3975 if (!conf->csign)
3976 return -1;
3977
Hai Shaloma20dcd72022-02-04 13:43:00 -08003978 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3979 if (!key)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003980 return -1;
3981
Hai Shaloma20dcd72022-02-04 13:43:00 -08003982 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003983
Hai Shaloma20dcd72022-02-04 13:43:00 -08003984 wpabuf_clear_free(key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003985 return ret;
3986}
3987
3988
Hai Shalomfdcde762020-04-02 11:19:20 -07003989static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3990{
3991 struct wpabuf *csign_pub = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003992 const u8 *addr[1];
3993 size_t len[1];
3994 int res;
3995
Hai Shaloma20dcd72022-02-04 13:43:00 -08003996 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
Hai Shalomfdcde762020-04-02 11:19:20 -07003997 if (!csign_pub) {
3998 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3999 return -1;
4000 }
4001
4002 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
4003 addr[0] = wpabuf_head(csign_pub);
4004 len[0] = wpabuf_len(csign_pub);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004005 res = sha256_vector(1, addr, len, conf->kid_hash);
Hai Shalomfdcde762020-04-02 11:19:20 -07004006 wpabuf_free(csign_pub);
4007 if (res < 0) {
4008 wpa_printf(MSG_DEBUG,
4009 "DPP: Failed to derive kid for C-sign-key");
4010 return -1;
4011 }
4012
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004013 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
4014 NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07004015 return conf->kid ? 0 : -1;
4016}
4017
4018
Hai Shalom899fcc72020-10-19 14:38:18 -07004019static struct dpp_configurator *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004020dpp_keygen_configurator(const char *curve, const u8 *privkey,
Hai Shalom899fcc72020-10-19 14:38:18 -07004021 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004022{
4023 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004024
4025 conf = os_zalloc(sizeof(*conf));
4026 if (!conf)
4027 return NULL;
4028
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004029 conf->curve = dpp_get_curve_name(curve);
4030 if (!conf->curve) {
4031 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
4032 os_free(conf);
4033 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004034 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004035
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004036 if (privkey)
4037 conf->csign = dpp_set_keypair(&conf->curve, privkey,
4038 privkey_len);
4039 else
4040 conf->csign = dpp_gen_keypair(conf->curve);
Hai Shalom899fcc72020-10-19 14:38:18 -07004041 if (pp_key)
4042 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
4043 pp_key_len);
4044 else
4045 conf->pp_key = dpp_gen_keypair(conf->curve);
4046 if (!conf->csign || !conf->pp_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004047 goto fail;
4048 conf->own = 1;
4049
Hai Shalomfdcde762020-04-02 11:19:20 -07004050 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004051 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004052 return conf;
4053fail:
4054 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07004055 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004056}
4057
4058
4059int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07004060 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004061{
4062 struct wpabuf *conf_obj;
4063 int ret = -1;
4064
4065 if (!auth->conf) {
4066 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
4067 return -1;
4068 }
4069
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004070 auth->curve = dpp_get_curve_name(curve);
4071 if (!auth->curve) {
4072 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
4073 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004074 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004075
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004076 wpa_printf(MSG_DEBUG,
4077 "DPP: Building own configuration/connector with curve %s",
4078 auth->curve->name);
4079
4080 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4081 if (!auth->own_protocol_key)
4082 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07004083 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004084 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07004085 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004086
Hai Shalom899fcc72020-10-19 14:38:18 -07004087 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004088 if (!conf_obj) {
4089 wpabuf_free(auth->conf_obj[0].c_sign_key);
4090 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004091 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004092 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004093 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4094 wpabuf_len(conf_obj));
4095fail:
4096 wpabuf_free(conf_obj);
4097 auth->peer_protocol_key = NULL;
4098 return ret;
4099}
4100
4101
4102static int dpp_compatible_netrole(const char *role1, const char *role2)
4103{
4104 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4105 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4106}
4107
4108
4109static int dpp_connector_compatible_group(struct json_token *root,
4110 const char *group_id,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004111 const char *net_role,
4112 bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004113{
4114 struct json_token *groups, *token;
4115
4116 groups = json_get_member(root, "groups");
4117 if (!groups || groups->type != JSON_ARRAY)
4118 return 0;
4119
4120 for (token = groups->child; token; token = token->sibling) {
4121 struct json_token *id, *role;
4122
4123 id = json_get_member(token, "groupId");
4124 if (!id || id->type != JSON_STRING)
4125 continue;
4126
4127 role = json_get_member(token, "netRole");
4128 if (!role || role->type != JSON_STRING)
4129 continue;
4130
4131 if (os_strcmp(id->string, "*") != 0 &&
4132 os_strcmp(group_id, "*") != 0 &&
4133 os_strcmp(id->string, group_id) != 0)
4134 continue;
4135
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004136 if (reconfig && os_strcmp(net_role, "configurator") == 0)
4137 return 1;
4138 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004139 return 1;
4140 }
4141
4142 return 0;
4143}
4144
4145
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004146int dpp_connector_match_groups(struct json_token *own_root,
4147 struct json_token *peer_root, bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004148{
4149 struct json_token *groups, *token;
4150
4151 groups = json_get_member(peer_root, "groups");
4152 if (!groups || groups->type != JSON_ARRAY) {
4153 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4154 return 0;
4155 }
4156
4157 for (token = groups->child; token; token = token->sibling) {
4158 struct json_token *id, *role;
4159
4160 id = json_get_member(token, "groupId");
4161 if (!id || id->type != JSON_STRING) {
4162 wpa_printf(MSG_DEBUG,
4163 "DPP: Missing peer groupId string");
4164 continue;
4165 }
4166
4167 role = json_get_member(token, "netRole");
4168 if (!role || role->type != JSON_STRING) {
4169 wpa_printf(MSG_DEBUG,
4170 "DPP: Missing peer groups::netRole string");
4171 continue;
4172 }
4173 wpa_printf(MSG_DEBUG,
4174 "DPP: peer connector group: groupId='%s' netRole='%s'",
4175 id->string, role->string);
4176 if (dpp_connector_compatible_group(own_root, id->string,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004177 role->string, reconfig)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004178 wpa_printf(MSG_DEBUG,
4179 "DPP: Compatible group/netRole in own connector");
4180 return 1;
4181 }
4182 }
4183
4184 return 0;
4185}
4186
4187
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004188struct json_token * dpp_parse_own_connector(const char *own_connector)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004189{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004190 unsigned char *own_conn;
4191 size_t own_conn_len;
4192 const char *pos, *end;
4193 struct json_token *own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004194
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004195 pos = os_strchr(own_connector, '.');
4196 if (!pos) {
4197 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4198 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004199 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004200 pos++;
4201 end = os_strchr(pos, '.');
4202 if (!end) {
4203 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4204 return NULL;
4205 }
4206 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4207 if (!own_conn) {
4208 wpa_printf(MSG_DEBUG,
4209 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4210 return NULL;
4211 }
4212
4213 own_root = json_parse((const char *) own_conn, own_conn_len);
4214 os_free(own_conn);
4215 if (!own_root)
4216 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4217
4218 return own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004219}
4220
4221
Roshan Pius3a1667e2018-07-03 15:17:14 -07004222enum dpp_status_error
4223dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4224 const u8 *net_access_key, size_t net_access_key_len,
4225 const u8 *csign_key, size_t csign_key_len,
4226 const u8 *peer_connector, size_t peer_connector_len,
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00004227 os_time_t *expiry, u8 *peer_key_hash)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004228{
4229 struct json_token *root = NULL, *netkey, *token;
4230 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004231 enum dpp_status_error ret = 255, res;
Sunil Ravi89eba102022-09-13 21:04:37 -07004232 struct crypto_ec_key *own_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004233 struct wpabuf *own_key_pub = NULL;
4234 const struct dpp_curve_params *curve, *own_curve;
4235 struct dpp_signed_connector_info info;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004236 size_t Nx_len;
4237 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4238
4239 os_memset(intro, 0, sizeof(*intro));
4240 os_memset(&info, 0, sizeof(info));
4241 if (expiry)
4242 *expiry = 0;
4243
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004244 own_key = dpp_set_keypair(&own_curve, net_access_key,
4245 net_access_key_len);
4246 if (!own_key) {
4247 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4248 goto fail;
4249 }
4250
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004251 own_root = dpp_parse_own_connector(own_connector);
4252 if (!own_root)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004253 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004254
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004255 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4256 peer_connector, peer_connector_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004257 if (res != DPP_STATUS_OK) {
4258 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004259 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004260 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004261
4262 root = json_parse((const char *) info.payload, info.payload_len);
4263 if (!root) {
4264 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004265 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004266 goto fail;
4267 }
4268
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004269 if (!dpp_connector_match_groups(own_root, root, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004270 wpa_printf(MSG_DEBUG,
4271 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004272 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004273 goto fail;
4274 }
4275
4276 token = json_get_member(root, "expiry");
4277 if (!token || token->type != JSON_STRING) {
4278 wpa_printf(MSG_DEBUG,
4279 "DPP: No expiry string found - connector does not expire");
4280 } else {
4281 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4282 if (dpp_key_expired(token->string, expiry)) {
4283 wpa_printf(MSG_DEBUG,
4284 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004285 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004286 goto fail;
4287 }
4288 }
4289
Hai Shaloma20dcd72022-02-04 13:43:00 -08004290#ifdef CONFIG_DPP3
4291 token = json_get_member(root, "version");
4292 if (token && token->type == JSON_NUMBER) {
4293 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4294 intro->peer_version = token->number;
4295 }
4296#endif /* CONFIG_DPP3 */
4297
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004298 netkey = json_get_member(root, "netAccessKey");
4299 if (!netkey || netkey->type != JSON_OBJECT) {
4300 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004301 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004302 goto fail;
4303 }
4304
Sunil Ravi89eba102022-09-13 21:04:37 -07004305 intro->peer_key = dpp_parse_jwk(netkey, &curve);
4306 if (!intro->peer_key) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004307 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004308 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004309 }
Sunil Ravi89eba102022-09-13 21:04:37 -07004310 dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004311
4312 if (own_curve != curve) {
4313 wpa_printf(MSG_DEBUG,
4314 "DPP: Mismatching netAccessKey curves (%s != %s)",
4315 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004316 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004317 goto fail;
4318 }
4319
4320 /* ECDH: N = nk * PK */
Sunil Ravi89eba102022-09-13 21:04:37 -07004321 if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004322 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004323
4324 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4325 Nx, Nx_len);
4326
4327 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4328 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4329 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4330 goto fail;
4331 }
4332 intro->pmk_len = curve->hash_len;
4333
4334 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
Sunil Ravi89eba102022-09-13 21:04:37 -07004335 if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4336 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004337 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4338 goto fail;
4339 }
4340
Sunil Ravi89eba102022-09-13 21:04:37 -07004341#ifdef CONFIG_DPP3
4342 if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4343 &intro->aead_id) < 0) {
4344 wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4345 curve->ike_group);
4346 goto fail;
4347 }
4348#endif /* CONFIG_DPP3 */
4349
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00004350 if (peer_key_hash)
4351 dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
4352
Roshan Pius3a1667e2018-07-03 15:17:14 -07004353 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004354fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07004355 if (ret != DPP_STATUS_OK)
Sunil Ravi89eba102022-09-13 21:04:37 -07004356 dpp_peer_intro_deinit(intro);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004357 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004358 os_free(info.payload);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004359 crypto_ec_key_deinit(own_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004360 wpabuf_free(own_key_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004361 json_free(root);
4362 json_free(own_root);
4363 return ret;
4364}
4365
4366
Sunil Ravi89eba102022-09-13 21:04:37 -07004367void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4368{
4369 if (!intro)
4370 return;
4371
4372 crypto_ec_key_deinit(intro->peer_key);
4373 os_memset(intro, 0, sizeof(*intro));
4374}
4375
4376
Hai Shaloma20dcd72022-02-04 13:43:00 -08004377#ifdef CONFIG_DPP3
4378int dpp_get_connector_version(const char *connector)
4379{
4380 struct json_token *root, *token;
4381 int ver = -1;
4382
4383 root = dpp_parse_own_connector(connector);
4384 if (!root)
4385 return -1;
4386
4387 token = json_get_member(root, "version");
4388 if (token && token->type == JSON_NUMBER)
4389 ver = token->number;
4390
4391 json_free(root);
4392 return ver;
4393}
4394#endif /* CONFIG_DPP3 */
4395
4396
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004397unsigned int dpp_next_id(struct dpp_global *dpp)
Hai Shalom021b0b52019-04-10 11:17:58 -07004398{
4399 struct dpp_bootstrap_info *bi;
4400 unsigned int max_id = 0;
4401
4402 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4403 if (bi->id > max_id)
4404 max_id = bi->id;
4405 }
4406 return max_id + 1;
4407}
4408
4409
4410static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4411{
4412 struct dpp_bootstrap_info *bi, *tmp;
4413 int found = 0;
4414
4415 if (!dpp)
4416 return -1;
4417
4418 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4419 struct dpp_bootstrap_info, list) {
4420 if (id && bi->id != id)
4421 continue;
4422 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07004423#ifdef CONFIG_DPP2
4424 if (dpp->remove_bi)
4425 dpp->remove_bi(dpp->cb_ctx, bi);
4426#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004427 dl_list_del(&bi->list);
4428 dpp_bootstrap_info_free(bi);
4429 }
4430
4431 if (id == 0)
4432 return 0; /* flush succeeds regardless of entries found */
4433 return found ? 0 : -1;
4434}
4435
4436
4437struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4438 const char *uri)
4439{
4440 struct dpp_bootstrap_info *bi;
4441
4442 if (!dpp)
4443 return NULL;
4444
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004445 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -07004446 if (!bi)
4447 return NULL;
4448
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004449 bi->type = DPP_BOOTSTRAP_QR_CODE;
4450 bi->id = dpp_next_id(dpp);
4451 dl_list_add(&dpp->bootstrap, &bi->list);
4452 return bi;
4453}
4454
4455
4456struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4457 const char *uri)
4458{
4459 struct dpp_bootstrap_info *bi;
4460
4461 if (!dpp)
4462 return NULL;
4463
4464 bi = dpp_parse_uri(uri);
4465 if (!bi)
4466 return NULL;
4467
4468 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004469 bi->id = dpp_next_id(dpp);
4470 dl_list_add(&dpp->bootstrap, &bi->list);
4471 return bi;
4472}
4473
4474
Sunil Ravia04bd252022-05-02 22:54:18 -07004475static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4476 char *txt)
4477{
4478 char *token, *context = NULL;
4479 u8 curves = 0;
4480
4481 if (!txt)
4482 return 0;
4483
4484 while ((token = str_token(txt, ":", &context))) {
4485 if (os_strcmp(token, "P-256") == 0) {
4486 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4487 } else if (os_strcmp(token, "P-384") == 0) {
4488 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4489 } else if (os_strcmp(token, "P-521") == 0) {
4490 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4491 } else if (os_strcmp(token, "BP-256") == 0) {
4492 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4493 } else if (os_strcmp(token, "BP-384") == 0) {
4494 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4495 } else if (os_strcmp(token, "BP-512") == 0) {
4496 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4497 } else {
4498 wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4499 token);
4500 return -1;
4501 }
4502 }
4503 bi->supported_curves = curves;
4504
4505 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4506 bi->supported_curves);
4507
4508 return 0;
4509}
4510
4511
Hai Shalom021b0b52019-04-10 11:17:58 -07004512int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4513{
Hai Shalomfdcde762020-04-02 11:19:20 -07004514 char *mac = NULL, *info = NULL, *curve = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00004515 char *key = NULL, *supported_curves = NULL, *host = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07004516 u8 *privkey = NULL;
4517 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004518 int ret = -1;
4519 struct dpp_bootstrap_info *bi;
4520
4521 if (!dpp)
4522 return -1;
4523
4524 bi = os_zalloc(sizeof(*bi));
4525 if (!bi)
4526 goto fail;
4527
4528 if (os_strstr(cmd, "type=qrcode"))
4529 bi->type = DPP_BOOTSTRAP_QR_CODE;
4530 else if (os_strstr(cmd, "type=pkex"))
4531 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004532 else if (os_strstr(cmd, "type=nfc-uri"))
4533 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004534 else
4535 goto fail;
4536
Hai Shalomfdcde762020-04-02 11:19:20 -07004537 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004538 mac = get_param(cmd, " mac=");
4539 info = get_param(cmd, " info=");
4540 curve = get_param(cmd, " curve=");
4541 key = get_param(cmd, " key=");
Sunil Ravia04bd252022-05-02 22:54:18 -07004542 supported_curves = get_param(cmd, " supported_curves=");
Sunil8cd6f4d2022-06-28 18:40:46 +00004543 host = get_param(cmd, " host=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004544
4545 if (key) {
4546 privkey_len = os_strlen(key) / 2;
4547 privkey = os_malloc(privkey_len);
4548 if (!privkey ||
4549 hexstr2bin(key, privkey, privkey_len) < 0)
4550 goto fail;
4551 }
4552
Hai Shalomfdcde762020-04-02 11:19:20 -07004553 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4554 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4555 dpp_parse_uri_mac(bi, mac) < 0 ||
4556 dpp_parse_uri_info(bi, info) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -07004557 dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +00004558 dpp_parse_uri_host(bi, host) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004559 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07004560 goto fail;
4561
Hai Shalom021b0b52019-04-10 11:17:58 -07004562 bi->id = dpp_next_id(dpp);
4563 dl_list_add(&dpp->bootstrap, &bi->list);
4564 ret = bi->id;
4565 bi = NULL;
4566fail:
4567 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -07004568 os_free(mac);
4569 os_free(info);
4570 str_clear_free(key);
Sunil Ravia04bd252022-05-02 22:54:18 -07004571 os_free(supported_curves);
Sunil8cd6f4d2022-06-28 18:40:46 +00004572 os_free(host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004573 bin_clear_free(privkey, privkey_len);
4574 dpp_bootstrap_info_free(bi);
4575 return ret;
4576}
4577
4578
4579struct dpp_bootstrap_info *
4580dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4581{
4582 struct dpp_bootstrap_info *bi;
4583
4584 if (!dpp)
4585 return NULL;
4586
4587 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4588 if (bi->id == id)
4589 return bi;
4590 }
4591 return NULL;
4592}
4593
4594
4595int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4596{
4597 unsigned int id_val;
4598
4599 if (os_strcmp(id, "*") == 0) {
4600 id_val = 0;
4601 } else {
4602 id_val = atoi(id);
4603 if (id_val == 0)
4604 return -1;
4605 }
4606
4607 return dpp_bootstrap_del(dpp, id_val);
4608}
4609
4610
Hai Shalom021b0b52019-04-10 11:17:58 -07004611const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4612{
4613 struct dpp_bootstrap_info *bi;
4614
4615 bi = dpp_bootstrap_get_id(dpp, id);
4616 if (!bi)
4617 return NULL;
4618 return bi->uri;
4619}
4620
4621
4622int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4623 char *reply, int reply_size)
4624{
4625 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004626 char pkhash[2 * SHA256_MAC_LEN + 1];
Sunil Ravia04bd252022-05-02 22:54:18 -07004627 char supp_curves[100];
Sunil8cd6f4d2022-06-28 18:40:46 +00004628 char host[100];
4629 int ret;
Hai Shalom021b0b52019-04-10 11:17:58 -07004630
4631 bi = dpp_bootstrap_get_id(dpp, id);
4632 if (!bi)
4633 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07004634 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4635 SHA256_MAC_LEN);
Sunil Ravia04bd252022-05-02 22:54:18 -07004636
4637 supp_curves[0] = '\0';
4638 if (bi->supported_curves) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004639 size_t i;
4640 char *pos = supp_curves;
4641 char *end = &supp_curves[sizeof(supp_curves)];
4642 const char *curve[6] = { "P-256", "P-384", "P-521",
4643 "BP-256", "BP-384", "BP-512" };
4644
4645 ret = os_snprintf(pos, end - pos, "supp_curves=");
4646 if (os_snprintf_error(end - pos, ret))
4647 return -1;
4648 pos += ret;
4649
4650 for (i = 0; i < ARRAY_SIZE(curve); i++) {
4651 if (!(bi->supported_curves & BIT(i)))
4652 continue;
4653 ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4654 if (os_snprintf_error(end - pos, ret))
4655 return -1;
4656 pos += ret;
4657 }
4658
4659 if (pos[-1] == ':')
4660 pos[-1] = '\n';
4661 else
4662 supp_curves[0] = '\0';
4663 }
4664
Sunil8cd6f4d2022-06-28 18:40:46 +00004665 host[0] = '\0';
4666 if (bi->host) {
4667 char buf[100];
4668
4669 ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4670 hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4671 bi->port);
4672 if (os_snprintf_error(sizeof(host), ret))
4673 return -1;
4674 }
4675
Hai Shalom021b0b52019-04-10 11:17:58 -07004676 return os_snprintf(reply, reply_size, "type=%s\n"
4677 "mac_addr=" MACSTR "\n"
4678 "info=%s\n"
4679 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -07004680 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07004681 "curve=%s\n"
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004682 "pkhash=%s\n"
Sunil8cd6f4d2022-06-28 18:40:46 +00004683 "version=%d\n%s%s",
Hai Shalom021b0b52019-04-10 11:17:58 -07004684 dpp_bootstrap_type_txt(bi->type),
4685 MAC2STR(bi->mac_addr),
4686 bi->info ? bi->info : "",
4687 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07004688 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -07004689 bi->curve->name,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004690 pkhash,
Sunil Ravia04bd252022-05-02 22:54:18 -07004691 bi->version,
Sunil8cd6f4d2022-06-28 18:40:46 +00004692 supp_curves,
4693 host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004694}
4695
4696
Hai Shalomfdcde762020-04-02 11:19:20 -07004697int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4698{
4699 struct dpp_bootstrap_info *bi;
4700
4701 bi = dpp_bootstrap_get_id(dpp, id);
4702 if (!bi)
4703 return -1;
4704
4705 str_clear_free(bi->configurator_params);
4706
4707 if (params) {
4708 bi->configurator_params = os_strdup(params);
4709 return bi->configurator_params ? 0 : -1;
4710 }
4711
4712 bi->configurator_params = NULL;
4713 return 0;
4714}
4715
4716
Hai Shalom021b0b52019-04-10 11:17:58 -07004717void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4718 const u8 *r_bootstrap,
4719 struct dpp_bootstrap_info **own_bi,
4720 struct dpp_bootstrap_info **peer_bi)
4721{
4722 struct dpp_bootstrap_info *bi;
4723
4724 *own_bi = NULL;
4725 *peer_bi = NULL;
4726 if (!dpp)
4727 return;
4728
4729 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4730 if (!*own_bi && bi->own &&
4731 os_memcmp(bi->pubkey_hash, r_bootstrap,
4732 SHA256_MAC_LEN) == 0) {
4733 wpa_printf(MSG_DEBUG,
4734 "DPP: Found matching own bootstrapping information");
4735 *own_bi = bi;
4736 }
4737
4738 if (!*peer_bi && !bi->own &&
4739 os_memcmp(bi->pubkey_hash, i_bootstrap,
4740 SHA256_MAC_LEN) == 0) {
4741 wpa_printf(MSG_DEBUG,
4742 "DPP: Found matching peer bootstrapping information");
4743 *peer_bi = bi;
4744 }
4745
4746 if (*own_bi && *peer_bi)
4747 break;
4748 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004749}
Hai Shalom021b0b52019-04-10 11:17:58 -07004750
Hai Shalomfdcde762020-04-02 11:19:20 -07004751
4752#ifdef CONFIG_DPP2
4753struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4754 const u8 *hash)
4755{
4756 struct dpp_bootstrap_info *bi;
4757
4758 if (!dpp)
4759 return NULL;
4760
4761 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4762 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4763 SHA256_MAC_LEN) == 0)
4764 return bi;
4765 }
4766
4767 return NULL;
4768}
4769#endif /* CONFIG_DPP2 */
4770
4771
4772static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4773 struct dpp_bootstrap_info *peer_bi)
4774{
4775 unsigned int i, freq = 0;
4776 enum hostapd_hw_mode mode;
4777 u8 op_class, channel;
4778 char chan[20];
4779
Hai Shalom899fcc72020-10-19 14:38:18 -07004780 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
Hai Shalomfdcde762020-04-02 11:19:20 -07004781 return 0; /* no channel preference/constraint */
4782
4783 for (i = 0; i < peer_bi->num_freq; i++) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004784 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004785 freq_included(own_bi->freq, own_bi->num_freq,
4786 peer_bi->freq[i])) {
4787 freq = peer_bi->freq[i];
4788 break;
4789 }
4790 }
4791 if (!freq) {
4792 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4793 return -1;
4794 }
4795
4796 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4797 if (mode == NUM_HOSTAPD_MODES) {
4798 wpa_printf(MSG_DEBUG,
4799 "DPP: Could not determine operating class or channel number for %u MHz",
4800 freq);
4801 }
4802
4803 wpa_printf(MSG_DEBUG,
4804 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4805 freq, op_class, channel);
4806 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4807 os_free(own_bi->chan);
4808 own_bi->chan = os_strdup(chan);
4809 own_bi->freq[0] = freq;
4810 own_bi->num_freq = 1;
4811 os_free(peer_bi->chan);
4812 peer_bi->chan = os_strdup(chan);
4813 peer_bi->freq[0] = freq;
4814 peer_bi->num_freq = 1;
4815
4816 return dpp_gen_uri(own_bi);
4817}
4818
4819
4820static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4821 struct dpp_bootstrap_info *peer_bi)
4822{
4823 if (peer_bi->curve == own_bi->curve)
4824 return 0;
4825
4826 wpa_printf(MSG_DEBUG,
4827 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4828
Hai Shaloma20dcd72022-02-04 13:43:00 -08004829 crypto_ec_key_deinit(own_bi->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -07004830 own_bi->pubkey = NULL;
4831
4832 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4833 dpp_gen_uri(own_bi) < 0)
4834 goto fail;
4835
4836 return 0;
4837fail:
4838 dl_list_del(&own_bi->list);
4839 dpp_bootstrap_info_free(own_bi);
4840 return -1;
4841}
4842
4843
4844int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4845 struct dpp_bootstrap_info *peer_bi)
4846{
4847 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4848 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4849 return -1;
4850 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004851}
4852
4853
4854static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4855{
4856 struct dpp_configurator *conf;
4857 unsigned int max_id = 0;
4858
4859 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4860 list) {
4861 if (conf->id > max_id)
4862 max_id = conf->id;
4863 }
4864 return max_id + 1;
4865}
4866
4867
4868int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4869{
Sunil Ravia04bd252022-05-02 22:54:18 -07004870 char *curve;
Hai Shalom899fcc72020-10-19 14:38:18 -07004871 char *key = NULL, *ppkey = NULL;
4872 u8 *privkey = NULL, *pp_key = NULL;
4873 size_t privkey_len = 0, pp_key_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004874 int ret = -1;
4875 struct dpp_configurator *conf = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07004876 const struct dpp_curve_params *net_access_key_curve = NULL;
4877
4878 curve = get_param(cmd, " net_access_key_curve=");
4879 if (curve) {
4880 net_access_key_curve = dpp_get_curve_name(curve);
4881 if (!net_access_key_curve) {
4882 wpa_printf(MSG_DEBUG,
4883 "DPP: Unsupported net_access_key_curve: %s",
4884 curve);
4885 goto fail;
4886 }
4887 os_free(curve);
4888 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004889
4890 curve = get_param(cmd, " curve=");
4891 key = get_param(cmd, " key=");
Hai Shalom899fcc72020-10-19 14:38:18 -07004892 ppkey = get_param(cmd, " ppkey=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004893
4894 if (key) {
4895 privkey_len = os_strlen(key) / 2;
4896 privkey = os_malloc(privkey_len);
4897 if (!privkey ||
4898 hexstr2bin(key, privkey, privkey_len) < 0)
4899 goto fail;
4900 }
4901
Hai Shalom899fcc72020-10-19 14:38:18 -07004902 if (ppkey) {
Hai Shalom60840252021-02-19 19:02:11 -08004903 pp_key_len = os_strlen(ppkey) / 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07004904 pp_key = os_malloc(pp_key_len);
4905 if (!pp_key ||
4906 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4907 goto fail;
4908 }
4909
4910 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4911 pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004912 if (!conf)
4913 goto fail;
4914
Sunil Ravia04bd252022-05-02 22:54:18 -07004915 conf->net_access_key_curve = net_access_key_curve;
Hai Shalom021b0b52019-04-10 11:17:58 -07004916 conf->id = dpp_next_configurator_id(dpp);
4917 dl_list_add(&dpp->configurator, &conf->list);
4918 ret = conf->id;
4919 conf = NULL;
4920fail:
4921 os_free(curve);
4922 str_clear_free(key);
Hai Shalom899fcc72020-10-19 14:38:18 -07004923 str_clear_free(ppkey);
Hai Shalom021b0b52019-04-10 11:17:58 -07004924 bin_clear_free(privkey, privkey_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004925 bin_clear_free(pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004926 dpp_configurator_free(conf);
4927 return ret;
4928}
4929
4930
Sunil Ravia04bd252022-05-02 22:54:18 -07004931int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4932{
4933 unsigned int id;
4934 struct dpp_configurator *conf;
4935 char *curve;
4936
4937 id = atoi(cmd);
4938 conf = dpp_configurator_get_id(dpp, id);
4939 if (!conf)
4940 return -1;
4941
4942 curve = get_param(cmd, " net_access_key_curve=");
4943 if (curve) {
4944 const struct dpp_curve_params *net_access_key_curve;
4945
4946 net_access_key_curve = dpp_get_curve_name(curve);
4947 os_free(curve);
4948 if (!net_access_key_curve)
4949 return -1;
4950 conf->net_access_key_curve = net_access_key_curve;
4951 }
4952
4953 return 0;
4954}
4955
4956
Hai Shalom021b0b52019-04-10 11:17:58 -07004957static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4958{
4959 struct dpp_configurator *conf, *tmp;
4960 int found = 0;
4961
4962 if (!dpp)
4963 return -1;
4964
4965 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4966 struct dpp_configurator, list) {
4967 if (id && conf->id != id)
4968 continue;
4969 found = 1;
4970 dl_list_del(&conf->list);
4971 dpp_configurator_free(conf);
4972 }
4973
4974 if (id == 0)
4975 return 0; /* flush succeeds regardless of entries found */
4976 return found ? 0 : -1;
4977}
4978
4979
4980int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4981{
4982 unsigned int id_val;
4983
4984 if (os_strcmp(id, "*") == 0) {
4985 id_val = 0;
4986 } else {
4987 id_val = atoi(id);
4988 if (id_val == 0)
4989 return -1;
4990 }
4991
4992 return dpp_configurator_del(dpp, id_val);
4993}
4994
4995
4996int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4997 char *buf, size_t buflen)
4998{
4999 struct dpp_configurator *conf;
5000
5001 conf = dpp_configurator_get_id(dpp, id);
5002 if (!conf)
5003 return -1;
5004
5005 return dpp_configurator_get_key(conf, buf, buflen);
5006}
5007
5008
Hai Shalom81f62d82019-07-22 12:10:00 -07005009#ifdef CONFIG_DPP2
5010
Hai Shalomfdcde762020-04-02 11:19:20 -07005011int dpp_configurator_from_backup(struct dpp_global *dpp,
5012 struct dpp_asymmetric_key *key)
5013{
5014 struct dpp_configurator *conf;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005015 const struct dpp_curve_params *curve, *curve_pp;
Hai Shalomfdcde762020-04-02 11:19:20 -07005016
Hai Shalom899fcc72020-10-19 14:38:18 -07005017 if (!key->csign || !key->pp_key)
Hai Shalomfdcde762020-04-02 11:19:20 -07005018 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005019
5020 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
Hai Shalomfdcde762020-04-02 11:19:20 -07005021 if (!curve) {
5022 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
5023 return -1;
5024 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08005025
5026 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
5027 if (!curve_pp) {
5028 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
Hai Shalom899fcc72020-10-19 14:38:18 -07005029 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08005030 }
5031
5032 if (curve != curve_pp) {
Hai Shalom899fcc72020-10-19 14:38:18 -07005033 wpa_printf(MSG_INFO,
5034 "DPP: Mismatch in c-sign-key and ppKey groups");
5035 return -1;
5036 }
Hai Shalomfdcde762020-04-02 11:19:20 -07005037
5038 conf = os_zalloc(sizeof(*conf));
5039 if (!conf)
5040 return -1;
5041 conf->curve = curve;
5042 conf->csign = key->csign;
5043 key->csign = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07005044 conf->pp_key = key->pp_key;
5045 key->pp_key = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07005046 conf->own = 1;
5047 if (dpp_configurator_gen_kid(conf) < 0) {
5048 dpp_configurator_free(conf);
5049 return -1;
5050 }
5051
5052 conf->id = dpp_next_configurator_id(dpp);
5053 dl_list_add(&dpp->configurator, &conf->list);
5054 return conf->id;
5055}
5056
5057
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005058struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
5059 const u8 *kid)
Hai Shalom81f62d82019-07-22 12:10:00 -07005060{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005061 struct dpp_configurator *conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07005062
5063 if (!dpp)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005064 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005065
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005066 dl_list_for_each(conf, &dpp->configurator,
5067 struct dpp_configurator, list) {
5068 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
5069 return conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07005070 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07005071 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005072}
5073
5074#endif /* CONFIG_DPP2 */
5075
5076
5077struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07005078{
5079 struct dpp_global *dpp;
5080
5081 dpp = os_zalloc(sizeof(*dpp));
5082 if (!dpp)
5083 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005084#ifdef CONFIG_DPP2
5085 dpp->cb_ctx = config->cb_ctx;
Hai Shalomfdcde762020-04-02 11:19:20 -07005086 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07005087#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005088
5089 dl_list_init(&dpp->bootstrap);
5090 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07005091#ifdef CONFIG_DPP2
5092 dl_list_init(&dpp->controllers);
5093 dl_list_init(&dpp->tcp_init);
Sunil Ravi89eba102022-09-13 21:04:37 -07005094 dpp->relay_sock = -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07005095#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005096
5097 return dpp;
5098}
5099
5100
5101void dpp_global_clear(struct dpp_global *dpp)
5102{
5103 if (!dpp)
5104 return;
5105
5106 dpp_bootstrap_del(dpp, 0);
5107 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07005108#ifdef CONFIG_DPP2
5109 dpp_tcp_init_flush(dpp);
5110 dpp_relay_flush_controllers(dpp);
5111 dpp_controller_stop(dpp);
5112#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005113}
5114
5115
5116void dpp_global_deinit(struct dpp_global *dpp)
5117{
5118 dpp_global_clear(dpp);
5119 os_free(dpp);
5120}
Hai Shalom81f62d82019-07-22 12:10:00 -07005121
5122
Sunil Ravi38ad1ed2023-01-17 23:58:31 +00005123void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
5124{
5125 u8 hash[SHA256_MAC_LEN];
5126 char hex[SHA256_MAC_LEN * 2 + 1];
5127
5128 if (auth->peer_protocol_key) {
5129 dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
5130 wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
5131 } else {
5132 hex[0] = '\0';
5133 }
5134 wpa_msg(auth->msg_ctx, MSG_INFO,
5135 DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d",
5136 initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1,
5137 auth->peer_bi ? (int) auth->peer_bi->id : -1);
5138}
5139
5140
Hai Shalom81f62d82019-07-22 12:10:00 -07005141#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07005142
Hai Shalomfdcde762020-04-02 11:19:20 -07005143struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5144{
5145 struct wpabuf *msg;
5146
5147 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5148
5149 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5150 if (!msg)
5151 return NULL;
5152
5153 /* Responder Bootstrapping Key Hash */
5154 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5155 wpa_hexdump_buf(MSG_DEBUG,
5156 "DPP: Presence Announcement frame attributes", msg);
5157 return msg;
5158}
Hai Shalom899fcc72020-10-19 14:38:18 -07005159
5160
5161void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5162 unsigned int freq, const u8 *hash)
5163{
5164 char hex[SHA256_MAC_LEN * 2 + 1];
5165
5166 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5167 wpa_msg(msg_ctx, MSG_INFO,
5168 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5169 id, MAC2STR(src), freq, hex);
5170}
5171
Hai Shalom81f62d82019-07-22 12:10:00 -07005172#endif /* CONFIG_DPP2 */
Sunil Ravi89eba102022-09-13 21:04:37 -07005173
5174
5175#ifdef CONFIG_DPP3
5176
5177struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5178{
5179 struct wpabuf *msg;
5180 const u8 *r_hash = bi->pubkey_hash_chirp;
5181#ifdef CONFIG_TESTING_OPTIONS
5182 u8 test_hash[SHA256_MAC_LEN];
5183#endif /* CONFIG_TESTING_OPTIONS */
5184
5185 wpa_printf(MSG_DEBUG,
5186 "DPP: Build Push Button Presence Announcement frame");
5187
5188 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5189 4 + SHA256_MAC_LEN);
5190 if (!msg)
5191 return NULL;
5192
5193#ifdef CONFIG_TESTING_OPTIONS
5194 if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5195 wpa_printf(MSG_INFO,
5196 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5197 os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5198 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5199 r_hash = test_hash;
5200 }
5201#endif /* CONFIG_TESTING_OPTIONS */
5202
5203 /* Responder Bootstrapping Key Hash */
5204 dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5205 wpa_hexdump_buf(MSG_DEBUG,
5206 "DPP: Push Button Presence Announcement frame attributes",
5207 msg);
5208 return msg;
5209}
5210
5211
5212struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5213 const u8 *e_hash,
5214 const u8 *c_nonce,
5215 size_t c_nonce_len)
5216{
5217 struct wpabuf *msg;
5218 const u8 *i_hash = bi->pubkey_hash_chirp;
5219#ifdef CONFIG_TESTING_OPTIONS
5220 u8 test_hash[SHA256_MAC_LEN];
5221#endif /* CONFIG_TESTING_OPTIONS */
5222
5223 wpa_printf(MSG_DEBUG,
5224 "DPP: Build Push Button Presence Announcement Response frame");
5225
5226 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5227 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5228 if (!msg)
5229 return NULL;
5230
5231#ifdef CONFIG_TESTING_OPTIONS
5232 if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5233 wpa_printf(MSG_INFO,
5234 "DPP: TESTING - invalid I-Bootstrap Key Hash");
5235 os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5236 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5237 i_hash = test_hash;
5238 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5239 wpa_printf(MSG_INFO,
5240 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5241 os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5242 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5243 e_hash = test_hash;
5244 }
5245#endif /* CONFIG_TESTING_OPTIONS */
5246
5247 /* Initiator Bootstrapping Key Hash */
5248 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5249 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5250 wpabuf_put_le16(msg, SHA256_MAC_LEN);
5251 wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5252
5253 /* Responder Bootstrapping Key Hash */
5254 dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5255
5256 /* Configurator Nonce */
5257 wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5258 wpabuf_put_le16(msg, c_nonce_len);
5259 wpabuf_put_data(msg, c_nonce, c_nonce_len);
5260
5261 wpa_hexdump_buf(MSG_DEBUG,
5262 "DPP: Push Button Presence Announcement Response frame attributes",
5263 msg);
5264 return msg;
5265}
5266
5267#endif /* CONFIG_DPP3 */