blob: fcc52416a4ea176b8bd314c18b3d7a4d19a537cd [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,
Hai Shalomc3565922019-10-28 11:58:20 -0700972 const char *mud_url, int *opclasses)
973{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800974 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -0700975 const char *tech = "infra";
976 const char *dpp_name;
Sunil Ravia04bd252022-05-02 22:54:18 -0700977 struct wpabuf *buf = NULL, *json = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700978 char *csr = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700979
980#ifdef CONFIG_TESTING_OPTIONS
981 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
982 static const char *bogus_tech = "knfra";
983
984 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
985 tech = bogus_tech;
986 }
987#endif /* CONFIG_TESTING_OPTIONS */
988
989 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800990 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -0700991
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800992 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -0700993 if (mud_url && mud_url[0])
994 len += 10 + os_strlen(mud_url);
Hai Shalom899fcc72020-10-19 14:38:18 -0700995#ifdef CONFIG_DPP2
996 if (auth->csr) {
997 size_t csr_len;
998
999 csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1000 wpabuf_len(auth->csr), &csr_len);
1001 if (!csr)
Sunil Ravia04bd252022-05-02 22:54:18 -07001002 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07001003 len += 30 + csr_len;
1004 }
1005#endif /* CONFIG_DPP2 */
Hai Shalomc3565922019-10-28 11:58:20 -07001006 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001007 if (!json)
Sunil Ravia04bd252022-05-02 22:54:18 -07001008 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001009
1010 json_start_object(json, NULL);
Sunil Ravia04bd252022-05-02 22:54:18 -07001011 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1012 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001013 json_value_sep(json);
1014 json_add_string(json, "wi-fi_tech", tech);
1015 json_value_sep(json);
1016 json_add_string(json, "netRole", dpp_netrole_str(netrole));
1017 if (mud_url && mud_url[0]) {
1018 json_value_sep(json);
1019 json_add_string(json, "mudurl", mud_url);
1020 }
Hai Shalomc3565922019-10-28 11:58:20 -07001021 if (opclasses) {
1022 int i;
1023
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001024 json_value_sep(json);
1025 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -07001026 for (i = 0; opclasses[i]; i++)
1027 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001028 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001029 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001030 if (csr) {
1031 json_value_sep(json);
1032 json_add_string(json, "pkcs10", csr);
1033 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001034 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -07001035
1036 buf = dpp_build_conf_req(auth, wpabuf_head(json));
Sunil Ravia04bd252022-05-02 22:54:18 -07001037fail:
Hai Shalomc3565922019-10-28 11:58:20 -07001038 wpabuf_free(json);
Hai Shalom899fcc72020-10-19 14:38:18 -07001039 os_free(csr);
Hai Shalomc3565922019-10-28 11:58:20 -07001040
1041 return buf;
1042}
1043
1044
Hai Shalom021b0b52019-04-10 11:17:58 -07001045static int bin_str_eq(const char *val, size_t len, const char *cmp)
1046{
1047 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1048}
1049
1050
1051struct dpp_configuration * dpp_configuration_alloc(const char *type)
1052{
1053 struct dpp_configuration *conf;
1054 const char *end;
1055 size_t len;
1056
1057 conf = os_zalloc(sizeof(*conf));
1058 if (!conf)
1059 goto fail;
1060
1061 end = os_strchr(type, ' ');
1062 if (end)
1063 len = end - type;
1064 else
1065 len = os_strlen(type);
1066
1067 if (bin_str_eq(type, len, "psk"))
1068 conf->akm = DPP_AKM_PSK;
1069 else if (bin_str_eq(type, len, "sae"))
1070 conf->akm = DPP_AKM_SAE;
1071 else if (bin_str_eq(type, len, "psk-sae") ||
1072 bin_str_eq(type, len, "psk+sae"))
1073 conf->akm = DPP_AKM_PSK_SAE;
1074 else if (bin_str_eq(type, len, "sae-dpp") ||
1075 bin_str_eq(type, len, "dpp+sae"))
1076 conf->akm = DPP_AKM_SAE_DPP;
1077 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1078 bin_str_eq(type, len, "dpp+psk+sae"))
1079 conf->akm = DPP_AKM_PSK_SAE_DPP;
1080 else if (bin_str_eq(type, len, "dpp"))
1081 conf->akm = DPP_AKM_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07001082 else if (bin_str_eq(type, len, "dot1x"))
1083 conf->akm = DPP_AKM_DOT1X;
Hai Shalom021b0b52019-04-10 11:17:58 -07001084 else
1085 goto fail;
1086
1087 return conf;
1088fail:
1089 dpp_configuration_free(conf);
1090 return NULL;
1091}
1092
1093
1094int dpp_akm_psk(enum dpp_akm akm)
1095{
1096 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1097 akm == DPP_AKM_PSK_SAE_DPP;
1098}
1099
1100
1101int dpp_akm_sae(enum dpp_akm akm)
1102{
1103 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1104 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1105}
1106
1107
1108int dpp_akm_legacy(enum dpp_akm akm)
1109{
1110 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1111 akm == DPP_AKM_SAE;
1112}
1113
1114
1115int dpp_akm_dpp(enum dpp_akm akm)
1116{
1117 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1118 akm == DPP_AKM_PSK_SAE_DPP;
1119}
1120
1121
1122int dpp_akm_ver2(enum dpp_akm akm)
1123{
1124 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1125}
1126
1127
1128int dpp_configuration_valid(const struct dpp_configuration *conf)
1129{
1130 if (conf->ssid_len == 0)
1131 return 0;
1132 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1133 return 0;
1134 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1135 return 0;
1136 return 1;
1137}
1138
1139
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001140void dpp_configuration_free(struct dpp_configuration *conf)
1141{
1142 if (!conf)
1143 return;
1144 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -07001145 os_free(conf->group_id);
Hai Shalom899fcc72020-10-19 14:38:18 -07001146 os_free(conf->csrattrs);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001147 bin_clear_free(conf, sizeof(*conf));
1148}
1149
1150
Hai Shalomc3565922019-10-28 11:58:20 -07001151static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1152 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -07001153{
1154 const char *pos, *end;
1155 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1156 struct dpp_configuration *conf = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001157 size_t len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001158
1159 pos = os_strstr(cmd, " conf=sta-");
1160 if (pos) {
1161 conf_sta = dpp_configuration_alloc(pos + 10);
1162 if (!conf_sta)
1163 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001164 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07001165 conf = conf_sta;
1166 }
1167
1168 pos = os_strstr(cmd, " conf=ap-");
1169 if (pos) {
1170 conf_ap = dpp_configuration_alloc(pos + 9);
1171 if (!conf_ap)
1172 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001173 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07001174 conf = conf_ap;
1175 }
1176
Hai Shalomfdcde762020-04-02 11:19:20 -07001177 pos = os_strstr(cmd, " conf=configurator");
1178 if (pos)
1179 auth->provision_configurator = 1;
1180
Hai Shalom021b0b52019-04-10 11:17:58 -07001181 if (!conf)
1182 return 0;
1183
1184 pos = os_strstr(cmd, " ssid=");
1185 if (pos) {
1186 pos += 6;
1187 end = os_strchr(pos, ' ');
1188 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1189 conf->ssid_len /= 2;
1190 if (conf->ssid_len > sizeof(conf->ssid) ||
1191 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1192 goto fail;
1193 } else {
1194#ifdef CONFIG_TESTING_OPTIONS
1195 /* use a default SSID for legacy testing reasons */
1196 os_memcpy(conf->ssid, "test", 4);
1197 conf->ssid_len = 4;
1198#else /* CONFIG_TESTING_OPTIONS */
1199 goto fail;
1200#endif /* CONFIG_TESTING_OPTIONS */
1201 }
1202
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001203 pos = os_strstr(cmd, " ssid_charset=");
1204 if (pos) {
1205 if (conf_ap) {
1206 wpa_printf(MSG_INFO,
1207 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1208 goto fail;
1209 }
1210 conf->ssid_charset = atoi(pos + 14);
1211 }
1212
Hai Shalom021b0b52019-04-10 11:17:58 -07001213 pos = os_strstr(cmd, " pass=");
1214 if (pos) {
1215 size_t pass_len;
1216
1217 pos += 6;
1218 end = os_strchr(pos, ' ');
1219 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1220 pass_len /= 2;
1221 if (pass_len > 63 || pass_len < 8)
1222 goto fail;
1223 conf->passphrase = os_zalloc(pass_len + 1);
1224 if (!conf->passphrase ||
1225 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1226 goto fail;
1227 }
1228
1229 pos = os_strstr(cmd, " psk=");
1230 if (pos) {
1231 pos += 5;
1232 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1233 goto fail;
1234 conf->psk_set = 1;
1235 }
1236
1237 pos = os_strstr(cmd, " group_id=");
1238 if (pos) {
1239 size_t group_id_len;
1240
1241 pos += 10;
1242 end = os_strchr(pos, ' ');
1243 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1244 conf->group_id = os_malloc(group_id_len + 1);
1245 if (!conf->group_id)
1246 goto fail;
1247 os_memcpy(conf->group_id, pos, group_id_len);
1248 conf->group_id[group_id_len] = '\0';
1249 }
1250
1251 pos = os_strstr(cmd, " expiry=");
1252 if (pos) {
1253 long int val;
1254
1255 pos += 8;
1256 val = strtol(pos, NULL, 0);
1257 if (val <= 0)
1258 goto fail;
1259 conf->netaccesskey_expiry = val;
1260 }
1261
Hai Shalom899fcc72020-10-19 14:38:18 -07001262 pos = os_strstr(cmd, " csrattrs=");
1263 if (pos) {
1264 pos += 10;
1265 end = os_strchr(pos, ' ');
1266 len = end ? (size_t) (end - pos) : os_strlen(pos);
1267 conf->csrattrs = os_zalloc(len + 1);
1268 if (!conf->csrattrs)
1269 goto fail;
1270 os_memcpy(conf->csrattrs, pos, len);
1271 }
1272
Hai Shalom021b0b52019-04-10 11:17:58 -07001273 if (!dpp_configuration_valid(conf))
1274 goto fail;
1275
Hai Shalomc3565922019-10-28 11:58:20 -07001276 if (idx == 0) {
1277 auth->conf_sta = conf_sta;
1278 auth->conf_ap = conf_ap;
1279 } else if (idx == 1) {
1280 auth->conf2_sta = conf_sta;
1281 auth->conf2_ap = conf_ap;
1282 } else {
1283 goto fail;
1284 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001285 return 0;
1286
1287fail:
1288 dpp_configuration_free(conf_sta);
1289 dpp_configuration_free(conf_ap);
1290 return -1;
1291}
1292
1293
Hai Shalomc3565922019-10-28 11:58:20 -07001294static int dpp_configuration_parse(struct dpp_authentication *auth,
1295 const char *cmd)
1296{
1297 const char *pos;
1298 char *tmp;
1299 size_t len;
1300 int res;
1301
1302 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1303 if (!pos)
1304 return dpp_configuration_parse_helper(auth, cmd, 0);
1305
1306 len = pos - cmd;
1307 tmp = os_malloc(len + 1);
1308 if (!tmp)
1309 goto fail;
1310 os_memcpy(tmp, cmd, len);
1311 tmp[len] = '\0';
1312 res = dpp_configuration_parse_helper(auth, cmd, 0);
1313 str_clear_free(tmp);
1314 if (res)
1315 goto fail;
1316 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1317 if (res)
1318 goto fail;
1319 return 0;
1320fail:
1321 dpp_configuration_free(auth->conf_sta);
1322 dpp_configuration_free(auth->conf2_sta);
1323 dpp_configuration_free(auth->conf_ap);
1324 dpp_configuration_free(auth->conf2_ap);
1325 return -1;
1326}
1327
1328
Hai Shalom021b0b52019-04-10 11:17:58 -07001329static struct dpp_configurator *
1330dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1331{
1332 struct dpp_configurator *conf;
1333
1334 if (!dpp)
1335 return NULL;
1336
1337 dl_list_for_each(conf, &dpp->configurator,
1338 struct dpp_configurator, list) {
1339 if (conf->id == id)
1340 return conf;
1341 }
1342 return NULL;
1343}
1344
1345
Hai Shalomfdcde762020-04-02 11:19:20 -07001346int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07001347{
1348 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07001349 char *tmp = NULL;
1350 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07001351
Hai Shalomfdcde762020-04-02 11:19:20 -07001352 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07001353 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07001354 auth->configurator_set = 1;
1355
1356 if (cmd[0] != ' ') {
1357 size_t len;
1358
1359 len = os_strlen(cmd);
1360 tmp = os_malloc(len + 2);
1361 if (!tmp)
1362 goto fail;
1363 tmp[0] = ' ';
1364 os_memcpy(tmp + 1, cmd, len + 1);
1365 cmd = tmp;
1366 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001367
1368 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1369
Hai Shaloma20dcd72022-02-04 13:43:00 -08001370 if (os_strstr(cmd, " conf=query")) {
1371 auth->configurator_set = 0;
1372 auth->use_config_query = true;
1373 ret = 0;
1374 goto fail;
1375 }
1376
Hai Shalom021b0b52019-04-10 11:17:58 -07001377 pos = os_strstr(cmd, " configurator=");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001378 if (!auth->conf && pos) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001379 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07001380 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07001381 if (!auth->conf) {
1382 wpa_printf(MSG_INFO,
1383 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07001384 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001385 }
1386 }
1387
Hai Shalomc3565922019-10-28 11:58:20 -07001388 pos = os_strstr(cmd, " conn_status=");
1389 if (pos) {
1390 pos += 13;
1391 auth->send_conn_status = atoi(pos);
1392 }
1393
1394 pos = os_strstr(cmd, " akm_use_selector=");
1395 if (pos) {
1396 pos += 18;
1397 auth->akm_use_selector = atoi(pos);
1398 }
1399
Hai Shalom021b0b52019-04-10 11:17:58 -07001400 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001401 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07001402 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07001403 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001404 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001405 ret = 0;
1406fail:
1407 os_free(tmp);
1408 return ret;
1409}
1410
1411
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001412void dpp_auth_deinit(struct dpp_authentication *auth)
1413{
Hai Shalomc3565922019-10-28 11:58:20 -07001414 unsigned int i;
1415
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001416 if (!auth)
1417 return;
1418 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07001419 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001420 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001421 dpp_configuration_free(auth->conf2_sta);
Hai Shaloma20dcd72022-02-04 13:43:00 -08001422 crypto_ec_key_deinit(auth->own_protocol_key);
1423 crypto_ec_key_deinit(auth->peer_protocol_key);
1424 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001425 wpabuf_free(auth->req_msg);
1426 wpabuf_free(auth->resp_msg);
1427 wpabuf_free(auth->conf_req);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001428 wpabuf_free(auth->reconfig_req_msg);
1429 wpabuf_free(auth->reconfig_resp_msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001430 for (i = 0; i < auth->num_conf_obj; i++) {
1431 struct dpp_config_obj *conf = &auth->conf_obj[i];
1432
1433 os_free(conf->connector);
1434 wpabuf_free(conf->c_sign_key);
Hai Shalom899fcc72020-10-19 14:38:18 -07001435 wpabuf_free(conf->certbag);
1436 wpabuf_free(conf->certs);
1437 wpabuf_free(conf->cacert);
1438 os_free(conf->server_name);
1439 wpabuf_free(conf->pp_key);
Hai Shalomc3565922019-10-28 11:58:20 -07001440 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001441#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -07001442 dpp_free_asymmetric_key(auth->conf_key_pkg);
Hai Shalom899fcc72020-10-19 14:38:18 -07001443 os_free(auth->csrattrs);
1444 wpabuf_free(auth->csr);
1445 wpabuf_free(auth->priv_key);
1446 wpabuf_free(auth->cacert);
1447 wpabuf_free(auth->certbag);
1448 os_free(auth->trusted_eap_server_name);
1449 wpabuf_free(auth->conf_resp_tcp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001450#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001451 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001452 dpp_bootstrap_info_free(auth->tmp_own_bi);
Hai Shalom899fcc72020-10-19 14:38:18 -07001453 if (auth->tmp_peer_bi) {
1454 dl_list_del(&auth->tmp_peer_bi->list);
1455 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1456 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001457 os_free(auth->e_name);
1458 os_free(auth->e_mud_url);
1459 os_free(auth->e_band_support);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001460#ifdef CONFIG_TESTING_OPTIONS
1461 os_free(auth->config_obj_override);
1462 os_free(auth->discovery_override);
1463 os_free(auth->groups_override);
1464#endif /* CONFIG_TESTING_OPTIONS */
1465 bin_clear_free(auth, sizeof(*auth));
1466}
1467
1468
1469static struct wpabuf *
1470dpp_build_conf_start(struct dpp_authentication *auth,
1471 struct dpp_configuration *conf, size_t tailroom)
1472{
1473 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001474
1475#ifdef CONFIG_TESTING_OPTIONS
1476 if (auth->discovery_override)
1477 tailroom += os_strlen(auth->discovery_override);
1478#endif /* CONFIG_TESTING_OPTIONS */
1479
1480 buf = wpabuf_alloc(200 + tailroom);
1481 if (!buf)
1482 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001483 json_start_object(buf, NULL);
1484 json_add_string(buf, "wi-fi_tech", "infra");
1485 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001486#ifdef CONFIG_TESTING_OPTIONS
1487 if (auth->discovery_override) {
1488 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1489 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001490 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001491 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001492 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001493 return buf;
1494 }
1495#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001496 json_start_object(buf, "discovery");
1497 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1498 json_add_string_escape(buf, "ssid", conf->ssid,
1499 conf->ssid_len) < 0) ||
1500 ((conf->ssid_charset && auth->peer_version >= 2) &&
1501 json_add_base64url(buf, "ssid64", conf->ssid,
1502 conf->ssid_len) < 0)) {
1503 wpabuf_free(buf);
1504 return NULL;
1505 }
1506 if (conf->ssid_charset > 0) {
1507 json_value_sep(buf);
1508 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1509 }
1510 json_end_object(buf);
1511 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001512
1513 return buf;
1514}
1515
1516
Hai Shaloma20dcd72022-02-04 13:43:00 -08001517int dpp_build_jwk(struct wpabuf *buf, const char *name,
1518 struct crypto_ec_key *key, const char *kid,
1519 const struct dpp_curve_params *curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001520{
1521 struct wpabuf *pub;
1522 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001523 int ret = -1;
1524
Hai Shaloma20dcd72022-02-04 13:43:00 -08001525 pub = crypto_ec_key_get_pubkey_point(key, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001526 if (!pub)
1527 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001528
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001529 json_start_object(buf, name);
1530 json_add_string(buf, "kty", "EC");
1531 json_value_sep(buf);
1532 json_add_string(buf, "crv", curve->jwk_crv);
1533 json_value_sep(buf);
1534 pos = wpabuf_head(pub);
1535 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1536 goto fail;
1537 json_value_sep(buf);
1538 pos += curve->prime_len;
1539 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1540 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001541 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001542 json_value_sep(buf);
1543 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001544 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001545 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001546 ret = 0;
1547fail:
1548 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001549 return ret;
1550}
1551
1552
Hai Shalom021b0b52019-04-10 11:17:58 -07001553static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1554 struct dpp_configuration *conf)
1555{
1556 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001557 json_add_string_escape(buf, "pass", conf->passphrase,
1558 os_strlen(conf->passphrase));
Hai Shalom021b0b52019-04-10 11:17:58 -07001559 } else if (conf->psk_set) {
1560 char psk[2 * sizeof(conf->psk) + 1];
1561
1562 wpa_snprintf_hex(psk, sizeof(psk),
1563 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001564 json_add_string(buf, "psk_hex", psk);
1565 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07001566 }
1567}
1568
1569
Hai Shaloma20dcd72022-02-04 13:43:00 -08001570const char * dpp_netrole_str(enum dpp_netrole netrole)
Hai Shalomc3565922019-10-28 11:58:20 -07001571{
1572 switch (netrole) {
1573 case DPP_NETROLE_STA:
1574 return "sta";
1575 case DPP_NETROLE_AP:
1576 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001577 case DPP_NETROLE_CONFIGURATOR:
1578 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07001579 default:
1580 return "??";
1581 }
1582}
1583
1584
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001585static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001586dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001587 struct dpp_configuration *conf)
1588{
1589 struct wpabuf *buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001590 char *signed_conn = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001591 size_t tailroom;
Sunil Ravia04bd252022-05-02 22:54:18 -07001592 const struct dpp_curve_params *curve; /* C-sign-key curve */
1593 const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001594 struct wpabuf *dppcon = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001595 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07001596 int incl_legacy;
1597 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07001598 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001599
1600 if (!auth->conf) {
1601 wpa_printf(MSG_INFO,
1602 "DPP: No configurator specified - cannot generate DPP config object");
1603 goto fail;
1604 }
1605 curve = auth->conf->curve;
Sunil Ravia04bd252022-05-02 22:54:18 -07001606 if (auth->new_curve && auth->new_key_received)
1607 nak_curve = auth->new_curve;
1608 else
1609 nak_curve = auth->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001610
Hai Shalom021b0b52019-04-10 11:17:58 -07001611 akm = conf->akm;
1612 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1613 wpa_printf(MSG_DEBUG,
1614 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1615 akm = DPP_AKM_DPP;
1616 }
1617
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001618#ifdef CONFIG_TESTING_OPTIONS
1619 if (auth->groups_override)
1620 extra_len += os_strlen(auth->groups_override);
1621#endif /* CONFIG_TESTING_OPTIONS */
1622
Hai Shalomce48b4a2018-09-05 11:41:35 -07001623 if (conf->group_id)
1624 extra_len += os_strlen(conf->group_id);
1625
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001626 /* Connector (JSON dppCon object) */
Sunil Ravia04bd252022-05-02 22:54:18 -07001627 dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001628 if (!dppcon)
1629 goto fail;
1630#ifdef CONFIG_TESTING_OPTIONS
1631 if (auth->groups_override) {
1632 wpabuf_put_u8(dppcon, '{');
1633 if (auth->groups_override) {
1634 wpa_printf(MSG_DEBUG,
1635 "DPP: TESTING - groups override: '%s'",
1636 auth->groups_override);
1637 wpabuf_put_str(dppcon, "\"groups\":");
1638 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001639 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001640 }
1641 goto skip_groups;
1642 }
1643#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001644 json_start_object(dppcon, NULL);
1645 json_start_array(dppcon, "groups");
1646 json_start_object(dppcon, NULL);
1647 json_add_string(dppcon, "groupId",
1648 conf->group_id ? conf->group_id : "*");
1649 json_value_sep(dppcon);
1650 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1651 json_end_object(dppcon);
1652 json_end_array(dppcon);
1653 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001654#ifdef CONFIG_TESTING_OPTIONS
1655skip_groups:
1656#endif /* CONFIG_TESTING_OPTIONS */
Sunil Ravia04bd252022-05-02 22:54:18 -07001657 if (!auth->peer_protocol_key) {
1658 wpa_printf(MSG_DEBUG,
1659 "DPP: No peer protocol key available to build netAccessKey JWK");
1660 goto fail;
1661 }
1662#ifdef CONFIG_DPP3
1663 if (auth->conf->net_access_key_curve &&
1664 auth->curve != auth->conf->net_access_key_curve &&
1665 !auth->new_key_received) {
1666 wpa_printf(MSG_DEBUG,
1667 "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1668 auth->curve->name,
1669 auth->conf->net_access_key_curve->name,
1670 auth->waiting_new_key ?
1671 "the required key not received" :
1672 "request a new key");
1673 if (auth->waiting_new_key)
1674 auth->waiting_new_key = false; /* failed */
1675 else
1676 auth->waiting_new_key = true;
1677 goto fail;
1678 }
1679#endif /* CONFIG_DPP3 */
1680 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1681 nak_curve) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001682 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1683 goto fail;
1684 }
1685 if (conf->netaccesskey_expiry) {
1686 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001687 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001688
1689 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1690 wpa_printf(MSG_DEBUG,
1691 "DPP: Failed to generate expiry string");
1692 goto fail;
1693 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001694 os_snprintf(expiry, sizeof(expiry),
1695 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1696 tm.year, tm.month, tm.day,
1697 tm.hour, tm.min, tm.sec);
1698 json_value_sep(dppcon);
1699 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001700 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08001701#ifdef CONFIG_DPP3
1702 json_value_sep(dppcon);
1703 json_add_int(dppcon, "version", auth->peer_version);
1704#endif /* CONFIG_DPP3 */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001705 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001706 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1707 (const char *) wpabuf_head(dppcon));
1708
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001709 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1710 if (!signed_conn)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001711 goto fail;
1712
Hai Shalom021b0b52019-04-10 11:17:58 -07001713 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001714 tailroom = 1000;
1715 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001716 tailroom += os_strlen(signed_conn);
Hai Shalom021b0b52019-04-10 11:17:58 -07001717 if (incl_legacy)
1718 tailroom += 1000;
Hai Shalom899fcc72020-10-19 14:38:18 -07001719 if (akm == DPP_AKM_DOT1X) {
1720 if (auth->certbag)
1721 tailroom += 2 * wpabuf_len(auth->certbag);
1722 if (auth->cacert)
1723 tailroom += 2 * wpabuf_len(auth->cacert);
1724 if (auth->trusted_eap_server_name)
1725 tailroom += os_strlen(auth->trusted_eap_server_name);
1726 tailroom += 1000;
1727 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001728 buf = dpp_build_conf_start(auth, conf, tailroom);
1729 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001730 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001731
Hai Shalomc3565922019-10-28 11:58:20 -07001732 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1733 akm_str = dpp_akm_selector_str(akm);
1734 else
1735 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001736 json_start_object(buf, "cred");
1737 json_add_string(buf, "akm", akm_str);
1738 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001739 if (incl_legacy) {
1740 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001741 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001742 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001743 if (akm == DPP_AKM_DOT1X) {
1744 json_start_object(buf, "entCreds");
1745 if (!auth->certbag)
1746 goto fail;
1747 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1748 wpabuf_len(auth->certbag));
1749 if (auth->cacert) {
1750 json_value_sep(buf);
1751 json_add_base64(buf, "caCert",
1752 wpabuf_head(auth->cacert),
1753 wpabuf_len(auth->cacert));
1754 }
1755 if (auth->trusted_eap_server_name) {
1756 json_value_sep(buf);
1757 json_add_string(buf, "trustedEapServerName",
1758 auth->trusted_eap_server_name);
1759 }
1760 json_value_sep(buf);
1761 json_start_array(buf, "eapMethods");
1762 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1763 json_end_array(buf);
1764 json_end_object(buf);
1765 json_value_sep(buf);
1766 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001767 wpabuf_put_str(buf, "\"signedConnector\":\"");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001768 wpabuf_put_str(buf, signed_conn);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001769 wpabuf_put_str(buf, "\"");
1770 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001771 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1772 curve) < 0) {
1773 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1774 goto fail;
1775 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001776#ifdef CONFIG_DPP2
1777 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1778 json_value_sep(buf);
1779 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1780 curve) < 0) {
1781 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1782 goto fail;
1783 }
1784 }
1785#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001786
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001787 json_end_object(buf);
1788 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001789
1790 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1791 wpabuf_head(buf), wpabuf_len(buf));
1792
Sunil Ravia04bd252022-05-02 22:54:18 -07001793#ifdef CONFIG_DPP3
1794 if (!auth->conf->net_access_key_curve) {
1795 /* All netAccessKey values used in the network will have to be
1796 * from the same curve for network introduction to work, so
1797 * hardcode the first used netAccessKey curve for consecutive
1798 * operations if there was no explicit configuration of which
1799 * curve to use. */
1800 wpa_printf(MSG_DEBUG,
1801 "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1802 nak_curve->name);
1803 auth->conf->net_access_key_curve = nak_curve;
1804 }
1805#endif /* CONFIG_DPP3 */
1806
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001807out:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001808 os_free(signed_conn);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001809 wpabuf_free(dppcon);
1810 return buf;
1811fail:
1812 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1813 wpabuf_free(buf);
1814 buf = NULL;
1815 goto out;
1816}
1817
1818
1819static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001820dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001821 struct dpp_configuration *conf)
1822{
1823 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001824 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001825
1826 buf = dpp_build_conf_start(auth, conf, 1000);
1827 if (!buf)
1828 return NULL;
1829
Hai Shalomc3565922019-10-28 11:58:20 -07001830 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1831 akm_str = dpp_akm_selector_str(conf->akm);
1832 else
1833 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001834 json_start_object(buf, "cred");
1835 json_add_string(buf, "akm", akm_str);
1836 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001837 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001838 json_end_object(buf);
1839 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001840
1841 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1842 wpabuf_head(buf), wpabuf_len(buf));
1843
1844 return buf;
1845}
1846
1847
Hai Shaloma20dcd72022-02-04 13:43:00 -08001848static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1849{
1850 struct dpp_bootstrap_info *bi;
1851
1852 if (auth->peer_bi)
1853 return auth->peer_bi->id;
1854 if (auth->tmp_peer_bi)
1855 return auth->tmp_peer_bi->id;
1856
1857 bi = os_zalloc(sizeof(*bi));
1858 if (!bi)
1859 return -1;
1860 bi->id = dpp_next_id(auth->global);
1861 dl_list_add(&auth->global->bootstrap, &bi->list);
1862 auth->tmp_peer_bi = bi;
1863 return bi->id;
1864}
1865
1866
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001867static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001868dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
Hai Shalom899fcc72020-10-19 14:38:18 -07001869 int idx, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001870{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001871 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001872
1873#ifdef CONFIG_TESTING_OPTIONS
1874 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07001875 if (idx != 0)
1876 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001877 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
1878 return wpabuf_alloc_copy(auth->config_obj_override,
1879 os_strlen(auth->config_obj_override));
1880 }
1881#endif /* CONFIG_TESTING_OPTIONS */
1882
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001883 if (idx == 0) {
1884 if (netrole == DPP_NETROLE_STA)
1885 conf = auth->conf_sta;
1886 else if (netrole == DPP_NETROLE_AP)
1887 conf = auth->conf_ap;
1888 } else if (idx == 1) {
1889 if (netrole == DPP_NETROLE_STA)
1890 conf = auth->conf2_sta;
1891 else if (netrole == DPP_NETROLE_AP)
1892 conf = auth->conf2_ap;
1893 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001894 if (!conf) {
Hai Shaloma20dcd72022-02-04 13:43:00 -08001895 if (idx == 0) {
1896 if (auth->use_config_query) {
1897 wpa_printf(MSG_DEBUG,
1898 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
1899 dpp_netrole_str(netrole));
1900 auth->waiting_config = true;
1901 dpp_get_peer_bi_id(auth);
1902 return NULL;
1903 }
Hai Shalomc3565922019-10-28 11:58:20 -07001904 wpa_printf(MSG_DEBUG,
1905 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001906 dpp_netrole_str(netrole));
Hai Shaloma20dcd72022-02-04 13:43:00 -08001907 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001908 return NULL;
1909 }
1910
Hai Shalom899fcc72020-10-19 14:38:18 -07001911 if (conf->akm == DPP_AKM_DOT1X) {
1912 if (!auth->conf) {
1913 wpa_printf(MSG_DEBUG,
1914 "DPP: No Configurator data available");
1915 return NULL;
1916 }
1917 if (!cert_req && !auth->certbag) {
1918 wpa_printf(MSG_DEBUG,
1919 "DPP: No certificate data available for dot1x configuration");
1920 return NULL;
1921 }
1922 return dpp_build_conf_obj_dpp(auth, conf);
1923 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001924 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07001925 return dpp_build_conf_obj_dpp(auth, conf);
1926 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001927}
1928
1929
Hai Shalom899fcc72020-10-19 14:38:18 -07001930struct wpabuf *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001931dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Hai Shalom899fcc72020-10-19 14:38:18 -07001932 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001933{
Sunil Ravia04bd252022-05-02 22:54:18 -07001934 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001935 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001936 struct wpabuf *clear = NULL, *msg = NULL;
1937 u8 *wrapped;
1938 const u8 *addr[1];
1939 size_t len[1];
1940 enum dpp_status_error status;
1941
Hai Shalom899fcc72020-10-19 14:38:18 -07001942 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
1943 status = auth->force_conf_resp_status;
1944 goto forced_status;
1945 }
1946
Hai Shalomfdcde762020-04-02 11:19:20 -07001947 if (netrole == DPP_NETROLE_CONFIGURATOR) {
1948#ifdef CONFIG_DPP2
1949 env_data = dpp_build_enveloped_data(auth);
1950#endif /* CONFIG_DPP2 */
1951 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07001952 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07001953 if (conf) {
1954 wpa_hexdump_ascii(MSG_DEBUG,
1955 "DPP: configurationObject JSON",
1956 wpabuf_head(conf), wpabuf_len(conf));
Hai Shalom899fcc72020-10-19 14:38:18 -07001957 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07001958 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001959 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001960
Hai Shaloma20dcd72022-02-04 13:43:00 -08001961 if (!conf && auth->waiting_config)
1962 return NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001963 if (conf || env_data)
1964 status = DPP_STATUS_OK;
1965 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
1966 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
1967 status = DPP_STATUS_CSR_NEEDED;
Sunil Ravia04bd252022-05-02 22:54:18 -07001968#ifdef CONFIG_DPP3
1969 else if (auth->waiting_new_key)
1970 status = DPP_STATUS_NEW_KEY_NEEDED;
1971#endif /* CONFIG_DPP3 */
Hai Shalom899fcc72020-10-19 14:38:18 -07001972 else
1973 status = DPP_STATUS_CONFIGURE_FAILURE;
1974forced_status:
Hai Shalom021b0b52019-04-10 11:17:58 -07001975 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001976
Hai Shalomc3565922019-10-28 11:58:20 -07001977 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001978 clear_len = 4 + e_nonce_len;
1979 if (conf)
1980 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07001981 if (conf2)
1982 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07001983 if (env_data)
1984 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001985 if (auth->peer_version >= 2 && auth->send_conn_status &&
1986 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07001987 clear_len += 4;
Hai Shalom899fcc72020-10-19 14:38:18 -07001988 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
1989 auth->conf_sta->csrattrs)
1990 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
Sunil Ravia04bd252022-05-02 22:54:18 -07001991#ifdef CONFIG_DPP3
1992 if (status == DPP_STATUS_NEW_KEY_NEEDED) {
1993 struct crypto_ec_key *new_pc;
1994
1995 clear_len += 6; /* Finite Cyclic Group attribute */
1996
1997 wpa_printf(MSG_DEBUG,
1998 "DPP: Generate a new own protocol key for the curve %s",
1999 auth->conf->net_access_key_curve->name);
2000 new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2001 if (!new_pc) {
2002 wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2003 return NULL;
2004 }
2005 pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2006 if (!pc) {
2007 crypto_ec_key_deinit(new_pc);
2008 return NULL;
2009 }
2010 crypto_ec_key_deinit(auth->own_protocol_key);
2011 auth->own_protocol_key = new_pc;
2012 auth->new_curve = auth->conf->net_access_key_curve;
2013 clear_len += 4 + wpabuf_len(pc);
2014 }
2015#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002016 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002017 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2018#ifdef CONFIG_TESTING_OPTIONS
2019 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2020 attr_len += 5;
2021#endif /* CONFIG_TESTING_OPTIONS */
2022 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002023 if (!clear || !msg)
2024 goto fail;
2025
Roshan Pius3a1667e2018-07-03 15:17:14 -07002026#ifdef CONFIG_TESTING_OPTIONS
2027 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2028 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2029 goto skip_e_nonce;
2030 }
2031 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2032 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2033 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2034 wpabuf_put_le16(clear, e_nonce_len);
2035 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2036 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2037 goto skip_e_nonce;
2038 }
2039 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2040 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2041 goto skip_wrapped_data;
2042 }
2043#endif /* CONFIG_TESTING_OPTIONS */
2044
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002045 /* E-nonce */
2046 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2047 wpabuf_put_le16(clear, e_nonce_len);
2048 wpabuf_put_data(clear, e_nonce, e_nonce_len);
2049
Roshan Pius3a1667e2018-07-03 15:17:14 -07002050#ifdef CONFIG_TESTING_OPTIONS
2051skip_e_nonce:
2052 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2053 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2054 goto skip_config_obj;
2055 }
2056#endif /* CONFIG_TESTING_OPTIONS */
2057
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002058 if (conf) {
2059 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2060 wpabuf_put_le16(clear, wpabuf_len(conf));
2061 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002062 }
Hai Shalomc3565922019-10-28 11:58:20 -07002063 if (auth->peer_version >= 2 && conf2) {
2064 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2065 wpabuf_put_le16(clear, wpabuf_len(conf2));
2066 wpabuf_put_buf(clear, conf2);
2067 } else if (conf2) {
2068 wpa_printf(MSG_DEBUG,
2069 "DPP: Second Config Object available, but peer does not support more than one");
2070 }
Hai Shalomfdcde762020-04-02 11:19:20 -07002071 if (env_data) {
2072 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2073 wpabuf_put_le16(clear, wpabuf_len(env_data));
2074 wpabuf_put_buf(clear, env_data);
2075 }
Hai Shalomc3565922019-10-28 11:58:20 -07002076
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002077 if (auth->peer_version >= 2 && auth->send_conn_status &&
Hai Shalom899fcc72020-10-19 14:38:18 -07002078 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
Hai Shalomc3565922019-10-28 11:58:20 -07002079 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2080 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2081 wpabuf_put_le16(clear, 0);
2082 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002083
Hai Shalom899fcc72020-10-19 14:38:18 -07002084 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2085 auth->conf_sta->csrattrs) {
2086 auth->waiting_csr = true;
2087 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2088 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2089 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2090 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2091 }
2092
Sunil Ravia04bd252022-05-02 22:54:18 -07002093#ifdef CONFIG_DPP3
2094 if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2095 auth->conf->net_access_key_curve) {
2096 u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2097
2098 /* Finite Cyclic Group attribute */
2099 wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2100 ike_group);
2101 wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2102 wpabuf_put_le16(clear, 2);
2103 wpabuf_put_le16(clear, ike_group);
2104
2105 if (pc) {
2106 wpa_printf(MSG_DEBUG, "DPP: Pc");
2107 wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2108 wpabuf_put_le16(clear, wpabuf_len(pc));
2109 wpabuf_put_buf(clear, pc);
2110 }
2111 }
2112#endif /* CONFIG_DPP3 */
2113
Roshan Pius3a1667e2018-07-03 15:17:14 -07002114#ifdef CONFIG_TESTING_OPTIONS
2115skip_config_obj:
2116 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2117 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2118 goto skip_status;
2119 }
2120 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2121 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2122 status = 255;
2123 }
2124#endif /* CONFIG_TESTING_OPTIONS */
2125
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002126 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07002127 dpp_build_attr_status(msg, status);
2128
2129#ifdef CONFIG_TESTING_OPTIONS
2130skip_status:
2131#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002132
2133 addr[0] = wpabuf_head(msg);
2134 len[0] = wpabuf_len(msg);
2135 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2136
2137 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2138 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2139 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2140
2141 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2142 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2143 wpabuf_head(clear), wpabuf_len(clear),
2144 1, addr, len, wrapped) < 0)
2145 goto fail;
2146 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2147 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002148
2149#ifdef CONFIG_TESTING_OPTIONS
2150 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2151 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2152 dpp_build_attr_status(msg, DPP_STATUS_OK);
2153 }
2154skip_wrapped_data:
2155#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002156
2157 wpa_hexdump_buf(MSG_DEBUG,
2158 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002159out:
Hai Shalomfdcde762020-04-02 11:19:20 -07002160 wpabuf_clear_free(conf);
2161 wpabuf_clear_free(conf2);
2162 wpabuf_clear_free(env_data);
2163 wpabuf_clear_free(clear);
Sunil Ravia04bd252022-05-02 22:54:18 -07002164 wpabuf_free(pc);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002165
2166 return msg;
2167fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002168 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002169 msg = NULL;
2170 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002171}
2172
2173
2174struct wpabuf *
2175dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2176 size_t attr_len)
2177{
2178 const u8 *wrapped_data, *e_nonce, *config_attr;
2179 u16 wrapped_data_len, e_nonce_len, config_attr_len;
2180 u8 *unwrapped = NULL;
2181 size_t unwrapped_len = 0;
2182 struct wpabuf *resp = NULL;
2183 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002184 enum dpp_netrole netrole;
Hai Shalom899fcc72020-10-19 14:38:18 -07002185 struct wpabuf *cert_req = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07002186#ifdef CONFIG_DPP3
2187 const u8 *i_proto;
2188 u16 i_proto_len;
2189#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002190
Roshan Pius3a1667e2018-07-03 15:17:14 -07002191#ifdef CONFIG_TESTING_OPTIONS
2192 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2193 wpa_printf(MSG_INFO,
2194 "DPP: TESTING - stop at Config Request");
2195 return NULL;
2196 }
2197#endif /* CONFIG_TESTING_OPTIONS */
2198
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002199 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002200 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002201 return NULL;
2202 }
2203
2204 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2205 &wrapped_data_len);
2206 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002207 dpp_auth_fail(auth,
2208 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002209 return NULL;
2210 }
2211
2212 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2213 wrapped_data, wrapped_data_len);
2214 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2215 unwrapped = os_malloc(unwrapped_len);
2216 if (!unwrapped)
2217 return NULL;
2218 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2219 wrapped_data, wrapped_data_len,
2220 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002221 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002222 goto fail;
2223 }
2224 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2225 unwrapped, unwrapped_len);
2226
2227 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002228 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002229 goto fail;
2230 }
2231
2232 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2233 DPP_ATTR_ENROLLEE_NONCE,
2234 &e_nonce_len);
2235 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002236 dpp_auth_fail(auth,
2237 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002238 goto fail;
2239 }
2240 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07002241 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002242
Sunil Ravia04bd252022-05-02 22:54:18 -07002243#ifdef CONFIG_DPP3
2244 i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2245 DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2246 if (i_proto && !auth->waiting_new_key) {
2247 dpp_auth_fail(auth,
2248 "Enrollee included a new protocol key even though one was not expected");
2249 goto fail;
2250 }
2251 if (i_proto) {
2252 struct crypto_ec_key *pe;
2253 u8 auth_i[DPP_MAX_HASH_LEN];
2254 const u8 *rx_auth_i;
2255 u16 rx_auth_i_len;
2256
2257 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2258 i_proto, i_proto_len);
2259
2260 pe = dpp_set_pubkey_point(auth->own_protocol_key,
2261 i_proto, i_proto_len);
2262 if (!pe) {
2263 dpp_auth_fail(auth,
2264 "Invalid Initiator Protocol Key (Pe)");
2265 goto fail;
2266 }
2267 dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2268 crypto_ec_key_deinit(auth->peer_protocol_key);
2269 auth->peer_protocol_key = pe;
2270 auth->new_key_received = true;
2271 auth->waiting_new_key = false;
2272
2273 if (dpp_derive_auth_i(auth, auth_i) < 0)
2274 goto fail;
2275
2276 rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2277 DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2278 if (!rx_auth_i) {
2279 dpp_auth_fail(auth,
2280 "Missing Initiator Authentication Tag");
2281 goto fail;
2282 }
2283 if (rx_auth_i_len != auth->curve->hash_len ||
2284 os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2285 dpp_auth_fail(auth,
2286 "Mismatch in Initiator Authenticating Tag");
2287 wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2288 rx_auth_i, rx_auth_i_len);
2289 wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2290 auth_i, auth->curve->hash_len);
2291 goto fail;
2292 }
2293 }
2294#endif /* CONFIG_DPP3 */
2295
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002296 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2297 DPP_ATTR_CONFIG_ATTR_OBJ,
2298 &config_attr_len);
2299 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002300 dpp_auth_fail(auth,
2301 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002302 goto fail;
2303 }
2304 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2305 config_attr, config_attr_len);
2306
2307 root = json_parse((const char *) config_attr, config_attr_len);
2308 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002309 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002310 goto fail;
2311 }
2312
2313 token = json_get_member(root, "name");
2314 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002315 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002316 goto fail;
2317 }
2318 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002319 os_free(auth->e_name);
2320 auth->e_name = os_strdup(token->string);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002321
2322 token = json_get_member(root, "wi-fi_tech");
2323 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002324 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002325 goto fail;
2326 }
2327 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2328 if (os_strcmp(token->string, "infra") != 0) {
2329 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2330 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002331 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002332 goto fail;
2333 }
2334
2335 token = json_get_member(root, "netRole");
2336 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002337 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002338 goto fail;
2339 }
2340 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2341 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002342 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002343 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002344 netrole = DPP_NETROLE_AP;
2345 } else if (os_strcmp(token->string, "configurator") == 0) {
2346 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002347 } else {
2348 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2349 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002350 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002351 goto fail;
2352 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002353 auth->e_netrole = netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002354
Hai Shalomc3565922019-10-28 11:58:20 -07002355 token = json_get_member(root, "mudurl");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002356 if (token && token->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002357 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002358 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2359 token->string);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002360 os_free(auth->e_mud_url);
2361 auth->e_mud_url = os_strdup(token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002362 }
Hai Shalomc3565922019-10-28 11:58:20 -07002363
2364 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08002365 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002366 if (token && token->type == JSON_ARRAY) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002367 int *opclass = NULL;
2368 char txt[200], *pos, *end;
2369 int i, res;
2370
Hai Shalom06768112019-12-04 15:49:43 -08002371 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07002372 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2373 token = token->child;
2374 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08002375 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07002376 wpa_printf(MSG_DEBUG,
2377 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08002378 } else {
2379 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2380 auth->band_list[auth->band_list_size++] = token->number;
2381 }
Hai Shalomc3565922019-10-28 11:58:20 -07002382 wpa_printf(MSG_DEBUG,
2383 "DPP: Supported global operating class: %d",
2384 token->number);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002385 int_array_add_unique(&opclass, token->number);
Hai Shalom06768112019-12-04 15:49:43 -08002386 }
Hai Shalomc3565922019-10-28 11:58:20 -07002387 token = token->sibling;
2388 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002389
2390 txt[0] = '\0';
2391 pos = txt;
2392 end = txt + sizeof(txt);
2393 for (i = 0; opclass && opclass[i]; i++) {
2394 res = os_snprintf(pos, end - pos, "%s%d",
2395 pos == txt ? "" : ",", opclass[i]);
2396 if (os_snprintf_error(end - pos, res)) {
2397 *pos = '\0';
2398 break;
2399 }
2400 pos += res;
2401 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08002402 os_free(auth->e_band_support);
2403 auth->e_band_support = opclass;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002404 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2405 txt);
Hai Shalomc3565922019-10-28 11:58:20 -07002406 }
2407
Hai Shalom899fcc72020-10-19 14:38:18 -07002408#ifdef CONFIG_DPP2
2409 cert_req = json_get_member_base64(root, "pkcs10");
2410 if (cert_req) {
2411 char *txt;
2412 int id;
2413
2414 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2415 if (dpp_validate_csr(auth, cert_req) < 0) {
2416 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2417 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2418 goto cont;
2419 }
2420
Hai Shaloma20dcd72022-02-04 13:43:00 -08002421 id = dpp_get_peer_bi_id(auth);
2422 if (id < 0)
2423 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002424
2425 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2426 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2427 wpabuf_len(cert_req), NULL);
2428 if (!txt)
2429 goto fail;
2430
2431 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2432 id, txt);
2433 os_free(txt);
2434 auth->waiting_csr = false;
2435 auth->waiting_cert = true;
2436 goto fail;
2437 }
2438cont:
2439#endif /* CONFIG_DPP2 */
2440
2441 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2442 cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002443
2444fail:
Hai Shalom899fcc72020-10-19 14:38:18 -07002445 wpabuf_free(cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002446 json_free(root);
2447 os_free(unwrapped);
2448 return resp;
2449}
2450
2451
Hai Shalomc3565922019-10-28 11:58:20 -07002452static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002453 struct json_token *cred)
2454{
2455 struct json_token *pass, *psk_hex;
2456
2457 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2458
2459 pass = json_get_member(cred, "pass");
2460 psk_hex = json_get_member(cred, "psk_hex");
2461
2462 if (pass && pass->type == JSON_STRING) {
2463 size_t len = os_strlen(pass->string);
2464
2465 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2466 pass->string, len);
2467 if (len < 8 || len > 63)
2468 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07002469 os_strlcpy(conf->passphrase, pass->string,
2470 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002471 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002472 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002473 wpa_printf(MSG_DEBUG,
2474 "DPP: Unexpected psk_hex with akm=sae");
2475 return -1;
2476 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002477 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07002478 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002479 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2480 return -1;
2481 }
2482 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07002483 conf->psk, PMK_LEN);
2484 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002485 } else {
2486 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2487 return -1;
2488 }
2489
Hai Shalomc3565922019-10-28 11:58:20 -07002490 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002491 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2492 return -1;
2493 }
2494
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002495 return 0;
2496}
2497
2498
Hai Shaloma20dcd72022-02-04 13:43:00 -08002499struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2500 const struct dpp_curve_params **key_curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002501{
2502 struct json_token *token;
2503 const struct dpp_curve_params *curve;
2504 struct wpabuf *x = NULL, *y = NULL;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002505 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002506
2507 token = json_get_member(jwk, "kty");
2508 if (!token || token->type != JSON_STRING) {
2509 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2510 goto fail;
2511 }
2512 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002513 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002514 token->string);
2515 goto fail;
2516 }
2517
2518 token = json_get_member(jwk, "crv");
2519 if (!token || token->type != JSON_STRING) {
2520 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2521 goto fail;
2522 }
2523 curve = dpp_get_curve_jwk_crv(token->string);
2524 if (!curve) {
2525 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2526 token->string);
2527 goto fail;
2528 }
2529
2530 x = json_get_member_base64url(jwk, "x");
2531 if (!x) {
2532 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2533 goto fail;
2534 }
2535 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2536 if (wpabuf_len(x) != curve->prime_len) {
2537 wpa_printf(MSG_DEBUG,
2538 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2539 (unsigned int) wpabuf_len(x),
2540 (unsigned int) curve->prime_len, curve->name);
2541 goto fail;
2542 }
2543
2544 y = json_get_member_base64url(jwk, "y");
2545 if (!y) {
2546 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2547 goto fail;
2548 }
2549 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2550 if (wpabuf_len(y) != curve->prime_len) {
2551 wpa_printf(MSG_DEBUG,
2552 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2553 (unsigned int) wpabuf_len(y),
2554 (unsigned int) curve->prime_len, curve->name);
2555 goto fail;
2556 }
2557
Hai Shaloma20dcd72022-02-04 13:43:00 -08002558 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2559 wpabuf_head(y), wpabuf_len(x));
2560 if (!key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002561 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002562
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002563 *key_curve = curve;
2564
2565fail:
2566 wpabuf_free(x);
2567 wpabuf_free(y);
2568
Hai Shaloma20dcd72022-02-04 13:43:00 -08002569 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002570}
2571
2572
2573int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2574{
2575 struct os_time now;
2576 unsigned int year, month, day, hour, min, sec;
2577 os_time_t utime;
2578 const char *pos;
2579
2580 /* ISO 8601 date and time:
2581 * <date>T<time>
2582 * YYYY-MM-DDTHH:MM:SSZ
2583 * YYYY-MM-DDTHH:MM:SS+03:00
2584 */
2585 if (os_strlen(timestamp) < 19) {
2586 wpa_printf(MSG_DEBUG,
2587 "DPP: Too short timestamp - assume expired key");
2588 return 1;
2589 }
2590 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2591 &year, &month, &day, &hour, &min, &sec) != 6) {
2592 wpa_printf(MSG_DEBUG,
2593 "DPP: Failed to parse expiration day - assume expired key");
2594 return 1;
2595 }
2596
2597 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2598 wpa_printf(MSG_DEBUG,
2599 "DPP: Invalid date/time information - assume expired key");
2600 return 1;
2601 }
2602
2603 pos = timestamp + 19;
2604 if (*pos == 'Z' || *pos == '\0') {
2605 /* In UTC - no need to adjust */
2606 } else if (*pos == '-' || *pos == '+') {
2607 int items;
2608
2609 /* Adjust local time to UTC */
2610 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2611 if (items < 1) {
2612 wpa_printf(MSG_DEBUG,
2613 "DPP: Invalid time zone designator (%s) - assume expired key",
2614 pos);
2615 return 1;
2616 }
2617 if (*pos == '-')
2618 utime += 3600 * hour;
2619 if (*pos == '+')
2620 utime -= 3600 * hour;
2621 if (items > 1) {
2622 if (*pos == '-')
2623 utime += 60 * min;
2624 if (*pos == '+')
2625 utime -= 60 * min;
2626 }
2627 } else {
2628 wpa_printf(MSG_DEBUG,
2629 "DPP: Invalid time zone designator (%s) - assume expired key",
2630 pos);
2631 return 1;
2632 }
2633 if (expiry)
2634 *expiry = utime;
2635
2636 if (os_get_time(&now) < 0) {
2637 wpa_printf(MSG_DEBUG,
2638 "DPP: Cannot get current time - assume expired key");
2639 return 1;
2640 }
2641
2642 if (now.sec > utime) {
2643 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2644 utime, now.sec);
2645 return 1;
2646 }
2647
2648 return 0;
2649}
2650
2651
2652static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002653 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002654 const unsigned char *payload,
2655 u16 payload_len)
2656{
2657 struct json_token *root, *groups, *netkey, *token;
2658 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002659 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002660 const struct dpp_curve_params *curve;
2661 unsigned int rules = 0;
2662
2663 root = json_parse((const char *) payload, payload_len);
2664 if (!root) {
2665 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2666 goto fail;
2667 }
2668
2669 groups = json_get_member(root, "groups");
2670 if (!groups || groups->type != JSON_ARRAY) {
2671 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2672 goto skip_groups;
2673 }
2674 for (token = groups->child; token; token = token->sibling) {
2675 struct json_token *id, *role;
2676
2677 id = json_get_member(token, "groupId");
2678 if (!id || id->type != JSON_STRING) {
2679 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2680 goto fail;
2681 }
2682
2683 role = json_get_member(token, "netRole");
2684 if (!role || role->type != JSON_STRING) {
2685 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2686 goto fail;
2687 }
2688 wpa_printf(MSG_DEBUG,
2689 "DPP: connector group: groupId='%s' netRole='%s'",
2690 id->string, role->string);
2691 rules++;
2692 }
2693skip_groups:
2694
2695 if (!rules) {
2696 wpa_printf(MSG_DEBUG,
2697 "DPP: Connector includes no groups");
2698 goto fail;
2699 }
2700
2701 token = json_get_member(root, "expiry");
2702 if (!token || token->type != JSON_STRING) {
2703 wpa_printf(MSG_DEBUG,
2704 "DPP: No expiry string found - connector does not expire");
2705 } else {
2706 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2707 if (dpp_key_expired(token->string,
2708 &auth->net_access_key_expiry)) {
2709 wpa_printf(MSG_DEBUG,
2710 "DPP: Connector (netAccessKey) has expired");
2711 goto fail;
2712 }
2713 }
2714
2715 netkey = json_get_member(root, "netAccessKey");
2716 if (!netkey || netkey->type != JSON_OBJECT) {
2717 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2718 goto fail;
2719 }
2720
2721 key = dpp_parse_jwk(netkey, &curve);
2722 if (!key)
2723 goto fail;
2724 dpp_debug_print_key("DPP: Received netAccessKey", key);
2725
Hai Shaloma20dcd72022-02-04 13:43:00 -08002726 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002727 wpa_printf(MSG_DEBUG,
2728 "DPP: netAccessKey in connector does not match own protocol key");
2729#ifdef CONFIG_TESTING_OPTIONS
2730 if (auth->ignore_netaccesskey_mismatch) {
2731 wpa_printf(MSG_DEBUG,
2732 "DPP: TESTING - skip netAccessKey mismatch");
2733 } else {
2734 goto fail;
2735 }
2736#else /* CONFIG_TESTING_OPTIONS */
2737 goto fail;
2738#endif /* CONFIG_TESTING_OPTIONS */
2739 }
2740
2741 ret = 0;
2742fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002743 crypto_ec_key_deinit(key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002744 json_free(root);
2745 return ret;
2746}
2747
2748
Hai Shaloma20dcd72022-02-04 13:43:00 -08002749static void dpp_copy_csign(struct dpp_config_obj *conf,
2750 struct crypto_ec_key *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002751{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002752 struct wpabuf *c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002753
Hai Shaloma20dcd72022-02-04 13:43:00 -08002754 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2755 if (!c_sign_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002756 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002757
Hai Shalomc3565922019-10-28 11:58:20 -07002758 wpabuf_free(conf->c_sign_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002759 conf->c_sign_key = c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002760}
2761
2762
Hai Shaloma20dcd72022-02-04 13:43:00 -08002763static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2764 struct crypto_ec_key *ppkey)
Hai Shalom899fcc72020-10-19 14:38:18 -07002765{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002766 struct wpabuf *pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002767
Hai Shaloma20dcd72022-02-04 13:43:00 -08002768 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2769 if (!pp_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002770 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002771
Hai Shalom899fcc72020-10-19 14:38:18 -07002772 wpabuf_free(conf->pp_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002773 conf->pp_key = pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002774}
2775
2776
Hai Shalomc3565922019-10-28 11:58:20 -07002777static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2778 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002779{
Hai Shaloma20dcd72022-02-04 13:43:00 -08002780 struct wpabuf *net_access_key;
2781 struct crypto_ec_key *own_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002782
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002783 own_key = auth->own_protocol_key;
2784#ifdef CONFIG_DPP2
2785 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2786 auth->reconfig_old_protocol_key)
2787 own_key = auth->reconfig_old_protocol_key;
2788#endif /* CONFIG_DPP2 */
Hai Shaloma20dcd72022-02-04 13:43:00 -08002789
2790 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2791 if (!net_access_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002792 return;
2793
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002794 wpabuf_free(auth->net_access_key);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002795 auth->net_access_key = net_access_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002796}
2797
2798
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002799static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002800 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002801 struct json_token *cred)
2802{
2803 struct dpp_signed_connector_info info;
Hai Shalom899fcc72020-10-19 14:38:18 -07002804 struct json_token *token, *csign, *ppkey;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002805 int ret = -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08002806 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002807 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002808 const char *signed_connector;
2809
2810 os_memset(&info, 0, sizeof(info));
2811
Hai Shalomc3565922019-10-28 11:58:20 -07002812 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002813 wpa_printf(MSG_DEBUG,
2814 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07002815 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07002816 return -1;
2817 }
2818
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002819 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2820
2821 csign = json_get_member(cred, "csign");
2822 if (!csign || csign->type != JSON_OBJECT) {
2823 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2824 goto fail;
2825 }
2826
2827 csign_pub = dpp_parse_jwk(csign, &key_curve);
2828 if (!csign_pub) {
2829 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
2830 goto fail;
2831 }
2832 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
2833
Hai Shalom899fcc72020-10-19 14:38:18 -07002834 ppkey = json_get_member(cred, "ppKey");
2835 if (ppkey && ppkey->type == JSON_OBJECT) {
2836 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2837 if (!pp_pub) {
2838 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2839 goto fail;
2840 }
2841 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2842 if (key_curve != pp_curve) {
2843 wpa_printf(MSG_DEBUG,
2844 "DPP: C-sign-key and ppKey do not use the same curve");
2845 goto fail;
2846 }
2847 }
2848
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002849 token = json_get_member(cred, "signedConnector");
2850 if (!token || token->type != JSON_STRING) {
2851 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
2852 goto fail;
2853 }
2854 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
2855 token->string, os_strlen(token->string));
2856 signed_connector = token->string;
2857
2858 if (os_strchr(signed_connector, '"') ||
2859 os_strchr(signed_connector, '\n')) {
2860 wpa_printf(MSG_DEBUG,
2861 "DPP: Unexpected character in signedConnector");
2862 goto fail;
2863 }
2864
2865 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002866 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002867 goto fail;
2868
Hai Shalomc3565922019-10-28 11:58:20 -07002869 if (dpp_parse_connector(auth, conf,
2870 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002871 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
2872 goto fail;
2873 }
2874
Hai Shalomc3565922019-10-28 11:58:20 -07002875 os_free(conf->connector);
2876 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002877
Hai Shalomc3565922019-10-28 11:58:20 -07002878 dpp_copy_csign(conf, csign_pub);
Hai Shalom899fcc72020-10-19 14:38:18 -07002879 if (pp_pub)
2880 dpp_copy_ppkey(conf, pp_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07002881 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07002882 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002883
2884 ret = 0;
2885fail:
Hai Shaloma20dcd72022-02-04 13:43:00 -08002886 crypto_ec_key_deinit(csign_pub);
2887 crypto_ec_key_deinit(pp_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002888 os_free(info.payload);
2889 return ret;
2890}
2891
2892
Hai Shalom899fcc72020-10-19 14:38:18 -07002893#ifdef CONFIG_DPP2
2894static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2895 struct dpp_config_obj *conf,
2896 struct json_token *cred)
2897{
2898 struct json_token *ent, *name;
2899
2900 ent = json_get_member(cred, "entCreds");
2901 if (!ent || ent->type != JSON_OBJECT) {
2902 dpp_auth_fail(auth, "No entCreds in JSON");
2903 return -1;
2904 }
2905
2906 conf->certbag = json_get_member_base64(ent, "certBag");
2907 if (!conf->certbag) {
2908 dpp_auth_fail(auth, "No certBag in JSON");
2909 return -1;
2910 }
2911 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
Hai Shaloma20dcd72022-02-04 13:43:00 -08002912 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
Hai Shalom899fcc72020-10-19 14:38:18 -07002913 if (!conf->certs) {
2914 dpp_auth_fail(auth, "No certificates in certBag");
2915 return -1;
2916 }
2917
2918 conf->cacert = json_get_member_base64(ent, "caCert");
2919 if (conf->cacert)
2920 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
2921 conf->cacert);
2922
2923 name = json_get_member(ent, "trustedEapServerName");
2924 if (name &&
2925 (name->type != JSON_STRING ||
2926 has_ctrl_char((const u8 *) name->string,
2927 os_strlen(name->string)))) {
2928 dpp_auth_fail(auth,
2929 "Invalid trustedEapServerName type in JSON");
2930 return -1;
2931 }
2932 if (name && name->string) {
2933 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
2934 name->string);
2935 conf->server_name = os_strdup(name->string);
2936 if (!conf->server_name)
2937 return -1;
2938 }
2939
2940 return 0;
2941}
2942#endif /* CONFIG_DPP2 */
2943
2944
Roshan Pius3a1667e2018-07-03 15:17:14 -07002945const char * dpp_akm_str(enum dpp_akm akm)
2946{
2947 switch (akm) {
2948 case DPP_AKM_DPP:
2949 return "dpp";
2950 case DPP_AKM_PSK:
2951 return "psk";
2952 case DPP_AKM_SAE:
2953 return "sae";
2954 case DPP_AKM_PSK_SAE:
2955 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07002956 case DPP_AKM_SAE_DPP:
2957 return "dpp+sae";
2958 case DPP_AKM_PSK_SAE_DPP:
2959 return "dpp+psk+sae";
Hai Shalom899fcc72020-10-19 14:38:18 -07002960 case DPP_AKM_DOT1X:
2961 return "dot1x";
Roshan Pius3a1667e2018-07-03 15:17:14 -07002962 default:
2963 return "??";
2964 }
2965}
2966
2967
Hai Shalomc3565922019-10-28 11:58:20 -07002968const char * dpp_akm_selector_str(enum dpp_akm akm)
2969{
2970 switch (akm) {
2971 case DPP_AKM_DPP:
2972 return "506F9A02";
2973 case DPP_AKM_PSK:
2974 return "000FAC02+000FAC06";
2975 case DPP_AKM_SAE:
2976 return "000FAC08";
2977 case DPP_AKM_PSK_SAE:
2978 return "000FAC02+000FAC06+000FAC08";
2979 case DPP_AKM_SAE_DPP:
2980 return "506F9A02+000FAC08";
2981 case DPP_AKM_PSK_SAE_DPP:
2982 return "506F9A02+000FAC08+000FAC02+000FAC06";
Hai Shalom899fcc72020-10-19 14:38:18 -07002983 case DPP_AKM_DOT1X:
2984 return "000FAC01+000FAC05";
Hai Shalomc3565922019-10-28 11:58:20 -07002985 default:
2986 return "??";
2987 }
2988}
2989
2990
Roshan Pius3a1667e2018-07-03 15:17:14 -07002991static enum dpp_akm dpp_akm_from_str(const char *akm)
2992{
Hai Shalomc3565922019-10-28 11:58:20 -07002993 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07002994 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002995
Roshan Pius3a1667e2018-07-03 15:17:14 -07002996 if (os_strcmp(akm, "psk") == 0)
2997 return DPP_AKM_PSK;
2998 if (os_strcmp(akm, "sae") == 0)
2999 return DPP_AKM_SAE;
3000 if (os_strcmp(akm, "psk+sae") == 0)
3001 return DPP_AKM_PSK_SAE;
3002 if (os_strcmp(akm, "dpp") == 0)
3003 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07003004 if (os_strcmp(akm, "dpp+sae") == 0)
3005 return DPP_AKM_SAE_DPP;
3006 if (os_strcmp(akm, "dpp+psk+sae") == 0)
3007 return DPP_AKM_PSK_SAE_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07003008 if (os_strcmp(akm, "dot1x") == 0)
3009 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003010
3011 pos = akm;
3012 while (*pos) {
3013 if (os_strlen(pos) < 8)
3014 break;
3015 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3016 dpp = 1;
3017 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3018 psk = 1;
3019 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3020 psk = 1;
3021 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3022 sae = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07003023 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3024 dot1x = 1;
3025 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3026 dot1x = 1;
Hai Shalomc3565922019-10-28 11:58:20 -07003027 pos += 8;
3028 if (*pos != '+')
3029 break;
3030 pos++;
3031 }
3032
3033 if (dpp && psk && sae)
3034 return DPP_AKM_PSK_SAE_DPP;
3035 if (dpp && sae)
3036 return DPP_AKM_SAE_DPP;
3037 if (dpp)
3038 return DPP_AKM_DPP;
3039 if (psk && sae)
3040 return DPP_AKM_PSK_SAE;
3041 if (sae)
3042 return DPP_AKM_SAE;
3043 if (psk)
3044 return DPP_AKM_PSK;
Hai Shalom899fcc72020-10-19 14:38:18 -07003045 if (dot1x)
3046 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07003047
Roshan Pius3a1667e2018-07-03 15:17:14 -07003048 return DPP_AKM_UNKNOWN;
3049}
3050
3051
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003052static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3053 const u8 *conf_obj, u16 conf_obj_len)
3054{
3055 int ret = -1;
3056 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07003057 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003058 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003059 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003060
3061 root = json_parse((const char *) conf_obj, conf_obj_len);
3062 if (!root)
3063 return -1;
3064 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003065 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003066 goto fail;
3067 }
3068
3069 token = json_get_member(root, "wi-fi_tech");
3070 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003071 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003072 goto fail;
3073 }
3074 if (os_strcmp(token->string, "infra") != 0) {
3075 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3076 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003077 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003078 goto fail;
3079 }
3080
3081 discovery = json_get_member(root, "discovery");
3082 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003083 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003084 goto fail;
3085 }
3086
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003087 ssid64 = json_get_member_base64url(discovery, "ssid64");
3088 if (ssid64) {
3089 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3090 wpabuf_head(ssid64), wpabuf_len(ssid64));
3091 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3092 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3093 goto fail;
3094 }
3095 } else {
3096 token = json_get_member(discovery, "ssid");
3097 if (!token || token->type != JSON_STRING) {
3098 dpp_auth_fail(auth,
3099 "No discovery::ssid string value found");
3100 goto fail;
3101 }
3102 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3103 token->string, os_strlen(token->string));
3104 if (os_strlen(token->string) > SSID_MAX_LEN) {
3105 dpp_auth_fail(auth,
3106 "Too long discovery::ssid string value");
3107 goto fail;
3108 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003109 }
Hai Shalomc3565922019-10-28 11:58:20 -07003110
3111 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3112 wpa_printf(MSG_DEBUG,
3113 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003114 ret = 0;
3115 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07003116 }
3117 conf = &auth->conf_obj[auth->num_conf_obj++];
3118
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003119 if (ssid64) {
3120 conf->ssid_len = wpabuf_len(ssid64);
3121 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3122 } else {
3123 conf->ssid_len = os_strlen(token->string);
3124 os_memcpy(conf->ssid, token->string, conf->ssid_len);
3125 }
3126
3127 token = json_get_member(discovery, "ssid_charset");
3128 if (token && token->type == JSON_NUMBER) {
3129 conf->ssid_charset = token->number;
3130 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3131 conf->ssid_charset);
3132 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003133
3134 cred = json_get_member(root, "cred");
3135 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003136 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003137 goto fail;
3138 }
3139
3140 token = json_get_member(cred, "akm");
3141 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003142 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003143 goto fail;
3144 }
Hai Shalomc3565922019-10-28 11:58:20 -07003145 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003146
Hai Shalomfdcde762020-04-02 11:19:20 -07003147 legacy = dpp_akm_legacy(conf->akm);
3148 if (legacy && auth->peer_version >= 2) {
3149 struct json_token *csign, *s_conn;
3150
3151 csign = json_get_member(cred, "csign");
3152 s_conn = json_get_member(cred, "signedConnector");
3153 if (csign && csign->type == JSON_OBJECT &&
3154 s_conn && s_conn->type == JSON_STRING)
3155 legacy = 0;
3156 }
3157 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07003158 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003159 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07003160 } else if (dpp_akm_dpp(conf->akm) ||
3161 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07003162 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003163 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07003164#ifdef CONFIG_DPP2
3165 } else if (conf->akm == DPP_AKM_DOT1X) {
3166 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3167 dpp_parse_cred_dpp(auth, conf, cred) < 0)
3168 goto fail;
3169#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003170 } else {
3171 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3172 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003173 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003174 goto fail;
3175 }
3176
3177 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3178 ret = 0;
3179fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003180 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003181 json_free(root);
3182 return ret;
3183}
3184
3185
Hai Shalom899fcc72020-10-19 14:38:18 -07003186#ifdef CONFIG_DPP2
3187static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3188{
3189 const u8 *b64;
3190 u16 b64_len;
3191
3192 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3193 if (!b64)
3194 return NULL;
3195 return base64_decode((const char *) b64, b64_len, len);
3196}
3197#endif /* CONFIG_DPP2 */
3198
3199
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003200int dpp_conf_resp_rx(struct dpp_authentication *auth,
3201 const struct wpabuf *resp)
3202{
3203 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3204 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07003205 const u8 *env_data;
3206 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003207 const u8 *addr[1];
3208 size_t len[1];
3209 u8 *unwrapped = NULL;
3210 size_t unwrapped_len = 0;
3211 int ret = -1;
3212
Hai Shalom021b0b52019-04-10 11:17:58 -07003213 auth->conf_resp_status = 255;
3214
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003215 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003216 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003217 return -1;
3218 }
3219
3220 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3221 DPP_ATTR_WRAPPED_DATA,
3222 &wrapped_data_len);
3223 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003224 dpp_auth_fail(auth,
3225 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003226 return -1;
3227 }
3228
3229 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3230 wrapped_data, wrapped_data_len);
3231 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3232 unwrapped = os_malloc(unwrapped_len);
3233 if (!unwrapped)
3234 return -1;
3235
3236 addr[0] = wpabuf_head(resp);
3237 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3238 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3239
3240 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3241 wrapped_data, wrapped_data_len,
3242 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003243 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003244 goto fail;
3245 }
3246 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3247 unwrapped, unwrapped_len);
3248
3249 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003250 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003251 goto fail;
3252 }
3253
3254 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3255 DPP_ATTR_ENROLLEE_NONCE,
3256 &e_nonce_len);
3257 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003258 dpp_auth_fail(auth,
3259 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003260 goto fail;
3261 }
3262 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3263 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003264 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003265 goto fail;
3266 }
3267
3268 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3269 DPP_ATTR_STATUS, &status_len);
3270 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003271 dpp_auth_fail(auth,
3272 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003273 goto fail;
3274 }
Hai Shalom021b0b52019-04-10 11:17:58 -07003275 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003276 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Hai Shalom899fcc72020-10-19 14:38:18 -07003277#ifdef CONFIG_DPP2
3278 if (status[0] == DPP_STATUS_CSR_NEEDED) {
3279 u8 *csrattrs;
3280 size_t csrattrs_len;
3281
3282 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3283
3284 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3285 &csrattrs_len);
3286 if (!csrattrs) {
3287 dpp_auth_fail(auth,
3288 "Missing or invalid CSR Attributes Request attribute");
3289 goto fail;
3290 }
3291 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3292 os_free(auth->csrattrs);
3293 auth->csrattrs = csrattrs;
3294 auth->csrattrs_len = csrattrs_len;
3295 ret = -2;
3296 goto fail;
3297 }
3298#endif /* CONFIG_DPP2 */
Sunil Ravia04bd252022-05-02 22:54:18 -07003299#ifdef CONFIG_DPP3
3300 if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3301 const u8 *fcgroup, *r_proto;
3302 u16 fcgroup_len, r_proto_len;
3303 u16 group;
3304 const struct dpp_curve_params *curve;
3305 struct crypto_ec_key *new_pe;
3306 struct crypto_ec_key *pc;
3307
3308 fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3309 DPP_ATTR_FINITE_CYCLIC_GROUP,
3310 &fcgroup_len);
3311 if (!fcgroup || fcgroup_len != 2) {
3312 dpp_auth_fail(auth,
3313 "Missing or invalid required Finite Cyclic Group attribute");
3314 goto fail;
3315 }
3316 group = WPA_GET_LE16(fcgroup);
3317
3318 wpa_printf(MSG_DEBUG,
3319 "DPP: Configurator requested a new protocol key from group %u",
3320 group);
3321 curve = dpp_get_curve_ike_group(group);
3322 if (!curve) {
3323 dpp_auth_fail(auth,
3324 "Unsupported group for new protocol key");
3325 goto fail;
3326 }
3327
3328 new_pe = dpp_gen_keypair(curve);
3329 if (!new_pe) {
3330 dpp_auth_fail(auth,
3331 "Failed to generate a new protocol key");
3332 goto fail;
3333 }
3334
3335 crypto_ec_key_deinit(auth->own_protocol_key);
3336 auth->own_protocol_key = new_pe;
3337 auth->new_curve = curve;
3338
3339 r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3340 DPP_ATTR_R_PROTOCOL_KEY,
3341 &r_proto_len);
3342 if (!r_proto) {
3343 dpp_auth_fail(auth,
3344 "Missing required Responder Protocol Key attribute (Pc)");
3345 goto fail;
3346 }
3347 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3348 r_proto, r_proto_len);
3349
3350 pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3351 if (!pc) {
3352 dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3353 goto fail;
3354 }
3355 dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3356
3357 crypto_ec_key_deinit(auth->peer_protocol_key);
3358 auth->peer_protocol_key = pc;
3359
3360 auth->waiting_new_key = true;
3361 ret = -3;
3362 goto fail;
3363 }
3364#endif /* CONFIG_DPP3 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003365 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003366 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003367 goto fail;
3368 }
3369
Hai Shalomfdcde762020-04-02 11:19:20 -07003370 env_data = dpp_get_attr(unwrapped, unwrapped_len,
3371 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3372#ifdef CONFIG_DPP2
3373 if (env_data &&
3374 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3375 goto fail;
3376#endif /* CONFIG_DPP2 */
3377
Hai Shalomc3565922019-10-28 11:58:20 -07003378 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3379 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003380 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003381 dpp_auth_fail(auth,
3382 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003383 goto fail;
3384 }
Hai Shalomc3565922019-10-28 11:58:20 -07003385 while (conf_obj) {
3386 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3387 conf_obj, conf_obj_len);
3388 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3389 goto fail;
3390 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3391 DPP_ATTR_CONFIG_OBJ,
3392 &conf_obj_len);
3393 }
3394
3395#ifdef CONFIG_DPP2
3396 status = dpp_get_attr(unwrapped, unwrapped_len,
3397 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3398 if (status) {
3399 wpa_printf(MSG_DEBUG,
3400 "DPP: Configurator requested connection status result");
3401 auth->conn_status_requested = 1;
3402 }
3403#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003404
3405 ret = 0;
3406
3407fail:
3408 os_free(unwrapped);
3409 return ret;
3410}
3411
3412
Hai Shalom021b0b52019-04-10 11:17:58 -07003413#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07003414
Hai Shalom021b0b52019-04-10 11:17:58 -07003415enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3416 const u8 *hdr,
3417 const u8 *attr_start, size_t attr_len)
3418{
3419 const u8 *wrapped_data, *status, *e_nonce;
3420 u16 wrapped_data_len, status_len, e_nonce_len;
3421 const u8 *addr[2];
3422 size_t len[2];
3423 u8 *unwrapped = NULL;
3424 size_t unwrapped_len = 0;
3425 enum dpp_status_error ret = 256;
3426
3427 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3428 &wrapped_data_len);
3429 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3430 dpp_auth_fail(auth,
3431 "Missing or invalid required Wrapped Data attribute");
3432 goto fail;
3433 }
3434 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3435 wrapped_data, wrapped_data_len);
3436
3437 attr_len = wrapped_data - 4 - attr_start;
3438
3439 addr[0] = hdr;
3440 len[0] = DPP_HDR_LEN;
3441 addr[1] = attr_start;
3442 len[1] = attr_len;
3443 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3444 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3445 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3446 wrapped_data, wrapped_data_len);
3447 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3448 unwrapped = os_malloc(unwrapped_len);
3449 if (!unwrapped)
3450 goto fail;
3451 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3452 wrapped_data, wrapped_data_len,
3453 2, addr, len, unwrapped) < 0) {
3454 dpp_auth_fail(auth, "AES-SIV decryption failed");
3455 goto fail;
3456 }
3457 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3458 unwrapped, unwrapped_len);
3459
3460 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3461 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3462 goto fail;
3463 }
3464
3465 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3466 DPP_ATTR_ENROLLEE_NONCE,
3467 &e_nonce_len);
3468 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3469 dpp_auth_fail(auth,
3470 "Missing or invalid Enrollee Nonce attribute");
3471 goto fail;
3472 }
3473 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3474 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3475 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3476 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3477 auth->e_nonce, e_nonce_len);
3478 goto fail;
3479 }
3480
3481 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3482 &status_len);
3483 if (!status || status_len < 1) {
3484 dpp_auth_fail(auth,
3485 "Missing or invalid required DPP Status attribute");
3486 goto fail;
3487 }
3488 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3489 ret = status[0];
3490
3491fail:
3492 bin_clear_free(unwrapped, unwrapped_len);
3493 return ret;
3494}
Hai Shalom021b0b52019-04-10 11:17:58 -07003495
3496
3497struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3498 enum dpp_status_error status)
3499{
3500 struct wpabuf *msg, *clear;
3501 size_t nonce_len, clear_len, attr_len;
3502 const u8 *addr[2];
3503 size_t len[2];
3504 u8 *wrapped;
3505
3506 nonce_len = auth->curve->nonce_len;
3507 clear_len = 5 + 4 + nonce_len;
3508 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3509 clear = wpabuf_alloc(clear_len);
3510 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3511 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003512 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07003513
3514 /* DPP Status */
3515 dpp_build_attr_status(clear, status);
3516
3517 /* E-nonce */
3518 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3519 wpabuf_put_le16(clear, nonce_len);
3520 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3521
3522 /* OUI, OUI type, Crypto Suite, DPP frame type */
3523 addr[0] = wpabuf_head_u8(msg) + 2;
3524 len[0] = 3 + 1 + 1 + 1;
3525 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3526
3527 /* Attributes before Wrapped Data (none) */
3528 addr[1] = wpabuf_put(msg, 0);
3529 len[1] = 0;
3530 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3531
3532 /* Wrapped Data */
3533 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3534 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3535 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3536
3537 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3538 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3539 wpabuf_head(clear), wpabuf_len(clear),
3540 2, addr, len, wrapped) < 0)
3541 goto fail;
3542
3543 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3544 wpabuf_free(clear);
3545 return msg;
3546fail:
3547 wpabuf_free(clear);
3548 wpabuf_free(msg);
3549 return NULL;
3550}
3551
3552
Hai Shalomc3565922019-10-28 11:58:20 -07003553static int valid_channel_list(const char *val)
3554{
3555 while (*val) {
3556 if (!((*val >= '0' && *val <= '9') ||
3557 *val == '/' || *val == ','))
3558 return 0;
3559 val++;
3560 }
3561
3562 return 1;
3563}
3564
3565
3566enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3567 const u8 *hdr,
3568 const u8 *attr_start,
3569 size_t attr_len,
3570 u8 *ssid, size_t *ssid_len,
3571 char **channel_list)
3572{
3573 const u8 *wrapped_data, *status, *e_nonce;
3574 u16 wrapped_data_len, status_len, e_nonce_len;
3575 const u8 *addr[2];
3576 size_t len[2];
3577 u8 *unwrapped = NULL;
3578 size_t unwrapped_len = 0;
3579 enum dpp_status_error ret = 256;
3580 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003581 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07003582
3583 *ssid_len = 0;
3584 *channel_list = NULL;
3585
3586 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3587 &wrapped_data_len);
3588 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3589 dpp_auth_fail(auth,
3590 "Missing or invalid required Wrapped Data attribute");
3591 goto fail;
3592 }
3593 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3594 wrapped_data, wrapped_data_len);
3595
3596 attr_len = wrapped_data - 4 - attr_start;
3597
3598 addr[0] = hdr;
3599 len[0] = DPP_HDR_LEN;
3600 addr[1] = attr_start;
3601 len[1] = attr_len;
3602 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3603 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3604 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3605 wrapped_data, wrapped_data_len);
3606 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3607 unwrapped = os_malloc(unwrapped_len);
3608 if (!unwrapped)
3609 goto fail;
3610 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3611 wrapped_data, wrapped_data_len,
3612 2, addr, len, unwrapped) < 0) {
3613 dpp_auth_fail(auth, "AES-SIV decryption failed");
3614 goto fail;
3615 }
3616 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3617 unwrapped, unwrapped_len);
3618
3619 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3620 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3621 goto fail;
3622 }
3623
3624 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3625 DPP_ATTR_ENROLLEE_NONCE,
3626 &e_nonce_len);
3627 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3628 dpp_auth_fail(auth,
3629 "Missing or invalid Enrollee Nonce attribute");
3630 goto fail;
3631 }
3632 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3633 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3634 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3635 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3636 auth->e_nonce, e_nonce_len);
3637 goto fail;
3638 }
3639
3640 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3641 &status_len);
3642 if (!status) {
3643 dpp_auth_fail(auth,
3644 "Missing required DPP Connection Status attribute");
3645 goto fail;
3646 }
3647 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3648 status, status_len);
3649
3650 root = json_parse((const char *) status, status_len);
3651 if (!root) {
3652 dpp_auth_fail(auth, "Could not parse connStatus");
3653 goto fail;
3654 }
3655
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003656 ssid64 = json_get_member_base64url(root, "ssid64");
3657 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3658 *ssid_len = wpabuf_len(ssid64);
3659 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07003660 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003661 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07003662
3663 token = json_get_member(root, "channelList");
3664 if (token && token->type == JSON_STRING &&
3665 valid_channel_list(token->string))
3666 *channel_list = os_strdup(token->string);
3667
3668 token = json_get_member(root, "result");
3669 if (!token || token->type != JSON_NUMBER) {
3670 dpp_auth_fail(auth, "No connStatus - result");
3671 goto fail;
3672 }
3673 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3674 ret = token->number;
3675
3676fail:
3677 json_free(root);
3678 bin_clear_free(unwrapped, unwrapped_len);
3679 return ret;
3680}
3681
3682
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003683struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3684 const u8 *ssid, size_t ssid_len,
3685 const char *channel_list)
3686{
3687 struct wpabuf *json;
3688
3689 json = wpabuf_alloc(1000);
3690 if (!json)
3691 return NULL;
3692 json_start_object(json, NULL);
3693 json_add_int(json, "result", result);
3694 if (ssid) {
3695 json_value_sep(json);
3696 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3697 wpabuf_free(json);
3698 return NULL;
3699 }
3700 }
3701 if (channel_list) {
3702 json_value_sep(json);
3703 json_add_string(json, "channelList", channel_list);
3704 }
3705 json_end_object(json);
3706 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3707 wpabuf_head(json), wpabuf_len(json));
3708
3709 return json;
3710}
3711
3712
Hai Shalomc3565922019-10-28 11:58:20 -07003713struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3714 enum dpp_status_error result,
3715 const u8 *ssid, size_t ssid_len,
3716 const char *channel_list)
3717{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003718 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07003719 size_t nonce_len, clear_len, attr_len;
3720 const u8 *addr[2];
3721 size_t len[2];
3722 u8 *wrapped;
3723
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003724 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
Hai Shalomc3565922019-10-28 11:58:20 -07003725 if (!json)
3726 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003727
3728 nonce_len = auth->curve->nonce_len;
3729 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3730 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3731 clear = wpabuf_alloc(clear_len);
3732 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3733 if (!clear || !msg)
3734 goto fail;
3735
3736 /* E-nonce */
3737 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3738 wpabuf_put_le16(clear, nonce_len);
3739 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3740
3741 /* DPP Connection Status */
3742 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3743 wpabuf_put_le16(clear, wpabuf_len(json));
3744 wpabuf_put_buf(clear, json);
3745
3746 /* OUI, OUI type, Crypto Suite, DPP frame type */
3747 addr[0] = wpabuf_head_u8(msg) + 2;
3748 len[0] = 3 + 1 + 1 + 1;
3749 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3750
3751 /* Attributes before Wrapped Data (none) */
3752 addr[1] = wpabuf_put(msg, 0);
3753 len[1] = 0;
3754 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3755
3756 /* Wrapped Data */
3757 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3758 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3759 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3760
3761 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3762 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3763 wpabuf_head(clear), wpabuf_len(clear),
3764 2, addr, len, wrapped) < 0)
3765 goto fail;
3766
3767 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3768 msg);
3769 wpabuf_free(json);
3770 wpabuf_free(clear);
3771 return msg;
3772fail:
3773 wpabuf_free(json);
3774 wpabuf_free(clear);
3775 wpabuf_free(msg);
3776 return NULL;
3777}
3778
3779#endif /* CONFIG_DPP2 */
3780
3781
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003782void dpp_configurator_free(struct dpp_configurator *conf)
3783{
3784 if (!conf)
3785 return;
Hai Shaloma20dcd72022-02-04 13:43:00 -08003786 crypto_ec_key_deinit(conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003787 os_free(conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003788 os_free(conf->connector);
Hai Shaloma20dcd72022-02-04 13:43:00 -08003789 crypto_ec_key_deinit(conf->connector_key);
3790 crypto_ec_key_deinit(conf->pp_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003791 os_free(conf);
3792}
3793
3794
Roshan Pius3a1667e2018-07-03 15:17:14 -07003795int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3796 size_t buflen)
3797{
Hai Shaloma20dcd72022-02-04 13:43:00 -08003798 struct wpabuf *key;
3799 int ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003800
3801 if (!conf->csign)
3802 return -1;
3803
Hai Shaloma20dcd72022-02-04 13:43:00 -08003804 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3805 if (!key)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003806 return -1;
3807
Hai Shaloma20dcd72022-02-04 13:43:00 -08003808 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003809
Hai Shaloma20dcd72022-02-04 13:43:00 -08003810 wpabuf_clear_free(key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003811 return ret;
3812}
3813
3814
Hai Shalomfdcde762020-04-02 11:19:20 -07003815static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3816{
3817 struct wpabuf *csign_pub = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003818 const u8 *addr[1];
3819 size_t len[1];
3820 int res;
3821
Hai Shaloma20dcd72022-02-04 13:43:00 -08003822 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
Hai Shalomfdcde762020-04-02 11:19:20 -07003823 if (!csign_pub) {
3824 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3825 return -1;
3826 }
3827
3828 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
3829 addr[0] = wpabuf_head(csign_pub);
3830 len[0] = wpabuf_len(csign_pub);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003831 res = sha256_vector(1, addr, len, conf->kid_hash);
Hai Shalomfdcde762020-04-02 11:19:20 -07003832 wpabuf_free(csign_pub);
3833 if (res < 0) {
3834 wpa_printf(MSG_DEBUG,
3835 "DPP: Failed to derive kid for C-sign-key");
3836 return -1;
3837 }
3838
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003839 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3840 NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07003841 return conf->kid ? 0 : -1;
3842}
3843
3844
Hai Shalom899fcc72020-10-19 14:38:18 -07003845static struct dpp_configurator *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003846dpp_keygen_configurator(const char *curve, const u8 *privkey,
Hai Shalom899fcc72020-10-19 14:38:18 -07003847 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003848{
3849 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003850
3851 conf = os_zalloc(sizeof(*conf));
3852 if (!conf)
3853 return NULL;
3854
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003855 conf->curve = dpp_get_curve_name(curve);
3856 if (!conf->curve) {
3857 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3858 os_free(conf);
3859 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003860 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003861
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003862 if (privkey)
3863 conf->csign = dpp_set_keypair(&conf->curve, privkey,
3864 privkey_len);
3865 else
3866 conf->csign = dpp_gen_keypair(conf->curve);
Hai Shalom899fcc72020-10-19 14:38:18 -07003867 if (pp_key)
3868 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3869 pp_key_len);
3870 else
3871 conf->pp_key = dpp_gen_keypair(conf->curve);
3872 if (!conf->csign || !conf->pp_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003873 goto fail;
3874 conf->own = 1;
3875
Hai Shalomfdcde762020-04-02 11:19:20 -07003876 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003877 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003878 return conf;
3879fail:
3880 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07003881 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003882}
3883
3884
3885int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003886 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003887{
3888 struct wpabuf *conf_obj;
3889 int ret = -1;
3890
3891 if (!auth->conf) {
3892 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
3893 return -1;
3894 }
3895
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003896 auth->curve = dpp_get_curve_name(curve);
3897 if (!auth->curve) {
3898 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3899 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003900 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003901
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003902 wpa_printf(MSG_DEBUG,
3903 "DPP: Building own configuration/connector with curve %s",
3904 auth->curve->name);
3905
3906 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
3907 if (!auth->own_protocol_key)
3908 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07003909 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003910 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07003911 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003912
Hai Shalom899fcc72020-10-19 14:38:18 -07003913 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003914 if (!conf_obj) {
3915 wpabuf_free(auth->conf_obj[0].c_sign_key);
3916 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003917 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003918 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003919 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
3920 wpabuf_len(conf_obj));
3921fail:
3922 wpabuf_free(conf_obj);
3923 auth->peer_protocol_key = NULL;
3924 return ret;
3925}
3926
3927
3928static int dpp_compatible_netrole(const char *role1, const char *role2)
3929{
3930 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
3931 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
3932}
3933
3934
3935static int dpp_connector_compatible_group(struct json_token *root,
3936 const char *group_id,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003937 const char *net_role,
3938 bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003939{
3940 struct json_token *groups, *token;
3941
3942 groups = json_get_member(root, "groups");
3943 if (!groups || groups->type != JSON_ARRAY)
3944 return 0;
3945
3946 for (token = groups->child; token; token = token->sibling) {
3947 struct json_token *id, *role;
3948
3949 id = json_get_member(token, "groupId");
3950 if (!id || id->type != JSON_STRING)
3951 continue;
3952
3953 role = json_get_member(token, "netRole");
3954 if (!role || role->type != JSON_STRING)
3955 continue;
3956
3957 if (os_strcmp(id->string, "*") != 0 &&
3958 os_strcmp(group_id, "*") != 0 &&
3959 os_strcmp(id->string, group_id) != 0)
3960 continue;
3961
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003962 if (reconfig && os_strcmp(net_role, "configurator") == 0)
3963 return 1;
3964 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003965 return 1;
3966 }
3967
3968 return 0;
3969}
3970
3971
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003972int dpp_connector_match_groups(struct json_token *own_root,
3973 struct json_token *peer_root, bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003974{
3975 struct json_token *groups, *token;
3976
3977 groups = json_get_member(peer_root, "groups");
3978 if (!groups || groups->type != JSON_ARRAY) {
3979 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
3980 return 0;
3981 }
3982
3983 for (token = groups->child; token; token = token->sibling) {
3984 struct json_token *id, *role;
3985
3986 id = json_get_member(token, "groupId");
3987 if (!id || id->type != JSON_STRING) {
3988 wpa_printf(MSG_DEBUG,
3989 "DPP: Missing peer groupId string");
3990 continue;
3991 }
3992
3993 role = json_get_member(token, "netRole");
3994 if (!role || role->type != JSON_STRING) {
3995 wpa_printf(MSG_DEBUG,
3996 "DPP: Missing peer groups::netRole string");
3997 continue;
3998 }
3999 wpa_printf(MSG_DEBUG,
4000 "DPP: peer connector group: groupId='%s' netRole='%s'",
4001 id->string, role->string);
4002 if (dpp_connector_compatible_group(own_root, id->string,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004003 role->string, reconfig)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004004 wpa_printf(MSG_DEBUG,
4005 "DPP: Compatible group/netRole in own connector");
4006 return 1;
4007 }
4008 }
4009
4010 return 0;
4011}
4012
4013
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004014struct json_token * dpp_parse_own_connector(const char *own_connector)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004015{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004016 unsigned char *own_conn;
4017 size_t own_conn_len;
4018 const char *pos, *end;
4019 struct json_token *own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004020
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004021 pos = os_strchr(own_connector, '.');
4022 if (!pos) {
4023 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4024 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004025 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004026 pos++;
4027 end = os_strchr(pos, '.');
4028 if (!end) {
4029 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4030 return NULL;
4031 }
4032 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4033 if (!own_conn) {
4034 wpa_printf(MSG_DEBUG,
4035 "DPP: Failed to base64url decode own signedConnector JWS Payload");
4036 return NULL;
4037 }
4038
4039 own_root = json_parse((const char *) own_conn, own_conn_len);
4040 os_free(own_conn);
4041 if (!own_root)
4042 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4043
4044 return own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004045}
4046
4047
Roshan Pius3a1667e2018-07-03 15:17:14 -07004048enum dpp_status_error
4049dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4050 const u8 *net_access_key, size_t net_access_key_len,
4051 const u8 *csign_key, size_t csign_key_len,
4052 const u8 *peer_connector, size_t peer_connector_len,
4053 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004054{
4055 struct json_token *root = NULL, *netkey, *token;
4056 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004057 enum dpp_status_error ret = 255, res;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004058 struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004059 struct wpabuf *own_key_pub = NULL;
4060 const struct dpp_curve_params *curve, *own_curve;
4061 struct dpp_signed_connector_info info;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004062 size_t Nx_len;
4063 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4064
4065 os_memset(intro, 0, sizeof(*intro));
4066 os_memset(&info, 0, sizeof(info));
4067 if (expiry)
4068 *expiry = 0;
4069
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004070 own_key = dpp_set_keypair(&own_curve, net_access_key,
4071 net_access_key_len);
4072 if (!own_key) {
4073 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4074 goto fail;
4075 }
4076
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004077 own_root = dpp_parse_own_connector(own_connector);
4078 if (!own_root)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004079 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004080
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004081 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4082 peer_connector, peer_connector_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004083 if (res != DPP_STATUS_OK) {
4084 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004085 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004086 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004087
4088 root = json_parse((const char *) info.payload, info.payload_len);
4089 if (!root) {
4090 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004091 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004092 goto fail;
4093 }
4094
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004095 if (!dpp_connector_match_groups(own_root, root, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004096 wpa_printf(MSG_DEBUG,
4097 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004098 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004099 goto fail;
4100 }
4101
4102 token = json_get_member(root, "expiry");
4103 if (!token || token->type != JSON_STRING) {
4104 wpa_printf(MSG_DEBUG,
4105 "DPP: No expiry string found - connector does not expire");
4106 } else {
4107 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4108 if (dpp_key_expired(token->string, expiry)) {
4109 wpa_printf(MSG_DEBUG,
4110 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004111 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004112 goto fail;
4113 }
4114 }
4115
Hai Shaloma20dcd72022-02-04 13:43:00 -08004116#ifdef CONFIG_DPP3
4117 token = json_get_member(root, "version");
4118 if (token && token->type == JSON_NUMBER) {
4119 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4120 intro->peer_version = token->number;
4121 }
4122#endif /* CONFIG_DPP3 */
4123
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004124 netkey = json_get_member(root, "netAccessKey");
4125 if (!netkey || netkey->type != JSON_OBJECT) {
4126 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07004127 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004128 goto fail;
4129 }
4130
4131 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004132 if (!peer_key) {
4133 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004134 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07004135 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004136 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
4137
4138 if (own_curve != curve) {
4139 wpa_printf(MSG_DEBUG,
4140 "DPP: Mismatching netAccessKey curves (%s != %s)",
4141 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07004142 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004143 goto fail;
4144 }
4145
4146 /* ECDH: N = nk * PK */
Hai Shalomc3565922019-10-28 11:58:20 -07004147 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004148 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004149
4150 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4151 Nx, Nx_len);
4152
4153 /* PMK = HKDF(<>, "DPP PMK", N.x) */
4154 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4155 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4156 goto fail;
4157 }
4158 intro->pmk_len = curve->hash_len;
4159
4160 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4161 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
4162 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4163 goto fail;
4164 }
4165
Roshan Pius3a1667e2018-07-03 15:17:14 -07004166 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004167fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07004168 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004169 os_memset(intro, 0, sizeof(*intro));
4170 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004171 os_free(info.payload);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004172 crypto_ec_key_deinit(own_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004173 wpabuf_free(own_key_pub);
Hai Shaloma20dcd72022-02-04 13:43:00 -08004174 crypto_ec_key_deinit(peer_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07004175 json_free(root);
4176 json_free(own_root);
4177 return ret;
4178}
4179
4180
Hai Shaloma20dcd72022-02-04 13:43:00 -08004181#ifdef CONFIG_DPP3
4182int dpp_get_connector_version(const char *connector)
4183{
4184 struct json_token *root, *token;
4185 int ver = -1;
4186
4187 root = dpp_parse_own_connector(connector);
4188 if (!root)
4189 return -1;
4190
4191 token = json_get_member(root, "version");
4192 if (token && token->type == JSON_NUMBER)
4193 ver = token->number;
4194
4195 json_free(root);
4196 return ver;
4197}
4198#endif /* CONFIG_DPP3 */
4199
4200
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004201unsigned int dpp_next_id(struct dpp_global *dpp)
Hai Shalom021b0b52019-04-10 11:17:58 -07004202{
4203 struct dpp_bootstrap_info *bi;
4204 unsigned int max_id = 0;
4205
4206 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4207 if (bi->id > max_id)
4208 max_id = bi->id;
4209 }
4210 return max_id + 1;
4211}
4212
4213
4214static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4215{
4216 struct dpp_bootstrap_info *bi, *tmp;
4217 int found = 0;
4218
4219 if (!dpp)
4220 return -1;
4221
4222 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4223 struct dpp_bootstrap_info, list) {
4224 if (id && bi->id != id)
4225 continue;
4226 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07004227#ifdef CONFIG_DPP2
4228 if (dpp->remove_bi)
4229 dpp->remove_bi(dpp->cb_ctx, bi);
4230#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004231 dl_list_del(&bi->list);
4232 dpp_bootstrap_info_free(bi);
4233 }
4234
4235 if (id == 0)
4236 return 0; /* flush succeeds regardless of entries found */
4237 return found ? 0 : -1;
4238}
4239
4240
4241struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4242 const char *uri)
4243{
4244 struct dpp_bootstrap_info *bi;
4245
4246 if (!dpp)
4247 return NULL;
4248
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004249 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -07004250 if (!bi)
4251 return NULL;
4252
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004253 bi->type = DPP_BOOTSTRAP_QR_CODE;
4254 bi->id = dpp_next_id(dpp);
4255 dl_list_add(&dpp->bootstrap, &bi->list);
4256 return bi;
4257}
4258
4259
4260struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4261 const char *uri)
4262{
4263 struct dpp_bootstrap_info *bi;
4264
4265 if (!dpp)
4266 return NULL;
4267
4268 bi = dpp_parse_uri(uri);
4269 if (!bi)
4270 return NULL;
4271
4272 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004273 bi->id = dpp_next_id(dpp);
4274 dl_list_add(&dpp->bootstrap, &bi->list);
4275 return bi;
4276}
4277
4278
Sunil Ravia04bd252022-05-02 22:54:18 -07004279static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4280 char *txt)
4281{
4282 char *token, *context = NULL;
4283 u8 curves = 0;
4284
4285 if (!txt)
4286 return 0;
4287
4288 while ((token = str_token(txt, ":", &context))) {
4289 if (os_strcmp(token, "P-256") == 0) {
4290 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4291 } else if (os_strcmp(token, "P-384") == 0) {
4292 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4293 } else if (os_strcmp(token, "P-521") == 0) {
4294 curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4295 } else if (os_strcmp(token, "BP-256") == 0) {
4296 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4297 } else if (os_strcmp(token, "BP-384") == 0) {
4298 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4299 } else if (os_strcmp(token, "BP-512") == 0) {
4300 curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4301 } else {
4302 wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4303 token);
4304 return -1;
4305 }
4306 }
4307 bi->supported_curves = curves;
4308
4309 wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4310 bi->supported_curves);
4311
4312 return 0;
4313}
4314
4315
Hai Shalom021b0b52019-04-10 11:17:58 -07004316int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4317{
Hai Shalomfdcde762020-04-02 11:19:20 -07004318 char *mac = NULL, *info = NULL, *curve = NULL;
Sunil8cd6f4d2022-06-28 18:40:46 +00004319 char *key = NULL, *supported_curves = NULL, *host = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07004320 u8 *privkey = NULL;
4321 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004322 int ret = -1;
4323 struct dpp_bootstrap_info *bi;
4324
4325 if (!dpp)
4326 return -1;
4327
4328 bi = os_zalloc(sizeof(*bi));
4329 if (!bi)
4330 goto fail;
4331
4332 if (os_strstr(cmd, "type=qrcode"))
4333 bi->type = DPP_BOOTSTRAP_QR_CODE;
4334 else if (os_strstr(cmd, "type=pkex"))
4335 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08004336 else if (os_strstr(cmd, "type=nfc-uri"))
4337 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07004338 else
4339 goto fail;
4340
Hai Shalomfdcde762020-04-02 11:19:20 -07004341 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004342 mac = get_param(cmd, " mac=");
4343 info = get_param(cmd, " info=");
4344 curve = get_param(cmd, " curve=");
4345 key = get_param(cmd, " key=");
Sunil Ravia04bd252022-05-02 22:54:18 -07004346 supported_curves = get_param(cmd, " supported_curves=");
Sunil8cd6f4d2022-06-28 18:40:46 +00004347 host = get_param(cmd, " host=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004348
4349 if (key) {
4350 privkey_len = os_strlen(key) / 2;
4351 privkey = os_malloc(privkey_len);
4352 if (!privkey ||
4353 hexstr2bin(key, privkey, privkey_len) < 0)
4354 goto fail;
4355 }
4356
Hai Shalomfdcde762020-04-02 11:19:20 -07004357 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4358 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4359 dpp_parse_uri_mac(bi, mac) < 0 ||
4360 dpp_parse_uri_info(bi, info) < 0 ||
Sunil Ravia04bd252022-05-02 22:54:18 -07004361 dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
Sunil8cd6f4d2022-06-28 18:40:46 +00004362 dpp_parse_uri_host(bi, host) < 0 ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004363 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07004364 goto fail;
4365
Hai Shalom021b0b52019-04-10 11:17:58 -07004366 bi->id = dpp_next_id(dpp);
4367 dl_list_add(&dpp->bootstrap, &bi->list);
4368 ret = bi->id;
4369 bi = NULL;
4370fail:
4371 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -07004372 os_free(mac);
4373 os_free(info);
4374 str_clear_free(key);
Sunil Ravia04bd252022-05-02 22:54:18 -07004375 os_free(supported_curves);
Sunil8cd6f4d2022-06-28 18:40:46 +00004376 os_free(host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004377 bin_clear_free(privkey, privkey_len);
4378 dpp_bootstrap_info_free(bi);
4379 return ret;
4380}
4381
4382
4383struct dpp_bootstrap_info *
4384dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4385{
4386 struct dpp_bootstrap_info *bi;
4387
4388 if (!dpp)
4389 return NULL;
4390
4391 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4392 if (bi->id == id)
4393 return bi;
4394 }
4395 return NULL;
4396}
4397
4398
4399int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4400{
4401 unsigned int id_val;
4402
4403 if (os_strcmp(id, "*") == 0) {
4404 id_val = 0;
4405 } else {
4406 id_val = atoi(id);
4407 if (id_val == 0)
4408 return -1;
4409 }
4410
4411 return dpp_bootstrap_del(dpp, id_val);
4412}
4413
4414
Hai Shalom021b0b52019-04-10 11:17:58 -07004415const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4416{
4417 struct dpp_bootstrap_info *bi;
4418
4419 bi = dpp_bootstrap_get_id(dpp, id);
4420 if (!bi)
4421 return NULL;
4422 return bi->uri;
4423}
4424
4425
4426int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4427 char *reply, int reply_size)
4428{
4429 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004430 char pkhash[2 * SHA256_MAC_LEN + 1];
Sunil Ravia04bd252022-05-02 22:54:18 -07004431 char supp_curves[100];
Sunil8cd6f4d2022-06-28 18:40:46 +00004432 char host[100];
4433 int ret;
Hai Shalom021b0b52019-04-10 11:17:58 -07004434
4435 bi = dpp_bootstrap_get_id(dpp, id);
4436 if (!bi)
4437 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07004438 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4439 SHA256_MAC_LEN);
Sunil Ravia04bd252022-05-02 22:54:18 -07004440
4441 supp_curves[0] = '\0';
4442 if (bi->supported_curves) {
Sunil Ravia04bd252022-05-02 22:54:18 -07004443 size_t i;
4444 char *pos = supp_curves;
4445 char *end = &supp_curves[sizeof(supp_curves)];
4446 const char *curve[6] = { "P-256", "P-384", "P-521",
4447 "BP-256", "BP-384", "BP-512" };
4448
4449 ret = os_snprintf(pos, end - pos, "supp_curves=");
4450 if (os_snprintf_error(end - pos, ret))
4451 return -1;
4452 pos += ret;
4453
4454 for (i = 0; i < ARRAY_SIZE(curve); i++) {
4455 if (!(bi->supported_curves & BIT(i)))
4456 continue;
4457 ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4458 if (os_snprintf_error(end - pos, ret))
4459 return -1;
4460 pos += ret;
4461 }
4462
4463 if (pos[-1] == ':')
4464 pos[-1] = '\n';
4465 else
4466 supp_curves[0] = '\0';
4467 }
4468
Sunil8cd6f4d2022-06-28 18:40:46 +00004469 host[0] = '\0';
4470 if (bi->host) {
4471 char buf[100];
4472
4473 ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4474 hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4475 bi->port);
4476 if (os_snprintf_error(sizeof(host), ret))
4477 return -1;
4478 }
4479
Hai Shalom021b0b52019-04-10 11:17:58 -07004480 return os_snprintf(reply, reply_size, "type=%s\n"
4481 "mac_addr=" MACSTR "\n"
4482 "info=%s\n"
4483 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -07004484 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07004485 "curve=%s\n"
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004486 "pkhash=%s\n"
Sunil8cd6f4d2022-06-28 18:40:46 +00004487 "version=%d\n%s%s",
Hai Shalom021b0b52019-04-10 11:17:58 -07004488 dpp_bootstrap_type_txt(bi->type),
4489 MAC2STR(bi->mac_addr),
4490 bi->info ? bi->info : "",
4491 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07004492 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -07004493 bi->curve->name,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004494 pkhash,
Sunil Ravia04bd252022-05-02 22:54:18 -07004495 bi->version,
Sunil8cd6f4d2022-06-28 18:40:46 +00004496 supp_curves,
4497 host);
Hai Shalom021b0b52019-04-10 11:17:58 -07004498}
4499
4500
Hai Shalomfdcde762020-04-02 11:19:20 -07004501int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4502{
4503 struct dpp_bootstrap_info *bi;
4504
4505 bi = dpp_bootstrap_get_id(dpp, id);
4506 if (!bi)
4507 return -1;
4508
4509 str_clear_free(bi->configurator_params);
4510
4511 if (params) {
4512 bi->configurator_params = os_strdup(params);
4513 return bi->configurator_params ? 0 : -1;
4514 }
4515
4516 bi->configurator_params = NULL;
4517 return 0;
4518}
4519
4520
Hai Shalom021b0b52019-04-10 11:17:58 -07004521void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4522 const u8 *r_bootstrap,
4523 struct dpp_bootstrap_info **own_bi,
4524 struct dpp_bootstrap_info **peer_bi)
4525{
4526 struct dpp_bootstrap_info *bi;
4527
4528 *own_bi = NULL;
4529 *peer_bi = NULL;
4530 if (!dpp)
4531 return;
4532
4533 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4534 if (!*own_bi && bi->own &&
4535 os_memcmp(bi->pubkey_hash, r_bootstrap,
4536 SHA256_MAC_LEN) == 0) {
4537 wpa_printf(MSG_DEBUG,
4538 "DPP: Found matching own bootstrapping information");
4539 *own_bi = bi;
4540 }
4541
4542 if (!*peer_bi && !bi->own &&
4543 os_memcmp(bi->pubkey_hash, i_bootstrap,
4544 SHA256_MAC_LEN) == 0) {
4545 wpa_printf(MSG_DEBUG,
4546 "DPP: Found matching peer bootstrapping information");
4547 *peer_bi = bi;
4548 }
4549
4550 if (*own_bi && *peer_bi)
4551 break;
4552 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004553}
Hai Shalom021b0b52019-04-10 11:17:58 -07004554
Hai Shalomfdcde762020-04-02 11:19:20 -07004555
4556#ifdef CONFIG_DPP2
4557struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4558 const u8 *hash)
4559{
4560 struct dpp_bootstrap_info *bi;
4561
4562 if (!dpp)
4563 return NULL;
4564
4565 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4566 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4567 SHA256_MAC_LEN) == 0)
4568 return bi;
4569 }
4570
4571 return NULL;
4572}
4573#endif /* CONFIG_DPP2 */
4574
4575
4576static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4577 struct dpp_bootstrap_info *peer_bi)
4578{
4579 unsigned int i, freq = 0;
4580 enum hostapd_hw_mode mode;
4581 u8 op_class, channel;
4582 char chan[20];
4583
Hai Shalom899fcc72020-10-19 14:38:18 -07004584 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
Hai Shalomfdcde762020-04-02 11:19:20 -07004585 return 0; /* no channel preference/constraint */
4586
4587 for (i = 0; i < peer_bi->num_freq; i++) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004588 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004589 freq_included(own_bi->freq, own_bi->num_freq,
4590 peer_bi->freq[i])) {
4591 freq = peer_bi->freq[i];
4592 break;
4593 }
4594 }
4595 if (!freq) {
4596 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4597 return -1;
4598 }
4599
4600 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4601 if (mode == NUM_HOSTAPD_MODES) {
4602 wpa_printf(MSG_DEBUG,
4603 "DPP: Could not determine operating class or channel number for %u MHz",
4604 freq);
4605 }
4606
4607 wpa_printf(MSG_DEBUG,
4608 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4609 freq, op_class, channel);
4610 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4611 os_free(own_bi->chan);
4612 own_bi->chan = os_strdup(chan);
4613 own_bi->freq[0] = freq;
4614 own_bi->num_freq = 1;
4615 os_free(peer_bi->chan);
4616 peer_bi->chan = os_strdup(chan);
4617 peer_bi->freq[0] = freq;
4618 peer_bi->num_freq = 1;
4619
4620 return dpp_gen_uri(own_bi);
4621}
4622
4623
4624static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4625 struct dpp_bootstrap_info *peer_bi)
4626{
4627 if (peer_bi->curve == own_bi->curve)
4628 return 0;
4629
4630 wpa_printf(MSG_DEBUG,
4631 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4632
Hai Shaloma20dcd72022-02-04 13:43:00 -08004633 crypto_ec_key_deinit(own_bi->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -07004634 own_bi->pubkey = NULL;
4635
4636 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4637 dpp_gen_uri(own_bi) < 0)
4638 goto fail;
4639
4640 return 0;
4641fail:
4642 dl_list_del(&own_bi->list);
4643 dpp_bootstrap_info_free(own_bi);
4644 return -1;
4645}
4646
4647
4648int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4649 struct dpp_bootstrap_info *peer_bi)
4650{
4651 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4652 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4653 return -1;
4654 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004655}
4656
4657
4658static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4659{
4660 struct dpp_configurator *conf;
4661 unsigned int max_id = 0;
4662
4663 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4664 list) {
4665 if (conf->id > max_id)
4666 max_id = conf->id;
4667 }
4668 return max_id + 1;
4669}
4670
4671
4672int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4673{
Sunil Ravia04bd252022-05-02 22:54:18 -07004674 char *curve;
Hai Shalom899fcc72020-10-19 14:38:18 -07004675 char *key = NULL, *ppkey = NULL;
4676 u8 *privkey = NULL, *pp_key = NULL;
4677 size_t privkey_len = 0, pp_key_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004678 int ret = -1;
4679 struct dpp_configurator *conf = NULL;
Sunil Ravia04bd252022-05-02 22:54:18 -07004680 const struct dpp_curve_params *net_access_key_curve = NULL;
4681
4682 curve = get_param(cmd, " net_access_key_curve=");
4683 if (curve) {
4684 net_access_key_curve = dpp_get_curve_name(curve);
4685 if (!net_access_key_curve) {
4686 wpa_printf(MSG_DEBUG,
4687 "DPP: Unsupported net_access_key_curve: %s",
4688 curve);
4689 goto fail;
4690 }
4691 os_free(curve);
4692 }
Hai Shalom021b0b52019-04-10 11:17:58 -07004693
4694 curve = get_param(cmd, " curve=");
4695 key = get_param(cmd, " key=");
Hai Shalom899fcc72020-10-19 14:38:18 -07004696 ppkey = get_param(cmd, " ppkey=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004697
4698 if (key) {
4699 privkey_len = os_strlen(key) / 2;
4700 privkey = os_malloc(privkey_len);
4701 if (!privkey ||
4702 hexstr2bin(key, privkey, privkey_len) < 0)
4703 goto fail;
4704 }
4705
Hai Shalom899fcc72020-10-19 14:38:18 -07004706 if (ppkey) {
Hai Shalom60840252021-02-19 19:02:11 -08004707 pp_key_len = os_strlen(ppkey) / 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07004708 pp_key = os_malloc(pp_key_len);
4709 if (!pp_key ||
4710 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4711 goto fail;
4712 }
4713
4714 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4715 pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004716 if (!conf)
4717 goto fail;
4718
Sunil Ravia04bd252022-05-02 22:54:18 -07004719 conf->net_access_key_curve = net_access_key_curve;
Hai Shalom021b0b52019-04-10 11:17:58 -07004720 conf->id = dpp_next_configurator_id(dpp);
4721 dl_list_add(&dpp->configurator, &conf->list);
4722 ret = conf->id;
4723 conf = NULL;
4724fail:
4725 os_free(curve);
4726 str_clear_free(key);
Hai Shalom899fcc72020-10-19 14:38:18 -07004727 str_clear_free(ppkey);
Hai Shalom021b0b52019-04-10 11:17:58 -07004728 bin_clear_free(privkey, privkey_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004729 bin_clear_free(pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004730 dpp_configurator_free(conf);
4731 return ret;
4732}
4733
4734
Sunil Ravia04bd252022-05-02 22:54:18 -07004735int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4736{
4737 unsigned int id;
4738 struct dpp_configurator *conf;
4739 char *curve;
4740
4741 id = atoi(cmd);
4742 conf = dpp_configurator_get_id(dpp, id);
4743 if (!conf)
4744 return -1;
4745
4746 curve = get_param(cmd, " net_access_key_curve=");
4747 if (curve) {
4748 const struct dpp_curve_params *net_access_key_curve;
4749
4750 net_access_key_curve = dpp_get_curve_name(curve);
4751 os_free(curve);
4752 if (!net_access_key_curve)
4753 return -1;
4754 conf->net_access_key_curve = net_access_key_curve;
4755 }
4756
4757 return 0;
4758}
4759
4760
Hai Shalom021b0b52019-04-10 11:17:58 -07004761static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4762{
4763 struct dpp_configurator *conf, *tmp;
4764 int found = 0;
4765
4766 if (!dpp)
4767 return -1;
4768
4769 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4770 struct dpp_configurator, list) {
4771 if (id && conf->id != id)
4772 continue;
4773 found = 1;
4774 dl_list_del(&conf->list);
4775 dpp_configurator_free(conf);
4776 }
4777
4778 if (id == 0)
4779 return 0; /* flush succeeds regardless of entries found */
4780 return found ? 0 : -1;
4781}
4782
4783
4784int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4785{
4786 unsigned int id_val;
4787
4788 if (os_strcmp(id, "*") == 0) {
4789 id_val = 0;
4790 } else {
4791 id_val = atoi(id);
4792 if (id_val == 0)
4793 return -1;
4794 }
4795
4796 return dpp_configurator_del(dpp, id_val);
4797}
4798
4799
4800int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4801 char *buf, size_t buflen)
4802{
4803 struct dpp_configurator *conf;
4804
4805 conf = dpp_configurator_get_id(dpp, id);
4806 if (!conf)
4807 return -1;
4808
4809 return dpp_configurator_get_key(conf, buf, buflen);
4810}
4811
4812
Hai Shalom81f62d82019-07-22 12:10:00 -07004813#ifdef CONFIG_DPP2
4814
Hai Shalomfdcde762020-04-02 11:19:20 -07004815int dpp_configurator_from_backup(struct dpp_global *dpp,
4816 struct dpp_asymmetric_key *key)
4817{
4818 struct dpp_configurator *conf;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004819 const struct dpp_curve_params *curve, *curve_pp;
Hai Shalomfdcde762020-04-02 11:19:20 -07004820
Hai Shalom899fcc72020-10-19 14:38:18 -07004821 if (!key->csign || !key->pp_key)
Hai Shalomfdcde762020-04-02 11:19:20 -07004822 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004823
4824 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
Hai Shalomfdcde762020-04-02 11:19:20 -07004825 if (!curve) {
4826 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4827 return -1;
4828 }
Hai Shaloma20dcd72022-02-04 13:43:00 -08004829
4830 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
4831 if (!curve_pp) {
4832 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
Hai Shalom899fcc72020-10-19 14:38:18 -07004833 return -1;
Hai Shaloma20dcd72022-02-04 13:43:00 -08004834 }
4835
4836 if (curve != curve_pp) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004837 wpa_printf(MSG_INFO,
4838 "DPP: Mismatch in c-sign-key and ppKey groups");
4839 return -1;
4840 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004841
4842 conf = os_zalloc(sizeof(*conf));
4843 if (!conf)
4844 return -1;
4845 conf->curve = curve;
4846 conf->csign = key->csign;
4847 key->csign = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07004848 conf->pp_key = key->pp_key;
4849 key->pp_key = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07004850 conf->own = 1;
4851 if (dpp_configurator_gen_kid(conf) < 0) {
4852 dpp_configurator_free(conf);
4853 return -1;
4854 }
4855
4856 conf->id = dpp_next_configurator_id(dpp);
4857 dl_list_add(&dpp->configurator, &conf->list);
4858 return conf->id;
4859}
4860
4861
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004862struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4863 const u8 *kid)
Hai Shalom81f62d82019-07-22 12:10:00 -07004864{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004865 struct dpp_configurator *conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004866
4867 if (!dpp)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004868 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004869
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004870 dl_list_for_each(conf, &dpp->configurator,
4871 struct dpp_configurator, list) {
4872 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4873 return conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004874 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004875 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004876}
4877
4878#endif /* CONFIG_DPP2 */
4879
4880
4881struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07004882{
4883 struct dpp_global *dpp;
4884
4885 dpp = os_zalloc(sizeof(*dpp));
4886 if (!dpp)
4887 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004888#ifdef CONFIG_DPP2
4889 dpp->cb_ctx = config->cb_ctx;
Hai Shalomfdcde762020-04-02 11:19:20 -07004890 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004891#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004892
4893 dl_list_init(&dpp->bootstrap);
4894 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07004895#ifdef CONFIG_DPP2
4896 dl_list_init(&dpp->controllers);
4897 dl_list_init(&dpp->tcp_init);
4898#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004899
4900 return dpp;
4901}
4902
4903
4904void dpp_global_clear(struct dpp_global *dpp)
4905{
4906 if (!dpp)
4907 return;
4908
4909 dpp_bootstrap_del(dpp, 0);
4910 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07004911#ifdef CONFIG_DPP2
4912 dpp_tcp_init_flush(dpp);
4913 dpp_relay_flush_controllers(dpp);
4914 dpp_controller_stop(dpp);
4915#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004916}
4917
4918
4919void dpp_global_deinit(struct dpp_global *dpp)
4920{
4921 dpp_global_clear(dpp);
4922 os_free(dpp);
4923}
Hai Shalom81f62d82019-07-22 12:10:00 -07004924
4925
4926#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07004927
Hai Shalomfdcde762020-04-02 11:19:20 -07004928struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
4929{
4930 struct wpabuf *msg;
4931
4932 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
4933
4934 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
4935 if (!msg)
4936 return NULL;
4937
4938 /* Responder Bootstrapping Key Hash */
4939 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
4940 wpa_hexdump_buf(MSG_DEBUG,
4941 "DPP: Presence Announcement frame attributes", msg);
4942 return msg;
4943}
Hai Shalom899fcc72020-10-19 14:38:18 -07004944
4945
4946void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
4947 unsigned int freq, const u8 *hash)
4948{
4949 char hex[SHA256_MAC_LEN * 2 + 1];
4950
4951 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
4952 wpa_msg(msg_ctx, MSG_INFO,
4953 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
4954 id, MAC2STR(src), freq, hex);
4955}
4956
Hai Shalom81f62d82019-07-22 12:10:00 -07004957#endif /* CONFIG_DPP2 */