blob: 559bdcd3ef2cefc4d5c17f16f080f3504723a5c8 [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 Ravi89eba102022-09-13 21:04:37 -07001038 if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1039 json_value_sep(json);
1040 wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1041 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001042 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001043
1044 buf = dpp_build_conf_req(auth, wpabuf_head(json));
Sunil Ravia04bd252022-05-02 22:54:18 -07001045fail:
Hai Shalomc3565922019-10-28 11:58:20 -07001046 wpabuf_free(json);
Hai Shalom899fcc72020-10-19 14:38:18 -07001047 os_free(csr);
Hai Shalomc3565922019-10-28 11:58:20 -07001048
1049 return buf;
1050}
1051
1052
Hai Shalom021b0b52019-04-10 11:17:58 -07001053static int bin_str_eq(const char *val, size_t len, const char *cmp)
1054{
1055 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1056}
1057
1058
1059struct dpp_configuration * dpp_configuration_alloc(const char *type)
1060{
1061 struct dpp_configuration *conf;
1062 const char *end;
1063 size_t len;
1064
1065 conf = os_zalloc(sizeof(*conf));
1066 if (!conf)
1067 goto fail;
1068
1069 end = os_strchr(type, ' ');
1070 if (end)
1071 len = end - type;
1072 else
1073 len = os_strlen(type);
1074
1075 if (bin_str_eq(type, len, "psk"))
1076 conf->akm = DPP_AKM_PSK;
1077 else if (bin_str_eq(type, len, "sae"))
1078 conf->akm = DPP_AKM_SAE;
1079 else if (bin_str_eq(type, len, "psk-sae") ||
1080 bin_str_eq(type, len, "psk+sae"))
1081 conf->akm = DPP_AKM_PSK_SAE;
1082 else if (bin_str_eq(type, len, "sae-dpp") ||
1083 bin_str_eq(type, len, "dpp+sae"))
1084 conf->akm = DPP_AKM_SAE_DPP;
1085 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1086 bin_str_eq(type, len, "dpp+psk+sae"))
1087 conf->akm = DPP_AKM_PSK_SAE_DPP;
1088 else if (bin_str_eq(type, len, "dpp"))
1089 conf->akm = DPP_AKM_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07001090 else if (bin_str_eq(type, len, "dot1x"))
1091 conf->akm = DPP_AKM_DOT1X;
Hai Shalom021b0b52019-04-10 11:17:58 -07001092 else
1093 goto fail;
1094
1095 return conf;
1096fail:
1097 dpp_configuration_free(conf);
1098 return NULL;
1099}
1100
1101
1102int dpp_akm_psk(enum dpp_akm akm)
1103{
1104 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1105 akm == DPP_AKM_PSK_SAE_DPP;
1106}
1107
1108
1109int dpp_akm_sae(enum dpp_akm akm)
1110{
1111 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1112 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1113}
1114
1115
1116int dpp_akm_legacy(enum dpp_akm akm)
1117{
1118 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1119 akm == DPP_AKM_SAE;
1120}
1121
1122
1123int dpp_akm_dpp(enum dpp_akm akm)
1124{
1125 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1126 akm == DPP_AKM_PSK_SAE_DPP;
1127}
1128
1129
1130int dpp_akm_ver2(enum dpp_akm akm)
1131{
1132 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1133}
1134
1135
1136int dpp_configuration_valid(const struct dpp_configuration *conf)
1137{
1138 if (conf->ssid_len == 0)
1139 return 0;
1140 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1141 return 0;
1142 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1143 return 0;
1144 return 1;
1145}
1146
1147
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001148void dpp_configuration_free(struct dpp_configuration *conf)
1149{
1150 if (!conf)
1151 return;
1152 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07001153 os_free(conf->group_id);
Hai Shalom899fcc72020-10-19 14:38:18 -07001154 os_free(conf->csrattrs);
Sunil Ravi89eba102022-09-13 21:04:37 -07001155 os_free(conf->extra_name);
1156 os_free(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001157 bin_clear_free(conf, sizeof(*conf));
1158}
1159
1160
Hai Shalomc3565922019-10-28 11:58:20 -07001161static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1162 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07001163{
1164 const char *pos, *end;
1165 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1166 struct dpp_configuration *conf = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001167 size_t len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001168
1169 pos = os_strstr(cmd, " conf=sta-");
1170 if (pos) {
1171 conf_sta = dpp_configuration_alloc(pos + 10);
1172 if (!conf_sta)
1173 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001174 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07001175 conf = conf_sta;
1176 }
1177
1178 pos = os_strstr(cmd, " conf=ap-");
1179 if (pos) {
1180 conf_ap = dpp_configuration_alloc(pos + 9);
1181 if (!conf_ap)
1182 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001183 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07001184 conf = conf_ap;
1185 }
1186
Hai Shalomfdcde762020-04-02 11:19:20 -07001187 pos = os_strstr(cmd, " conf=configurator");
1188 if (pos)
1189 auth->provision_configurator = 1;
1190
Hai Shalom021b0b52019-04-10 11:17:58 -07001191 if (!conf)
1192 return 0;
1193
1194 pos = os_strstr(cmd, " ssid=");
1195 if (pos) {
1196 pos += 6;
1197 end = os_strchr(pos, ' ');
1198 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1199 conf->ssid_len /= 2;
1200 if (conf->ssid_len > sizeof(conf->ssid) ||
1201 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1202 goto fail;
1203 } else {
1204#ifdef CONFIG_TESTING_OPTIONS
1205 /* use a default SSID for legacy testing reasons */
1206 os_memcpy(conf->ssid, "test", 4);
1207 conf->ssid_len = 4;
1208#else /* CONFIG_TESTING_OPTIONS */
1209 goto fail;
1210#endif /* CONFIG_TESTING_OPTIONS */
1211 }
1212
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001213 pos = os_strstr(cmd, " ssid_charset=");
1214 if (pos) {
1215 if (conf_ap) {
1216 wpa_printf(MSG_INFO,
1217 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1218 goto fail;
1219 }
1220 conf->ssid_charset = atoi(pos + 14);
1221 }
1222
Hai Shalom021b0b52019-04-10 11:17:58 -07001223 pos = os_strstr(cmd, " pass=");
1224 if (pos) {
1225 size_t pass_len;
1226
1227 pos += 6;
1228 end = os_strchr(pos, ' ');
1229 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1230 pass_len /= 2;
1231 if (pass_len > 63 || pass_len < 8)
1232 goto fail;
1233 conf->passphrase = os_zalloc(pass_len + 1);
1234 if (!conf->passphrase ||
1235 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1236 goto fail;
1237 }
1238
1239 pos = os_strstr(cmd, " psk=");
1240 if (pos) {
1241 pos += 5;
1242 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1243 goto fail;
1244 conf->psk_set = 1;
1245 }
1246
1247 pos = os_strstr(cmd, " group_id=");
1248 if (pos) {
1249 size_t group_id_len;
1250
1251 pos += 10;
1252 end = os_strchr(pos, ' ');
1253 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1254 conf->group_id = os_malloc(group_id_len + 1);
1255 if (!conf->group_id)
1256 goto fail;
1257 os_memcpy(conf->group_id, pos, group_id_len);
1258 conf->group_id[group_id_len] = '\0';
1259 }
1260
1261 pos = os_strstr(cmd, " expiry=");
1262 if (pos) {
1263 long int val;
1264
1265 pos += 8;
1266 val = strtol(pos, NULL, 0);
1267 if (val <= 0)
1268 goto fail;
1269 conf->netaccesskey_expiry = val;
1270 }
1271
Hai Shalom899fcc72020-10-19 14:38:18 -07001272 pos = os_strstr(cmd, " csrattrs=");
1273 if (pos) {
1274 pos += 10;
1275 end = os_strchr(pos, ' ');
1276 len = end ? (size_t) (end - pos) : os_strlen(pos);
1277 conf->csrattrs = os_zalloc(len + 1);
1278 if (!conf->csrattrs)
1279 goto fail;
1280 os_memcpy(conf->csrattrs, pos, len);
1281 }
1282
Sunil Ravi89eba102022-09-13 21:04:37 -07001283 pos = os_strstr(cmd, " conf_extra_name=");
1284 if (pos) {
1285 pos += 17;
1286 end = os_strchr(pos, ' ');
1287 len = end ? (size_t) (end - pos) : os_strlen(pos);
1288 conf->extra_name = os_zalloc(len + 1);
1289 if (!conf->extra_name)
1290 goto fail;
1291 os_memcpy(conf->extra_name, pos, len);
1292 }
1293
1294 pos = os_strstr(cmd, " conf_extra_value=");
1295 if (pos) {
1296 pos += 18;
1297 end = os_strchr(pos, ' ');
1298 len = end ? (size_t) (end - pos) : os_strlen(pos);
1299 len /= 2;
1300 conf->extra_value = os_zalloc(len + 1);
1301 if (!conf->extra_value ||
1302 hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1303 goto fail;
1304 }
1305
Hai Shalom021b0b52019-04-10 11:17:58 -07001306 if (!dpp_configuration_valid(conf))
1307 goto fail;
1308
Hai Shalomc3565922019-10-28 11:58:20 -07001309 if (idx == 0) {
1310 auth->conf_sta = conf_sta;
1311 auth->conf_ap = conf_ap;
1312 } else if (idx == 1) {
1313 auth->conf2_sta = conf_sta;
1314 auth->conf2_ap = conf_ap;
1315 } else {
1316 goto fail;
1317 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001318 return 0;
1319
1320fail:
1321 dpp_configuration_free(conf_sta);
1322 dpp_configuration_free(conf_ap);
1323 return -1;
1324}
1325
1326
Hai Shalomc3565922019-10-28 11:58:20 -07001327static int dpp_configuration_parse(struct dpp_authentication *auth,
1328 const char *cmd)
1329{
1330 const char *pos;
1331 char *tmp;
1332 size_t len;
1333 int res;
1334
1335 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1336 if (!pos)
1337 return dpp_configuration_parse_helper(auth, cmd, 0);
1338
1339 len = pos - cmd;
1340 tmp = os_malloc(len + 1);
1341 if (!tmp)
1342 goto fail;
1343 os_memcpy(tmp, cmd, len);
1344 tmp[len] = '\0';
1345 res = dpp_configuration_parse_helper(auth, cmd, 0);
1346 str_clear_free(tmp);
1347 if (res)
1348 goto fail;
1349 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1350 if (res)
1351 goto fail;
1352 return 0;
1353fail:
1354 dpp_configuration_free(auth->conf_sta);
1355 dpp_configuration_free(auth->conf2_sta);
1356 dpp_configuration_free(auth->conf_ap);
1357 dpp_configuration_free(auth->conf2_ap);
1358 return -1;
1359}
1360
1361
Hai Shalom021b0b52019-04-10 11:17:58 -07001362static struct dpp_configurator *
1363dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1364{
1365 struct dpp_configurator *conf;
1366
1367 if (!dpp)
1368 return NULL;
1369
1370 dl_list_for_each(conf, &dpp->configurator,
1371 struct dpp_configurator, list) {
1372 if (conf->id == id)
1373 return conf;
1374 }
1375 return NULL;
1376}
1377
1378
Hai Shalomfdcde762020-04-02 11:19:20 -07001379int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07001380{
1381 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07001382 char *tmp = NULL;
1383 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07001384
Hai Shalomfdcde762020-04-02 11:19:20 -07001385 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07001386 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07001387 auth->configurator_set = 1;
1388
1389 if (cmd[0] != ' ') {
1390 size_t len;
1391
1392 len = os_strlen(cmd);
1393 tmp = os_malloc(len + 2);
1394 if (!tmp)
1395 goto fail;
1396 tmp[0] = ' ';
1397 os_memcpy(tmp + 1, cmd, len + 1);
1398 cmd = tmp;
1399 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001400
1401 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1402
Hai Shaloma20dcd72022-02-04 13:43:00 -08001403 if (os_strstr(cmd, " conf=query")) {
1404 auth->configurator_set = 0;
1405 auth->use_config_query = true;
1406 ret = 0;
1407 goto fail;
1408 }
1409
Hai Shalom021b0b52019-04-10 11:17:58 -07001410 pos = os_strstr(cmd, " configurator=");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001411 if (!auth->conf && pos) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001412 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07001413 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07001414 if (!auth->conf) {
1415 wpa_printf(MSG_INFO,
1416 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07001417 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001418 }
1419 }
1420
Hai Shalomc3565922019-10-28 11:58:20 -07001421 pos = os_strstr(cmd, " conn_status=");
1422 if (pos) {
1423 pos += 13;
1424 auth->send_conn_status = atoi(pos);
1425 }
1426
1427 pos = os_strstr(cmd, " akm_use_selector=");
1428 if (pos) {
1429 pos += 18;
1430 auth->akm_use_selector = atoi(pos);
1431 }
1432
Hai Shalom021b0b52019-04-10 11:17:58 -07001433 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001434 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07001435 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07001436 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001437 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001438 ret = 0;
1439fail:
1440 os_free(tmp);
1441 return ret;
1442}
1443
1444
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001445void dpp_auth_deinit(struct dpp_authentication *auth)
1446{
Hai Shalomc3565922019-10-28 11:58:20 -07001447 unsigned int i;
1448
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001449 if (!auth)
1450 return;
1451 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07001452 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001453 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001454 dpp_configuration_free(auth->conf2_sta);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001455 crypto_ec_key_deinit(auth->own_protocol_key);
1456 crypto_ec_key_deinit(auth->peer_protocol_key);
1457 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001458 wpabuf_free(auth->req_msg);
1459 wpabuf_free(auth->resp_msg);
1460 wpabuf_free(auth->conf_req);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001461 wpabuf_free(auth->reconfig_req_msg);
1462 wpabuf_free(auth->reconfig_resp_msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001463 for (i = 0; i < auth->num_conf_obj; i++) {
1464 struct dpp_config_obj *conf = &auth->conf_obj[i];
1465
1466 os_free(conf->connector);
1467 wpabuf_free(conf->c_sign_key);
Hai Shalom899fcc72020-10-19 14:38:18 -07001468 wpabuf_free(conf->certbag);
1469 wpabuf_free(conf->certs);
1470 wpabuf_free(conf->cacert);
1471 os_free(conf->server_name);
1472 wpabuf_free(conf->pp_key);
Hai Shalomc3565922019-10-28 11:58:20 -07001473 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001474#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -07001475 dpp_free_asymmetric_key(auth->conf_key_pkg);
Hai Shalom899fcc72020-10-19 14:38:18 -07001476 os_free(auth->csrattrs);
1477 wpabuf_free(auth->csr);
1478 wpabuf_free(auth->priv_key);
1479 wpabuf_free(auth->cacert);
1480 wpabuf_free(auth->certbag);
1481 os_free(auth->trusted_eap_server_name);
1482 wpabuf_free(auth->conf_resp_tcp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001483#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001484 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001485 dpp_bootstrap_info_free(auth->tmp_own_bi);
Hai Shalom899fcc72020-10-19 14:38:18 -07001486 if (auth->tmp_peer_bi) {
1487 dl_list_del(&auth->tmp_peer_bi->list);
1488 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1489 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001490 os_free(auth->e_name);
1491 os_free(auth->e_mud_url);
1492 os_free(auth->e_band_support);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001493#ifdef CONFIG_TESTING_OPTIONS
1494 os_free(auth->config_obj_override);
1495 os_free(auth->discovery_override);
1496 os_free(auth->groups_override);
1497#endif /* CONFIG_TESTING_OPTIONS */
1498 bin_clear_free(auth, sizeof(*auth));
1499}
1500
1501
1502static struct wpabuf *
1503dpp_build_conf_start(struct dpp_authentication *auth,
1504 struct dpp_configuration *conf, size_t tailroom)
1505{
1506 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001507
1508#ifdef CONFIG_TESTING_OPTIONS
1509 if (auth->discovery_override)
1510 tailroom += os_strlen(auth->discovery_override);
1511#endif /* CONFIG_TESTING_OPTIONS */
1512
1513 buf = wpabuf_alloc(200 + tailroom);
1514 if (!buf)
1515 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001516 json_start_object(buf, NULL);
1517 json_add_string(buf, "wi-fi_tech", "infra");
1518 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001519#ifdef CONFIG_TESTING_OPTIONS
1520 if (auth->discovery_override) {
1521 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1522 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001523 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001524 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001525 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001526 return buf;
1527 }
1528#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001529 json_start_object(buf, "discovery");
1530 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1531 json_add_string_escape(buf, "ssid", conf->ssid,
1532 conf->ssid_len) < 0) ||
1533 ((conf->ssid_charset && auth->peer_version >= 2) &&
1534 json_add_base64url(buf, "ssid64", conf->ssid,
1535 conf->ssid_len) < 0)) {
1536 wpabuf_free(buf);
1537 return NULL;
1538 }
1539 if (conf->ssid_charset > 0) {
1540 json_value_sep(buf);
1541 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1542 }
1543 json_end_object(buf);
1544 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001545
1546 return buf;
1547}
1548
1549
Hai Shaloma20dcd72022-02-04 13:43:00 -08001550int dpp_build_jwk(struct wpabuf *buf, const char *name,
1551 struct crypto_ec_key *key, const char *kid,
1552 const struct dpp_curve_params *curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001553{
1554 struct wpabuf *pub;
1555 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001556 int ret = -1;
1557
Hai Shaloma20dcd72022-02-04 13:43:00 -08001558 pub = crypto_ec_key_get_pubkey_point(key, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001559 if (!pub)
1560 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001561
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001562 json_start_object(buf, name);
1563 json_add_string(buf, "kty", "EC");
1564 json_value_sep(buf);
1565 json_add_string(buf, "crv", curve->jwk_crv);
1566 json_value_sep(buf);
1567 pos = wpabuf_head(pub);
1568 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1569 goto fail;
1570 json_value_sep(buf);
1571 pos += curve->prime_len;
1572 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1573 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001574 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001575 json_value_sep(buf);
1576 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001577 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001578 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001579 ret = 0;
1580fail:
1581 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001582 return ret;
1583}
1584
1585
Hai Shalom021b0b52019-04-10 11:17:58 -07001586static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1587 struct dpp_configuration *conf)
1588{
1589 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001590 json_add_string_escape(buf, "pass", conf->passphrase,
1591 os_strlen(conf->passphrase));
Hai Shalom021b0b52019-04-10 11:17:58 -07001592 } else if (conf->psk_set) {
1593 char psk[2 * sizeof(conf->psk) + 1];
1594
1595 wpa_snprintf_hex(psk, sizeof(psk),
1596 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001597 json_add_string(buf, "psk_hex", psk);
1598 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07001599 }
1600}
1601
1602
Hai Shaloma20dcd72022-02-04 13:43:00 -08001603const char * dpp_netrole_str(enum dpp_netrole netrole)
Hai Shalomc3565922019-10-28 11:58:20 -07001604{
1605 switch (netrole) {
1606 case DPP_NETROLE_STA:
1607 return "sta";
1608 case DPP_NETROLE_AP:
1609 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001610 case DPP_NETROLE_CONFIGURATOR:
1611 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07001612 default:
1613 return "??";
1614 }
1615}
1616
1617
Sunil Ravi89eba102022-09-13 21:04:37 -07001618static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1619{
1620 enum dpp_bootstrap_supported_curves idx;
1621
1622 if (!bi || !bi->supported_curves)
1623 return true; /* no support indication available */
1624
1625 if (os_strcmp(curve, "prime256v1") == 0)
1626 idx = DPP_BOOTSTRAP_CURVE_P_256;
1627 else if (os_strcmp(curve, "secp384r1") == 0)
1628 idx = DPP_BOOTSTRAP_CURVE_P_384;
1629 else if (os_strcmp(curve, "secp521r1") == 0)
1630 idx = DPP_BOOTSTRAP_CURVE_P_521;
1631 else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1632 idx = DPP_BOOTSTRAP_CURVE_BP_256;
1633 else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1634 idx = DPP_BOOTSTRAP_CURVE_BP_384;
1635 else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1636 idx = DPP_BOOTSTRAP_CURVE_BP_512;
1637 else
1638 return true;
1639
1640 return bi->supported_curves & BIT(idx);
1641}
1642
1643
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001644static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001645dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001646 struct dpp_configuration *conf)
1647{
1648 struct wpabuf *buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001649 char *signed_conn = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001650 size_t tailroom;
Sunil Ravia04bd252022-05-02 22:54:18 -07001651 const struct dpp_curve_params *curve; /* C-sign-key curve */
1652 const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001653 struct wpabuf *dppcon = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001654 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07001655 int incl_legacy;
1656 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07001657 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001658
1659 if (!auth->conf) {
1660 wpa_printf(MSG_INFO,
1661 "DPP: No configurator specified - cannot generate DPP config object");
1662 goto fail;
1663 }
1664 curve = auth->conf->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001665 if (dpp_akm_dpp(conf->akm) &&
1666 !dpp_supports_curve(curve->name, auth->peer_bi)) {
1667 wpa_printf(MSG_DEBUG,
1668 "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1669 curve->name);
1670 goto fail;
1671 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001672 if (auth->new_curve && auth->new_key_received)
1673 nak_curve = auth->new_curve;
1674 else
1675 nak_curve = auth->curve;
Sunil Ravi89eba102022-09-13 21:04:37 -07001676 if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1677 wpa_printf(MSG_DEBUG,
1678 "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1679 nak_curve->name);
1680 goto fail;
1681 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001682
Hai Shalom021b0b52019-04-10 11:17:58 -07001683 akm = conf->akm;
1684 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1685 wpa_printf(MSG_DEBUG,
1686 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1687 akm = DPP_AKM_DPP;
1688 }
1689
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001690#ifdef CONFIG_TESTING_OPTIONS
1691 if (auth->groups_override)
1692 extra_len += os_strlen(auth->groups_override);
1693#endif /* CONFIG_TESTING_OPTIONS */
1694
Hai Shalomce48b4a2018-09-05 11:41:35 -07001695 if (conf->group_id)
1696 extra_len += os_strlen(conf->group_id);
1697
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001698 /* Connector (JSON dppCon object) */
Sunil Ravia04bd252022-05-02 22:54:18 -07001699 dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001700 if (!dppcon)
1701 goto fail;
1702#ifdef CONFIG_TESTING_OPTIONS
1703 if (auth->groups_override) {
1704 wpabuf_put_u8(dppcon, '{');
1705 if (auth->groups_override) {
1706 wpa_printf(MSG_DEBUG,
1707 "DPP: TESTING - groups override: '%s'",
1708 auth->groups_override);
1709 wpabuf_put_str(dppcon, "\"groups\":");
1710 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001711 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001712 }
1713 goto skip_groups;
1714 }
1715#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001716 json_start_object(dppcon, NULL);
1717 json_start_array(dppcon, "groups");
1718 json_start_object(dppcon, NULL);
1719 json_add_string(dppcon, "groupId",
1720 conf->group_id ? conf->group_id : "*");
1721 json_value_sep(dppcon);
1722 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1723 json_end_object(dppcon);
1724 json_end_array(dppcon);
1725 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001726#ifdef CONFIG_TESTING_OPTIONS
1727skip_groups:
1728#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravia04bd252022-05-02 22:54:18 -07001729 if (!auth->peer_protocol_key) {
1730 wpa_printf(MSG_DEBUG,
1731 "DPP: No peer protocol key available to build netAccessKey JWK");
1732 goto fail;
1733 }
1734#ifdef CONFIG_DPP3
1735 if (auth->conf->net_access_key_curve &&
1736 auth->curve != auth->conf->net_access_key_curve &&
1737 !auth->new_key_received) {
Sunil Ravi89eba102022-09-13 21:04:37 -07001738 if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1739 auth->peer_bi)) {
1740 wpa_printf(MSG_DEBUG,
1741 "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1742 auth->conf->net_access_key_curve->name);
1743 goto fail;
1744 }
Sunil Ravia04bd252022-05-02 22:54:18 -07001745 wpa_printf(MSG_DEBUG,
1746 "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1747 auth->curve->name,
1748 auth->conf->net_access_key_curve->name,
1749 auth->waiting_new_key ?
1750 "the required key not received" :
1751 "request a new key");
1752 if (auth->waiting_new_key)
1753 auth->waiting_new_key = false; /* failed */
1754 else
1755 auth->waiting_new_key = true;
1756 goto fail;
1757 }
1758#endif /* CONFIG_DPP3 */
1759 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1760 nak_curve) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001761 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1762 goto fail;
1763 }
1764 if (conf->netaccesskey_expiry) {
1765 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001766 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001767
1768 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1769 wpa_printf(MSG_DEBUG,
1770 "DPP: Failed to generate expiry string");
1771 goto fail;
1772 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001773 os_snprintf(expiry, sizeof(expiry),
1774 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1775 tm.year, tm.month, tm.day,
1776 tm.hour, tm.min, tm.sec);
1777 json_value_sep(dppcon);
1778 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001779 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001780#ifdef CONFIG_DPP3
1781 json_value_sep(dppcon);
1782 json_add_int(dppcon, "version", auth->peer_version);
1783#endif /* CONFIG_DPP3 */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001784 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001785 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1786 (const char *) wpabuf_head(dppcon));
1787
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001788 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1789 if (!signed_conn)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001790 goto fail;
1791
Hai Shalom021b0b52019-04-10 11:17:58 -07001792 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001793 tailroom = 1000;
1794 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001795 tailroom += os_strlen(signed_conn);
Hai Shalom021b0b52019-04-10 11:17:58 -07001796 if (incl_legacy)
1797 tailroom += 1000;
Hai Shalom899fcc72020-10-19 14:38:18 -07001798 if (akm == DPP_AKM_DOT1X) {
1799 if (auth->certbag)
1800 tailroom += 2 * wpabuf_len(auth->certbag);
1801 if (auth->cacert)
1802 tailroom += 2 * wpabuf_len(auth->cacert);
1803 if (auth->trusted_eap_server_name)
1804 tailroom += os_strlen(auth->trusted_eap_server_name);
1805 tailroom += 1000;
1806 }
Sunil Ravi89eba102022-09-13 21:04:37 -07001807 if (conf->extra_name && conf->extra_value)
1808 tailroom += 10 + os_strlen(conf->extra_name) +
1809 os_strlen(conf->extra_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001810 buf = dpp_build_conf_start(auth, conf, tailroom);
1811 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001812 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001813
Hai Shalomc3565922019-10-28 11:58:20 -07001814 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1815 akm_str = dpp_akm_selector_str(akm);
1816 else
1817 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001818 json_start_object(buf, "cred");
1819 json_add_string(buf, "akm", akm_str);
1820 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001821 if (incl_legacy) {
1822 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001823 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001824 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001825 if (akm == DPP_AKM_DOT1X) {
1826 json_start_object(buf, "entCreds");
1827 if (!auth->certbag)
1828 goto fail;
1829 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1830 wpabuf_len(auth->certbag));
1831 if (auth->cacert) {
1832 json_value_sep(buf);
1833 json_add_base64(buf, "caCert",
1834 wpabuf_head(auth->cacert),
1835 wpabuf_len(auth->cacert));
1836 }
1837 if (auth->trusted_eap_server_name) {
1838 json_value_sep(buf);
1839 json_add_string(buf, "trustedEapServerName",
1840 auth->trusted_eap_server_name);
1841 }
1842 json_value_sep(buf);
1843 json_start_array(buf, "eapMethods");
1844 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1845 json_end_array(buf);
1846 json_end_object(buf);
1847 json_value_sep(buf);
1848 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001849 wpabuf_put_str(buf, "\"signedConnector\":\"");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001850 wpabuf_put_str(buf, signed_conn);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001851 wpabuf_put_str(buf, "\"");
1852 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001853 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1854 curve) < 0) {
1855 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1856 goto fail;
1857 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001858#ifdef CONFIG_DPP2
1859 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1860 json_value_sep(buf);
1861 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1862 curve) < 0) {
1863 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1864 goto fail;
1865 }
1866 }
1867#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001868
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001869 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001870 if (conf->extra_name && conf->extra_value) {
1871 json_value_sep(buf);
1872 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1873 conf->extra_value);
1874 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001875 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001876
1877 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1878 wpabuf_head(buf), wpabuf_len(buf));
1879
Sunil Ravia04bd252022-05-02 22:54:18 -07001880#ifdef CONFIG_DPP3
1881 if (!auth->conf->net_access_key_curve) {
1882 /* All netAccessKey values used in the network will have to be
1883 * from the same curve for network introduction to work, so
1884 * hardcode the first used netAccessKey curve for consecutive
1885 * operations if there was no explicit configuration of which
1886 * curve to use. */
1887 wpa_printf(MSG_DEBUG,
1888 "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1889 nak_curve->name);
1890 auth->conf->net_access_key_curve = nak_curve;
1891 }
1892#endif /* CONFIG_DPP3 */
1893
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001894out:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001895 os_free(signed_conn);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001896 wpabuf_free(dppcon);
1897 return buf;
1898fail:
1899 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1900 wpabuf_free(buf);
1901 buf = NULL;
1902 goto out;
1903}
1904
1905
1906static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001907dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001908 struct dpp_configuration *conf)
1909{
1910 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001911 const char *akm_str;
Sunil Ravi89eba102022-09-13 21:04:37 -07001912 size_t len = 1000;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001913
Sunil Ravi89eba102022-09-13 21:04:37 -07001914 if (conf->extra_name && conf->extra_value)
1915 len += 10 + os_strlen(conf->extra_name) +
1916 os_strlen(conf->extra_value);
1917 buf = dpp_build_conf_start(auth, conf, len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001918 if (!buf)
1919 return NULL;
1920
Hai Shalomc3565922019-10-28 11:58:20 -07001921 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1922 akm_str = dpp_akm_selector_str(conf->akm);
1923 else
1924 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001925 json_start_object(buf, "cred");
1926 json_add_string(buf, "akm", akm_str);
1927 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001928 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001929 json_end_object(buf);
Sunil Ravi89eba102022-09-13 21:04:37 -07001930 if (conf->extra_name && conf->extra_value) {
1931 json_value_sep(buf);
1932 wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1933 conf->extra_value);
1934 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001935 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001936
1937 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1938 wpabuf_head(buf), wpabuf_len(buf));
1939
1940 return buf;
1941}
1942
1943
Hai Shaloma20dcd72022-02-04 13:43:00 -08001944static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1945{
1946 struct dpp_bootstrap_info *bi;
1947
1948 if (auth->peer_bi)
1949 return auth->peer_bi->id;
1950 if (auth->tmp_peer_bi)
1951 return auth->tmp_peer_bi->id;
1952
1953 bi = os_zalloc(sizeof(*bi));
1954 if (!bi)
1955 return -1;
1956 bi->id = dpp_next_id(auth->global);
1957 dl_list_add(&auth->global->bootstrap, &bi->list);
1958 auth->tmp_peer_bi = bi;
1959 return bi->id;
1960}
1961
1962
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001963static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001964dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
Hai Shalom899fcc72020-10-19 14:38:18 -07001965 int idx, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001966{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001967 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001968
1969#ifdef CONFIG_TESTING_OPTIONS
1970 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07001971 if (idx != 0)
1972 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001973 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
1974 return wpabuf_alloc_copy(auth->config_obj_override,
1975 os_strlen(auth->config_obj_override));
1976 }
1977#endif /* CONFIG_TESTING_OPTIONS */
1978
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001979 if (idx == 0) {
1980 if (netrole == DPP_NETROLE_STA)
1981 conf = auth->conf_sta;
1982 else if (netrole == DPP_NETROLE_AP)
1983 conf = auth->conf_ap;
1984 } else if (idx == 1) {
1985 if (netrole == DPP_NETROLE_STA)
1986 conf = auth->conf2_sta;
1987 else if (netrole == DPP_NETROLE_AP)
1988 conf = auth->conf2_ap;
1989 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001990 if (!conf) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001991 if (idx == 0) {
1992 if (auth->use_config_query) {
1993 wpa_printf(MSG_DEBUG,
1994 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
1995 dpp_netrole_str(netrole));
1996 auth->waiting_config = true;
1997 dpp_get_peer_bi_id(auth);
1998 return NULL;
1999 }
Hai Shalomc3565922019-10-28 11:58:20 -07002000 wpa_printf(MSG_DEBUG,
2001 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002002 dpp_netrole_str(netrole));
Hai Shaloma20dcd72022-02-04 13:43:00 -08002003 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002004 return NULL;
2005 }
2006
Hai Shalom899fcc72020-10-19 14:38:18 -07002007 if (conf->akm == DPP_AKM_DOT1X) {
2008 if (!auth->conf) {
2009 wpa_printf(MSG_DEBUG,
2010 "DPP: No Configurator data available");
2011 return NULL;
2012 }
2013 if (!cert_req && !auth->certbag) {
2014 wpa_printf(MSG_DEBUG,
2015 "DPP: No certificate data available for dot1x configuration");
2016 return NULL;
2017 }
2018 return dpp_build_conf_obj_dpp(auth, conf);
2019 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002020 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07002021 return dpp_build_conf_obj_dpp(auth, conf);
2022 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002023}
2024
2025
Hai Shalom899fcc72020-10-19 14:38:18 -07002026struct wpabuf *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002027dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Hai Shalom899fcc72020-10-19 14:38:18 -07002028 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002029{
Sunil Ravia04bd252022-05-02 22:54:18 -07002030 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07002031 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002032 struct wpabuf *clear = NULL, *msg = NULL;
2033 u8 *wrapped;
2034 const u8 *addr[1];
2035 size_t len[1];
2036 enum dpp_status_error status;
2037
Hai Shalom899fcc72020-10-19 14:38:18 -07002038 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2039 status = auth->force_conf_resp_status;
2040 goto forced_status;
2041 }
2042
Hai Shalomfdcde762020-04-02 11:19:20 -07002043 if (netrole == DPP_NETROLE_CONFIGURATOR) {
2044#ifdef CONFIG_DPP2
2045 env_data = dpp_build_enveloped_data(auth);
2046#endif /* CONFIG_DPP2 */
2047 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07002048 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002049 if (conf) {
2050 wpa_hexdump_ascii(MSG_DEBUG,
2051 "DPP: configurationObject JSON",
2052 wpabuf_head(conf), wpabuf_len(conf));
Hai Shalom899fcc72020-10-19 14:38:18 -07002053 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07002054 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002055 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002056
Hai Shaloma20dcd72022-02-04 13:43:00 -08002057 if (!conf && auth->waiting_config)
2058 return NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002059 if (conf || env_data)
2060 status = DPP_STATUS_OK;
2061 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2062 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2063 status = DPP_STATUS_CSR_NEEDED;
Sunil Ravia04bd252022-05-02 22:54:18 -07002064#ifdef CONFIG_DPP3
2065 else if (auth->waiting_new_key)
2066 status = DPP_STATUS_NEW_KEY_NEEDED;
2067#endif /* CONFIG_DPP3 */
Hai Shalom899fcc72020-10-19 14:38:18 -07002068 else
2069 status = DPP_STATUS_CONFIGURE_FAILURE;
2070forced_status:
Hai Shalom021b0b52019-04-10 11:17:58 -07002071 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002072
Hai Shalomc3565922019-10-28 11:58:20 -07002073 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002074 clear_len = 4 + e_nonce_len;
2075 if (conf)
2076 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07002077 if (conf2)
2078 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07002079 if (env_data)
2080 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002081 if (auth->peer_version >= 2 && auth->send_conn_status &&
2082 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07002083 clear_len += 4;
Hai Shalom899fcc72020-10-19 14:38:18 -07002084 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2085 auth->conf_sta->csrattrs)
2086 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
Sunil Ravia04bd252022-05-02 22:54:18 -07002087#ifdef CONFIG_DPP3
2088 if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2089 struct crypto_ec_key *new_pc;
2090
2091 clear_len += 6; /* Finite Cyclic Group attribute */
2092
2093 wpa_printf(MSG_DEBUG,
2094 "DPP: Generate a new own protocol key for the curve %s",
2095 auth->conf->net_access_key_curve->name);
2096 new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2097 if (!new_pc) {
2098 wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2099 return NULL;
2100 }
2101 pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2102 if (!pc) {
2103 crypto_ec_key_deinit(new_pc);
2104 return NULL;
2105 }
2106 crypto_ec_key_deinit(auth->own_protocol_key);
2107 auth->own_protocol_key = new_pc;
2108 auth->new_curve = auth->conf->net_access_key_curve;
2109 clear_len += 4 + wpabuf_len(pc);
2110 }
2111#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002112 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002113 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2114#ifdef CONFIG_TESTING_OPTIONS
2115 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2116 attr_len += 5;
2117#endif /* CONFIG_TESTING_OPTIONS */
2118 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002119 if (!clear || !msg)
2120 goto fail;
2121
Roshan Pius3a1667e2018-07-03 15:17:14 -07002122#ifdef CONFIG_TESTING_OPTIONS
2123 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2124 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2125 goto skip_e_nonce;
2126 }
2127 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2128 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2129 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2130 wpabuf_put_le16(clear, e_nonce_len);
2131 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2132 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2133 goto skip_e_nonce;
2134 }
2135 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2136 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2137 goto skip_wrapped_data;
2138 }
2139#endif /* CONFIG_TESTING_OPTIONS */
2140
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002141 /* E-nonce */
2142 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2143 wpabuf_put_le16(clear, e_nonce_len);
2144 wpabuf_put_data(clear, e_nonce, e_nonce_len);
2145
Roshan Pius3a1667e2018-07-03 15:17:14 -07002146#ifdef CONFIG_TESTING_OPTIONS
2147skip_e_nonce:
2148 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2149 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2150 goto skip_config_obj;
2151 }
2152#endif /* CONFIG_TESTING_OPTIONS */
2153
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002154 if (conf) {
2155 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2156 wpabuf_put_le16(clear, wpabuf_len(conf));
2157 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002158 }
Hai Shalomc3565922019-10-28 11:58:20 -07002159 if (auth->peer_version >= 2 && conf2) {
2160 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2161 wpabuf_put_le16(clear, wpabuf_len(conf2));
2162 wpabuf_put_buf(clear, conf2);
2163 } else if (conf2) {
2164 wpa_printf(MSG_DEBUG,
2165 "DPP: Second Config Object available, but peer does not support more than one");
2166 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002167 if (env_data) {
2168 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2169 wpabuf_put_le16(clear, wpabuf_len(env_data));
2170 wpabuf_put_buf(clear, env_data);
2171 }
Hai Shalomc3565922019-10-28 11:58:20 -07002172
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002173 if (auth->peer_version >= 2 && auth->send_conn_status &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002174 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002175 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2176 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2177 wpabuf_put_le16(clear, 0);
2178 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002179
Hai Shalom899fcc72020-10-19 14:38:18 -07002180 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2181 auth->conf_sta->csrattrs) {
2182 auth->waiting_csr = true;
2183 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2184 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2185 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2186 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2187 }
2188
Sunil Ravia04bd252022-05-02 22:54:18 -07002189#ifdef CONFIG_DPP3
2190 if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2191 auth->conf->net_access_key_curve) {
2192 u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2193
2194 /* Finite Cyclic Group attribute */
2195 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2196 ike_group);
2197 wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2198 wpabuf_put_le16(clear, 2);
2199 wpabuf_put_le16(clear, ike_group);
2200
2201 if (pc) {
2202 wpa_printf(MSG_DEBUG, "DPP: Pc");
2203 wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2204 wpabuf_put_le16(clear, wpabuf_len(pc));
2205 wpabuf_put_buf(clear, pc);
2206 }
2207 }
2208#endif /* CONFIG_DPP3 */
2209
Roshan Pius3a1667e2018-07-03 15:17:14 -07002210#ifdef CONFIG_TESTING_OPTIONS
2211skip_config_obj:
2212 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2213 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2214 goto skip_status;
2215 }
2216 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2217 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2218 status = 255;
2219 }
2220#endif /* CONFIG_TESTING_OPTIONS */
2221
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002222 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002223 dpp_build_attr_status(msg, status);
2224
2225#ifdef CONFIG_TESTING_OPTIONS
2226skip_status:
2227#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002228
2229 addr[0] = wpabuf_head(msg);
2230 len[0] = wpabuf_len(msg);
2231 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2232
2233 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2234 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2235 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2236
2237 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2238 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2239 wpabuf_head(clear), wpabuf_len(clear),
2240 1, addr, len, wrapped) < 0)
2241 goto fail;
2242 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2243 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002244
2245#ifdef CONFIG_TESTING_OPTIONS
2246 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2247 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2248 dpp_build_attr_status(msg, DPP_STATUS_OK);
2249 }
2250skip_wrapped_data:
2251#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002252
2253 wpa_hexdump_buf(MSG_DEBUG,
2254 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002255out:
Hai Shalomfdcde762020-04-02 11:19:20 -07002256 wpabuf_clear_free(conf);
2257 wpabuf_clear_free(conf2);
2258 wpabuf_clear_free(env_data);
2259 wpabuf_clear_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -07002260 wpabuf_free(pc);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002261
2262 return msg;
2263fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002264 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002265 msg = NULL;
2266 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002267}
2268
2269
2270struct wpabuf *
2271dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2272 size_t attr_len)
2273{
2274 const u8 *wrapped_data, *e_nonce, *config_attr;
2275 u16 wrapped_data_len, e_nonce_len, config_attr_len;
2276 u8 *unwrapped = NULL;
2277 size_t unwrapped_len = 0;
2278 struct wpabuf *resp = NULL;
2279 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002280 enum dpp_netrole netrole;
Hai Shalom899fcc72020-10-19 14:38:18 -07002281 struct wpabuf *cert_req = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07002282#ifdef CONFIG_DPP3
2283 const u8 *i_proto;
2284 u16 i_proto_len;
2285#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002286
Roshan Pius3a1667e2018-07-03 15:17:14 -07002287#ifdef CONFIG_TESTING_OPTIONS
2288 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2289 wpa_printf(MSG_INFO,
2290 "DPP: TESTING - stop at Config Request");
2291 return NULL;
2292 }
2293#endif /* CONFIG_TESTING_OPTIONS */
2294
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002295 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002296 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002297 return NULL;
2298 }
2299
2300 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2301 &wrapped_data_len);
2302 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002303 dpp_auth_fail(auth,
2304 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002305 return NULL;
2306 }
2307
2308 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2309 wrapped_data, wrapped_data_len);
2310 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2311 unwrapped = os_malloc(unwrapped_len);
2312 if (!unwrapped)
2313 return NULL;
2314 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2315 wrapped_data, wrapped_data_len,
2316 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002317 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002318 goto fail;
2319 }
2320 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2321 unwrapped, unwrapped_len);
2322
2323 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002324 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002325 goto fail;
2326 }
2327
2328 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2329 DPP_ATTR_ENROLLEE_NONCE,
2330 &e_nonce_len);
2331 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002332 dpp_auth_fail(auth,
2333 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002334 goto fail;
2335 }
2336 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07002337 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002338
Sunil Ravia04bd252022-05-02 22:54:18 -07002339#ifdef CONFIG_DPP3
2340 i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2341 DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2342 if (i_proto && !auth->waiting_new_key) {
2343 dpp_auth_fail(auth,
2344 "Enrollee included a new protocol key even though one was not expected");
2345 goto fail;
2346 }
2347 if (i_proto) {
2348 struct crypto_ec_key *pe;
2349 u8 auth_i[DPP_MAX_HASH_LEN];
2350 const u8 *rx_auth_i;
2351 u16 rx_auth_i_len;
2352
2353 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2354 i_proto, i_proto_len);
2355
2356 pe = dpp_set_pubkey_point(auth->own_protocol_key,
2357 i_proto, i_proto_len);
2358 if (!pe) {
2359 dpp_auth_fail(auth,
2360 "Invalid Initiator Protocol Key (Pe)");
2361 goto fail;
2362 }
2363 dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2364 crypto_ec_key_deinit(auth->peer_protocol_key);
2365 auth->peer_protocol_key = pe;
2366 auth->new_key_received = true;
2367 auth->waiting_new_key = false;
2368
2369 if (dpp_derive_auth_i(auth, auth_i) < 0)
2370 goto fail;
2371
2372 rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2373 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2374 if (!rx_auth_i) {
2375 dpp_auth_fail(auth,
2376 "Missing Initiator Authentication Tag");
2377 goto fail;
2378 }
2379 if (rx_auth_i_len != auth->curve->hash_len ||
2380 os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2381 dpp_auth_fail(auth,
2382 "Mismatch in Initiator Authenticating Tag");
2383 wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2384 rx_auth_i, rx_auth_i_len);
2385 wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2386 auth_i, auth->curve->hash_len);
2387 goto fail;
2388 }
2389 }
2390#endif /* CONFIG_DPP3 */
2391
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002392 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2393 DPP_ATTR_CONFIG_ATTR_OBJ,
2394 &config_attr_len);
2395 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002396 dpp_auth_fail(auth,
2397 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002398 goto fail;
2399 }
2400 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2401 config_attr, config_attr_len);
2402
2403 root = json_parse((const char *) config_attr, config_attr_len);
2404 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002405 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002406 goto fail;
2407 }
2408
2409 token = json_get_member(root, "name");
2410 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002411 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002412 goto fail;
2413 }
2414 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002415 os_free(auth->e_name);
2416 auth->e_name = os_strdup(token->string);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002417
2418 token = json_get_member(root, "wi-fi_tech");
2419 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002420 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002421 goto fail;
2422 }
2423 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2424 if (os_strcmp(token->string, "infra") != 0) {
2425 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2426 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002427 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002428 goto fail;
2429 }
2430
2431 token = json_get_member(root, "netRole");
2432 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002433 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002434 goto fail;
2435 }
2436 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2437 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002438 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002439 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002440 netrole = DPP_NETROLE_AP;
2441 } else if (os_strcmp(token->string, "configurator") == 0) {
2442 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002443 } else {
2444 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2445 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002446 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002447 goto fail;
2448 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002449 auth->e_netrole = netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002450
Hai Shalomc3565922019-10-28 11:58:20 -07002451 token = json_get_member(root, "mudurl");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002452 if (token && token->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002453 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002454 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2455 token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002456 os_free(auth->e_mud_url);
2457 auth->e_mud_url = os_strdup(token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002458 }
Hai Shalomc3565922019-10-28 11:58:20 -07002459
2460 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08002461 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002462 if (token && token->type == JSON_ARRAY) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002463 int *opclass = NULL;
2464 char txt[200], *pos, *end;
2465 int i, res;
2466
Hai Shalom06768112019-12-04 15:49:43 -08002467 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07002468 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2469 token = token->child;
2470 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08002471 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07002472 wpa_printf(MSG_DEBUG,
2473 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08002474 } else {
2475 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2476 auth->band_list[auth->band_list_size++] = token->number;
2477 }
Hai Shalomc3565922019-10-28 11:58:20 -07002478 wpa_printf(MSG_DEBUG,
2479 "DPP: Supported global operating class: %d",
2480 token->number);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002481 int_array_add_unique(&opclass, token->number);
Hai Shalom06768112019-12-04 15:49:43 -08002482 }
Hai Shalomc3565922019-10-28 11:58:20 -07002483 token = token->sibling;
2484 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002485
2486 txt[0] = '\0';
2487 pos = txt;
2488 end = txt + sizeof(txt);
2489 for (i = 0; opclass && opclass[i]; i++) {
2490 res = os_snprintf(pos, end - pos, "%s%d",
2491 pos == txt ? "" : ",", opclass[i]);
2492 if (os_snprintf_error(end - pos, res)) {
2493 *pos = '\0';
2494 break;
2495 }
2496 pos += res;
2497 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002498 os_free(auth->e_band_support);
2499 auth->e_band_support = opclass;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002500 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2501 txt);
Hai Shalomc3565922019-10-28 11:58:20 -07002502 }
2503
Hai Shalom899fcc72020-10-19 14:38:18 -07002504#ifdef CONFIG_DPP2
2505 cert_req = json_get_member_base64(root, "pkcs10");
2506 if (cert_req) {
2507 char *txt;
2508 int id;
2509
2510 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2511 if (dpp_validate_csr(auth, cert_req) < 0) {
2512 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2513 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2514 goto cont;
2515 }
2516
Hai Shaloma20dcd72022-02-04 13:43:00 -08002517 id = dpp_get_peer_bi_id(auth);
2518 if (id < 0)
2519 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002520
2521 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2522 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2523 wpabuf_len(cert_req), NULL);
2524 if (!txt)
2525 goto fail;
2526
2527 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2528 id, txt);
2529 os_free(txt);
2530 auth->waiting_csr = false;
2531 auth->waiting_cert = true;
2532 goto fail;
2533 }
2534cont:
2535#endif /* CONFIG_DPP2 */
2536
2537 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2538 cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002539
2540fail:
Hai Shalom899fcc72020-10-19 14:38:18 -07002541 wpabuf_free(cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002542 json_free(root);
2543 os_free(unwrapped);
2544 return resp;
2545}
2546
2547
Hai Shalomc3565922019-10-28 11:58:20 -07002548static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002549 struct json_token *cred)
2550{
2551 struct json_token *pass, *psk_hex;
2552
2553 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2554
2555 pass = json_get_member(cred, "pass");
2556 psk_hex = json_get_member(cred, "psk_hex");
2557
2558 if (pass && pass->type == JSON_STRING) {
2559 size_t len = os_strlen(pass->string);
2560
2561 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2562 pass->string, len);
2563 if (len < 8 || len > 63)
2564 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07002565 os_strlcpy(conf->passphrase, pass->string,
2566 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002567 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002568 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002569 wpa_printf(MSG_DEBUG,
2570 "DPP: Unexpected psk_hex with akm=sae");
2571 return -1;
2572 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002573 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07002574 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002575 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2576 return -1;
2577 }
2578 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07002579 conf->psk, PMK_LEN);
2580 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002581 } else {
2582 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2583 return -1;
2584 }
2585
Hai Shalomc3565922019-10-28 11:58:20 -07002586 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002587 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2588 return -1;
2589 }
2590
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002591 return 0;
2592}
2593
2594
Hai Shaloma20dcd72022-02-04 13:43:00 -08002595struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2596 const struct dpp_curve_params **key_curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002597{
2598 struct json_token *token;
2599 const struct dpp_curve_params *curve;
2600 struct wpabuf *x = NULL, *y = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002601 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002602
2603 token = json_get_member(jwk, "kty");
2604 if (!token || token->type != JSON_STRING) {
2605 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2606 goto fail;
2607 }
2608 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002609 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002610 token->string);
2611 goto fail;
2612 }
2613
2614 token = json_get_member(jwk, "crv");
2615 if (!token || token->type != JSON_STRING) {
2616 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2617 goto fail;
2618 }
2619 curve = dpp_get_curve_jwk_crv(token->string);
2620 if (!curve) {
2621 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2622 token->string);
2623 goto fail;
2624 }
2625
2626 x = json_get_member_base64url(jwk, "x");
2627 if (!x) {
2628 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2629 goto fail;
2630 }
2631 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2632 if (wpabuf_len(x) != curve->prime_len) {
2633 wpa_printf(MSG_DEBUG,
2634 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2635 (unsigned int) wpabuf_len(x),
2636 (unsigned int) curve->prime_len, curve->name);
2637 goto fail;
2638 }
2639
2640 y = json_get_member_base64url(jwk, "y");
2641 if (!y) {
2642 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2643 goto fail;
2644 }
2645 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2646 if (wpabuf_len(y) != curve->prime_len) {
2647 wpa_printf(MSG_DEBUG,
2648 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2649 (unsigned int) wpabuf_len(y),
2650 (unsigned int) curve->prime_len, curve->name);
2651 goto fail;
2652 }
2653
Hai Shaloma20dcd72022-02-04 13:43:00 -08002654 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2655 wpabuf_head(y), wpabuf_len(x));
2656 if (!key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002657 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002658
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002659 *key_curve = curve;
2660
2661fail:
2662 wpabuf_free(x);
2663 wpabuf_free(y);
2664
Hai Shaloma20dcd72022-02-04 13:43:00 -08002665 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002666}
2667
2668
2669int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2670{
2671 struct os_time now;
2672 unsigned int year, month, day, hour, min, sec;
2673 os_time_t utime;
2674 const char *pos;
2675
2676 /* ISO 8601 date and time:
2677 * <date>T<time>
2678 * YYYY-MM-DDTHH:MM:SSZ
2679 * YYYY-MM-DDTHH:MM:SS+03:00
2680 */
2681 if (os_strlen(timestamp) < 19) {
2682 wpa_printf(MSG_DEBUG,
2683 "DPP: Too short timestamp - assume expired key");
2684 return 1;
2685 }
2686 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2687 &year, &month, &day, &hour, &min, &sec) != 6) {
2688 wpa_printf(MSG_DEBUG,
2689 "DPP: Failed to parse expiration day - assume expired key");
2690 return 1;
2691 }
2692
2693 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2694 wpa_printf(MSG_DEBUG,
2695 "DPP: Invalid date/time information - assume expired key");
2696 return 1;
2697 }
2698
2699 pos = timestamp + 19;
2700 if (*pos == 'Z' || *pos == '\0') {
2701 /* In UTC - no need to adjust */
2702 } else if (*pos == '-' || *pos == '+') {
2703 int items;
2704
2705 /* Adjust local time to UTC */
2706 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2707 if (items < 1) {
2708 wpa_printf(MSG_DEBUG,
2709 "DPP: Invalid time zone designator (%s) - assume expired key",
2710 pos);
2711 return 1;
2712 }
2713 if (*pos == '-')
2714 utime += 3600 * hour;
2715 if (*pos == '+')
2716 utime -= 3600 * hour;
2717 if (items > 1) {
2718 if (*pos == '-')
2719 utime += 60 * min;
2720 if (*pos == '+')
2721 utime -= 60 * min;
2722 }
2723 } else {
2724 wpa_printf(MSG_DEBUG,
2725 "DPP: Invalid time zone designator (%s) - assume expired key",
2726 pos);
2727 return 1;
2728 }
2729 if (expiry)
2730 *expiry = utime;
2731
2732 if (os_get_time(&now) < 0) {
2733 wpa_printf(MSG_DEBUG,
2734 "DPP: Cannot get current time - assume expired key");
2735 return 1;
2736 }
2737
2738 if (now.sec > utime) {
2739 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2740 utime, now.sec);
2741 return 1;
2742 }
2743
2744 return 0;
2745}
2746
2747
2748static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002749 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002750 const unsigned char *payload,
2751 u16 payload_len)
2752{
2753 struct json_token *root, *groups, *netkey, *token;
2754 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002755 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002756 const struct dpp_curve_params *curve;
2757 unsigned int rules = 0;
2758
2759 root = json_parse((const char *) payload, payload_len);
2760 if (!root) {
2761 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2762 goto fail;
2763 }
2764
2765 groups = json_get_member(root, "groups");
2766 if (!groups || groups->type != JSON_ARRAY) {
2767 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2768 goto skip_groups;
2769 }
2770 for (token = groups->child; token; token = token->sibling) {
2771 struct json_token *id, *role;
2772
2773 id = json_get_member(token, "groupId");
2774 if (!id || id->type != JSON_STRING) {
2775 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2776 goto fail;
2777 }
2778
2779 role = json_get_member(token, "netRole");
2780 if (!role || role->type != JSON_STRING) {
2781 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2782 goto fail;
2783 }
2784 wpa_printf(MSG_DEBUG,
2785 "DPP: connector group: groupId='%s' netRole='%s'",
2786 id->string, role->string);
2787 rules++;
2788 }
2789skip_groups:
2790
2791 if (!rules) {
2792 wpa_printf(MSG_DEBUG,
2793 "DPP: Connector includes no groups");
2794 goto fail;
2795 }
2796
2797 token = json_get_member(root, "expiry");
2798 if (!token || token->type != JSON_STRING) {
2799 wpa_printf(MSG_DEBUG,
2800 "DPP: No expiry string found - connector does not expire");
2801 } else {
2802 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2803 if (dpp_key_expired(token->string,
2804 &auth->net_access_key_expiry)) {
2805 wpa_printf(MSG_DEBUG,
2806 "DPP: Connector (netAccessKey) has expired");
2807 goto fail;
2808 }
2809 }
2810
2811 netkey = json_get_member(root, "netAccessKey");
2812 if (!netkey || netkey->type != JSON_OBJECT) {
2813 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2814 goto fail;
2815 }
2816
2817 key = dpp_parse_jwk(netkey, &curve);
2818 if (!key)
2819 goto fail;
2820 dpp_debug_print_key("DPP: Received netAccessKey", key);
2821
Hai Shaloma20dcd72022-02-04 13:43:00 -08002822 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002823 wpa_printf(MSG_DEBUG,
2824 "DPP: netAccessKey in connector does not match own protocol key");
2825#ifdef CONFIG_TESTING_OPTIONS
2826 if (auth->ignore_netaccesskey_mismatch) {
2827 wpa_printf(MSG_DEBUG,
2828 "DPP: TESTING - skip netAccessKey mismatch");
2829 } else {
2830 goto fail;
2831 }
2832#else /* CONFIG_TESTING_OPTIONS */
2833 goto fail;
2834#endif /* CONFIG_TESTING_OPTIONS */
2835 }
2836
2837 ret = 0;
2838fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002839 crypto_ec_key_deinit(key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002840 json_free(root);
2841 return ret;
2842}
2843
2844
Hai Shaloma20dcd72022-02-04 13:43:00 -08002845static void dpp_copy_csign(struct dpp_config_obj *conf,
2846 struct crypto_ec_key *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002847{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002848 struct wpabuf *c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002849
Hai Shaloma20dcd72022-02-04 13:43:00 -08002850 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2851 if (!c_sign_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002852 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002853
Hai Shalomc3565922019-10-28 11:58:20 -07002854 wpabuf_free(conf->c_sign_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002855 conf->c_sign_key = c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002856}
2857
2858
Hai Shaloma20dcd72022-02-04 13:43:00 -08002859static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2860 struct crypto_ec_key *ppkey)
Hai Shalom899fcc72020-10-19 14:38:18 -07002861{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002862 struct wpabuf *pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002863
Hai Shaloma20dcd72022-02-04 13:43:00 -08002864 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2865 if (!pp_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002866 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002867
Hai Shalom899fcc72020-10-19 14:38:18 -07002868 wpabuf_free(conf->pp_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002869 conf->pp_key = pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002870}
2871
2872
Hai Shalomc3565922019-10-28 11:58:20 -07002873static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2874 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002875{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002876 struct wpabuf *net_access_key;
2877 struct crypto_ec_key *own_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002878
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002879 own_key = auth->own_protocol_key;
2880#ifdef CONFIG_DPP2
2881 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2882 auth->reconfig_old_protocol_key)
2883 own_key = auth->reconfig_old_protocol_key;
2884#endif /* CONFIG_DPP2 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002885
2886 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2887 if (!net_access_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002888 return;
2889
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002890 wpabuf_free(auth->net_access_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002891 auth->net_access_key = net_access_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002892}
2893
2894
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002895static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002896 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002897 struct json_token *cred)
2898{
2899 struct dpp_signed_connector_info info;
Hai Shalom899fcc72020-10-19 14:38:18 -07002900 struct json_token *token, *csign, *ppkey;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002901 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002902 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002903 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002904 const char *signed_connector;
2905
2906 os_memset(&info, 0, sizeof(info));
2907
Hai Shalomc3565922019-10-28 11:58:20 -07002908 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002909 wpa_printf(MSG_DEBUG,
2910 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07002911 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07002912 return -1;
2913 }
2914
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002915 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2916
2917 csign = json_get_member(cred, "csign");
2918 if (!csign || csign->type != JSON_OBJECT) {
2919 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2920 goto fail;
2921 }
2922
2923 csign_pub = dpp_parse_jwk(csign, &key_curve);
2924 if (!csign_pub) {
2925 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
2926 goto fail;
2927 }
2928 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
2929
Hai Shalom899fcc72020-10-19 14:38:18 -07002930 ppkey = json_get_member(cred, "ppKey");
2931 if (ppkey && ppkey->type == JSON_OBJECT) {
2932 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2933 if (!pp_pub) {
2934 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2935 goto fail;
2936 }
2937 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2938 if (key_curve != pp_curve) {
2939 wpa_printf(MSG_DEBUG,
2940 "DPP: C-sign-key and ppKey do not use the same curve");
2941 goto fail;
2942 }
2943 }
2944
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002945 token = json_get_member(cred, "signedConnector");
2946 if (!token || token->type != JSON_STRING) {
2947 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
2948 goto fail;
2949 }
2950 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
2951 token->string, os_strlen(token->string));
2952 signed_connector = token->string;
2953
2954 if (os_strchr(signed_connector, '"') ||
2955 os_strchr(signed_connector, '\n')) {
2956 wpa_printf(MSG_DEBUG,
2957 "DPP: Unexpected character in signedConnector");
2958 goto fail;
2959 }
2960
2961 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002962 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002963 goto fail;
2964
Hai Shalomc3565922019-10-28 11:58:20 -07002965 if (dpp_parse_connector(auth, conf,
2966 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002967 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
2968 goto fail;
2969 }
2970
Hai Shalomc3565922019-10-28 11:58:20 -07002971 os_free(conf->connector);
2972 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002973
Hai Shalomc3565922019-10-28 11:58:20 -07002974 dpp_copy_csign(conf, csign_pub);
Hai Shalom899fcc72020-10-19 14:38:18 -07002975 if (pp_pub)
2976 dpp_copy_ppkey(conf, pp_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07002977 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07002978 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002979
2980 ret = 0;
2981fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002982 crypto_ec_key_deinit(csign_pub);
2983 crypto_ec_key_deinit(pp_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002984 os_free(info.payload);
2985 return ret;
2986}
2987
2988
Hai Shalom899fcc72020-10-19 14:38:18 -07002989#ifdef CONFIG_DPP2
2990static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2991 struct dpp_config_obj *conf,
2992 struct json_token *cred)
2993{
2994 struct json_token *ent, *name;
2995
2996 ent = json_get_member(cred, "entCreds");
2997 if (!ent || ent->type != JSON_OBJECT) {
2998 dpp_auth_fail(auth, "No entCreds in JSON");
2999 return -1;
3000 }
3001
3002 conf->certbag = json_get_member_base64(ent, "certBag");
3003 if (!conf->certbag) {
3004 dpp_auth_fail(auth, "No certBag in JSON");
3005 return -1;
3006 }
3007 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003008 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
Hai Shalom899fcc72020-10-19 14:38:18 -07003009 if (!conf->certs) {
3010 dpp_auth_fail(auth, "No certificates in certBag");
3011 return -1;
3012 }
3013
3014 conf->cacert = json_get_member_base64(ent, "caCert");
3015 if (conf->cacert)
3016 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3017 conf->cacert);
3018
3019 name = json_get_member(ent, "trustedEapServerName");
3020 if (name &&
3021 (name->type != JSON_STRING ||
3022 has_ctrl_char((const u8 *) name->string,
3023 os_strlen(name->string)))) {
3024 dpp_auth_fail(auth,
3025 "Invalid trustedEapServerName type in JSON");
3026 return -1;
3027 }
3028 if (name && name->string) {
3029 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3030 name->string);
3031 conf->server_name = os_strdup(name->string);
3032 if (!conf->server_name)
3033 return -1;
3034 }
3035
3036 return 0;
3037}
3038#endif /* CONFIG_DPP2 */
3039
3040
Roshan Pius3a1667e2018-07-03 15:17:14 -07003041const char * dpp_akm_str(enum dpp_akm akm)
3042{
3043 switch (akm) {
3044 case DPP_AKM_DPP:
3045 return "dpp";
3046 case DPP_AKM_PSK:
3047 return "psk";
3048 case DPP_AKM_SAE:
3049 return "sae";
3050 case DPP_AKM_PSK_SAE:
3051 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07003052 case DPP_AKM_SAE_DPP:
3053 return "dpp+sae";
3054 case DPP_AKM_PSK_SAE_DPP:
3055 return "dpp+psk+sae";
Hai Shalom899fcc72020-10-19 14:38:18 -07003056 case DPP_AKM_DOT1X:
3057 return "dot1x";
Roshan Pius3a1667e2018-07-03 15:17:14 -07003058 default:
3059 return "??";
3060 }
3061}
3062
3063
Hai Shalomc3565922019-10-28 11:58:20 -07003064const char * dpp_akm_selector_str(enum dpp_akm akm)
3065{
3066 switch (akm) {
3067 case DPP_AKM_DPP:
3068 return "506F9A02";
3069 case DPP_AKM_PSK:
3070 return "000FAC02+000FAC06";
3071 case DPP_AKM_SAE:
3072 return "000FAC08";
3073 case DPP_AKM_PSK_SAE:
3074 return "000FAC02+000FAC06+000FAC08";
3075 case DPP_AKM_SAE_DPP:
3076 return "506F9A02+000FAC08";
3077 case DPP_AKM_PSK_SAE_DPP:
3078 return "506F9A02+000FAC08+000FAC02+000FAC06";
Hai Shalom899fcc72020-10-19 14:38:18 -07003079 case DPP_AKM_DOT1X:
3080 return "000FAC01+000FAC05";
Hai Shalomc3565922019-10-28 11:58:20 -07003081 default:
3082 return "??";
3083 }
3084}
3085
3086
Roshan Pius3a1667e2018-07-03 15:17:14 -07003087static enum dpp_akm dpp_akm_from_str(const char *akm)
3088{
Hai Shalomc3565922019-10-28 11:58:20 -07003089 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07003090 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07003091
Roshan Pius3a1667e2018-07-03 15:17:14 -07003092 if (os_strcmp(akm, "psk") == 0)
3093 return DPP_AKM_PSK;
3094 if (os_strcmp(akm, "sae") == 0)
3095 return DPP_AKM_SAE;
3096 if (os_strcmp(akm, "psk+sae") == 0)
3097 return DPP_AKM_PSK_SAE;
3098 if (os_strcmp(akm, "dpp") == 0)
3099 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07003100 if (os_strcmp(akm, "dpp+sae") == 0)
3101 return DPP_AKM_SAE_DPP;
3102 if (os_strcmp(akm, "dpp+psk+sae") == 0)
3103 return DPP_AKM_PSK_SAE_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07003104 if (os_strcmp(akm, "dot1x") == 0)
3105 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003106
3107 pos = akm;
3108 while (*pos) {
3109 if (os_strlen(pos) < 8)
3110 break;
3111 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3112 dpp = 1;
3113 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3114 psk = 1;
3115 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3116 psk = 1;
3117 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3118 sae = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07003119 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3120 dot1x = 1;
3121 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3122 dot1x = 1;
Hai Shalomc3565922019-10-28 11:58:20 -07003123 pos += 8;
3124 if (*pos != '+')
3125 break;
3126 pos++;
3127 }
3128
3129 if (dpp && psk && sae)
3130 return DPP_AKM_PSK_SAE_DPP;
3131 if (dpp && sae)
3132 return DPP_AKM_SAE_DPP;
3133 if (dpp)
3134 return DPP_AKM_DPP;
3135 if (psk && sae)
3136 return DPP_AKM_PSK_SAE;
3137 if (sae)
3138 return DPP_AKM_SAE;
3139 if (psk)
3140 return DPP_AKM_PSK;
Hai Shalom899fcc72020-10-19 14:38:18 -07003141 if (dot1x)
3142 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003143
Roshan Pius3a1667e2018-07-03 15:17:14 -07003144 return DPP_AKM_UNKNOWN;
3145}
3146
3147
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003148static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3149 const u8 *conf_obj, u16 conf_obj_len)
3150{
3151 int ret = -1;
3152 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07003153 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003154 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003155 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003156
3157 root = json_parse((const char *) conf_obj, conf_obj_len);
3158 if (!root)
3159 return -1;
3160 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003161 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003162 goto fail;
3163 }
3164
3165 token = json_get_member(root, "wi-fi_tech");
3166 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003167 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003168 goto fail;
3169 }
3170 if (os_strcmp(token->string, "infra") != 0) {
3171 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3172 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003173 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003174 goto fail;
3175 }
3176
3177 discovery = json_get_member(root, "discovery");
3178 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003179 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003180 goto fail;
3181 }
3182
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003183 ssid64 = json_get_member_base64url(discovery, "ssid64");
3184 if (ssid64) {
3185 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3186 wpabuf_head(ssid64), wpabuf_len(ssid64));
3187 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3188 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3189 goto fail;
3190 }
3191 } else {
3192 token = json_get_member(discovery, "ssid");
3193 if (!token || token->type != JSON_STRING) {
3194 dpp_auth_fail(auth,
3195 "No discovery::ssid string value found");
3196 goto fail;
3197 }
3198 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3199 token->string, os_strlen(token->string));
3200 if (os_strlen(token->string) > SSID_MAX_LEN) {
3201 dpp_auth_fail(auth,
3202 "Too long discovery::ssid string value");
3203 goto fail;
3204 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003205 }
Hai Shalomc3565922019-10-28 11:58:20 -07003206
3207 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3208 wpa_printf(MSG_DEBUG,
3209 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003210 ret = 0;
3211 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003212 }
3213 conf = &auth->conf_obj[auth->num_conf_obj++];
3214
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003215 if (ssid64) {
3216 conf->ssid_len = wpabuf_len(ssid64);
3217 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3218 } else {
3219 conf->ssid_len = os_strlen(token->string);
3220 os_memcpy(conf->ssid, token->string, conf->ssid_len);
3221 }
3222
3223 token = json_get_member(discovery, "ssid_charset");
3224 if (token && token->type == JSON_NUMBER) {
3225 conf->ssid_charset = token->number;
3226 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3227 conf->ssid_charset);
3228 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003229
3230 cred = json_get_member(root, "cred");
3231 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003232 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003233 goto fail;
3234 }
3235
3236 token = json_get_member(cred, "akm");
3237 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003238 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003239 goto fail;
3240 }
Hai Shalomc3565922019-10-28 11:58:20 -07003241 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003242
Hai Shalomfdcde762020-04-02 11:19:20 -07003243 legacy = dpp_akm_legacy(conf->akm);
3244 if (legacy && auth->peer_version >= 2) {
3245 struct json_token *csign, *s_conn;
3246
3247 csign = json_get_member(cred, "csign");
3248 s_conn = json_get_member(cred, "signedConnector");
3249 if (csign && csign->type == JSON_OBJECT &&
3250 s_conn && s_conn->type == JSON_STRING)
3251 legacy = 0;
3252 }
3253 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07003254 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003255 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003256 } else if (dpp_akm_dpp(conf->akm) ||
3257 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07003258 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003259 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07003260#ifdef CONFIG_DPP2
3261 } else if (conf->akm == DPP_AKM_DOT1X) {
3262 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3263 dpp_parse_cred_dpp(auth, conf, cred) < 0)
3264 goto fail;
3265#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003266 } else {
3267 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3268 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003269 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003270 goto fail;
3271 }
3272
3273 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3274 ret = 0;
3275fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003276 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003277 json_free(root);
3278 return ret;
3279}
3280
3281
Hai Shalom899fcc72020-10-19 14:38:18 -07003282#ifdef CONFIG_DPP2
3283static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3284{
3285 const u8 *b64;
3286 u16 b64_len;
3287
3288 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3289 if (!b64)
3290 return NULL;
3291 return base64_decode((const char *) b64, b64_len, len);
3292}
3293#endif /* CONFIG_DPP2 */
3294
3295
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003296int dpp_conf_resp_rx(struct dpp_authentication *auth,
3297 const struct wpabuf *resp)
3298{
3299 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3300 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07003301 const u8 *env_data;
3302 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003303 const u8 *addr[1];
3304 size_t len[1];
3305 u8 *unwrapped = NULL;
3306 size_t unwrapped_len = 0;
3307 int ret = -1;
3308
Hai Shalom021b0b52019-04-10 11:17:58 -07003309 auth->conf_resp_status = 255;
3310
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003311 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003312 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003313 return -1;
3314 }
3315
3316 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3317 DPP_ATTR_WRAPPED_DATA,
3318 &wrapped_data_len);
3319 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003320 dpp_auth_fail(auth,
3321 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003322 return -1;
3323 }
3324
3325 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3326 wrapped_data, wrapped_data_len);
3327 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3328 unwrapped = os_malloc(unwrapped_len);
3329 if (!unwrapped)
3330 return -1;
3331
3332 addr[0] = wpabuf_head(resp);
3333 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3334 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3335
3336 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3337 wrapped_data, wrapped_data_len,
3338 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003339 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003340 goto fail;
3341 }
3342 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3343 unwrapped, unwrapped_len);
3344
3345 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003346 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003347 goto fail;
3348 }
3349
3350 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3351 DPP_ATTR_ENROLLEE_NONCE,
3352 &e_nonce_len);
3353 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003354 dpp_auth_fail(auth,
3355 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003356 goto fail;
3357 }
3358 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3359 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003360 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003361 goto fail;
3362 }
3363
3364 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3365 DPP_ATTR_STATUS, &status_len);
3366 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003367 dpp_auth_fail(auth,
3368 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003369 goto fail;
3370 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003371 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003372 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Hai Shalom899fcc72020-10-19 14:38:18 -07003373#ifdef CONFIG_DPP2
3374 if (status[0] == DPP_STATUS_CSR_NEEDED) {
3375 u8 *csrattrs;
3376 size_t csrattrs_len;
3377
3378 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3379
3380 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3381 &csrattrs_len);
3382 if (!csrattrs) {
3383 dpp_auth_fail(auth,
3384 "Missing or invalid CSR Attributes Request attribute");
3385 goto fail;
3386 }
3387 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3388 os_free(auth->csrattrs);
3389 auth->csrattrs = csrattrs;
3390 auth->csrattrs_len = csrattrs_len;
3391 ret = -2;
3392 goto fail;
3393 }
3394#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07003395#ifdef CONFIG_DPP3
3396 if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3397 const u8 *fcgroup, *r_proto;
3398 u16 fcgroup_len, r_proto_len;
3399 u16 group;
3400 const struct dpp_curve_params *curve;
3401 struct crypto_ec_key *new_pe;
3402 struct crypto_ec_key *pc;
3403
3404 fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3405 DPP_ATTR_FINITE_CYCLIC_GROUP,
3406 &fcgroup_len);
3407 if (!fcgroup || fcgroup_len != 2) {
3408 dpp_auth_fail(auth,
3409 "Missing or invalid required Finite Cyclic Group attribute");
3410 goto fail;
3411 }
3412 group = WPA_GET_LE16(fcgroup);
3413
3414 wpa_printf(MSG_DEBUG,
3415 "DPP: Configurator requested a new protocol key from group %u",
3416 group);
3417 curve = dpp_get_curve_ike_group(group);
3418 if (!curve) {
3419 dpp_auth_fail(auth,
3420 "Unsupported group for new protocol key");
3421 goto fail;
3422 }
3423
3424 new_pe = dpp_gen_keypair(curve);
3425 if (!new_pe) {
3426 dpp_auth_fail(auth,
3427 "Failed to generate a new protocol key");
3428 goto fail;
3429 }
3430
3431 crypto_ec_key_deinit(auth->own_protocol_key);
3432 auth->own_protocol_key = new_pe;
3433 auth->new_curve = curve;
3434
3435 r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3436 DPP_ATTR_R_PROTOCOL_KEY,
3437 &r_proto_len);
3438 if (!r_proto) {
3439 dpp_auth_fail(auth,
3440 "Missing required Responder Protocol Key attribute (Pc)");
3441 goto fail;
3442 }
3443 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3444 r_proto, r_proto_len);
3445
3446 pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3447 if (!pc) {
3448 dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3449 goto fail;
3450 }
3451 dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3452
3453 crypto_ec_key_deinit(auth->peer_protocol_key);
3454 auth->peer_protocol_key = pc;
3455
3456 auth->waiting_new_key = true;
3457 ret = -3;
3458 goto fail;
3459 }
3460#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003461 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003462 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003463 goto fail;
3464 }
3465
Hai Shalomfdcde762020-04-02 11:19:20 -07003466 env_data = dpp_get_attr(unwrapped, unwrapped_len,
3467 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3468#ifdef CONFIG_DPP2
3469 if (env_data &&
3470 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3471 goto fail;
3472#endif /* CONFIG_DPP2 */
3473
Hai Shalomc3565922019-10-28 11:58:20 -07003474 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3475 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003476 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003477 dpp_auth_fail(auth,
3478 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003479 goto fail;
3480 }
Hai Shalomc3565922019-10-28 11:58:20 -07003481 while (conf_obj) {
3482 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3483 conf_obj, conf_obj_len);
3484 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3485 goto fail;
3486 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3487 DPP_ATTR_CONFIG_OBJ,
3488 &conf_obj_len);
3489 }
3490
3491#ifdef CONFIG_DPP2
3492 status = dpp_get_attr(unwrapped, unwrapped_len,
3493 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3494 if (status) {
3495 wpa_printf(MSG_DEBUG,
3496 "DPP: Configurator requested connection status result");
3497 auth->conn_status_requested = 1;
3498 }
3499#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003500
3501 ret = 0;
3502
3503fail:
3504 os_free(unwrapped);
3505 return ret;
3506}
3507
3508
Hai Shalom021b0b52019-04-10 11:17:58 -07003509#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07003510
Hai Shalom021b0b52019-04-10 11:17:58 -07003511enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3512 const u8 *hdr,
3513 const u8 *attr_start, size_t attr_len)
3514{
3515 const u8 *wrapped_data, *status, *e_nonce;
3516 u16 wrapped_data_len, status_len, e_nonce_len;
3517 const u8 *addr[2];
3518 size_t len[2];
3519 u8 *unwrapped = NULL;
3520 size_t unwrapped_len = 0;
3521 enum dpp_status_error ret = 256;
3522
3523 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3524 &wrapped_data_len);
3525 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3526 dpp_auth_fail(auth,
3527 "Missing or invalid required Wrapped Data attribute");
3528 goto fail;
3529 }
3530 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3531 wrapped_data, wrapped_data_len);
3532
3533 attr_len = wrapped_data - 4 - attr_start;
3534
3535 addr[0] = hdr;
3536 len[0] = DPP_HDR_LEN;
3537 addr[1] = attr_start;
3538 len[1] = attr_len;
3539 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3540 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3541 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3542 wrapped_data, wrapped_data_len);
3543 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3544 unwrapped = os_malloc(unwrapped_len);
3545 if (!unwrapped)
3546 goto fail;
3547 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3548 wrapped_data, wrapped_data_len,
3549 2, addr, len, unwrapped) < 0) {
3550 dpp_auth_fail(auth, "AES-SIV decryption failed");
3551 goto fail;
3552 }
3553 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3554 unwrapped, unwrapped_len);
3555
3556 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3557 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3558 goto fail;
3559 }
3560
3561 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3562 DPP_ATTR_ENROLLEE_NONCE,
3563 &e_nonce_len);
3564 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3565 dpp_auth_fail(auth,
3566 "Missing or invalid Enrollee Nonce attribute");
3567 goto fail;
3568 }
3569 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3570 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3571 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3572 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3573 auth->e_nonce, e_nonce_len);
3574 goto fail;
3575 }
3576
3577 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3578 &status_len);
3579 if (!status || status_len < 1) {
3580 dpp_auth_fail(auth,
3581 "Missing or invalid required DPP Status attribute");
3582 goto fail;
3583 }
3584 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3585 ret = status[0];
3586
3587fail:
3588 bin_clear_free(unwrapped, unwrapped_len);
3589 return ret;
3590}
Hai Shalom021b0b52019-04-10 11:17:58 -07003591
3592
3593struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3594 enum dpp_status_error status)
3595{
3596 struct wpabuf *msg, *clear;
3597 size_t nonce_len, clear_len, attr_len;
3598 const u8 *addr[2];
3599 size_t len[2];
3600 u8 *wrapped;
3601
3602 nonce_len = auth->curve->nonce_len;
3603 clear_len = 5 + 4 + nonce_len;
3604 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3605 clear = wpabuf_alloc(clear_len);
3606 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3607 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003608 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07003609
3610 /* DPP Status */
3611 dpp_build_attr_status(clear, status);
3612
3613 /* E-nonce */
3614 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3615 wpabuf_put_le16(clear, nonce_len);
3616 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3617
3618 /* OUI, OUI type, Crypto Suite, DPP frame type */
3619 addr[0] = wpabuf_head_u8(msg) + 2;
3620 len[0] = 3 + 1 + 1 + 1;
3621 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3622
3623 /* Attributes before Wrapped Data (none) */
3624 addr[1] = wpabuf_put(msg, 0);
3625 len[1] = 0;
3626 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3627
3628 /* Wrapped Data */
3629 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3630 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3631 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3632
3633 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3634 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3635 wpabuf_head(clear), wpabuf_len(clear),
3636 2, addr, len, wrapped) < 0)
3637 goto fail;
3638
3639 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3640 wpabuf_free(clear);
3641 return msg;
3642fail:
3643 wpabuf_free(clear);
3644 wpabuf_free(msg);
3645 return NULL;
3646}
3647
3648
Hai Shalomc3565922019-10-28 11:58:20 -07003649static int valid_channel_list(const char *val)
3650{
3651 while (*val) {
3652 if (!((*val >= '0' && *val <= '9') ||
3653 *val == '/' || *val == ','))
3654 return 0;
3655 val++;
3656 }
3657
3658 return 1;
3659}
3660
3661
3662enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3663 const u8 *hdr,
3664 const u8 *attr_start,
3665 size_t attr_len,
3666 u8 *ssid, size_t *ssid_len,
3667 char **channel_list)
3668{
3669 const u8 *wrapped_data, *status, *e_nonce;
3670 u16 wrapped_data_len, status_len, e_nonce_len;
3671 const u8 *addr[2];
3672 size_t len[2];
3673 u8 *unwrapped = NULL;
3674 size_t unwrapped_len = 0;
3675 enum dpp_status_error ret = 256;
3676 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003677 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07003678
3679 *ssid_len = 0;
3680 *channel_list = NULL;
3681
3682 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3683 &wrapped_data_len);
3684 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3685 dpp_auth_fail(auth,
3686 "Missing or invalid required Wrapped Data attribute");
3687 goto fail;
3688 }
3689 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3690 wrapped_data, wrapped_data_len);
3691
3692 attr_len = wrapped_data - 4 - attr_start;
3693
3694 addr[0] = hdr;
3695 len[0] = DPP_HDR_LEN;
3696 addr[1] = attr_start;
3697 len[1] = attr_len;
3698 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3699 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3700 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3701 wrapped_data, wrapped_data_len);
3702 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3703 unwrapped = os_malloc(unwrapped_len);
3704 if (!unwrapped)
3705 goto fail;
3706 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3707 wrapped_data, wrapped_data_len,
3708 2, addr, len, unwrapped) < 0) {
3709 dpp_auth_fail(auth, "AES-SIV decryption failed");
3710 goto fail;
3711 }
3712 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3713 unwrapped, unwrapped_len);
3714
3715 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3716 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3717 goto fail;
3718 }
3719
3720 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3721 DPP_ATTR_ENROLLEE_NONCE,
3722 &e_nonce_len);
3723 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3724 dpp_auth_fail(auth,
3725 "Missing or invalid Enrollee Nonce attribute");
3726 goto fail;
3727 }
3728 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3729 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3730 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3731 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3732 auth->e_nonce, e_nonce_len);
3733 goto fail;
3734 }
3735
3736 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3737 &status_len);
3738 if (!status) {
3739 dpp_auth_fail(auth,
3740 "Missing required DPP Connection Status attribute");
3741 goto fail;
3742 }
3743 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3744 status, status_len);
3745
3746 root = json_parse((const char *) status, status_len);
3747 if (!root) {
3748 dpp_auth_fail(auth, "Could not parse connStatus");
3749 goto fail;
3750 }
3751
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003752 ssid64 = json_get_member_base64url(root, "ssid64");
3753 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3754 *ssid_len = wpabuf_len(ssid64);
3755 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07003756 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003757 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07003758
3759 token = json_get_member(root, "channelList");
3760 if (token && token->type == JSON_STRING &&
3761 valid_channel_list(token->string))
3762 *channel_list = os_strdup(token->string);
3763
3764 token = json_get_member(root, "result");
3765 if (!token || token->type != JSON_NUMBER) {
3766 dpp_auth_fail(auth, "No connStatus - result");
3767 goto fail;
3768 }
3769 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3770 ret = token->number;
3771
3772fail:
3773 json_free(root);
3774 bin_clear_free(unwrapped, unwrapped_len);
3775 return ret;
3776}
3777
3778
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003779struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3780 const u8 *ssid, size_t ssid_len,
3781 const char *channel_list)
3782{
3783 struct wpabuf *json;
3784
3785 json = wpabuf_alloc(1000);
3786 if (!json)
3787 return NULL;
3788 json_start_object(json, NULL);
3789 json_add_int(json, "result", result);
3790 if (ssid) {
3791 json_value_sep(json);
3792 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3793 wpabuf_free(json);
3794 return NULL;
3795 }
3796 }
3797 if (channel_list) {
3798 json_value_sep(json);
3799 json_add_string(json, "channelList", channel_list);
3800 }
3801 json_end_object(json);
3802 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3803 wpabuf_head(json), wpabuf_len(json));
3804
3805 return json;
3806}
3807
3808
Hai Shalomc3565922019-10-28 11:58:20 -07003809struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3810 enum dpp_status_error result,
3811 const u8 *ssid, size_t ssid_len,
3812 const char *channel_list)
3813{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003814 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07003815 size_t nonce_len, clear_len, attr_len;
3816 const u8 *addr[2];
3817 size_t len[2];
3818 u8 *wrapped;
3819
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003820 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
Hai Shalomc3565922019-10-28 11:58:20 -07003821 if (!json)
3822 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003823
3824 nonce_len = auth->curve->nonce_len;
3825 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3826 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3827 clear = wpabuf_alloc(clear_len);
3828 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3829 if (!clear || !msg)
3830 goto fail;
3831
3832 /* E-nonce */
3833 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3834 wpabuf_put_le16(clear, nonce_len);
3835 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3836
3837 /* DPP Connection Status */
3838 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3839 wpabuf_put_le16(clear, wpabuf_len(json));
3840 wpabuf_put_buf(clear, json);
3841
3842 /* OUI, OUI type, Crypto Suite, DPP frame type */
3843 addr[0] = wpabuf_head_u8(msg) + 2;
3844 len[0] = 3 + 1 + 1 + 1;
3845 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3846
3847 /* Attributes before Wrapped Data (none) */
3848 addr[1] = wpabuf_put(msg, 0);
3849 len[1] = 0;
3850 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3851
3852 /* Wrapped Data */
3853 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3854 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3855 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3856
3857 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3858 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3859 wpabuf_head(clear), wpabuf_len(clear),
3860 2, addr, len, wrapped) < 0)
3861 goto fail;
3862
3863 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3864 msg);
3865 wpabuf_free(json);
3866 wpabuf_free(clear);
3867 return msg;
3868fail:
3869 wpabuf_free(json);
3870 wpabuf_free(clear);
3871 wpabuf_free(msg);
3872 return NULL;
3873}
3874
3875#endif /* CONFIG_DPP2 */
3876
3877
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003878void dpp_configurator_free(struct dpp_configurator *conf)
3879{
3880 if (!conf)
3881 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003882 crypto_ec_key_deinit(conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003883 os_free(conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003884 os_free(conf->connector);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003885 crypto_ec_key_deinit(conf->connector_key);
3886 crypto_ec_key_deinit(conf->pp_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003887 os_free(conf);
3888}
3889
3890
Roshan Pius3a1667e2018-07-03 15:17:14 -07003891int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3892 size_t buflen)
3893{
Hai Shaloma20dcd72022-02-04 13:43:00 -08003894 struct wpabuf *key;
3895 int ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003896
3897 if (!conf->csign)
3898 return -1;
3899
Hai Shaloma20dcd72022-02-04 13:43:00 -08003900 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3901 if (!key)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003902 return -1;
3903
Hai Shaloma20dcd72022-02-04 13:43:00 -08003904 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003905
Hai Shaloma20dcd72022-02-04 13:43:00 -08003906 wpabuf_clear_free(key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003907 return ret;
3908}
3909
3910
Hai Shalomfdcde762020-04-02 11:19:20 -07003911static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3912{
3913 struct wpabuf *csign_pub = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003914 const u8 *addr[1];
3915 size_t len[1];
3916 int res;
3917
Hai Shaloma20dcd72022-02-04 13:43:00 -08003918 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
Hai Shalomfdcde762020-04-02 11:19:20 -07003919 if (!csign_pub) {
3920 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3921 return -1;
3922 }
3923
3924 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
3925 addr[0] = wpabuf_head(csign_pub);
3926 len[0] = wpabuf_len(csign_pub);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003927 res = sha256_vector(1, addr, len, conf->kid_hash);
Hai Shalomfdcde762020-04-02 11:19:20 -07003928 wpabuf_free(csign_pub);
3929 if (res < 0) {
3930 wpa_printf(MSG_DEBUG,
3931 "DPP: Failed to derive kid for C-sign-key");
3932 return -1;
3933 }
3934
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003935 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3936 NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07003937 return conf->kid ? 0 : -1;
3938}
3939
3940
Hai Shalom899fcc72020-10-19 14:38:18 -07003941static struct dpp_configurator *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003942dpp_keygen_configurator(const char *curve, const u8 *privkey,
Hai Shalom899fcc72020-10-19 14:38:18 -07003943 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003944{
3945 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003946
3947 conf = os_zalloc(sizeof(*conf));
3948 if (!conf)
3949 return NULL;
3950
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003951 conf->curve = dpp_get_curve_name(curve);
3952 if (!conf->curve) {
3953 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3954 os_free(conf);
3955 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003956 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003957
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003958 if (privkey)
3959 conf->csign = dpp_set_keypair(&conf->curve, privkey,
3960 privkey_len);
3961 else
3962 conf->csign = dpp_gen_keypair(conf->curve);
Hai Shalom899fcc72020-10-19 14:38:18 -07003963 if (pp_key)
3964 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3965 pp_key_len);
3966 else
3967 conf->pp_key = dpp_gen_keypair(conf->curve);
3968 if (!conf->csign || !conf->pp_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003969 goto fail;
3970 conf->own = 1;
3971
Hai Shalomfdcde762020-04-02 11:19:20 -07003972 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003973 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003974 return conf;
3975fail:
3976 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07003977 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003978}
3979
3980
3981int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003982 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003983{
3984 struct wpabuf *conf_obj;
3985 int ret = -1;
3986
3987 if (!auth->conf) {
3988 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
3989 return -1;
3990 }
3991
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003992 auth->curve = dpp_get_curve_name(curve);
3993 if (!auth->curve) {
3994 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3995 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003996 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003997
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003998 wpa_printf(MSG_DEBUG,
3999 "DPP: Building own configuration/connector with curve %s",
4000 auth->curve->name);
4001
4002 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4003 if (!auth->own_protocol_key)
4004 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07004005 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004006 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07004007 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004008
Hai Shalom899fcc72020-10-19 14:38:18 -07004009 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004010 if (!conf_obj) {
4011 wpabuf_free(auth->conf_obj[0].c_sign_key);
4012 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004013 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004014 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004015 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4016 wpabuf_len(conf_obj));
4017fail:
4018 wpabuf_free(conf_obj);
4019 auth->peer_protocol_key = NULL;
4020 return ret;
4021}
4022
4023
4024static int dpp_compatible_netrole(const char *role1, const char *role2)
4025{
4026 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4027 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4028}
4029
4030
4031static int dpp_connector_compatible_group(struct json_token *root,
4032 const char *group_id,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004033 const char *net_role,
4034 bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004035{
4036 struct json_token *groups, *token;
4037
4038 groups = json_get_member(root, "groups");
4039 if (!groups || groups->type != JSON_ARRAY)
4040 return 0;
4041
4042 for (token = groups->child; token; token = token->sibling) {
4043 struct json_token *id, *role;
4044
4045 id = json_get_member(token, "groupId");
4046 if (!id || id->type != JSON_STRING)
4047 continue;
4048
4049 role = json_get_member(token, "netRole");
4050 if (!role || role->type != JSON_STRING)
4051 continue;
4052
4053 if (os_strcmp(id->string, "*") != 0 &&
4054 os_strcmp(group_id, "*") != 0 &&
4055 os_strcmp(id->string, group_id) != 0)
4056 continue;
4057
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004058 if (reconfig && os_strcmp(net_role, "configurator") == 0)
4059 return 1;
4060 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004061 return 1;
4062 }
4063
4064 return 0;
4065}
4066
4067
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004068int dpp_connector_match_groups(struct json_token *own_root,
4069 struct json_token *peer_root, bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004070{
4071 struct json_token *groups, *token;
4072
4073 groups = json_get_member(peer_root, "groups");
4074 if (!groups || groups->type != JSON_ARRAY) {
4075 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4076 return 0;
4077 }
4078
4079 for (token = groups->child; token; token = token->sibling) {
4080 struct json_token *id, *role;
4081
4082 id = json_get_member(token, "groupId");
4083 if (!id || id->type != JSON_STRING) {
4084 wpa_printf(MSG_DEBUG,
4085 "DPP: Missing peer groupId string");
4086 continue;
4087 }
4088
4089 role = json_get_member(token, "netRole");
4090 if (!role || role->type != JSON_STRING) {
4091 wpa_printf(MSG_DEBUG,
4092 "DPP: Missing peer groups::netRole string");
4093 continue;
4094 }
4095 wpa_printf(MSG_DEBUG,
4096 "DPP: peer connector group: groupId='%s' netRole='%s'",
4097 id->string, role->string);
4098 if (dpp_connector_compatible_group(own_root, id->string,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004099 role->string, reconfig)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004100 wpa_printf(MSG_DEBUG,
4101 "DPP: Compatible group/netRole in own connector");
4102 return 1;
4103 }
4104 }
4105
4106 return 0;
4107}
4108
4109
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004110struct json_token * dpp_parse_own_connector(const char *own_connector)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004111{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004112 unsigned char *own_conn;
4113 size_t own_conn_len;
4114 const char *pos, *end;
4115 struct json_token *own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004116
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004117 pos = os_strchr(own_connector, '.');
4118 if (!pos) {
4119 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4120 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004121 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004122 pos++;
4123 end = os_strchr(pos, '.');
4124 if (!end) {
4125 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4126 return NULL;
4127 }
4128 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4129 if (!own_conn) {
4130 wpa_printf(MSG_DEBUG,
4131 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4132 return NULL;
4133 }
4134
4135 own_root = json_parse((const char *) own_conn, own_conn_len);
4136 os_free(own_conn);
4137 if (!own_root)
4138 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4139
4140 return own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004141}
4142
4143
Roshan Pius3a1667e2018-07-03 15:17:14 -07004144enum dpp_status_error
4145dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4146 const u8 *net_access_key, size_t net_access_key_len,
4147 const u8 *csign_key, size_t csign_key_len,
4148 const u8 *peer_connector, size_t peer_connector_len,
4149 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004150{
4151 struct json_token *root = NULL, *netkey, *token;
4152 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004153 enum dpp_status_error ret = 255, res;
Sunil Ravi89eba102022-09-13 21:04:37 -07004154 struct crypto_ec_key *own_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004155 struct wpabuf *own_key_pub = NULL;
4156 const struct dpp_curve_params *curve, *own_curve;
4157 struct dpp_signed_connector_info info;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004158 size_t Nx_len;
4159 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4160
4161 os_memset(intro, 0, sizeof(*intro));
4162 os_memset(&info, 0, sizeof(info));
4163 if (expiry)
4164 *expiry = 0;
4165
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004166 own_key = dpp_set_keypair(&own_curve, net_access_key,
4167 net_access_key_len);
4168 if (!own_key) {
4169 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4170 goto fail;
4171 }
4172
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004173 own_root = dpp_parse_own_connector(own_connector);
4174 if (!own_root)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004175 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004176
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004177 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4178 peer_connector, peer_connector_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004179 if (res != DPP_STATUS_OK) {
4180 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004181 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004182 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004183
4184 root = json_parse((const char *) info.payload, info.payload_len);
4185 if (!root) {
4186 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004187 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004188 goto fail;
4189 }
4190
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004191 if (!dpp_connector_match_groups(own_root, root, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004192 wpa_printf(MSG_DEBUG,
4193 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004194 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004195 goto fail;
4196 }
4197
4198 token = json_get_member(root, "expiry");
4199 if (!token || token->type != JSON_STRING) {
4200 wpa_printf(MSG_DEBUG,
4201 "DPP: No expiry string found - connector does not expire");
4202 } else {
4203 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4204 if (dpp_key_expired(token->string, expiry)) {
4205 wpa_printf(MSG_DEBUG,
4206 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004207 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004208 goto fail;
4209 }
4210 }
4211
Hai Shaloma20dcd72022-02-04 13:43:00 -08004212#ifdef CONFIG_DPP3
4213 token = json_get_member(root, "version");
4214 if (token && token->type == JSON_NUMBER) {
4215 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4216 intro->peer_version = token->number;
4217 }
4218#endif /* CONFIG_DPP3 */
4219
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004220 netkey = json_get_member(root, "netAccessKey");
4221 if (!netkey || netkey->type != JSON_OBJECT) {
4222 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004223 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004224 goto fail;
4225 }
4226
Sunil Ravi89eba102022-09-13 21:04:37 -07004227 intro->peer_key = dpp_parse_jwk(netkey, &curve);
4228 if (!intro->peer_key) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07004229 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004230 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004231 }
Sunil Ravi89eba102022-09-13 21:04:37 -07004232 dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004233
4234 if (own_curve != curve) {
4235 wpa_printf(MSG_DEBUG,
4236 "DPP: Mismatching netAccessKey curves (%s != %s)",
4237 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004238 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004239 goto fail;
4240 }
4241
4242 /* ECDH: N = nk * PK */
Sunil Ravi89eba102022-09-13 21:04:37 -07004243 if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004244 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004245
4246 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4247 Nx, Nx_len);
4248
4249 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4250 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4251 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4252 goto fail;
4253 }
4254 intro->pmk_len = curve->hash_len;
4255
4256 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
Sunil Ravi89eba102022-09-13 21:04:37 -07004257 if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4258 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004259 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4260 goto fail;
4261 }
4262
Sunil Ravi89eba102022-09-13 21:04:37 -07004263#ifdef CONFIG_DPP3
4264 if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4265 &intro->aead_id) < 0) {
4266 wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4267 curve->ike_group);
4268 goto fail;
4269 }
4270#endif /* CONFIG_DPP3 */
4271
Roshan Pius3a1667e2018-07-03 15:17:14 -07004272 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004273fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07004274 if (ret != DPP_STATUS_OK)
Sunil Ravi89eba102022-09-13 21:04:37 -07004275 dpp_peer_intro_deinit(intro);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004276 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004277 os_free(info.payload);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004278 crypto_ec_key_deinit(own_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004279 wpabuf_free(own_key_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004280 json_free(root);
4281 json_free(own_root);
4282 return ret;
4283}
4284
4285
Sunil Ravi89eba102022-09-13 21:04:37 -07004286void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4287{
4288 if (!intro)
4289 return;
4290
4291 crypto_ec_key_deinit(intro->peer_key);
4292 os_memset(intro, 0, sizeof(*intro));
4293}
4294
4295
Hai Shaloma20dcd72022-02-04 13:43:00 -08004296#ifdef CONFIG_DPP3
4297int dpp_get_connector_version(const char *connector)
4298{
4299 struct json_token *root, *token;
4300 int ver = -1;
4301
4302 root = dpp_parse_own_connector(connector);
4303 if (!root)
4304 return -1;
4305
4306 token = json_get_member(root, "version");
4307 if (token && token->type == JSON_NUMBER)
4308 ver = token->number;
4309
4310 json_free(root);
4311 return ver;
4312}
4313#endif /* CONFIG_DPP3 */
4314
4315
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004316unsigned int dpp_next_id(struct dpp_global *dpp)
Hai Shalom021b0b52019-04-10 11:17:58 -07004317{
4318 struct dpp_bootstrap_info *bi;
4319 unsigned int max_id = 0;
4320
4321 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4322 if (bi->id > max_id)
4323 max_id = bi->id;
4324 }
4325 return max_id + 1;
4326}
4327
4328
4329static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4330{
4331 struct dpp_bootstrap_info *bi, *tmp;
4332 int found = 0;
4333
4334 if (!dpp)
4335 return -1;
4336
4337 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4338 struct dpp_bootstrap_info, list) {
4339 if (id && bi->id != id)
4340 continue;
4341 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07004342#ifdef CONFIG_DPP2
4343 if (dpp->remove_bi)
4344 dpp->remove_bi(dpp->cb_ctx, bi);
4345#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004346 dl_list_del(&bi->list);
4347 dpp_bootstrap_info_free(bi);
4348 }
4349
4350 if (id == 0)
4351 return 0; /* flush succeeds regardless of entries found */
4352 return found ? 0 : -1;
4353}
4354
4355
4356struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4357 const char *uri)
4358{
4359 struct dpp_bootstrap_info *bi;
4360
4361 if (!dpp)
4362 return NULL;
4363
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004364 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -07004365 if (!bi)
4366 return NULL;
4367
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004368 bi->type = DPP_BOOTSTRAP_QR_CODE;
4369 bi->id = dpp_next_id(dpp);
4370 dl_list_add(&dpp->bootstrap, &bi->list);
4371 return bi;
4372}
4373
4374
4375struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4376 const char *uri)
4377{
4378 struct dpp_bootstrap_info *bi;
4379
4380 if (!dpp)
4381 return NULL;
4382
4383 bi = dpp_parse_uri(uri);
4384 if (!bi)
4385 return NULL;
4386
4387 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004388 bi->id = dpp_next_id(dpp);
4389 dl_list_add(&dpp->bootstrap, &bi->list);
4390 return bi;
4391}
4392
4393
Sunil Ravia04bd252022-05-02 22:54:18 -07004394static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4395 char *txt)
4396{
4397 char *token, *context = NULL;
4398 u8 curves = 0;
4399
4400 if (!txt)
4401 return 0;
4402
4403 while ((token = str_token(txt, ":", &context))) {
4404 if (os_strcmp(token, "P-256") == 0) {
4405 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4406 } else if (os_strcmp(token, "P-384") == 0) {
4407 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4408 } else if (os_strcmp(token, "P-521") == 0) {
4409 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4410 } else if (os_strcmp(token, "BP-256") == 0) {
4411 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4412 } else if (os_strcmp(token, "BP-384") == 0) {
4413 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4414 } else if (os_strcmp(token, "BP-512") == 0) {
4415 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4416 } else {
4417 wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4418 token);
4419 return -1;
4420 }
4421 }
4422 bi->supported_curves = curves;
4423
4424 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4425 bi->supported_curves);
4426
4427 return 0;
4428}
4429
4430
Hai Shalom021b0b52019-04-10 11:17:58 -07004431int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4432{
Hai Shalomfdcde762020-04-02 11:19:20 -07004433 char *mac = NULL, *info = NULL, *curve = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00004434 char *key = NULL, *supported_curves = NULL, *host = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07004435 u8 *privkey = NULL;
4436 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004437 int ret = -1;
4438 struct dpp_bootstrap_info *bi;
4439
4440 if (!dpp)
4441 return -1;
4442
4443 bi = os_zalloc(sizeof(*bi));
4444 if (!bi)
4445 goto fail;
4446
4447 if (os_strstr(cmd, "type=qrcode"))
4448 bi->type = DPP_BOOTSTRAP_QR_CODE;
4449 else if (os_strstr(cmd, "type=pkex"))
4450 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004451 else if (os_strstr(cmd, "type=nfc-uri"))
4452 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004453 else
4454 goto fail;
4455
Hai Shalomfdcde762020-04-02 11:19:20 -07004456 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004457 mac = get_param(cmd, " mac=");
4458 info = get_param(cmd, " info=");
4459 curve = get_param(cmd, " curve=");
4460 key = get_param(cmd, " key=");
Sunil Ravia04bd252022-05-02 22:54:18 -07004461 supported_curves = get_param(cmd, " supported_curves=");
Sunil8cd6f4d2022-06-28 18:40:46 +00004462 host = get_param(cmd, " host=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004463
4464 if (key) {
4465 privkey_len = os_strlen(key) / 2;
4466 privkey = os_malloc(privkey_len);
4467 if (!privkey ||
4468 hexstr2bin(key, privkey, privkey_len) < 0)
4469 goto fail;
4470 }
4471
Hai Shalomfdcde762020-04-02 11:19:20 -07004472 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4473 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4474 dpp_parse_uri_mac(bi, mac) < 0 ||
4475 dpp_parse_uri_info(bi, info) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -07004476 dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +00004477 dpp_parse_uri_host(bi, host) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004478 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07004479 goto fail;
4480
Hai Shalom021b0b52019-04-10 11:17:58 -07004481 bi->id = dpp_next_id(dpp);
4482 dl_list_add(&dpp->bootstrap, &bi->list);
4483 ret = bi->id;
4484 bi = NULL;
4485fail:
4486 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -07004487 os_free(mac);
4488 os_free(info);
4489 str_clear_free(key);
Sunil Ravia04bd252022-05-02 22:54:18 -07004490 os_free(supported_curves);
Sunil8cd6f4d2022-06-28 18:40:46 +00004491 os_free(host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004492 bin_clear_free(privkey, privkey_len);
4493 dpp_bootstrap_info_free(bi);
4494 return ret;
4495}
4496
4497
4498struct dpp_bootstrap_info *
4499dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4500{
4501 struct dpp_bootstrap_info *bi;
4502
4503 if (!dpp)
4504 return NULL;
4505
4506 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4507 if (bi->id == id)
4508 return bi;
4509 }
4510 return NULL;
4511}
4512
4513
4514int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4515{
4516 unsigned int id_val;
4517
4518 if (os_strcmp(id, "*") == 0) {
4519 id_val = 0;
4520 } else {
4521 id_val = atoi(id);
4522 if (id_val == 0)
4523 return -1;
4524 }
4525
4526 return dpp_bootstrap_del(dpp, id_val);
4527}
4528
4529
Hai Shalom021b0b52019-04-10 11:17:58 -07004530const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4531{
4532 struct dpp_bootstrap_info *bi;
4533
4534 bi = dpp_bootstrap_get_id(dpp, id);
4535 if (!bi)
4536 return NULL;
4537 return bi->uri;
4538}
4539
4540
4541int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4542 char *reply, int reply_size)
4543{
4544 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004545 char pkhash[2 * SHA256_MAC_LEN + 1];
Sunil Ravia04bd252022-05-02 22:54:18 -07004546 char supp_curves[100];
Sunil8cd6f4d2022-06-28 18:40:46 +00004547 char host[100];
4548 int ret;
Hai Shalom021b0b52019-04-10 11:17:58 -07004549
4550 bi = dpp_bootstrap_get_id(dpp, id);
4551 if (!bi)
4552 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07004553 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4554 SHA256_MAC_LEN);
Sunil Ravia04bd252022-05-02 22:54:18 -07004555
4556 supp_curves[0] = '\0';
4557 if (bi->supported_curves) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004558 size_t i;
4559 char *pos = supp_curves;
4560 char *end = &supp_curves[sizeof(supp_curves)];
4561 const char *curve[6] = { "P-256", "P-384", "P-521",
4562 "BP-256", "BP-384", "BP-512" };
4563
4564 ret = os_snprintf(pos, end - pos, "supp_curves=");
4565 if (os_snprintf_error(end - pos, ret))
4566 return -1;
4567 pos += ret;
4568
4569 for (i = 0; i < ARRAY_SIZE(curve); i++) {
4570 if (!(bi->supported_curves & BIT(i)))
4571 continue;
4572 ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4573 if (os_snprintf_error(end - pos, ret))
4574 return -1;
4575 pos += ret;
4576 }
4577
4578 if (pos[-1] == ':')
4579 pos[-1] = '\n';
4580 else
4581 supp_curves[0] = '\0';
4582 }
4583
Sunil8cd6f4d2022-06-28 18:40:46 +00004584 host[0] = '\0';
4585 if (bi->host) {
4586 char buf[100];
4587
4588 ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4589 hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4590 bi->port);
4591 if (os_snprintf_error(sizeof(host), ret))
4592 return -1;
4593 }
4594
Hai Shalom021b0b52019-04-10 11:17:58 -07004595 return os_snprintf(reply, reply_size, "type=%s\n"
4596 "mac_addr=" MACSTR "\n"
4597 "info=%s\n"
4598 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -07004599 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07004600 "curve=%s\n"
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004601 "pkhash=%s\n"
Sunil8cd6f4d2022-06-28 18:40:46 +00004602 "version=%d\n%s%s",
Hai Shalom021b0b52019-04-10 11:17:58 -07004603 dpp_bootstrap_type_txt(bi->type),
4604 MAC2STR(bi->mac_addr),
4605 bi->info ? bi->info : "",
4606 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07004607 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -07004608 bi->curve->name,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004609 pkhash,
Sunil Ravia04bd252022-05-02 22:54:18 -07004610 bi->version,
Sunil8cd6f4d2022-06-28 18:40:46 +00004611 supp_curves,
4612 host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004613}
4614
4615
Hai Shalomfdcde762020-04-02 11:19:20 -07004616int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4617{
4618 struct dpp_bootstrap_info *bi;
4619
4620 bi = dpp_bootstrap_get_id(dpp, id);
4621 if (!bi)
4622 return -1;
4623
4624 str_clear_free(bi->configurator_params);
4625
4626 if (params) {
4627 bi->configurator_params = os_strdup(params);
4628 return bi->configurator_params ? 0 : -1;
4629 }
4630
4631 bi->configurator_params = NULL;
4632 return 0;
4633}
4634
4635
Hai Shalom021b0b52019-04-10 11:17:58 -07004636void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4637 const u8 *r_bootstrap,
4638 struct dpp_bootstrap_info **own_bi,
4639 struct dpp_bootstrap_info **peer_bi)
4640{
4641 struct dpp_bootstrap_info *bi;
4642
4643 *own_bi = NULL;
4644 *peer_bi = NULL;
4645 if (!dpp)
4646 return;
4647
4648 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4649 if (!*own_bi && bi->own &&
4650 os_memcmp(bi->pubkey_hash, r_bootstrap,
4651 SHA256_MAC_LEN) == 0) {
4652 wpa_printf(MSG_DEBUG,
4653 "DPP: Found matching own bootstrapping information");
4654 *own_bi = bi;
4655 }
4656
4657 if (!*peer_bi && !bi->own &&
4658 os_memcmp(bi->pubkey_hash, i_bootstrap,
4659 SHA256_MAC_LEN) == 0) {
4660 wpa_printf(MSG_DEBUG,
4661 "DPP: Found matching peer bootstrapping information");
4662 *peer_bi = bi;
4663 }
4664
4665 if (*own_bi && *peer_bi)
4666 break;
4667 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004668}
Hai Shalom021b0b52019-04-10 11:17:58 -07004669
Hai Shalomfdcde762020-04-02 11:19:20 -07004670
4671#ifdef CONFIG_DPP2
4672struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4673 const u8 *hash)
4674{
4675 struct dpp_bootstrap_info *bi;
4676
4677 if (!dpp)
4678 return NULL;
4679
4680 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4681 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4682 SHA256_MAC_LEN) == 0)
4683 return bi;
4684 }
4685
4686 return NULL;
4687}
4688#endif /* CONFIG_DPP2 */
4689
4690
4691static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4692 struct dpp_bootstrap_info *peer_bi)
4693{
4694 unsigned int i, freq = 0;
4695 enum hostapd_hw_mode mode;
4696 u8 op_class, channel;
4697 char chan[20];
4698
Hai Shalom899fcc72020-10-19 14:38:18 -07004699 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
Hai Shalomfdcde762020-04-02 11:19:20 -07004700 return 0; /* no channel preference/constraint */
4701
4702 for (i = 0; i < peer_bi->num_freq; i++) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004703 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004704 freq_included(own_bi->freq, own_bi->num_freq,
4705 peer_bi->freq[i])) {
4706 freq = peer_bi->freq[i];
4707 break;
4708 }
4709 }
4710 if (!freq) {
4711 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4712 return -1;
4713 }
4714
4715 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4716 if (mode == NUM_HOSTAPD_MODES) {
4717 wpa_printf(MSG_DEBUG,
4718 "DPP: Could not determine operating class or channel number for %u MHz",
4719 freq);
4720 }
4721
4722 wpa_printf(MSG_DEBUG,
4723 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4724 freq, op_class, channel);
4725 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4726 os_free(own_bi->chan);
4727 own_bi->chan = os_strdup(chan);
4728 own_bi->freq[0] = freq;
4729 own_bi->num_freq = 1;
4730 os_free(peer_bi->chan);
4731 peer_bi->chan = os_strdup(chan);
4732 peer_bi->freq[0] = freq;
4733 peer_bi->num_freq = 1;
4734
4735 return dpp_gen_uri(own_bi);
4736}
4737
4738
4739static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4740 struct dpp_bootstrap_info *peer_bi)
4741{
4742 if (peer_bi->curve == own_bi->curve)
4743 return 0;
4744
4745 wpa_printf(MSG_DEBUG,
4746 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4747
Hai Shaloma20dcd72022-02-04 13:43:00 -08004748 crypto_ec_key_deinit(own_bi->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -07004749 own_bi->pubkey = NULL;
4750
4751 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4752 dpp_gen_uri(own_bi) < 0)
4753 goto fail;
4754
4755 return 0;
4756fail:
4757 dl_list_del(&own_bi->list);
4758 dpp_bootstrap_info_free(own_bi);
4759 return -1;
4760}
4761
4762
4763int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4764 struct dpp_bootstrap_info *peer_bi)
4765{
4766 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4767 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4768 return -1;
4769 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004770}
4771
4772
4773static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4774{
4775 struct dpp_configurator *conf;
4776 unsigned int max_id = 0;
4777
4778 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4779 list) {
4780 if (conf->id > max_id)
4781 max_id = conf->id;
4782 }
4783 return max_id + 1;
4784}
4785
4786
4787int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4788{
Sunil Ravia04bd252022-05-02 22:54:18 -07004789 char *curve;
Hai Shalom899fcc72020-10-19 14:38:18 -07004790 char *key = NULL, *ppkey = NULL;
4791 u8 *privkey = NULL, *pp_key = NULL;
4792 size_t privkey_len = 0, pp_key_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004793 int ret = -1;
4794 struct dpp_configurator *conf = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07004795 const struct dpp_curve_params *net_access_key_curve = NULL;
4796
4797 curve = get_param(cmd, " net_access_key_curve=");
4798 if (curve) {
4799 net_access_key_curve = dpp_get_curve_name(curve);
4800 if (!net_access_key_curve) {
4801 wpa_printf(MSG_DEBUG,
4802 "DPP: Unsupported net_access_key_curve: %s",
4803 curve);
4804 goto fail;
4805 }
4806 os_free(curve);
4807 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004808
4809 curve = get_param(cmd, " curve=");
4810 key = get_param(cmd, " key=");
Hai Shalom899fcc72020-10-19 14:38:18 -07004811 ppkey = get_param(cmd, " ppkey=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004812
4813 if (key) {
4814 privkey_len = os_strlen(key) / 2;
4815 privkey = os_malloc(privkey_len);
4816 if (!privkey ||
4817 hexstr2bin(key, privkey, privkey_len) < 0)
4818 goto fail;
4819 }
4820
Hai Shalom899fcc72020-10-19 14:38:18 -07004821 if (ppkey) {
Hai Shalom60840252021-02-19 19:02:11 -08004822 pp_key_len = os_strlen(ppkey) / 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07004823 pp_key = os_malloc(pp_key_len);
4824 if (!pp_key ||
4825 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4826 goto fail;
4827 }
4828
4829 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4830 pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004831 if (!conf)
4832 goto fail;
4833
Sunil Ravia04bd252022-05-02 22:54:18 -07004834 conf->net_access_key_curve = net_access_key_curve;
Hai Shalom021b0b52019-04-10 11:17:58 -07004835 conf->id = dpp_next_configurator_id(dpp);
4836 dl_list_add(&dpp->configurator, &conf->list);
4837 ret = conf->id;
4838 conf = NULL;
4839fail:
4840 os_free(curve);
4841 str_clear_free(key);
Hai Shalom899fcc72020-10-19 14:38:18 -07004842 str_clear_free(ppkey);
Hai Shalom021b0b52019-04-10 11:17:58 -07004843 bin_clear_free(privkey, privkey_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004844 bin_clear_free(pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004845 dpp_configurator_free(conf);
4846 return ret;
4847}
4848
4849
Sunil Ravia04bd252022-05-02 22:54:18 -07004850int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4851{
4852 unsigned int id;
4853 struct dpp_configurator *conf;
4854 char *curve;
4855
4856 id = atoi(cmd);
4857 conf = dpp_configurator_get_id(dpp, id);
4858 if (!conf)
4859 return -1;
4860
4861 curve = get_param(cmd, " net_access_key_curve=");
4862 if (curve) {
4863 const struct dpp_curve_params *net_access_key_curve;
4864
4865 net_access_key_curve = dpp_get_curve_name(curve);
4866 os_free(curve);
4867 if (!net_access_key_curve)
4868 return -1;
4869 conf->net_access_key_curve = net_access_key_curve;
4870 }
4871
4872 return 0;
4873}
4874
4875
Hai Shalom021b0b52019-04-10 11:17:58 -07004876static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4877{
4878 struct dpp_configurator *conf, *tmp;
4879 int found = 0;
4880
4881 if (!dpp)
4882 return -1;
4883
4884 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4885 struct dpp_configurator, list) {
4886 if (id && conf->id != id)
4887 continue;
4888 found = 1;
4889 dl_list_del(&conf->list);
4890 dpp_configurator_free(conf);
4891 }
4892
4893 if (id == 0)
4894 return 0; /* flush succeeds regardless of entries found */
4895 return found ? 0 : -1;
4896}
4897
4898
4899int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4900{
4901 unsigned int id_val;
4902
4903 if (os_strcmp(id, "*") == 0) {
4904 id_val = 0;
4905 } else {
4906 id_val = atoi(id);
4907 if (id_val == 0)
4908 return -1;
4909 }
4910
4911 return dpp_configurator_del(dpp, id_val);
4912}
4913
4914
4915int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4916 char *buf, size_t buflen)
4917{
4918 struct dpp_configurator *conf;
4919
4920 conf = dpp_configurator_get_id(dpp, id);
4921 if (!conf)
4922 return -1;
4923
4924 return dpp_configurator_get_key(conf, buf, buflen);
4925}
4926
4927
Hai Shalom81f62d82019-07-22 12:10:00 -07004928#ifdef CONFIG_DPP2
4929
Hai Shalomfdcde762020-04-02 11:19:20 -07004930int dpp_configurator_from_backup(struct dpp_global *dpp,
4931 struct dpp_asymmetric_key *key)
4932{
4933 struct dpp_configurator *conf;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004934 const struct dpp_curve_params *curve, *curve_pp;
Hai Shalomfdcde762020-04-02 11:19:20 -07004935
Hai Shalom899fcc72020-10-19 14:38:18 -07004936 if (!key->csign || !key->pp_key)
Hai Shalomfdcde762020-04-02 11:19:20 -07004937 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004938
4939 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
Hai Shalomfdcde762020-04-02 11:19:20 -07004940 if (!curve) {
4941 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4942 return -1;
4943 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08004944
4945 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
4946 if (!curve_pp) {
4947 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
Hai Shalom899fcc72020-10-19 14:38:18 -07004948 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004949 }
4950
4951 if (curve != curve_pp) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004952 wpa_printf(MSG_INFO,
4953 "DPP: Mismatch in c-sign-key and ppKey groups");
4954 return -1;
4955 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004956
4957 conf = os_zalloc(sizeof(*conf));
4958 if (!conf)
4959 return -1;
4960 conf->curve = curve;
4961 conf->csign = key->csign;
4962 key->csign = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07004963 conf->pp_key = key->pp_key;
4964 key->pp_key = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07004965 conf->own = 1;
4966 if (dpp_configurator_gen_kid(conf) < 0) {
4967 dpp_configurator_free(conf);
4968 return -1;
4969 }
4970
4971 conf->id = dpp_next_configurator_id(dpp);
4972 dl_list_add(&dpp->configurator, &conf->list);
4973 return conf->id;
4974}
4975
4976
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004977struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4978 const u8 *kid)
Hai Shalom81f62d82019-07-22 12:10:00 -07004979{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004980 struct dpp_configurator *conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004981
4982 if (!dpp)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004983 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004984
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004985 dl_list_for_each(conf, &dpp->configurator,
4986 struct dpp_configurator, list) {
4987 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4988 return conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004989 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004990 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004991}
4992
4993#endif /* CONFIG_DPP2 */
4994
4995
4996struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07004997{
4998 struct dpp_global *dpp;
4999
5000 dpp = os_zalloc(sizeof(*dpp));
5001 if (!dpp)
5002 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07005003#ifdef CONFIG_DPP2
5004 dpp->cb_ctx = config->cb_ctx;
Hai Shalomfdcde762020-04-02 11:19:20 -07005005 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07005006#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005007
5008 dl_list_init(&dpp->bootstrap);
5009 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07005010#ifdef CONFIG_DPP2
5011 dl_list_init(&dpp->controllers);
5012 dl_list_init(&dpp->tcp_init);
Sunil Ravi89eba102022-09-13 21:04:37 -07005013 dpp->relay_sock = -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07005014#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005015
5016 return dpp;
5017}
5018
5019
5020void dpp_global_clear(struct dpp_global *dpp)
5021{
5022 if (!dpp)
5023 return;
5024
5025 dpp_bootstrap_del(dpp, 0);
5026 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07005027#ifdef CONFIG_DPP2
5028 dpp_tcp_init_flush(dpp);
5029 dpp_relay_flush_controllers(dpp);
5030 dpp_controller_stop(dpp);
5031#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07005032}
5033
5034
5035void dpp_global_deinit(struct dpp_global *dpp)
5036{
5037 dpp_global_clear(dpp);
5038 os_free(dpp);
5039}
Hai Shalom81f62d82019-07-22 12:10:00 -07005040
5041
5042#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07005043
Hai Shalomfdcde762020-04-02 11:19:20 -07005044struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5045{
5046 struct wpabuf *msg;
5047
5048 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5049
5050 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5051 if (!msg)
5052 return NULL;
5053
5054 /* Responder Bootstrapping Key Hash */
5055 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5056 wpa_hexdump_buf(MSG_DEBUG,
5057 "DPP: Presence Announcement frame attributes", msg);
5058 return msg;
5059}
Hai Shalom899fcc72020-10-19 14:38:18 -07005060
5061
5062void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5063 unsigned int freq, const u8 *hash)
5064{
5065 char hex[SHA256_MAC_LEN * 2 + 1];
5066
5067 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5068 wpa_msg(msg_ctx, MSG_INFO,
5069 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5070 id, MAC2STR(src), freq, hex);
5071}
5072
Hai Shalom81f62d82019-07-22 12:10:00 -07005073#endif /* CONFIG_DPP2 */
Sunil Ravi89eba102022-09-13 21:04:37 -07005074
5075
5076#ifdef CONFIG_DPP3
5077
5078struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5079{
5080 struct wpabuf *msg;
5081 const u8 *r_hash = bi->pubkey_hash_chirp;
5082#ifdef CONFIG_TESTING_OPTIONS
5083 u8 test_hash[SHA256_MAC_LEN];
5084#endif /* CONFIG_TESTING_OPTIONS */
5085
5086 wpa_printf(MSG_DEBUG,
5087 "DPP: Build Push Button Presence Announcement frame");
5088
5089 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5090 4 + SHA256_MAC_LEN);
5091 if (!msg)
5092 return NULL;
5093
5094#ifdef CONFIG_TESTING_OPTIONS
5095 if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5096 wpa_printf(MSG_INFO,
5097 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5098 os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5099 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5100 r_hash = test_hash;
5101 }
5102#endif /* CONFIG_TESTING_OPTIONS */
5103
5104 /* Responder Bootstrapping Key Hash */
5105 dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5106 wpa_hexdump_buf(MSG_DEBUG,
5107 "DPP: Push Button Presence Announcement frame attributes",
5108 msg);
5109 return msg;
5110}
5111
5112
5113struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5114 const u8 *e_hash,
5115 const u8 *c_nonce,
5116 size_t c_nonce_len)
5117{
5118 struct wpabuf *msg;
5119 const u8 *i_hash = bi->pubkey_hash_chirp;
5120#ifdef CONFIG_TESTING_OPTIONS
5121 u8 test_hash[SHA256_MAC_LEN];
5122#endif /* CONFIG_TESTING_OPTIONS */
5123
5124 wpa_printf(MSG_DEBUG,
5125 "DPP: Build Push Button Presence Announcement Response frame");
5126
5127 msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5128 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5129 if (!msg)
5130 return NULL;
5131
5132#ifdef CONFIG_TESTING_OPTIONS
5133 if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5134 wpa_printf(MSG_INFO,
5135 "DPP: TESTING - invalid I-Bootstrap Key Hash");
5136 os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5137 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5138 i_hash = test_hash;
5139 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5140 wpa_printf(MSG_INFO,
5141 "DPP: TESTING - invalid R-Bootstrap Key Hash");
5142 os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5143 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5144 e_hash = test_hash;
5145 }
5146#endif /* CONFIG_TESTING_OPTIONS */
5147
5148 /* Initiator Bootstrapping Key Hash */
5149 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5150 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5151 wpabuf_put_le16(msg, SHA256_MAC_LEN);
5152 wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5153
5154 /* Responder Bootstrapping Key Hash */
5155 dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5156
5157 /* Configurator Nonce */
5158 wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5159 wpabuf_put_le16(msg, c_nonce_len);
5160 wpabuf_put_data(msg, c_nonce, c_nonce_len);
5161
5162 wpa_hexdump_buf(MSG_DEBUG,
5163 "DPP: Push Button Presence Announcement Response frame attributes",
5164 msg);
5165 return msg;
5166}
5167
5168#endif /* CONFIG_DPP3 */