blob: 42a930212957a05c49cf5a41d16ea073086ca0a9 [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 Shalomc1a21442022-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"
16#include "common/ieee802_11_common.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070017#include "common/wpa_ctrl.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070018#include "common/gas.h"
Hai Shalom899fcc72020-10-19 14:38:18 -070019#include "eap_common/eap_defs.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070020#include "crypto/crypto.h"
21#include "crypto/random.h"
22#include "crypto/aes.h"
23#include "crypto/aes_siv.h"
Roshan Pius3a1667e2018-07-03 15:17:14 -070024#include "drivers/driver.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070025#include "dpp.h"
Hai Shalom4fbc08f2020-05-18 12:37:00 -070026#include "dpp_i.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070027
28
Roshan Pius3a1667e2018-07-03 15:17:14 -070029#ifdef CONFIG_TESTING_OPTIONS
Hai Shalomc1a21442022-02-04 13:43:00 -080030#ifdef CONFIG_DPP3
31int dpp_version_override = 3;
32#elif defined(CONFIG_DPP2)
Hai Shalom4fbc08f2020-05-18 12:37:00 -070033int dpp_version_override = 2;
34#else
35int dpp_version_override = 1;
36#endif
Roshan Pius3a1667e2018-07-03 15:17:14 -070037enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
Roshan Pius3a1667e2018-07-03 15:17:14 -070038#endif /* CONFIG_TESTING_OPTIONS */
39
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070040
Hai Shalom4fbc08f2020-05-18 12:37:00 -070041void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
Roshan Pius3a1667e2018-07-03 15:17:14 -070042{
43 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
44}
45
46
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070047struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
48 size_t len)
49{
50 struct wpabuf *msg;
51
52 msg = wpabuf_alloc(8 + len);
53 if (!msg)
54 return NULL;
55 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
56 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
57 wpabuf_put_be24(msg, OUI_WFA);
58 wpabuf_put_u8(msg, DPP_OUI_TYPE);
59 wpabuf_put_u8(msg, 1); /* Crypto Suite */
60 wpabuf_put_u8(msg, type);
61 return msg;
62}
63
64
65const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
66{
67 u16 id, alen;
68 const u8 *pos = buf, *end = buf + len;
69
70 while (end - pos >= 4) {
71 id = WPA_GET_LE16(pos);
72 pos += 2;
73 alen = WPA_GET_LE16(pos);
74 pos += 2;
75 if (alen > end - pos)
76 return NULL;
77 if (id == req_id) {
78 *ret_len = alen;
79 return pos;
80 }
81 pos += alen;
82 }
83
84 return NULL;
85}
86
87
Hai Shalomc3565922019-10-28 11:58:20 -070088static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
89 u16 req_id, u16 *ret_len)
90{
91 u16 id, alen;
92 const u8 *pos, *end = buf + len;
93
94 if (!prev)
95 pos = buf;
96 else
97 pos = prev + WPA_GET_LE16(prev - 2);
98 while (end - pos >= 4) {
99 id = WPA_GET_LE16(pos);
100 pos += 2;
101 alen = WPA_GET_LE16(pos);
102 pos += 2;
103 if (alen > end - pos)
104 return NULL;
105 if (id == req_id) {
106 *ret_len = alen;
107 return pos;
108 }
109 pos += alen;
110 }
111
112 return NULL;
113}
114
115
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700116int dpp_check_attrs(const u8 *buf, size_t len)
117{
118 const u8 *pos, *end;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700119 int wrapped_data = 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700120
121 pos = buf;
122 end = buf + len;
123 while (end - pos >= 4) {
124 u16 id, alen;
125
126 id = WPA_GET_LE16(pos);
127 pos += 2;
128 alen = WPA_GET_LE16(pos);
129 pos += 2;
130 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
131 id, alen);
132 if (alen > end - pos) {
133 wpa_printf(MSG_DEBUG,
134 "DPP: Truncated message - not enough room for the attribute - dropped");
135 return -1;
136 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700137 if (wrapped_data) {
138 wpa_printf(MSG_DEBUG,
139 "DPP: An unexpected attribute included after the Wrapped Data attribute");
140 return -1;
141 }
142 if (id == DPP_ATTR_WRAPPED_DATA)
143 wrapped_data = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700144 pos += alen;
145 }
146
147 if (end != pos) {
148 wpa_printf(MSG_DEBUG,
149 "DPP: Unexpected octets (%d) after the last attribute",
150 (int) (end - pos));
151 return -1;
152 }
153
154 return 0;
155}
156
157
158void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
159{
160 if (!info)
161 return;
162 os_free(info->uri);
163 os_free(info->info);
Hai Shalomfdcde762020-04-02 11:19:20 -0700164 os_free(info->chan);
165 os_free(info->pk);
Hai Shalomc1a21442022-02-04 13:43:00 -0800166 crypto_ec_key_deinit(info->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -0700167 str_clear_free(info->configurator_params);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700168 os_free(info);
169}
170
171
172const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
173{
174 switch (type) {
175 case DPP_BOOTSTRAP_QR_CODE:
176 return "QRCODE";
177 case DPP_BOOTSTRAP_PKEX:
178 return "PKEX";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800179 case DPP_BOOTSTRAP_NFC_URI:
180 return "NFC-URI";
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700181 }
182 return "??";
183}
184
185
186static int dpp_uri_valid_info(const char *info)
187{
188 while (*info) {
189 unsigned char val = *info++;
190
191 if (val < 0x20 || val > 0x7e || val == 0x3b)
192 return 0;
193 }
194
195 return 1;
196}
197
198
199static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
200{
201 bi->uri = os_strdup(uri);
202 return bi->uri ? 0 : -1;
203}
204
205
206int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
207 const char *chan_list)
208{
Hai Shalom81f62d82019-07-22 12:10:00 -0700209 const char *pos = chan_list, *pos2;
210 int opclass = -1, channel, freq;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700211
212 while (pos && *pos && *pos != ';') {
Hai Shalom81f62d82019-07-22 12:10:00 -0700213 pos2 = pos;
214 while (*pos2 >= '0' && *pos2 <= '9')
215 pos2++;
216 if (*pos2 == '/') {
217 opclass = atoi(pos);
218 pos = pos2 + 1;
219 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700220 if (opclass <= 0)
221 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700222 channel = atoi(pos);
223 if (channel <= 0)
224 goto fail;
225 while (*pos >= '0' && *pos <= '9')
226 pos++;
227 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
228 wpa_printf(MSG_DEBUG,
229 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
230 opclass, channel, freq);
Hai Shalom899fcc72020-10-19 14:38:18 -0700231 bi->channels_listed = true;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700232 if (freq < 0) {
233 wpa_printf(MSG_DEBUG,
234 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
235 opclass, channel);
236 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
237 wpa_printf(MSG_DEBUG,
238 "DPP: Too many channels in URI channel-list - ignore list");
239 bi->num_freq = 0;
240 break;
241 } else {
242 bi->freq[bi->num_freq++] = freq;
243 }
244
245 if (*pos == ';' || *pos == '\0')
246 break;
247 if (*pos != ',')
248 goto fail;
249 pos++;
250 }
251
252 return 0;
253fail:
254 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
255 return -1;
256}
257
258
259int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
260{
261 if (!mac)
262 return 0;
263
264 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
265 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
266 return -1;
267 }
268
269 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
270
271 return 0;
272}
273
274
275int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
276{
277 const char *end;
278
279 if (!info)
280 return 0;
281
282 end = os_strchr(info, ';');
283 if (!end)
284 end = info + os_strlen(info);
285 bi->info = os_malloc(end - info + 1);
286 if (!bi->info)
287 return -1;
288 os_memcpy(bi->info, info, end - info);
289 bi->info[end - info] = '\0';
290 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
291 if (!dpp_uri_valid_info(bi->info)) {
292 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
293 return -1;
294 }
295
296 return 0;
297}
298
299
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700300int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700301{
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700302#ifdef CONFIG_DPP2
303 if (!version || DPP_VERSION < 2)
304 return 0;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700305
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700306 if (*version == '1')
307 bi->version = 1;
308 else if (*version == '2')
309 bi->version = 2;
Hai Shalomc1a21442022-02-04 13:43:00 -0800310 else if (*version == '3')
311 bi->version = 3;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700312 else
313 wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700314
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700315 wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
316#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700317
318 return 0;
319}
320
321
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700322static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
323{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700324 u8 *data;
325 size_t data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700326 int res;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700327 const char *end;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700328
329 end = os_strchr(info, ';');
330 if (!end)
331 return -1;
332
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800333 data = base64_decode(info, end - info, &data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700334 if (!data) {
335 wpa_printf(MSG_DEBUG,
336 "DPP: Invalid base64 encoding on URI public-key");
337 return -1;
338 }
339 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
340 data, data_len);
341
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700342 res = dpp_get_subject_public_key(bi, data, data_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700343 os_free(data);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700344 return res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700345}
346
347
348static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
349{
350 const char *pos = uri;
351 const char *end;
352 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700353 const char *version = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700354 struct dpp_bootstrap_info *bi;
355
356 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
357
358 if (os_strncmp(pos, "DPP:", 4) != 0) {
359 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
360 return NULL;
361 }
362 pos += 4;
363
364 for (;;) {
365 end = os_strchr(pos, ';');
366 if (!end)
367 break;
368
369 if (end == pos) {
370 /* Handle terminating ";;" and ignore unexpected ";"
371 * for parsing robustness. */
372 pos++;
373 continue;
374 }
375
376 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
377 chan_list = pos + 2;
378 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
379 mac = pos + 2;
380 else if (pos[0] == 'I' && pos[1] == ':' && !info)
381 info = pos + 2;
382 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
383 pk = pos + 2;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700384 else if (pos[0] == 'V' && pos[1] == ':' && !version)
385 version = pos + 2;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700386 else
387 wpa_hexdump_ascii(MSG_DEBUG,
388 "DPP: Ignore unrecognized URI parameter",
389 pos, end - pos);
390 pos = end + 1;
391 }
392
393 if (!pk) {
394 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
395 return NULL;
396 }
397
398 bi = os_zalloc(sizeof(*bi));
399 if (!bi)
400 return NULL;
401
402 if (dpp_clone_uri(bi, uri) < 0 ||
403 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
404 dpp_parse_uri_mac(bi, mac) < 0 ||
405 dpp_parse_uri_info(bi, info) < 0 ||
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700406 dpp_parse_uri_version(bi, version) < 0 ||
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700407 dpp_parse_uri_pk(bi, pk) < 0) {
408 dpp_bootstrap_info_free(bi);
409 bi = NULL;
410 }
411
412 return bi;
413}
414
415
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700416void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700417{
Roshan Pius3a1667e2018-07-03 15:17:14 -0700418 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
419 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
420 wpabuf_put_le16(msg, 1);
421 wpabuf_put_u8(msg, status);
422}
423
424
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700425void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700426{
427 if (hash) {
428 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
429 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
430 wpabuf_put_le16(msg, SHA256_MAC_LEN);
431 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
432 }
433}
434
435
Roshan Pius3a1667e2018-07-03 15:17:14 -0700436static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
437 u16 num_modes, unsigned int freq)
438{
439 u16 m;
440 int c, flag;
441
442 if (!own_modes || !num_modes)
443 return 1;
444
445 for (m = 0; m < num_modes; m++) {
446 for (c = 0; c < own_modes[m].num_channels; c++) {
447 if ((unsigned int) own_modes[m].channels[c].freq !=
448 freq)
449 continue;
450 flag = own_modes[m].channels[c].flag;
451 if (!(flag & (HOSTAPD_CHAN_DISABLED |
452 HOSTAPD_CHAN_NO_IR |
453 HOSTAPD_CHAN_RADAR)))
454 return 1;
455 }
456 }
457
458 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
459 return 0;
460}
461
462
463static int freq_included(const unsigned int freqs[], unsigned int num,
464 unsigned int freq)
465{
466 while (num > 0) {
467 if (freqs[--num] == freq)
468 return 1;
469 }
470 return 0;
471}
472
473
474static void freq_to_start(unsigned int freqs[], unsigned int num,
475 unsigned int freq)
476{
477 unsigned int i;
478
479 for (i = 0; i < num; i++) {
480 if (freqs[i] == freq)
481 break;
482 }
483 if (i == 0 || i >= num)
484 return;
485 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
486 freqs[0] = freq;
487}
488
489
490static int dpp_channel_intersect(struct dpp_authentication *auth,
491 struct hostapd_hw_modes *own_modes,
492 u16 num_modes)
493{
494 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
495 unsigned int i, freq;
496
497 for (i = 0; i < peer_bi->num_freq; i++) {
498 freq = peer_bi->freq[i];
499 if (freq_included(auth->freq, auth->num_freq, freq))
500 continue;
501 if (dpp_channel_ok_init(own_modes, num_modes, freq))
502 auth->freq[auth->num_freq++] = freq;
503 }
504 if (!auth->num_freq) {
505 wpa_printf(MSG_INFO,
506 "DPP: No available channels for initiating DPP Authentication");
507 return -1;
508 }
509 auth->curr_freq = auth->freq[0];
510 return 0;
511}
512
513
514static int dpp_channel_local_list(struct dpp_authentication *auth,
515 struct hostapd_hw_modes *own_modes,
516 u16 num_modes)
517{
518 u16 m;
519 int c, flag;
520 unsigned int freq;
521
522 auth->num_freq = 0;
523
524 if (!own_modes || !num_modes) {
525 auth->freq[0] = 2412;
526 auth->freq[1] = 2437;
527 auth->freq[2] = 2462;
528 auth->num_freq = 3;
529 return 0;
530 }
531
532 for (m = 0; m < num_modes; m++) {
533 for (c = 0; c < own_modes[m].num_channels; c++) {
534 freq = own_modes[m].channels[c].freq;
535 flag = own_modes[m].channels[c].flag;
536 if (flag & (HOSTAPD_CHAN_DISABLED |
537 HOSTAPD_CHAN_NO_IR |
538 HOSTAPD_CHAN_RADAR))
539 continue;
540 if (freq_included(auth->freq, auth->num_freq, freq))
541 continue;
542 auth->freq[auth->num_freq++] = freq;
543 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
544 m = num_modes;
545 break;
546 }
547 }
548 }
549
550 return auth->num_freq == 0 ? -1 : 0;
551}
552
553
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700554int dpp_prepare_channel_list(struct dpp_authentication *auth,
555 unsigned int neg_freq,
556 struct hostapd_hw_modes *own_modes, u16 num_modes)
Roshan Pius3a1667e2018-07-03 15:17:14 -0700557{
558 int res;
559 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
560 unsigned int i;
561
Hai Shalomfdcde762020-04-02 11:19:20 -0700562 if (!own_modes) {
563 if (!neg_freq)
564 return -1;
565 auth->num_freq = 1;
566 auth->freq[0] = neg_freq;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700567 auth->curr_freq = neg_freq;
Hai Shalomfdcde762020-04-02 11:19:20 -0700568 return 0;
569 }
570
Roshan Pius3a1667e2018-07-03 15:17:14 -0700571 if (auth->peer_bi->num_freq > 0)
572 res = dpp_channel_intersect(auth, own_modes, num_modes);
573 else
574 res = dpp_channel_local_list(auth, own_modes, num_modes);
575 if (res < 0)
576 return res;
577
578 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
579 * likely channels first. */
580 freq_to_start(auth->freq, auth->num_freq, 2462);
581 freq_to_start(auth->freq, auth->num_freq, 2412);
582 freq_to_start(auth->freq, auth->num_freq, 2437);
583
584 auth->freq_idx = 0;
585 auth->curr_freq = auth->freq[0];
586
587 pos = freqs;
588 end = pos + sizeof(freqs);
589 for (i = 0; i < auth->num_freq; i++) {
590 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
591 if (os_snprintf_error(end - pos, res))
592 break;
593 pos += res;
594 }
595 *pos = '\0';
596 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
597 freqs);
598
599 return 0;
600}
601
602
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700603int dpp_gen_uri(struct dpp_bootstrap_info *bi)
Hai Shalomfdcde762020-04-02 11:19:20 -0700604{
605 char macstr[ETH_ALEN * 2 + 10];
606 size_t len;
607
608 len = 4; /* "DPP:" */
609 if (bi->chan)
610 len += 3 + os_strlen(bi->chan); /* C:...; */
611 if (is_zero_ether_addr(bi->mac_addr))
612 macstr[0] = '\0';
613 else
614 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
615 MAC2STR(bi->mac_addr));
616 len += os_strlen(macstr); /* M:...; */
617 if (bi->info)
618 len += 3 + os_strlen(bi->info); /* I:...; */
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700619#ifdef CONFIG_DPP2
620 len += 4; /* V:2; */
621#endif /* CONFIG_DPP2 */
Hai Shalomfdcde762020-04-02 11:19:20 -0700622 len += 4 + os_strlen(bi->pk); /* K:...;; */
623
624 os_free(bi->uri);
625 bi->uri = os_malloc(len + 1);
626 if (!bi->uri)
627 return -1;
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700628 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;",
Hai Shalomfdcde762020-04-02 11:19:20 -0700629 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
630 bi->chan ? ";" : "",
631 macstr,
632 bi->info ? "I:" : "", bi->info ? bi->info : "",
633 bi->info ? ";" : "",
Hai Shalomc1a21442022-02-04 13:43:00 -0800634 DPP_VERSION == 3 ? "V:3;" :
635 (DPP_VERSION == 2 ? "V:2;" : ""),
Hai Shalomfdcde762020-04-02 11:19:20 -0700636 bi->pk);
637 return 0;
638}
639
640
Hai Shalomfdcde762020-04-02 11:19:20 -0700641struct dpp_authentication *
642dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
643{
644 struct dpp_authentication *auth;
645
646 auth = os_zalloc(sizeof(*auth));
647 if (!auth)
648 return NULL;
649 auth->global = dpp;
650 auth->msg_ctx = msg_ctx;
651 auth->conf_resp_status = 255;
652 return auth;
653}
654
655
Hai Shalom021b0b52019-04-10 11:17:58 -0700656static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
657 const char *json)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700658{
659 size_t nonce_len;
660 size_t json_len, clear_len;
661 struct wpabuf *clear = NULL, *msg = NULL;
662 u8 *wrapped;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700663 size_t attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700664
665 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
666
667 nonce_len = auth->curve->nonce_len;
668 if (random_get_bytes(auth->e_nonce, nonce_len)) {
669 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
670 goto fail;
671 }
672 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
673 json_len = os_strlen(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700674 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700675
676 /* { E-nonce, configAttrib }ke */
677 clear_len = 4 + nonce_len + 4 + json_len;
678 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700679 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
680#ifdef CONFIG_TESTING_OPTIONS
681 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
682 attr_len += 5;
683#endif /* CONFIG_TESTING_OPTIONS */
684 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700685 if (!clear || !msg)
686 goto fail;
687
Roshan Pius3a1667e2018-07-03 15:17:14 -0700688#ifdef CONFIG_TESTING_OPTIONS
689 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
690 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
691 goto skip_e_nonce;
692 }
693 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
694 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
695 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
696 wpabuf_put_le16(clear, nonce_len - 1);
697 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
698 goto skip_e_nonce;
699 }
700 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
701 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
702 goto skip_wrapped_data;
703 }
704#endif /* CONFIG_TESTING_OPTIONS */
705
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700706 /* E-nonce */
707 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
708 wpabuf_put_le16(clear, nonce_len);
709 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
710
Roshan Pius3a1667e2018-07-03 15:17:14 -0700711#ifdef CONFIG_TESTING_OPTIONS
712skip_e_nonce:
713 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
714 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
715 goto skip_conf_attr_obj;
716 }
717#endif /* CONFIG_TESTING_OPTIONS */
718
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700719 /* configAttrib */
720 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
721 wpabuf_put_le16(clear, json_len);
722 wpabuf_put_data(clear, json, json_len);
723
Roshan Pius3a1667e2018-07-03 15:17:14 -0700724#ifdef CONFIG_TESTING_OPTIONS
725skip_conf_attr_obj:
726#endif /* CONFIG_TESTING_OPTIONS */
727
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700728 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
729 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
730 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
731
732 /* No AES-SIV AD */
733 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
734 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
735 wpabuf_head(clear), wpabuf_len(clear),
736 0, NULL, NULL, wrapped) < 0)
737 goto fail;
738 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
739 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
740
Roshan Pius3a1667e2018-07-03 15:17:14 -0700741#ifdef CONFIG_TESTING_OPTIONS
742 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
743 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
744 dpp_build_attr_status(msg, DPP_STATUS_OK);
745 }
746skip_wrapped_data:
747#endif /* CONFIG_TESTING_OPTIONS */
748
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700749 wpa_hexdump_buf(MSG_DEBUG,
750 "DPP: Configuration Request frame attributes", msg);
751 wpabuf_free(clear);
752 return msg;
753
754fail:
755 wpabuf_free(clear);
756 wpabuf_free(msg);
757 return NULL;
758}
759
760
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700761void dpp_write_adv_proto(struct wpabuf *buf)
Hai Shalom021b0b52019-04-10 11:17:58 -0700762{
763 /* Advertisement Protocol IE */
764 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
765 wpabuf_put_u8(buf, 8); /* Length */
766 wpabuf_put_u8(buf, 0x7f);
767 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
768 wpabuf_put_u8(buf, 5);
769 wpabuf_put_be24(buf, OUI_WFA);
770 wpabuf_put_u8(buf, DPP_OUI_TYPE);
771 wpabuf_put_u8(buf, 0x01);
772}
773
774
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700775void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
Hai Shalom021b0b52019-04-10 11:17:58 -0700776{
777 /* GAS Query */
778 wpabuf_put_le16(buf, wpabuf_len(query));
779 wpabuf_put_buf(buf, query);
780}
781
782
783struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
784 const char *json)
785{
786 struct wpabuf *buf, *conf_req;
787
788 conf_req = dpp_build_conf_req_attr(auth, json);
789 if (!conf_req) {
790 wpa_printf(MSG_DEBUG,
791 "DPP: No configuration request data available");
792 return NULL;
793 }
794
795 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
796 if (!buf) {
797 wpabuf_free(conf_req);
798 return NULL;
799 }
800
801 dpp_write_adv_proto(buf);
802 dpp_write_gas_query(buf, conf_req);
803 wpabuf_free(conf_req);
804 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
805
806 return buf;
807}
808
809
Hai Shalomc3565922019-10-28 11:58:20 -0700810struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800811 const char *name,
812 enum dpp_netrole netrole,
Hai Shalomc3565922019-10-28 11:58:20 -0700813 const char *mud_url, int *opclasses)
814{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800815 size_t len, name_len;
Hai Shalomc3565922019-10-28 11:58:20 -0700816 const char *tech = "infra";
817 const char *dpp_name;
Hai Shalomc3565922019-10-28 11:58:20 -0700818 struct wpabuf *buf, *json;
Hai Shalom899fcc72020-10-19 14:38:18 -0700819 char *csr = NULL;
Hai Shalomc3565922019-10-28 11:58:20 -0700820
821#ifdef CONFIG_TESTING_OPTIONS
822 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
823 static const char *bogus_tech = "knfra";
824
825 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
826 tech = bogus_tech;
827 }
828#endif /* CONFIG_TESTING_OPTIONS */
829
830 dpp_name = name ? name : "Test";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800831 name_len = os_strlen(dpp_name);
Hai Shalomc3565922019-10-28 11:58:20 -0700832
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800833 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
Hai Shalomc3565922019-10-28 11:58:20 -0700834 if (mud_url && mud_url[0])
835 len += 10 + os_strlen(mud_url);
Hai Shalom899fcc72020-10-19 14:38:18 -0700836#ifdef CONFIG_DPP2
837 if (auth->csr) {
838 size_t csr_len;
839
840 csr = base64_encode_no_lf(wpabuf_head(auth->csr),
841 wpabuf_len(auth->csr), &csr_len);
842 if (!csr)
843 return NULL;
844 len += 30 + csr_len;
845 }
846#endif /* CONFIG_DPP2 */
Hai Shalomc3565922019-10-28 11:58:20 -0700847 json = wpabuf_alloc(len);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800848 if (!json)
849 return NULL;
850
851 json_start_object(json, NULL);
852 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
853 wpabuf_free(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700854 return NULL;
855 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800856 json_value_sep(json);
857 json_add_string(json, "wi-fi_tech", tech);
858 json_value_sep(json);
859 json_add_string(json, "netRole", dpp_netrole_str(netrole));
860 if (mud_url && mud_url[0]) {
861 json_value_sep(json);
862 json_add_string(json, "mudurl", mud_url);
863 }
Hai Shalomc3565922019-10-28 11:58:20 -0700864 if (opclasses) {
865 int i;
866
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800867 json_value_sep(json);
868 json_start_array(json, "bandSupport");
Hai Shalomc3565922019-10-28 11:58:20 -0700869 for (i = 0; opclasses[i]; i++)
870 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800871 json_end_array(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700872 }
Hai Shalom899fcc72020-10-19 14:38:18 -0700873 if (csr) {
874 json_value_sep(json);
875 json_add_string(json, "pkcs10", csr);
876 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -0800877 json_end_object(json);
Hai Shalomc3565922019-10-28 11:58:20 -0700878
879 buf = dpp_build_conf_req(auth, wpabuf_head(json));
880 wpabuf_free(json);
Hai Shalom899fcc72020-10-19 14:38:18 -0700881 os_free(csr);
Hai Shalomc3565922019-10-28 11:58:20 -0700882
883 return buf;
884}
885
886
Hai Shalom021b0b52019-04-10 11:17:58 -0700887static int bin_str_eq(const char *val, size_t len, const char *cmp)
888{
889 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
890}
891
892
893struct dpp_configuration * dpp_configuration_alloc(const char *type)
894{
895 struct dpp_configuration *conf;
896 const char *end;
897 size_t len;
898
899 conf = os_zalloc(sizeof(*conf));
900 if (!conf)
901 goto fail;
902
903 end = os_strchr(type, ' ');
904 if (end)
905 len = end - type;
906 else
907 len = os_strlen(type);
908
909 if (bin_str_eq(type, len, "psk"))
910 conf->akm = DPP_AKM_PSK;
911 else if (bin_str_eq(type, len, "sae"))
912 conf->akm = DPP_AKM_SAE;
913 else if (bin_str_eq(type, len, "psk-sae") ||
914 bin_str_eq(type, len, "psk+sae"))
915 conf->akm = DPP_AKM_PSK_SAE;
916 else if (bin_str_eq(type, len, "sae-dpp") ||
917 bin_str_eq(type, len, "dpp+sae"))
918 conf->akm = DPP_AKM_SAE_DPP;
919 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
920 bin_str_eq(type, len, "dpp+psk+sae"))
921 conf->akm = DPP_AKM_PSK_SAE_DPP;
922 else if (bin_str_eq(type, len, "dpp"))
923 conf->akm = DPP_AKM_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -0700924 else if (bin_str_eq(type, len, "dot1x"))
925 conf->akm = DPP_AKM_DOT1X;
Hai Shalom021b0b52019-04-10 11:17:58 -0700926 else
927 goto fail;
928
929 return conf;
930fail:
931 dpp_configuration_free(conf);
932 return NULL;
933}
934
935
936int dpp_akm_psk(enum dpp_akm akm)
937{
938 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
939 akm == DPP_AKM_PSK_SAE_DPP;
940}
941
942
943int dpp_akm_sae(enum dpp_akm akm)
944{
945 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
946 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
947}
948
949
950int dpp_akm_legacy(enum dpp_akm akm)
951{
952 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
953 akm == DPP_AKM_SAE;
954}
955
956
957int dpp_akm_dpp(enum dpp_akm akm)
958{
959 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
960 akm == DPP_AKM_PSK_SAE_DPP;
961}
962
963
964int dpp_akm_ver2(enum dpp_akm akm)
965{
966 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
967}
968
969
970int dpp_configuration_valid(const struct dpp_configuration *conf)
971{
972 if (conf->ssid_len == 0)
973 return 0;
974 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
975 return 0;
976 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
977 return 0;
978 return 1;
979}
980
981
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700982void dpp_configuration_free(struct dpp_configuration *conf)
983{
984 if (!conf)
985 return;
986 str_clear_free(conf->passphrase);
Hai Shalomce48b4a2018-09-05 11:41:35 -0700987 os_free(conf->group_id);
Hai Shalom899fcc72020-10-19 14:38:18 -0700988 os_free(conf->csrattrs);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700989 bin_clear_free(conf, sizeof(*conf));
990}
991
992
Hai Shalomc3565922019-10-28 11:58:20 -0700993static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
994 const char *cmd, int idx)
Hai Shalom021b0b52019-04-10 11:17:58 -0700995{
996 const char *pos, *end;
997 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
998 struct dpp_configuration *conf = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -0700999 size_t len;
Hai Shalom021b0b52019-04-10 11:17:58 -07001000
1001 pos = os_strstr(cmd, " conf=sta-");
1002 if (pos) {
1003 conf_sta = dpp_configuration_alloc(pos + 10);
1004 if (!conf_sta)
1005 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001006 conf_sta->netrole = DPP_NETROLE_STA;
Hai Shalom021b0b52019-04-10 11:17:58 -07001007 conf = conf_sta;
1008 }
1009
1010 pos = os_strstr(cmd, " conf=ap-");
1011 if (pos) {
1012 conf_ap = dpp_configuration_alloc(pos + 9);
1013 if (!conf_ap)
1014 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07001015 conf_ap->netrole = DPP_NETROLE_AP;
Hai Shalom021b0b52019-04-10 11:17:58 -07001016 conf = conf_ap;
1017 }
1018
Hai Shalomfdcde762020-04-02 11:19:20 -07001019 pos = os_strstr(cmd, " conf=configurator");
1020 if (pos)
1021 auth->provision_configurator = 1;
1022
Hai Shalom021b0b52019-04-10 11:17:58 -07001023 if (!conf)
1024 return 0;
1025
1026 pos = os_strstr(cmd, " ssid=");
1027 if (pos) {
1028 pos += 6;
1029 end = os_strchr(pos, ' ');
1030 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1031 conf->ssid_len /= 2;
1032 if (conf->ssid_len > sizeof(conf->ssid) ||
1033 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1034 goto fail;
1035 } else {
1036#ifdef CONFIG_TESTING_OPTIONS
1037 /* use a default SSID for legacy testing reasons */
1038 os_memcpy(conf->ssid, "test", 4);
1039 conf->ssid_len = 4;
1040#else /* CONFIG_TESTING_OPTIONS */
1041 goto fail;
1042#endif /* CONFIG_TESTING_OPTIONS */
1043 }
1044
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001045 pos = os_strstr(cmd, " ssid_charset=");
1046 if (pos) {
1047 if (conf_ap) {
1048 wpa_printf(MSG_INFO,
1049 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1050 goto fail;
1051 }
1052 conf->ssid_charset = atoi(pos + 14);
1053 }
1054
Hai Shalom021b0b52019-04-10 11:17:58 -07001055 pos = os_strstr(cmd, " pass=");
1056 if (pos) {
1057 size_t pass_len;
1058
1059 pos += 6;
1060 end = os_strchr(pos, ' ');
1061 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1062 pass_len /= 2;
1063 if (pass_len > 63 || pass_len < 8)
1064 goto fail;
1065 conf->passphrase = os_zalloc(pass_len + 1);
1066 if (!conf->passphrase ||
1067 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1068 goto fail;
1069 }
1070
1071 pos = os_strstr(cmd, " psk=");
1072 if (pos) {
1073 pos += 5;
1074 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1075 goto fail;
1076 conf->psk_set = 1;
1077 }
1078
1079 pos = os_strstr(cmd, " group_id=");
1080 if (pos) {
1081 size_t group_id_len;
1082
1083 pos += 10;
1084 end = os_strchr(pos, ' ');
1085 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1086 conf->group_id = os_malloc(group_id_len + 1);
1087 if (!conf->group_id)
1088 goto fail;
1089 os_memcpy(conf->group_id, pos, group_id_len);
1090 conf->group_id[group_id_len] = '\0';
1091 }
1092
1093 pos = os_strstr(cmd, " expiry=");
1094 if (pos) {
1095 long int val;
1096
1097 pos += 8;
1098 val = strtol(pos, NULL, 0);
1099 if (val <= 0)
1100 goto fail;
1101 conf->netaccesskey_expiry = val;
1102 }
1103
Hai Shalom899fcc72020-10-19 14:38:18 -07001104 pos = os_strstr(cmd, " csrattrs=");
1105 if (pos) {
1106 pos += 10;
1107 end = os_strchr(pos, ' ');
1108 len = end ? (size_t) (end - pos) : os_strlen(pos);
1109 conf->csrattrs = os_zalloc(len + 1);
1110 if (!conf->csrattrs)
1111 goto fail;
1112 os_memcpy(conf->csrattrs, pos, len);
1113 }
1114
Hai Shalom021b0b52019-04-10 11:17:58 -07001115 if (!dpp_configuration_valid(conf))
1116 goto fail;
1117
Hai Shalomc3565922019-10-28 11:58:20 -07001118 if (idx == 0) {
1119 auth->conf_sta = conf_sta;
1120 auth->conf_ap = conf_ap;
1121 } else if (idx == 1) {
1122 auth->conf2_sta = conf_sta;
1123 auth->conf2_ap = conf_ap;
1124 } else {
1125 goto fail;
1126 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001127 return 0;
1128
1129fail:
1130 dpp_configuration_free(conf_sta);
1131 dpp_configuration_free(conf_ap);
1132 return -1;
1133}
1134
1135
Hai Shalomc3565922019-10-28 11:58:20 -07001136static int dpp_configuration_parse(struct dpp_authentication *auth,
1137 const char *cmd)
1138{
1139 const char *pos;
1140 char *tmp;
1141 size_t len;
1142 int res;
1143
1144 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1145 if (!pos)
1146 return dpp_configuration_parse_helper(auth, cmd, 0);
1147
1148 len = pos - cmd;
1149 tmp = os_malloc(len + 1);
1150 if (!tmp)
1151 goto fail;
1152 os_memcpy(tmp, cmd, len);
1153 tmp[len] = '\0';
1154 res = dpp_configuration_parse_helper(auth, cmd, 0);
1155 str_clear_free(tmp);
1156 if (res)
1157 goto fail;
1158 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1159 if (res)
1160 goto fail;
1161 return 0;
1162fail:
1163 dpp_configuration_free(auth->conf_sta);
1164 dpp_configuration_free(auth->conf2_sta);
1165 dpp_configuration_free(auth->conf_ap);
1166 dpp_configuration_free(auth->conf2_ap);
1167 return -1;
1168}
1169
1170
Hai Shalom021b0b52019-04-10 11:17:58 -07001171static struct dpp_configurator *
1172dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1173{
1174 struct dpp_configurator *conf;
1175
1176 if (!dpp)
1177 return NULL;
1178
1179 dl_list_for_each(conf, &dpp->configurator,
1180 struct dpp_configurator, list) {
1181 if (conf->id == id)
1182 return conf;
1183 }
1184 return NULL;
1185}
1186
1187
Hai Shalomfdcde762020-04-02 11:19:20 -07001188int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
Hai Shalom021b0b52019-04-10 11:17:58 -07001189{
1190 const char *pos;
Hai Shalomfdcde762020-04-02 11:19:20 -07001191 char *tmp = NULL;
1192 int ret = -1;
Hai Shalom021b0b52019-04-10 11:17:58 -07001193
Hai Shalomfdcde762020-04-02 11:19:20 -07001194 if (!cmd || auth->configurator_set)
Hai Shalom021b0b52019-04-10 11:17:58 -07001195 return 0;
Hai Shalomfdcde762020-04-02 11:19:20 -07001196 auth->configurator_set = 1;
1197
1198 if (cmd[0] != ' ') {
1199 size_t len;
1200
1201 len = os_strlen(cmd);
1202 tmp = os_malloc(len + 2);
1203 if (!tmp)
1204 goto fail;
1205 tmp[0] = ' ';
1206 os_memcpy(tmp + 1, cmd, len + 1);
1207 cmd = tmp;
1208 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001209
1210 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1211
Hai Shalomc1a21442022-02-04 13:43:00 -08001212 if (os_strstr(cmd, " conf=query")) {
1213 auth->configurator_set = 0;
1214 auth->use_config_query = true;
1215 ret = 0;
1216 goto fail;
1217 }
1218
Hai Shalom021b0b52019-04-10 11:17:58 -07001219 pos = os_strstr(cmd, " configurator=");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001220 if (!auth->conf && pos) {
Hai Shalom021b0b52019-04-10 11:17:58 -07001221 pos += 14;
Hai Shalomfdcde762020-04-02 11:19:20 -07001222 auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
Hai Shalom021b0b52019-04-10 11:17:58 -07001223 if (!auth->conf) {
1224 wpa_printf(MSG_INFO,
1225 "DPP: Could not find the specified configurator");
Hai Shalomfdcde762020-04-02 11:19:20 -07001226 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001227 }
1228 }
1229
Hai Shalomc3565922019-10-28 11:58:20 -07001230 pos = os_strstr(cmd, " conn_status=");
1231 if (pos) {
1232 pos += 13;
1233 auth->send_conn_status = atoi(pos);
1234 }
1235
1236 pos = os_strstr(cmd, " akm_use_selector=");
1237 if (pos) {
1238 pos += 18;
1239 auth->akm_use_selector = atoi(pos);
1240 }
1241
Hai Shalom021b0b52019-04-10 11:17:58 -07001242 if (dpp_configuration_parse(auth, cmd) < 0) {
Hai Shalomfdcde762020-04-02 11:19:20 -07001243 wpa_msg(auth->msg_ctx, MSG_INFO,
Hai Shalom021b0b52019-04-10 11:17:58 -07001244 "DPP: Failed to set configurator parameters");
Hai Shalomfdcde762020-04-02 11:19:20 -07001245 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07001246 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001247 ret = 0;
1248fail:
1249 os_free(tmp);
1250 return ret;
1251}
1252
1253
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001254void dpp_auth_deinit(struct dpp_authentication *auth)
1255{
Hai Shalomc3565922019-10-28 11:58:20 -07001256 unsigned int i;
1257
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001258 if (!auth)
1259 return;
1260 dpp_configuration_free(auth->conf_ap);
Hai Shalomc3565922019-10-28 11:58:20 -07001261 dpp_configuration_free(auth->conf2_ap);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001262 dpp_configuration_free(auth->conf_sta);
Hai Shalomc3565922019-10-28 11:58:20 -07001263 dpp_configuration_free(auth->conf2_sta);
Hai Shalomc1a21442022-02-04 13:43:00 -08001264 crypto_ec_key_deinit(auth->own_protocol_key);
1265 crypto_ec_key_deinit(auth->peer_protocol_key);
1266 crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001267 wpabuf_free(auth->req_msg);
1268 wpabuf_free(auth->resp_msg);
1269 wpabuf_free(auth->conf_req);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001270 wpabuf_free(auth->reconfig_req_msg);
1271 wpabuf_free(auth->reconfig_resp_msg);
Hai Shalomc3565922019-10-28 11:58:20 -07001272 for (i = 0; i < auth->num_conf_obj; i++) {
1273 struct dpp_config_obj *conf = &auth->conf_obj[i];
1274
1275 os_free(conf->connector);
1276 wpabuf_free(conf->c_sign_key);
Hai Shalom899fcc72020-10-19 14:38:18 -07001277 wpabuf_free(conf->certbag);
1278 wpabuf_free(conf->certs);
1279 wpabuf_free(conf->cacert);
1280 os_free(conf->server_name);
1281 wpabuf_free(conf->pp_key);
Hai Shalomc3565922019-10-28 11:58:20 -07001282 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001283#ifdef CONFIG_DPP2
Hai Shalomfdcde762020-04-02 11:19:20 -07001284 dpp_free_asymmetric_key(auth->conf_key_pkg);
Hai Shalom899fcc72020-10-19 14:38:18 -07001285 os_free(auth->csrattrs);
1286 wpabuf_free(auth->csr);
1287 wpabuf_free(auth->priv_key);
1288 wpabuf_free(auth->cacert);
1289 wpabuf_free(auth->certbag);
1290 os_free(auth->trusted_eap_server_name);
1291 wpabuf_free(auth->conf_resp_tcp);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001292#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001293 wpabuf_free(auth->net_access_key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001294 dpp_bootstrap_info_free(auth->tmp_own_bi);
Hai Shalom899fcc72020-10-19 14:38:18 -07001295 if (auth->tmp_peer_bi) {
1296 dl_list_del(&auth->tmp_peer_bi->list);
1297 dpp_bootstrap_info_free(auth->tmp_peer_bi);
1298 }
Hai Shalomc1a21442022-02-04 13:43:00 -08001299 os_free(auth->e_name);
1300 os_free(auth->e_mud_url);
1301 os_free(auth->e_band_support);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001302#ifdef CONFIG_TESTING_OPTIONS
1303 os_free(auth->config_obj_override);
1304 os_free(auth->discovery_override);
1305 os_free(auth->groups_override);
1306#endif /* CONFIG_TESTING_OPTIONS */
1307 bin_clear_free(auth, sizeof(*auth));
1308}
1309
1310
1311static struct wpabuf *
1312dpp_build_conf_start(struct dpp_authentication *auth,
1313 struct dpp_configuration *conf, size_t tailroom)
1314{
1315 struct wpabuf *buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001316
1317#ifdef CONFIG_TESTING_OPTIONS
1318 if (auth->discovery_override)
1319 tailroom += os_strlen(auth->discovery_override);
1320#endif /* CONFIG_TESTING_OPTIONS */
1321
1322 buf = wpabuf_alloc(200 + tailroom);
1323 if (!buf)
1324 return NULL;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001325 json_start_object(buf, NULL);
1326 json_add_string(buf, "wi-fi_tech", "infra");
1327 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001328#ifdef CONFIG_TESTING_OPTIONS
1329 if (auth->discovery_override) {
1330 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1331 auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001332 wpabuf_put_str(buf, "\"discovery\":");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001333 wpabuf_put_str(buf, auth->discovery_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001334 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001335 return buf;
1336 }
1337#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001338 json_start_object(buf, "discovery");
1339 if (((!conf->ssid_charset || auth->peer_version < 2) &&
1340 json_add_string_escape(buf, "ssid", conf->ssid,
1341 conf->ssid_len) < 0) ||
1342 ((conf->ssid_charset && auth->peer_version >= 2) &&
1343 json_add_base64url(buf, "ssid64", conf->ssid,
1344 conf->ssid_len) < 0)) {
1345 wpabuf_free(buf);
1346 return NULL;
1347 }
1348 if (conf->ssid_charset > 0) {
1349 json_value_sep(buf);
1350 json_add_int(buf, "ssid_charset", conf->ssid_charset);
1351 }
1352 json_end_object(buf);
1353 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001354
1355 return buf;
1356}
1357
1358
Hai Shalomc1a21442022-02-04 13:43:00 -08001359int dpp_build_jwk(struct wpabuf *buf, const char *name,
1360 struct crypto_ec_key *key, const char *kid,
1361 const struct dpp_curve_params *curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001362{
1363 struct wpabuf *pub;
1364 const u8 *pos;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001365 int ret = -1;
1366
Hai Shalomc1a21442022-02-04 13:43:00 -08001367 pub = crypto_ec_key_get_pubkey_point(key, 0);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001368 if (!pub)
1369 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001370
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001371 json_start_object(buf, name);
1372 json_add_string(buf, "kty", "EC");
1373 json_value_sep(buf);
1374 json_add_string(buf, "crv", curve->jwk_crv);
1375 json_value_sep(buf);
1376 pos = wpabuf_head(pub);
1377 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1378 goto fail;
1379 json_value_sep(buf);
1380 pos += curve->prime_len;
1381 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1382 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001383 if (kid) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001384 json_value_sep(buf);
1385 json_add_string(buf, "kid", kid);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001386 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001387 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001388 ret = 0;
1389fail:
1390 wpabuf_free(pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001391 return ret;
1392}
1393
1394
Hai Shalom021b0b52019-04-10 11:17:58 -07001395static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1396 struct dpp_configuration *conf)
1397{
1398 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001399 json_add_string_escape(buf, "pass", conf->passphrase,
1400 os_strlen(conf->passphrase));
Hai Shalom021b0b52019-04-10 11:17:58 -07001401 } else if (conf->psk_set) {
1402 char psk[2 * sizeof(conf->psk) + 1];
1403
1404 wpa_snprintf_hex(psk, sizeof(psk),
1405 conf->psk, sizeof(conf->psk));
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001406 json_add_string(buf, "psk_hex", psk);
1407 forced_memzero(psk, sizeof(psk));
Hai Shalom021b0b52019-04-10 11:17:58 -07001408 }
1409}
1410
1411
Hai Shalomc1a21442022-02-04 13:43:00 -08001412const char * dpp_netrole_str(enum dpp_netrole netrole)
Hai Shalomc3565922019-10-28 11:58:20 -07001413{
1414 switch (netrole) {
1415 case DPP_NETROLE_STA:
1416 return "sta";
1417 case DPP_NETROLE_AP:
1418 return "ap";
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001419 case DPP_NETROLE_CONFIGURATOR:
1420 return "configurator";
Hai Shalomc3565922019-10-28 11:58:20 -07001421 default:
1422 return "??";
1423 }
1424}
1425
1426
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001427static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001428dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001429 struct dpp_configuration *conf)
1430{
1431 struct wpabuf *buf = NULL;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001432 char *signed_conn = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001433 size_t tailroom;
1434 const struct dpp_curve_params *curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001435 struct wpabuf *dppcon = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001436 size_t extra_len = 1000;
Hai Shalom021b0b52019-04-10 11:17:58 -07001437 int incl_legacy;
1438 enum dpp_akm akm;
Hai Shalomc3565922019-10-28 11:58:20 -07001439 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001440
1441 if (!auth->conf) {
1442 wpa_printf(MSG_INFO,
1443 "DPP: No configurator specified - cannot generate DPP config object");
1444 goto fail;
1445 }
1446 curve = auth->conf->curve;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001447
Hai Shalom021b0b52019-04-10 11:17:58 -07001448 akm = conf->akm;
1449 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1450 wpa_printf(MSG_DEBUG,
1451 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1452 akm = DPP_AKM_DPP;
1453 }
1454
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001455#ifdef CONFIG_TESTING_OPTIONS
1456 if (auth->groups_override)
1457 extra_len += os_strlen(auth->groups_override);
1458#endif /* CONFIG_TESTING_OPTIONS */
1459
Hai Shalomce48b4a2018-09-05 11:41:35 -07001460 if (conf->group_id)
1461 extra_len += os_strlen(conf->group_id);
1462
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001463 /* Connector (JSON dppCon object) */
1464 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
1465 if (!dppcon)
1466 goto fail;
1467#ifdef CONFIG_TESTING_OPTIONS
1468 if (auth->groups_override) {
1469 wpabuf_put_u8(dppcon, '{');
1470 if (auth->groups_override) {
1471 wpa_printf(MSG_DEBUG,
1472 "DPP: TESTING - groups override: '%s'",
1473 auth->groups_override);
1474 wpabuf_put_str(dppcon, "\"groups\":");
1475 wpabuf_put_str(dppcon, auth->groups_override);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001476 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001477 }
1478 goto skip_groups;
1479 }
1480#endif /* CONFIG_TESTING_OPTIONS */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001481 json_start_object(dppcon, NULL);
1482 json_start_array(dppcon, "groups");
1483 json_start_object(dppcon, NULL);
1484 json_add_string(dppcon, "groupId",
1485 conf->group_id ? conf->group_id : "*");
1486 json_value_sep(dppcon);
1487 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1488 json_end_object(dppcon);
1489 json_end_array(dppcon);
1490 json_value_sep(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001491#ifdef CONFIG_TESTING_OPTIONS
1492skip_groups:
1493#endif /* CONFIG_TESTING_OPTIONS */
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001494 if (!auth->peer_protocol_key ||
1495 dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001496 auth->curve) < 0) {
1497 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1498 goto fail;
1499 }
1500 if (conf->netaccesskey_expiry) {
1501 struct os_tm tm;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001502 char expiry[30];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001503
1504 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1505 wpa_printf(MSG_DEBUG,
1506 "DPP: Failed to generate expiry string");
1507 goto fail;
1508 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001509 os_snprintf(expiry, sizeof(expiry),
1510 "%04u-%02u-%02uT%02u:%02u:%02uZ",
1511 tm.year, tm.month, tm.day,
1512 tm.hour, tm.min, tm.sec);
1513 json_value_sep(dppcon);
1514 json_add_string(dppcon, "expiry", expiry);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001515 }
Hai Shalomc1a21442022-02-04 13:43:00 -08001516#ifdef CONFIG_DPP3
1517 json_value_sep(dppcon);
1518 json_add_int(dppcon, "version", auth->peer_version);
1519#endif /* CONFIG_DPP3 */
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001520 json_end_object(dppcon);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001521 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1522 (const char *) wpabuf_head(dppcon));
1523
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001524 signed_conn = dpp_sign_connector(auth->conf, dppcon);
1525 if (!signed_conn)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001526 goto fail;
1527
Hai Shalom021b0b52019-04-10 11:17:58 -07001528 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001529 tailroom = 1000;
1530 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001531 tailroom += os_strlen(signed_conn);
Hai Shalom021b0b52019-04-10 11:17:58 -07001532 if (incl_legacy)
1533 tailroom += 1000;
Hai Shalom899fcc72020-10-19 14:38:18 -07001534 if (akm == DPP_AKM_DOT1X) {
1535 if (auth->certbag)
1536 tailroom += 2 * wpabuf_len(auth->certbag);
1537 if (auth->cacert)
1538 tailroom += 2 * wpabuf_len(auth->cacert);
1539 if (auth->trusted_eap_server_name)
1540 tailroom += os_strlen(auth->trusted_eap_server_name);
1541 tailroom += 1000;
1542 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001543 buf = dpp_build_conf_start(auth, conf, tailroom);
1544 if (!buf)
Roshan Pius3a1667e2018-07-03 15:17:14 -07001545 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001546
Hai Shalomc3565922019-10-28 11:58:20 -07001547 if (auth->akm_use_selector && dpp_akm_ver2(akm))
1548 akm_str = dpp_akm_selector_str(akm);
1549 else
1550 akm_str = dpp_akm_str(akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001551 json_start_object(buf, "cred");
1552 json_add_string(buf, "akm", akm_str);
1553 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001554 if (incl_legacy) {
1555 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001556 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001557 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001558 if (akm == DPP_AKM_DOT1X) {
1559 json_start_object(buf, "entCreds");
1560 if (!auth->certbag)
1561 goto fail;
1562 json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1563 wpabuf_len(auth->certbag));
1564 if (auth->cacert) {
1565 json_value_sep(buf);
1566 json_add_base64(buf, "caCert",
1567 wpabuf_head(auth->cacert),
1568 wpabuf_len(auth->cacert));
1569 }
1570 if (auth->trusted_eap_server_name) {
1571 json_value_sep(buf);
1572 json_add_string(buf, "trustedEapServerName",
1573 auth->trusted_eap_server_name);
1574 }
1575 json_value_sep(buf);
1576 json_start_array(buf, "eapMethods");
1577 wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1578 json_end_array(buf);
1579 json_end_object(buf);
1580 json_value_sep(buf);
1581 }
Hai Shalom021b0b52019-04-10 11:17:58 -07001582 wpabuf_put_str(buf, "\"signedConnector\":\"");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001583 wpabuf_put_str(buf, signed_conn);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001584 wpabuf_put_str(buf, "\"");
1585 json_value_sep(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001586 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1587 curve) < 0) {
1588 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1589 goto fail;
1590 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001591#ifdef CONFIG_DPP2
1592 if (auth->peer_version >= 2 && auth->conf->pp_key) {
1593 json_value_sep(buf);
1594 if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1595 curve) < 0) {
1596 wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1597 goto fail;
1598 }
1599 }
1600#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001601
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001602 json_end_object(buf);
1603 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001604
1605 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1606 wpabuf_head(buf), wpabuf_len(buf));
1607
1608out:
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001609 os_free(signed_conn);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001610 wpabuf_free(dppcon);
1611 return buf;
1612fail:
1613 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1614 wpabuf_free(buf);
1615 buf = NULL;
1616 goto out;
1617}
1618
1619
1620static struct wpabuf *
Hai Shalomc3565922019-10-28 11:58:20 -07001621dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001622 struct dpp_configuration *conf)
1623{
1624 struct wpabuf *buf;
Hai Shalomc3565922019-10-28 11:58:20 -07001625 const char *akm_str;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001626
1627 buf = dpp_build_conf_start(auth, conf, 1000);
1628 if (!buf)
1629 return NULL;
1630
Hai Shalomc3565922019-10-28 11:58:20 -07001631 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1632 akm_str = dpp_akm_selector_str(conf->akm);
1633 else
1634 akm_str = dpp_akm_str(conf->akm);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001635 json_start_object(buf, "cred");
1636 json_add_string(buf, "akm", akm_str);
1637 json_value_sep(buf);
Hai Shalom021b0b52019-04-10 11:17:58 -07001638 dpp_build_legacy_cred_params(buf, conf);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001639 json_end_object(buf);
1640 json_end_object(buf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001641
1642 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1643 wpabuf_head(buf), wpabuf_len(buf));
1644
1645 return buf;
1646}
1647
1648
Hai Shalomc1a21442022-02-04 13:43:00 -08001649static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1650{
1651 struct dpp_bootstrap_info *bi;
1652
1653 if (auth->peer_bi)
1654 return auth->peer_bi->id;
1655 if (auth->tmp_peer_bi)
1656 return auth->tmp_peer_bi->id;
1657
1658 bi = os_zalloc(sizeof(*bi));
1659 if (!bi)
1660 return -1;
1661 bi->id = dpp_next_id(auth->global);
1662 dl_list_add(&auth->global->bootstrap, &bi->list);
1663 auth->tmp_peer_bi = bi;
1664 return bi->id;
1665}
1666
1667
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001668static struct wpabuf *
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001669dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
Hai Shalom899fcc72020-10-19 14:38:18 -07001670 int idx, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001671{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001672 struct dpp_configuration *conf = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001673
1674#ifdef CONFIG_TESTING_OPTIONS
1675 if (auth->config_obj_override) {
Hai Shalomc3565922019-10-28 11:58:20 -07001676 if (idx != 0)
1677 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001678 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
1679 return wpabuf_alloc_copy(auth->config_obj_override,
1680 os_strlen(auth->config_obj_override));
1681 }
1682#endif /* CONFIG_TESTING_OPTIONS */
1683
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001684 if (idx == 0) {
1685 if (netrole == DPP_NETROLE_STA)
1686 conf = auth->conf_sta;
1687 else if (netrole == DPP_NETROLE_AP)
1688 conf = auth->conf_ap;
1689 } else if (idx == 1) {
1690 if (netrole == DPP_NETROLE_STA)
1691 conf = auth->conf2_sta;
1692 else if (netrole == DPP_NETROLE_AP)
1693 conf = auth->conf2_ap;
1694 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001695 if (!conf) {
Hai Shalomc1a21442022-02-04 13:43:00 -08001696 if (idx == 0) {
1697 if (auth->use_config_query) {
1698 wpa_printf(MSG_DEBUG,
1699 "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
1700 dpp_netrole_str(netrole));
1701 auth->waiting_config = true;
1702 dpp_get_peer_bi_id(auth);
1703 return NULL;
1704 }
Hai Shalomc3565922019-10-28 11:58:20 -07001705 wpa_printf(MSG_DEBUG,
1706 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001707 dpp_netrole_str(netrole));
Hai Shalomc1a21442022-02-04 13:43:00 -08001708 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001709 return NULL;
1710 }
1711
Hai Shalom899fcc72020-10-19 14:38:18 -07001712 if (conf->akm == DPP_AKM_DOT1X) {
1713 if (!auth->conf) {
1714 wpa_printf(MSG_DEBUG,
1715 "DPP: No Configurator data available");
1716 return NULL;
1717 }
1718 if (!cert_req && !auth->certbag) {
1719 wpa_printf(MSG_DEBUG,
1720 "DPP: No certificate data available for dot1x configuration");
1721 return NULL;
1722 }
1723 return dpp_build_conf_obj_dpp(auth, conf);
1724 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001725 if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
Hai Shalomc3565922019-10-28 11:58:20 -07001726 return dpp_build_conf_obj_dpp(auth, conf);
1727 return dpp_build_conf_obj_legacy(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001728}
1729
1730
Hai Shalom899fcc72020-10-19 14:38:18 -07001731struct wpabuf *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001732dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
Hai Shalom899fcc72020-10-19 14:38:18 -07001733 u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001734{
Hai Shalomfdcde762020-04-02 11:19:20 -07001735 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001736 size_t clear_len, attr_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001737 struct wpabuf *clear = NULL, *msg = NULL;
1738 u8 *wrapped;
1739 const u8 *addr[1];
1740 size_t len[1];
1741 enum dpp_status_error status;
1742
Hai Shalom899fcc72020-10-19 14:38:18 -07001743 if (auth->force_conf_resp_status != DPP_STATUS_OK) {
1744 status = auth->force_conf_resp_status;
1745 goto forced_status;
1746 }
1747
Hai Shalomfdcde762020-04-02 11:19:20 -07001748 if (netrole == DPP_NETROLE_CONFIGURATOR) {
1749#ifdef CONFIG_DPP2
1750 env_data = dpp_build_enveloped_data(auth);
1751#endif /* CONFIG_DPP2 */
1752 } else {
Hai Shalom899fcc72020-10-19 14:38:18 -07001753 conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07001754 if (conf) {
1755 wpa_hexdump_ascii(MSG_DEBUG,
1756 "DPP: configurationObject JSON",
1757 wpabuf_head(conf), wpabuf_len(conf));
Hai Shalom899fcc72020-10-19 14:38:18 -07001758 conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
Hai Shalomfdcde762020-04-02 11:19:20 -07001759 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001760 }
Hai Shalom899fcc72020-10-19 14:38:18 -07001761
Hai Shalomc1a21442022-02-04 13:43:00 -08001762 if (!conf && auth->waiting_config)
1763 return NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07001764 if (conf || env_data)
1765 status = DPP_STATUS_OK;
1766 else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
1767 auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
1768 status = DPP_STATUS_CSR_NEEDED;
1769 else
1770 status = DPP_STATUS_CONFIGURE_FAILURE;
1771forced_status:
Hai Shalom021b0b52019-04-10 11:17:58 -07001772 auth->conf_resp_status = status;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001773
Hai Shalomc3565922019-10-28 11:58:20 -07001774 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001775 clear_len = 4 + e_nonce_len;
1776 if (conf)
1777 clear_len += 4 + wpabuf_len(conf);
Hai Shalomc3565922019-10-28 11:58:20 -07001778 if (conf2)
1779 clear_len += 4 + wpabuf_len(conf2);
Hai Shalomfdcde762020-04-02 11:19:20 -07001780 if (env_data)
1781 clear_len += 4 + wpabuf_len(env_data);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001782 if (auth->peer_version >= 2 && auth->send_conn_status &&
1783 netrole == DPP_NETROLE_STA)
Hai Shalomc3565922019-10-28 11:58:20 -07001784 clear_len += 4;
Hai Shalom899fcc72020-10-19 14:38:18 -07001785 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
1786 auth->conf_sta->csrattrs)
1787 clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001788 clear = wpabuf_alloc(clear_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001789 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
1790#ifdef CONFIG_TESTING_OPTIONS
1791 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
1792 attr_len += 5;
1793#endif /* CONFIG_TESTING_OPTIONS */
1794 msg = wpabuf_alloc(attr_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001795 if (!clear || !msg)
1796 goto fail;
1797
Roshan Pius3a1667e2018-07-03 15:17:14 -07001798#ifdef CONFIG_TESTING_OPTIONS
1799 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
1800 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
1801 goto skip_e_nonce;
1802 }
1803 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
1804 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
1805 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
1806 wpabuf_put_le16(clear, e_nonce_len);
1807 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
1808 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
1809 goto skip_e_nonce;
1810 }
1811 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
1812 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1813 goto skip_wrapped_data;
1814 }
1815#endif /* CONFIG_TESTING_OPTIONS */
1816
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001817 /* E-nonce */
1818 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
1819 wpabuf_put_le16(clear, e_nonce_len);
1820 wpabuf_put_data(clear, e_nonce, e_nonce_len);
1821
Roshan Pius3a1667e2018-07-03 15:17:14 -07001822#ifdef CONFIG_TESTING_OPTIONS
1823skip_e_nonce:
1824 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
1825 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
1826 goto skip_config_obj;
1827 }
1828#endif /* CONFIG_TESTING_OPTIONS */
1829
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001830 if (conf) {
1831 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
1832 wpabuf_put_le16(clear, wpabuf_len(conf));
1833 wpabuf_put_buf(clear, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001834 }
Hai Shalomc3565922019-10-28 11:58:20 -07001835 if (auth->peer_version >= 2 && conf2) {
1836 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
1837 wpabuf_put_le16(clear, wpabuf_len(conf2));
1838 wpabuf_put_buf(clear, conf2);
1839 } else if (conf2) {
1840 wpa_printf(MSG_DEBUG,
1841 "DPP: Second Config Object available, but peer does not support more than one");
1842 }
Hai Shalomfdcde762020-04-02 11:19:20 -07001843 if (env_data) {
1844 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
1845 wpabuf_put_le16(clear, wpabuf_len(env_data));
1846 wpabuf_put_buf(clear, env_data);
1847 }
Hai Shalomc3565922019-10-28 11:58:20 -07001848
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001849 if (auth->peer_version >= 2 && auth->send_conn_status &&
Hai Shalom899fcc72020-10-19 14:38:18 -07001850 netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
Hai Shalomc3565922019-10-28 11:58:20 -07001851 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
1852 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
1853 wpabuf_put_le16(clear, 0);
1854 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001855
Hai Shalom899fcc72020-10-19 14:38:18 -07001856 if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
1857 auth->conf_sta->csrattrs) {
1858 auth->waiting_csr = true;
1859 wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
1860 wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
1861 wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
1862 wpabuf_put_str(clear, auth->conf_sta->csrattrs);
1863 }
1864
Roshan Pius3a1667e2018-07-03 15:17:14 -07001865#ifdef CONFIG_TESTING_OPTIONS
1866skip_config_obj:
1867 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
1868 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
1869 goto skip_status;
1870 }
1871 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
1872 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
1873 status = 255;
1874 }
1875#endif /* CONFIG_TESTING_OPTIONS */
1876
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001877 /* DPP Status */
Roshan Pius3a1667e2018-07-03 15:17:14 -07001878 dpp_build_attr_status(msg, status);
1879
1880#ifdef CONFIG_TESTING_OPTIONS
1881skip_status:
1882#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001883
1884 addr[0] = wpabuf_head(msg);
1885 len[0] = wpabuf_len(msg);
1886 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
1887
1888 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1889 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1890 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
1891
1892 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
1893 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
1894 wpabuf_head(clear), wpabuf_len(clear),
1895 1, addr, len, wrapped) < 0)
1896 goto fail;
1897 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1898 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001899
1900#ifdef CONFIG_TESTING_OPTIONS
1901 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
1902 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1903 dpp_build_attr_status(msg, DPP_STATUS_OK);
1904 }
1905skip_wrapped_data:
1906#endif /* CONFIG_TESTING_OPTIONS */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001907
1908 wpa_hexdump_buf(MSG_DEBUG,
1909 "DPP: Configuration Response attributes", msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001910out:
Hai Shalomfdcde762020-04-02 11:19:20 -07001911 wpabuf_clear_free(conf);
1912 wpabuf_clear_free(conf2);
1913 wpabuf_clear_free(env_data);
1914 wpabuf_clear_free(clear);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001915
1916 return msg;
1917fail:
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001918 wpabuf_free(msg);
Roshan Pius3a1667e2018-07-03 15:17:14 -07001919 msg = NULL;
1920 goto out;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001921}
1922
1923
1924struct wpabuf *
1925dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
1926 size_t attr_len)
1927{
1928 const u8 *wrapped_data, *e_nonce, *config_attr;
1929 u16 wrapped_data_len, e_nonce_len, config_attr_len;
1930 u8 *unwrapped = NULL;
1931 size_t unwrapped_len = 0;
1932 struct wpabuf *resp = NULL;
1933 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08001934 enum dpp_netrole netrole;
Hai Shalom899fcc72020-10-19 14:38:18 -07001935 struct wpabuf *cert_req = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001936
Roshan Pius3a1667e2018-07-03 15:17:14 -07001937#ifdef CONFIG_TESTING_OPTIONS
1938 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
1939 wpa_printf(MSG_INFO,
1940 "DPP: TESTING - stop at Config Request");
1941 return NULL;
1942 }
1943#endif /* CONFIG_TESTING_OPTIONS */
1944
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001945 if (dpp_check_attrs(attr_start, attr_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001946 dpp_auth_fail(auth, "Invalid attribute in config request");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001947 return NULL;
1948 }
1949
1950 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
1951 &wrapped_data_len);
1952 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001953 dpp_auth_fail(auth,
1954 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001955 return NULL;
1956 }
1957
1958 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1959 wrapped_data, wrapped_data_len);
1960 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1961 unwrapped = os_malloc(unwrapped_len);
1962 if (!unwrapped)
1963 return NULL;
1964 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
1965 wrapped_data, wrapped_data_len,
1966 0, NULL, NULL, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001967 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001968 goto fail;
1969 }
1970 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1971 unwrapped, unwrapped_len);
1972
1973 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001974 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001975 goto fail;
1976 }
1977
1978 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
1979 DPP_ATTR_ENROLLEE_NONCE,
1980 &e_nonce_len);
1981 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001982 dpp_auth_fail(auth,
1983 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001984 goto fail;
1985 }
1986 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07001987 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001988
1989 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
1990 DPP_ATTR_CONFIG_ATTR_OBJ,
1991 &config_attr_len);
1992 if (!config_attr) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001993 dpp_auth_fail(auth,
1994 "Missing or invalid Config Attributes attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001995 goto fail;
1996 }
1997 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
1998 config_attr, config_attr_len);
1999
2000 root = json_parse((const char *) config_attr, config_attr_len);
2001 if (!root) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002002 dpp_auth_fail(auth, "Could not parse Config Attributes");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002003 goto fail;
2004 }
2005
2006 token = json_get_member(root, "name");
2007 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002008 dpp_auth_fail(auth, "No Config Attributes - name");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002009 goto fail;
2010 }
2011 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
Hai Shalomc1a21442022-02-04 13:43:00 -08002012 os_free(auth->e_name);
2013 auth->e_name = os_strdup(token->string);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002014
2015 token = json_get_member(root, "wi-fi_tech");
2016 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002017 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002018 goto fail;
2019 }
2020 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2021 if (os_strcmp(token->string, "infra") != 0) {
2022 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2023 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002024 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002025 goto fail;
2026 }
2027
2028 token = json_get_member(root, "netRole");
2029 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002030 dpp_auth_fail(auth, "No Config Attributes - netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002031 goto fail;
2032 }
2033 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2034 if (os_strcmp(token->string, "sta") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002035 netrole = DPP_NETROLE_STA;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002036 } else if (os_strcmp(token->string, "ap") == 0) {
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002037 netrole = DPP_NETROLE_AP;
2038 } else if (os_strcmp(token->string, "configurator") == 0) {
2039 netrole = DPP_NETROLE_CONFIGURATOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002040 } else {
2041 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2042 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002043 dpp_auth_fail(auth, "Unsupported netRole");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002044 goto fail;
2045 }
Hai Shalom899fcc72020-10-19 14:38:18 -07002046 auth->e_netrole = netrole;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002047
Hai Shalomc3565922019-10-28 11:58:20 -07002048 token = json_get_member(root, "mudurl");
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002049 if (token && token->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002050 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002051 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2052 token->string);
Hai Shalomc1a21442022-02-04 13:43:00 -08002053 os_free(auth->e_mud_url);
2054 auth->e_mud_url = os_strdup(token->string);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002055 }
Hai Shalomc3565922019-10-28 11:58:20 -07002056
2057 token = json_get_member(root, "bandSupport");
Hai Shalom06768112019-12-04 15:49:43 -08002058 auth->band_list_size = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002059 if (token && token->type == JSON_ARRAY) {
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002060 int *opclass = NULL;
2061 char txt[200], *pos, *end;
2062 int i, res;
2063
Hai Shalom06768112019-12-04 15:49:43 -08002064 memset(auth->band_list, 0, sizeof(auth->band_list));
Hai Shalomc3565922019-10-28 11:58:20 -07002065 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2066 token = token->child;
2067 while (token) {
Hai Shalom06768112019-12-04 15:49:43 -08002068 if (token->type != JSON_NUMBER) {
Hai Shalomc3565922019-10-28 11:58:20 -07002069 wpa_printf(MSG_DEBUG,
2070 "DPP: Invalid bandSupport array member type");
Hai Shalom06768112019-12-04 15:49:43 -08002071 } else {
2072 if (auth->band_list_size < DPP_MAX_CHANNELS) {
2073 auth->band_list[auth->band_list_size++] = token->number;
2074 }
Hai Shalomc3565922019-10-28 11:58:20 -07002075 wpa_printf(MSG_DEBUG,
2076 "DPP: Supported global operating class: %d",
2077 token->number);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002078 int_array_add_unique(&opclass, token->number);
Hai Shalom06768112019-12-04 15:49:43 -08002079 }
Hai Shalomc3565922019-10-28 11:58:20 -07002080 token = token->sibling;
2081 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002082
2083 txt[0] = '\0';
2084 pos = txt;
2085 end = txt + sizeof(txt);
2086 for (i = 0; opclass && opclass[i]; i++) {
2087 res = os_snprintf(pos, end - pos, "%s%d",
2088 pos == txt ? "" : ",", opclass[i]);
2089 if (os_snprintf_error(end - pos, res)) {
2090 *pos = '\0';
2091 break;
2092 }
2093 pos += res;
2094 }
Hai Shalomc1a21442022-02-04 13:43:00 -08002095 os_free(auth->e_band_support);
2096 auth->e_band_support = opclass;
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002097 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2098 txt);
Hai Shalomc3565922019-10-28 11:58:20 -07002099 }
2100
Hai Shalom899fcc72020-10-19 14:38:18 -07002101#ifdef CONFIG_DPP2
2102 cert_req = json_get_member_base64(root, "pkcs10");
2103 if (cert_req) {
2104 char *txt;
2105 int id;
2106
2107 wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2108 if (dpp_validate_csr(auth, cert_req) < 0) {
2109 wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2110 auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2111 goto cont;
2112 }
2113
Hai Shalomc1a21442022-02-04 13:43:00 -08002114 id = dpp_get_peer_bi_id(auth);
2115 if (id < 0)
2116 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002117
2118 wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2119 txt = base64_encode_no_lf(wpabuf_head(cert_req),
2120 wpabuf_len(cert_req), NULL);
2121 if (!txt)
2122 goto fail;
2123
2124 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2125 id, txt);
2126 os_free(txt);
2127 auth->waiting_csr = false;
2128 auth->waiting_cert = true;
2129 goto fail;
2130 }
2131cont:
2132#endif /* CONFIG_DPP2 */
2133
2134 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2135 cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002136
2137fail:
Hai Shalom899fcc72020-10-19 14:38:18 -07002138 wpabuf_free(cert_req);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002139 json_free(root);
2140 os_free(unwrapped);
2141 return resp;
2142}
2143
2144
Hai Shalomc3565922019-10-28 11:58:20 -07002145static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002146 struct json_token *cred)
2147{
2148 struct json_token *pass, *psk_hex;
2149
2150 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2151
2152 pass = json_get_member(cred, "pass");
2153 psk_hex = json_get_member(cred, "psk_hex");
2154
2155 if (pass && pass->type == JSON_STRING) {
2156 size_t len = os_strlen(pass->string);
2157
2158 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2159 pass->string, len);
2160 if (len < 8 || len > 63)
2161 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07002162 os_strlcpy(conf->passphrase, pass->string,
2163 sizeof(conf->passphrase));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002164 } else if (psk_hex && psk_hex->type == JSON_STRING) {
Hai Shalomc3565922019-10-28 11:58:20 -07002165 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002166 wpa_printf(MSG_DEBUG,
2167 "DPP: Unexpected psk_hex with akm=sae");
2168 return -1;
2169 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002170 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
Hai Shalomc3565922019-10-28 11:58:20 -07002171 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002172 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2173 return -1;
2174 }
2175 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
Hai Shalomc3565922019-10-28 11:58:20 -07002176 conf->psk, PMK_LEN);
2177 conf->psk_set = 1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002178 } else {
2179 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2180 return -1;
2181 }
2182
Hai Shalomc3565922019-10-28 11:58:20 -07002183 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002184 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2185 return -1;
2186 }
2187
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002188 return 0;
2189}
2190
2191
Hai Shalomc1a21442022-02-04 13:43:00 -08002192struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2193 const struct dpp_curve_params **key_curve)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002194{
2195 struct json_token *token;
2196 const struct dpp_curve_params *curve;
2197 struct wpabuf *x = NULL, *y = NULL;
Hai Shalomc1a21442022-02-04 13:43:00 -08002198 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002199
2200 token = json_get_member(jwk, "kty");
2201 if (!token || token->type != JSON_STRING) {
2202 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2203 goto fail;
2204 }
2205 if (os_strcmp(token->string, "EC") != 0) {
Hai Shalom74f70d42019-02-11 14:42:39 -08002206 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002207 token->string);
2208 goto fail;
2209 }
2210
2211 token = json_get_member(jwk, "crv");
2212 if (!token || token->type != JSON_STRING) {
2213 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2214 goto fail;
2215 }
2216 curve = dpp_get_curve_jwk_crv(token->string);
2217 if (!curve) {
2218 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2219 token->string);
2220 goto fail;
2221 }
2222
2223 x = json_get_member_base64url(jwk, "x");
2224 if (!x) {
2225 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2226 goto fail;
2227 }
2228 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2229 if (wpabuf_len(x) != curve->prime_len) {
2230 wpa_printf(MSG_DEBUG,
2231 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2232 (unsigned int) wpabuf_len(x),
2233 (unsigned int) curve->prime_len, curve->name);
2234 goto fail;
2235 }
2236
2237 y = json_get_member_base64url(jwk, "y");
2238 if (!y) {
2239 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2240 goto fail;
2241 }
2242 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2243 if (wpabuf_len(y) != curve->prime_len) {
2244 wpa_printf(MSG_DEBUG,
2245 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2246 (unsigned int) wpabuf_len(y),
2247 (unsigned int) curve->prime_len, curve->name);
2248 goto fail;
2249 }
2250
Hai Shalomc1a21442022-02-04 13:43:00 -08002251 key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2252 wpabuf_head(y), wpabuf_len(x));
2253 if (!key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002254 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002255
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002256 *key_curve = curve;
2257
2258fail:
2259 wpabuf_free(x);
2260 wpabuf_free(y);
2261
Hai Shalomc1a21442022-02-04 13:43:00 -08002262 return key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002263}
2264
2265
2266int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2267{
2268 struct os_time now;
2269 unsigned int year, month, day, hour, min, sec;
2270 os_time_t utime;
2271 const char *pos;
2272
2273 /* ISO 8601 date and time:
2274 * <date>T<time>
2275 * YYYY-MM-DDTHH:MM:SSZ
2276 * YYYY-MM-DDTHH:MM:SS+03:00
2277 */
2278 if (os_strlen(timestamp) < 19) {
2279 wpa_printf(MSG_DEBUG,
2280 "DPP: Too short timestamp - assume expired key");
2281 return 1;
2282 }
2283 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2284 &year, &month, &day, &hour, &min, &sec) != 6) {
2285 wpa_printf(MSG_DEBUG,
2286 "DPP: Failed to parse expiration day - assume expired key");
2287 return 1;
2288 }
2289
2290 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2291 wpa_printf(MSG_DEBUG,
2292 "DPP: Invalid date/time information - assume expired key");
2293 return 1;
2294 }
2295
2296 pos = timestamp + 19;
2297 if (*pos == 'Z' || *pos == '\0') {
2298 /* In UTC - no need to adjust */
2299 } else if (*pos == '-' || *pos == '+') {
2300 int items;
2301
2302 /* Adjust local time to UTC */
2303 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2304 if (items < 1) {
2305 wpa_printf(MSG_DEBUG,
2306 "DPP: Invalid time zone designator (%s) - assume expired key",
2307 pos);
2308 return 1;
2309 }
2310 if (*pos == '-')
2311 utime += 3600 * hour;
2312 if (*pos == '+')
2313 utime -= 3600 * hour;
2314 if (items > 1) {
2315 if (*pos == '-')
2316 utime += 60 * min;
2317 if (*pos == '+')
2318 utime -= 60 * min;
2319 }
2320 } else {
2321 wpa_printf(MSG_DEBUG,
2322 "DPP: Invalid time zone designator (%s) - assume expired key",
2323 pos);
2324 return 1;
2325 }
2326 if (expiry)
2327 *expiry = utime;
2328
2329 if (os_get_time(&now) < 0) {
2330 wpa_printf(MSG_DEBUG,
2331 "DPP: Cannot get current time - assume expired key");
2332 return 1;
2333 }
2334
2335 if (now.sec > utime) {
2336 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
2337 utime, now.sec);
2338 return 1;
2339 }
2340
2341 return 0;
2342}
2343
2344
2345static int dpp_parse_connector(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002346 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002347 const unsigned char *payload,
2348 u16 payload_len)
2349{
2350 struct json_token *root, *groups, *netkey, *token;
2351 int ret = -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08002352 struct crypto_ec_key *key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002353 const struct dpp_curve_params *curve;
2354 unsigned int rules = 0;
2355
2356 root = json_parse((const char *) payload, payload_len);
2357 if (!root) {
2358 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2359 goto fail;
2360 }
2361
2362 groups = json_get_member(root, "groups");
2363 if (!groups || groups->type != JSON_ARRAY) {
2364 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2365 goto skip_groups;
2366 }
2367 for (token = groups->child; token; token = token->sibling) {
2368 struct json_token *id, *role;
2369
2370 id = json_get_member(token, "groupId");
2371 if (!id || id->type != JSON_STRING) {
2372 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2373 goto fail;
2374 }
2375
2376 role = json_get_member(token, "netRole");
2377 if (!role || role->type != JSON_STRING) {
2378 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2379 goto fail;
2380 }
2381 wpa_printf(MSG_DEBUG,
2382 "DPP: connector group: groupId='%s' netRole='%s'",
2383 id->string, role->string);
2384 rules++;
2385 }
2386skip_groups:
2387
2388 if (!rules) {
2389 wpa_printf(MSG_DEBUG,
2390 "DPP: Connector includes no groups");
2391 goto fail;
2392 }
2393
2394 token = json_get_member(root, "expiry");
2395 if (!token || token->type != JSON_STRING) {
2396 wpa_printf(MSG_DEBUG,
2397 "DPP: No expiry string found - connector does not expire");
2398 } else {
2399 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2400 if (dpp_key_expired(token->string,
2401 &auth->net_access_key_expiry)) {
2402 wpa_printf(MSG_DEBUG,
2403 "DPP: Connector (netAccessKey) has expired");
2404 goto fail;
2405 }
2406 }
2407
2408 netkey = json_get_member(root, "netAccessKey");
2409 if (!netkey || netkey->type != JSON_OBJECT) {
2410 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2411 goto fail;
2412 }
2413
2414 key = dpp_parse_jwk(netkey, &curve);
2415 if (!key)
2416 goto fail;
2417 dpp_debug_print_key("DPP: Received netAccessKey", key);
2418
Hai Shalomc1a21442022-02-04 13:43:00 -08002419 if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002420 wpa_printf(MSG_DEBUG,
2421 "DPP: netAccessKey in connector does not match own protocol key");
2422#ifdef CONFIG_TESTING_OPTIONS
2423 if (auth->ignore_netaccesskey_mismatch) {
2424 wpa_printf(MSG_DEBUG,
2425 "DPP: TESTING - skip netAccessKey mismatch");
2426 } else {
2427 goto fail;
2428 }
2429#else /* CONFIG_TESTING_OPTIONS */
2430 goto fail;
2431#endif /* CONFIG_TESTING_OPTIONS */
2432 }
2433
2434 ret = 0;
2435fail:
Hai Shalomc1a21442022-02-04 13:43:00 -08002436 crypto_ec_key_deinit(key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002437 json_free(root);
2438 return ret;
2439}
2440
2441
Hai Shalomc1a21442022-02-04 13:43:00 -08002442static void dpp_copy_csign(struct dpp_config_obj *conf,
2443 struct crypto_ec_key *csign)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002444{
Hai Shalomc1a21442022-02-04 13:43:00 -08002445 struct wpabuf *c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002446
Hai Shalomc1a21442022-02-04 13:43:00 -08002447 c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2448 if (!c_sign_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002449 return;
Hai Shalomc1a21442022-02-04 13:43:00 -08002450
Hai Shalomc3565922019-10-28 11:58:20 -07002451 wpabuf_free(conf->c_sign_key);
Hai Shalomc1a21442022-02-04 13:43:00 -08002452 conf->c_sign_key = c_sign_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002453}
2454
2455
Hai Shalomc1a21442022-02-04 13:43:00 -08002456static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2457 struct crypto_ec_key *ppkey)
Hai Shalom899fcc72020-10-19 14:38:18 -07002458{
Hai Shalomc1a21442022-02-04 13:43:00 -08002459 struct wpabuf *pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002460
Hai Shalomc1a21442022-02-04 13:43:00 -08002461 pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2462 if (!pp_key)
Hai Shalom899fcc72020-10-19 14:38:18 -07002463 return;
Hai Shalomc1a21442022-02-04 13:43:00 -08002464
Hai Shalom899fcc72020-10-19 14:38:18 -07002465 wpabuf_free(conf->pp_key);
Hai Shalomc1a21442022-02-04 13:43:00 -08002466 conf->pp_key = pp_key;
Hai Shalom899fcc72020-10-19 14:38:18 -07002467}
2468
2469
Hai Shalomc3565922019-10-28 11:58:20 -07002470static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2471 struct dpp_config_obj *conf)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002472{
Hai Shalomc1a21442022-02-04 13:43:00 -08002473 struct wpabuf *net_access_key;
2474 struct crypto_ec_key *own_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002475
Hai Shalom4fbc08f2020-05-18 12:37:00 -07002476 own_key = auth->own_protocol_key;
2477#ifdef CONFIG_DPP2
2478 if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2479 auth->reconfig_old_protocol_key)
2480 own_key = auth->reconfig_old_protocol_key;
2481#endif /* CONFIG_DPP2 */
Hai Shalomc1a21442022-02-04 13:43:00 -08002482
2483 net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2484 if (!net_access_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002485 return;
2486
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002487 wpabuf_free(auth->net_access_key);
Hai Shalomc1a21442022-02-04 13:43:00 -08002488 auth->net_access_key = net_access_key;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002489}
2490
2491
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002492static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
Hai Shalomc3565922019-10-28 11:58:20 -07002493 struct dpp_config_obj *conf,
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002494 struct json_token *cred)
2495{
2496 struct dpp_signed_connector_info info;
Hai Shalom899fcc72020-10-19 14:38:18 -07002497 struct json_token *token, *csign, *ppkey;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002498 int ret = -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08002499 struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07002500 const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002501 const char *signed_connector;
2502
2503 os_memset(&info, 0, sizeof(info));
2504
Hai Shalomc3565922019-10-28 11:58:20 -07002505 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
Hai Shalom021b0b52019-04-10 11:17:58 -07002506 wpa_printf(MSG_DEBUG,
2507 "DPP: Legacy credential included in Connector credential");
Hai Shalomc3565922019-10-28 11:58:20 -07002508 if (dpp_parse_cred_legacy(conf, cred) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07002509 return -1;
2510 }
2511
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002512 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2513
2514 csign = json_get_member(cred, "csign");
2515 if (!csign || csign->type != JSON_OBJECT) {
2516 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2517 goto fail;
2518 }
2519
2520 csign_pub = dpp_parse_jwk(csign, &key_curve);
2521 if (!csign_pub) {
2522 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
2523 goto fail;
2524 }
2525 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
2526
Hai Shalom899fcc72020-10-19 14:38:18 -07002527 ppkey = json_get_member(cred, "ppKey");
2528 if (ppkey && ppkey->type == JSON_OBJECT) {
2529 pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2530 if (!pp_pub) {
2531 wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2532 goto fail;
2533 }
2534 dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2535 if (key_curve != pp_curve) {
2536 wpa_printf(MSG_DEBUG,
2537 "DPP: C-sign-key and ppKey do not use the same curve");
2538 goto fail;
2539 }
2540 }
2541
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002542 token = json_get_member(cred, "signedConnector");
2543 if (!token || token->type != JSON_STRING) {
2544 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
2545 goto fail;
2546 }
2547 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
2548 token->string, os_strlen(token->string));
2549 signed_connector = token->string;
2550
2551 if (os_strchr(signed_connector, '"') ||
2552 os_strchr(signed_connector, '\n')) {
2553 wpa_printf(MSG_DEBUG,
2554 "DPP: Unexpected character in signedConnector");
2555 goto fail;
2556 }
2557
2558 if (dpp_process_signed_connector(&info, csign_pub,
Roshan Pius3a1667e2018-07-03 15:17:14 -07002559 signed_connector) != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002560 goto fail;
2561
Hai Shalomc3565922019-10-28 11:58:20 -07002562 if (dpp_parse_connector(auth, conf,
2563 info.payload, info.payload_len) < 0) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002564 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
2565 goto fail;
2566 }
2567
Hai Shalomc3565922019-10-28 11:58:20 -07002568 os_free(conf->connector);
2569 conf->connector = os_strdup(signed_connector);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002570
Hai Shalomc3565922019-10-28 11:58:20 -07002571 dpp_copy_csign(conf, csign_pub);
Hai Shalom899fcc72020-10-19 14:38:18 -07002572 if (pp_pub)
2573 dpp_copy_ppkey(conf, pp_pub);
Hai Shalomb755a2a2020-04-23 21:49:02 -07002574 if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
Hai Shalomfdcde762020-04-02 11:19:20 -07002575 dpp_copy_netaccesskey(auth, conf);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002576
2577 ret = 0;
2578fail:
Hai Shalomc1a21442022-02-04 13:43:00 -08002579 crypto_ec_key_deinit(csign_pub);
2580 crypto_ec_key_deinit(pp_pub);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002581 os_free(info.payload);
2582 return ret;
2583}
2584
2585
Hai Shalom899fcc72020-10-19 14:38:18 -07002586#ifdef CONFIG_DPP2
2587static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2588 struct dpp_config_obj *conf,
2589 struct json_token *cred)
2590{
2591 struct json_token *ent, *name;
2592
2593 ent = json_get_member(cred, "entCreds");
2594 if (!ent || ent->type != JSON_OBJECT) {
2595 dpp_auth_fail(auth, "No entCreds in JSON");
2596 return -1;
2597 }
2598
2599 conf->certbag = json_get_member_base64(ent, "certBag");
2600 if (!conf->certbag) {
2601 dpp_auth_fail(auth, "No certBag in JSON");
2602 return -1;
2603 }
2604 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
Hai Shalomc1a21442022-02-04 13:43:00 -08002605 conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
Hai Shalom899fcc72020-10-19 14:38:18 -07002606 if (!conf->certs) {
2607 dpp_auth_fail(auth, "No certificates in certBag");
2608 return -1;
2609 }
2610
2611 conf->cacert = json_get_member_base64(ent, "caCert");
2612 if (conf->cacert)
2613 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
2614 conf->cacert);
2615
2616 name = json_get_member(ent, "trustedEapServerName");
2617 if (name &&
2618 (name->type != JSON_STRING ||
2619 has_ctrl_char((const u8 *) name->string,
2620 os_strlen(name->string)))) {
2621 dpp_auth_fail(auth,
2622 "Invalid trustedEapServerName type in JSON");
2623 return -1;
2624 }
2625 if (name && name->string) {
2626 wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
2627 name->string);
2628 conf->server_name = os_strdup(name->string);
2629 if (!conf->server_name)
2630 return -1;
2631 }
2632
2633 return 0;
2634}
2635#endif /* CONFIG_DPP2 */
2636
2637
Roshan Pius3a1667e2018-07-03 15:17:14 -07002638const char * dpp_akm_str(enum dpp_akm akm)
2639{
2640 switch (akm) {
2641 case DPP_AKM_DPP:
2642 return "dpp";
2643 case DPP_AKM_PSK:
2644 return "psk";
2645 case DPP_AKM_SAE:
2646 return "sae";
2647 case DPP_AKM_PSK_SAE:
2648 return "psk+sae";
Hai Shalom021b0b52019-04-10 11:17:58 -07002649 case DPP_AKM_SAE_DPP:
2650 return "dpp+sae";
2651 case DPP_AKM_PSK_SAE_DPP:
2652 return "dpp+psk+sae";
Hai Shalom899fcc72020-10-19 14:38:18 -07002653 case DPP_AKM_DOT1X:
2654 return "dot1x";
Roshan Pius3a1667e2018-07-03 15:17:14 -07002655 default:
2656 return "??";
2657 }
2658}
2659
2660
Hai Shalomc3565922019-10-28 11:58:20 -07002661const char * dpp_akm_selector_str(enum dpp_akm akm)
2662{
2663 switch (akm) {
2664 case DPP_AKM_DPP:
2665 return "506F9A02";
2666 case DPP_AKM_PSK:
2667 return "000FAC02+000FAC06";
2668 case DPP_AKM_SAE:
2669 return "000FAC08";
2670 case DPP_AKM_PSK_SAE:
2671 return "000FAC02+000FAC06+000FAC08";
2672 case DPP_AKM_SAE_DPP:
2673 return "506F9A02+000FAC08";
2674 case DPP_AKM_PSK_SAE_DPP:
2675 return "506F9A02+000FAC08+000FAC02+000FAC06";
Hai Shalom899fcc72020-10-19 14:38:18 -07002676 case DPP_AKM_DOT1X:
2677 return "000FAC01+000FAC05";
Hai Shalomc3565922019-10-28 11:58:20 -07002678 default:
2679 return "??";
2680 }
2681}
2682
2683
Roshan Pius3a1667e2018-07-03 15:17:14 -07002684static enum dpp_akm dpp_akm_from_str(const char *akm)
2685{
Hai Shalomc3565922019-10-28 11:58:20 -07002686 const char *pos;
Hai Shalom899fcc72020-10-19 14:38:18 -07002687 int dpp = 0, psk = 0, sae = 0, dot1x = 0;
Hai Shalomc3565922019-10-28 11:58:20 -07002688
Roshan Pius3a1667e2018-07-03 15:17:14 -07002689 if (os_strcmp(akm, "psk") == 0)
2690 return DPP_AKM_PSK;
2691 if (os_strcmp(akm, "sae") == 0)
2692 return DPP_AKM_SAE;
2693 if (os_strcmp(akm, "psk+sae") == 0)
2694 return DPP_AKM_PSK_SAE;
2695 if (os_strcmp(akm, "dpp") == 0)
2696 return DPP_AKM_DPP;
Hai Shalom021b0b52019-04-10 11:17:58 -07002697 if (os_strcmp(akm, "dpp+sae") == 0)
2698 return DPP_AKM_SAE_DPP;
2699 if (os_strcmp(akm, "dpp+psk+sae") == 0)
2700 return DPP_AKM_PSK_SAE_DPP;
Hai Shalom899fcc72020-10-19 14:38:18 -07002701 if (os_strcmp(akm, "dot1x") == 0)
2702 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07002703
2704 pos = akm;
2705 while (*pos) {
2706 if (os_strlen(pos) < 8)
2707 break;
2708 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
2709 dpp = 1;
2710 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
2711 psk = 1;
2712 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
2713 psk = 1;
2714 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
2715 sae = 1;
Hai Shalom899fcc72020-10-19 14:38:18 -07002716 else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
2717 dot1x = 1;
2718 else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
2719 dot1x = 1;
Hai Shalomc3565922019-10-28 11:58:20 -07002720 pos += 8;
2721 if (*pos != '+')
2722 break;
2723 pos++;
2724 }
2725
2726 if (dpp && psk && sae)
2727 return DPP_AKM_PSK_SAE_DPP;
2728 if (dpp && sae)
2729 return DPP_AKM_SAE_DPP;
2730 if (dpp)
2731 return DPP_AKM_DPP;
2732 if (psk && sae)
2733 return DPP_AKM_PSK_SAE;
2734 if (sae)
2735 return DPP_AKM_SAE;
2736 if (psk)
2737 return DPP_AKM_PSK;
Hai Shalom899fcc72020-10-19 14:38:18 -07002738 if (dot1x)
2739 return DPP_AKM_DOT1X;
Hai Shalomc3565922019-10-28 11:58:20 -07002740
Roshan Pius3a1667e2018-07-03 15:17:14 -07002741 return DPP_AKM_UNKNOWN;
2742}
2743
2744
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002745static int dpp_parse_conf_obj(struct dpp_authentication *auth,
2746 const u8 *conf_obj, u16 conf_obj_len)
2747{
2748 int ret = -1;
2749 struct json_token *root, *token, *discovery, *cred;
Hai Shalomc3565922019-10-28 11:58:20 -07002750 struct dpp_config_obj *conf;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002751 struct wpabuf *ssid64 = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07002752 int legacy;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002753
2754 root = json_parse((const char *) conf_obj, conf_obj_len);
2755 if (!root)
2756 return -1;
2757 if (root->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002758 dpp_auth_fail(auth, "JSON root is not an object");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002759 goto fail;
2760 }
2761
2762 token = json_get_member(root, "wi-fi_tech");
2763 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002764 dpp_auth_fail(auth, "No wi-fi_tech string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002765 goto fail;
2766 }
2767 if (os_strcmp(token->string, "infra") != 0) {
2768 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
2769 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002770 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002771 goto fail;
2772 }
2773
2774 discovery = json_get_member(root, "discovery");
2775 if (!discovery || discovery->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002776 dpp_auth_fail(auth, "No discovery object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002777 goto fail;
2778 }
2779
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002780 ssid64 = json_get_member_base64url(discovery, "ssid64");
2781 if (ssid64) {
2782 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
2783 wpabuf_head(ssid64), wpabuf_len(ssid64));
2784 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
2785 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
2786 goto fail;
2787 }
2788 } else {
2789 token = json_get_member(discovery, "ssid");
2790 if (!token || token->type != JSON_STRING) {
2791 dpp_auth_fail(auth,
2792 "No discovery::ssid string value found");
2793 goto fail;
2794 }
2795 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
2796 token->string, os_strlen(token->string));
2797 if (os_strlen(token->string) > SSID_MAX_LEN) {
2798 dpp_auth_fail(auth,
2799 "Too long discovery::ssid string value");
2800 goto fail;
2801 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002802 }
Hai Shalomc3565922019-10-28 11:58:20 -07002803
2804 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
2805 wpa_printf(MSG_DEBUG,
2806 "DPP: No room for this many Config Objects - ignore this one");
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002807 ret = 0;
2808 goto fail;
Hai Shalomc3565922019-10-28 11:58:20 -07002809 }
2810 conf = &auth->conf_obj[auth->num_conf_obj++];
2811
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002812 if (ssid64) {
2813 conf->ssid_len = wpabuf_len(ssid64);
2814 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
2815 } else {
2816 conf->ssid_len = os_strlen(token->string);
2817 os_memcpy(conf->ssid, token->string, conf->ssid_len);
2818 }
2819
2820 token = json_get_member(discovery, "ssid_charset");
2821 if (token && token->type == JSON_NUMBER) {
2822 conf->ssid_charset = token->number;
2823 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
2824 conf->ssid_charset);
2825 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002826
2827 cred = json_get_member(root, "cred");
2828 if (!cred || cred->type != JSON_OBJECT) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002829 dpp_auth_fail(auth, "No cred object in JSON");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002830 goto fail;
2831 }
2832
2833 token = json_get_member(cred, "akm");
2834 if (!token || token->type != JSON_STRING) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002835 dpp_auth_fail(auth, "No cred::akm string value found");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002836 goto fail;
2837 }
Hai Shalomc3565922019-10-28 11:58:20 -07002838 conf->akm = dpp_akm_from_str(token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002839
Hai Shalomfdcde762020-04-02 11:19:20 -07002840 legacy = dpp_akm_legacy(conf->akm);
2841 if (legacy && auth->peer_version >= 2) {
2842 struct json_token *csign, *s_conn;
2843
2844 csign = json_get_member(cred, "csign");
2845 s_conn = json_get_member(cred, "signedConnector");
2846 if (csign && csign->type == JSON_OBJECT &&
2847 s_conn && s_conn->type == JSON_STRING)
2848 legacy = 0;
2849 }
2850 if (legacy) {
Hai Shalomc3565922019-10-28 11:58:20 -07002851 if (dpp_parse_cred_legacy(conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002852 goto fail;
Hai Shalomfdcde762020-04-02 11:19:20 -07002853 } else if (dpp_akm_dpp(conf->akm) ||
2854 (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
Hai Shalomc3565922019-10-28 11:58:20 -07002855 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002856 goto fail;
Hai Shalom899fcc72020-10-19 14:38:18 -07002857#ifdef CONFIG_DPP2
2858 } else if (conf->akm == DPP_AKM_DOT1X) {
2859 if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
2860 dpp_parse_cred_dpp(auth, conf, cred) < 0)
2861 goto fail;
2862#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002863 } else {
2864 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
2865 token->string);
Roshan Pius3a1667e2018-07-03 15:17:14 -07002866 dpp_auth_fail(auth, "Unsupported akm");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002867 goto fail;
2868 }
2869
2870 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
2871 ret = 0;
2872fail:
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08002873 wpabuf_free(ssid64);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002874 json_free(root);
2875 return ret;
2876}
2877
2878
Hai Shalom899fcc72020-10-19 14:38:18 -07002879#ifdef CONFIG_DPP2
2880static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
2881{
2882 const u8 *b64;
2883 u16 b64_len;
2884
2885 b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
2886 if (!b64)
2887 return NULL;
2888 return base64_decode((const char *) b64, b64_len, len);
2889}
2890#endif /* CONFIG_DPP2 */
2891
2892
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002893int dpp_conf_resp_rx(struct dpp_authentication *auth,
2894 const struct wpabuf *resp)
2895{
2896 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
2897 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
Hai Shalomfdcde762020-04-02 11:19:20 -07002898 const u8 *env_data;
2899 u16 env_data_len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002900 const u8 *addr[1];
2901 size_t len[1];
2902 u8 *unwrapped = NULL;
2903 size_t unwrapped_len = 0;
2904 int ret = -1;
2905
Hai Shalom021b0b52019-04-10 11:17:58 -07002906 auth->conf_resp_status = 255;
2907
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002908 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002909 dpp_auth_fail(auth, "Invalid attribute in config response");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002910 return -1;
2911 }
2912
2913 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
2914 DPP_ATTR_WRAPPED_DATA,
2915 &wrapped_data_len);
2916 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002917 dpp_auth_fail(auth,
2918 "Missing or invalid required Wrapped Data attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002919 return -1;
2920 }
2921
2922 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2923 wrapped_data, wrapped_data_len);
2924 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2925 unwrapped = os_malloc(unwrapped_len);
2926 if (!unwrapped)
2927 return -1;
2928
2929 addr[0] = wpabuf_head(resp);
2930 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
2931 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2932
2933 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2934 wrapped_data, wrapped_data_len,
2935 1, addr, len, unwrapped) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002936 dpp_auth_fail(auth, "AES-SIV decryption failed");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002937 goto fail;
2938 }
2939 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2940 unwrapped, unwrapped_len);
2941
2942 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002943 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002944 goto fail;
2945 }
2946
2947 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2948 DPP_ATTR_ENROLLEE_NONCE,
2949 &e_nonce_len);
2950 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002951 dpp_auth_fail(auth,
2952 "Missing or invalid Enrollee Nonce attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002953 goto fail;
2954 }
2955 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
2956 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002957 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002958 goto fail;
2959 }
2960
2961 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
2962 DPP_ATTR_STATUS, &status_len);
2963 if (!status || status_len < 1) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002964 dpp_auth_fail(auth,
2965 "Missing or invalid required DPP Status attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002966 goto fail;
2967 }
Hai Shalom021b0b52019-04-10 11:17:58 -07002968 auth->conf_resp_status = status[0];
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002969 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
Hai Shalom899fcc72020-10-19 14:38:18 -07002970#ifdef CONFIG_DPP2
2971 if (status[0] == DPP_STATUS_CSR_NEEDED) {
2972 u8 *csrattrs;
2973 size_t csrattrs_len;
2974
2975 wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
2976
2977 csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
2978 &csrattrs_len);
2979 if (!csrattrs) {
2980 dpp_auth_fail(auth,
2981 "Missing or invalid CSR Attributes Request attribute");
2982 goto fail;
2983 }
2984 wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
2985 os_free(auth->csrattrs);
2986 auth->csrattrs = csrattrs;
2987 auth->csrattrs_len = csrattrs_len;
2988 ret = -2;
2989 goto fail;
2990 }
2991#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002992 if (status[0] != DPP_STATUS_OK) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07002993 dpp_auth_fail(auth, "Configurator rejected configuration");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07002994 goto fail;
2995 }
2996
Hai Shalomfdcde762020-04-02 11:19:20 -07002997 env_data = dpp_get_attr(unwrapped, unwrapped_len,
2998 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
2999#ifdef CONFIG_DPP2
3000 if (env_data &&
3001 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3002 goto fail;
3003#endif /* CONFIG_DPP2 */
3004
Hai Shalomc3565922019-10-28 11:58:20 -07003005 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3006 &conf_obj_len);
Hai Shalomfdcde762020-04-02 11:19:20 -07003007 if (!conf_obj && !env_data) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07003008 dpp_auth_fail(auth,
3009 "Missing required Configuration Object attribute");
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003010 goto fail;
3011 }
Hai Shalomc3565922019-10-28 11:58:20 -07003012 while (conf_obj) {
3013 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3014 conf_obj, conf_obj_len);
3015 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3016 goto fail;
3017 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3018 DPP_ATTR_CONFIG_OBJ,
3019 &conf_obj_len);
3020 }
3021
3022#ifdef CONFIG_DPP2
3023 status = dpp_get_attr(unwrapped, unwrapped_len,
3024 DPP_ATTR_SEND_CONN_STATUS, &status_len);
3025 if (status) {
3026 wpa_printf(MSG_DEBUG,
3027 "DPP: Configurator requested connection status result");
3028 auth->conn_status_requested = 1;
3029 }
3030#endif /* CONFIG_DPP2 */
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003031
3032 ret = 0;
3033
3034fail:
3035 os_free(unwrapped);
3036 return ret;
3037}
3038
3039
Hai Shalom021b0b52019-04-10 11:17:58 -07003040#ifdef CONFIG_DPP2
Hai Shalomc3565922019-10-28 11:58:20 -07003041
Hai Shalom021b0b52019-04-10 11:17:58 -07003042enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3043 const u8 *hdr,
3044 const u8 *attr_start, size_t attr_len)
3045{
3046 const u8 *wrapped_data, *status, *e_nonce;
3047 u16 wrapped_data_len, status_len, e_nonce_len;
3048 const u8 *addr[2];
3049 size_t len[2];
3050 u8 *unwrapped = NULL;
3051 size_t unwrapped_len = 0;
3052 enum dpp_status_error ret = 256;
3053
3054 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3055 &wrapped_data_len);
3056 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3057 dpp_auth_fail(auth,
3058 "Missing or invalid required Wrapped Data attribute");
3059 goto fail;
3060 }
3061 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3062 wrapped_data, wrapped_data_len);
3063
3064 attr_len = wrapped_data - 4 - attr_start;
3065
3066 addr[0] = hdr;
3067 len[0] = DPP_HDR_LEN;
3068 addr[1] = attr_start;
3069 len[1] = attr_len;
3070 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3071 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3072 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3073 wrapped_data, wrapped_data_len);
3074 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3075 unwrapped = os_malloc(unwrapped_len);
3076 if (!unwrapped)
3077 goto fail;
3078 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3079 wrapped_data, wrapped_data_len,
3080 2, addr, len, unwrapped) < 0) {
3081 dpp_auth_fail(auth, "AES-SIV decryption failed");
3082 goto fail;
3083 }
3084 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3085 unwrapped, unwrapped_len);
3086
3087 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3088 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3089 goto fail;
3090 }
3091
3092 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3093 DPP_ATTR_ENROLLEE_NONCE,
3094 &e_nonce_len);
3095 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3096 dpp_auth_fail(auth,
3097 "Missing or invalid Enrollee Nonce attribute");
3098 goto fail;
3099 }
3100 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3101 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3102 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3103 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3104 auth->e_nonce, e_nonce_len);
3105 goto fail;
3106 }
3107
3108 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3109 &status_len);
3110 if (!status || status_len < 1) {
3111 dpp_auth_fail(auth,
3112 "Missing or invalid required DPP Status attribute");
3113 goto fail;
3114 }
3115 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3116 ret = status[0];
3117
3118fail:
3119 bin_clear_free(unwrapped, unwrapped_len);
3120 return ret;
3121}
Hai Shalom021b0b52019-04-10 11:17:58 -07003122
3123
3124struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3125 enum dpp_status_error status)
3126{
3127 struct wpabuf *msg, *clear;
3128 size_t nonce_len, clear_len, attr_len;
3129 const u8 *addr[2];
3130 size_t len[2];
3131 u8 *wrapped;
3132
3133 nonce_len = auth->curve->nonce_len;
3134 clear_len = 5 + 4 + nonce_len;
3135 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3136 clear = wpabuf_alloc(clear_len);
3137 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3138 if (!clear || !msg)
Hai Shalomc3565922019-10-28 11:58:20 -07003139 goto fail;
Hai Shalom021b0b52019-04-10 11:17:58 -07003140
3141 /* DPP Status */
3142 dpp_build_attr_status(clear, status);
3143
3144 /* E-nonce */
3145 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3146 wpabuf_put_le16(clear, nonce_len);
3147 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3148
3149 /* OUI, OUI type, Crypto Suite, DPP frame type */
3150 addr[0] = wpabuf_head_u8(msg) + 2;
3151 len[0] = 3 + 1 + 1 + 1;
3152 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3153
3154 /* Attributes before Wrapped Data (none) */
3155 addr[1] = wpabuf_put(msg, 0);
3156 len[1] = 0;
3157 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3158
3159 /* Wrapped Data */
3160 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3161 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3162 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3163
3164 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3165 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3166 wpabuf_head(clear), wpabuf_len(clear),
3167 2, addr, len, wrapped) < 0)
3168 goto fail;
3169
3170 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3171 wpabuf_free(clear);
3172 return msg;
3173fail:
3174 wpabuf_free(clear);
3175 wpabuf_free(msg);
3176 return NULL;
3177}
3178
3179
Hai Shalomc3565922019-10-28 11:58:20 -07003180static int valid_channel_list(const char *val)
3181{
3182 while (*val) {
3183 if (!((*val >= '0' && *val <= '9') ||
3184 *val == '/' || *val == ','))
3185 return 0;
3186 val++;
3187 }
3188
3189 return 1;
3190}
3191
3192
3193enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3194 const u8 *hdr,
3195 const u8 *attr_start,
3196 size_t attr_len,
3197 u8 *ssid, size_t *ssid_len,
3198 char **channel_list)
3199{
3200 const u8 *wrapped_data, *status, *e_nonce;
3201 u16 wrapped_data_len, status_len, e_nonce_len;
3202 const u8 *addr[2];
3203 size_t len[2];
3204 u8 *unwrapped = NULL;
3205 size_t unwrapped_len = 0;
3206 enum dpp_status_error ret = 256;
3207 struct json_token *root = NULL, *token;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003208 struct wpabuf *ssid64;
Hai Shalomc3565922019-10-28 11:58:20 -07003209
3210 *ssid_len = 0;
3211 *channel_list = NULL;
3212
3213 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3214 &wrapped_data_len);
3215 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3216 dpp_auth_fail(auth,
3217 "Missing or invalid required Wrapped Data attribute");
3218 goto fail;
3219 }
3220 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3221 wrapped_data, wrapped_data_len);
3222
3223 attr_len = wrapped_data - 4 - attr_start;
3224
3225 addr[0] = hdr;
3226 len[0] = DPP_HDR_LEN;
3227 addr[1] = attr_start;
3228 len[1] = attr_len;
3229 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3230 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3231 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3232 wrapped_data, wrapped_data_len);
3233 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3234 unwrapped = os_malloc(unwrapped_len);
3235 if (!unwrapped)
3236 goto fail;
3237 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3238 wrapped_data, wrapped_data_len,
3239 2, addr, len, unwrapped) < 0) {
3240 dpp_auth_fail(auth, "AES-SIV decryption failed");
3241 goto fail;
3242 }
3243 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3244 unwrapped, unwrapped_len);
3245
3246 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3247 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3248 goto fail;
3249 }
3250
3251 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3252 DPP_ATTR_ENROLLEE_NONCE,
3253 &e_nonce_len);
3254 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3255 dpp_auth_fail(auth,
3256 "Missing or invalid Enrollee Nonce attribute");
3257 goto fail;
3258 }
3259 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3260 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3261 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3262 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3263 auth->e_nonce, e_nonce_len);
3264 goto fail;
3265 }
3266
3267 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3268 &status_len);
3269 if (!status) {
3270 dpp_auth_fail(auth,
3271 "Missing required DPP Connection Status attribute");
3272 goto fail;
3273 }
3274 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3275 status, status_len);
3276
3277 root = json_parse((const char *) status, status_len);
3278 if (!root) {
3279 dpp_auth_fail(auth, "Could not parse connStatus");
3280 goto fail;
3281 }
3282
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003283 ssid64 = json_get_member_base64url(root, "ssid64");
3284 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3285 *ssid_len = wpabuf_len(ssid64);
3286 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
Hai Shalomc3565922019-10-28 11:58:20 -07003287 }
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003288 wpabuf_free(ssid64);
Hai Shalomc3565922019-10-28 11:58:20 -07003289
3290 token = json_get_member(root, "channelList");
3291 if (token && token->type == JSON_STRING &&
3292 valid_channel_list(token->string))
3293 *channel_list = os_strdup(token->string);
3294
3295 token = json_get_member(root, "result");
3296 if (!token || token->type != JSON_NUMBER) {
3297 dpp_auth_fail(auth, "No connStatus - result");
3298 goto fail;
3299 }
3300 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3301 ret = token->number;
3302
3303fail:
3304 json_free(root);
3305 bin_clear_free(unwrapped, unwrapped_len);
3306 return ret;
3307}
3308
3309
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003310struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3311 const u8 *ssid, size_t ssid_len,
3312 const char *channel_list)
3313{
3314 struct wpabuf *json;
3315
3316 json = wpabuf_alloc(1000);
3317 if (!json)
3318 return NULL;
3319 json_start_object(json, NULL);
3320 json_add_int(json, "result", result);
3321 if (ssid) {
3322 json_value_sep(json);
3323 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3324 wpabuf_free(json);
3325 return NULL;
3326 }
3327 }
3328 if (channel_list) {
3329 json_value_sep(json);
3330 json_add_string(json, "channelList", channel_list);
3331 }
3332 json_end_object(json);
3333 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3334 wpabuf_head(json), wpabuf_len(json));
3335
3336 return json;
3337}
3338
3339
Hai Shalomc3565922019-10-28 11:58:20 -07003340struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3341 enum dpp_status_error result,
3342 const u8 *ssid, size_t ssid_len,
3343 const char *channel_list)
3344{
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003345 struct wpabuf *msg = NULL, *clear = NULL, *json;
Hai Shalomc3565922019-10-28 11:58:20 -07003346 size_t nonce_len, clear_len, attr_len;
3347 const u8 *addr[2];
3348 size_t len[2];
3349 u8 *wrapped;
3350
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003351 json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
Hai Shalomc3565922019-10-28 11:58:20 -07003352 if (!json)
3353 return NULL;
Hai Shalomc3565922019-10-28 11:58:20 -07003354
3355 nonce_len = auth->curve->nonce_len;
3356 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3357 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3358 clear = wpabuf_alloc(clear_len);
3359 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3360 if (!clear || !msg)
3361 goto fail;
3362
3363 /* E-nonce */
3364 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3365 wpabuf_put_le16(clear, nonce_len);
3366 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3367
3368 /* DPP Connection Status */
3369 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3370 wpabuf_put_le16(clear, wpabuf_len(json));
3371 wpabuf_put_buf(clear, json);
3372
3373 /* OUI, OUI type, Crypto Suite, DPP frame type */
3374 addr[0] = wpabuf_head_u8(msg) + 2;
3375 len[0] = 3 + 1 + 1 + 1;
3376 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3377
3378 /* Attributes before Wrapped Data (none) */
3379 addr[1] = wpabuf_put(msg, 0);
3380 len[1] = 0;
3381 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3382
3383 /* Wrapped Data */
3384 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3385 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3386 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3387
3388 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3389 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3390 wpabuf_head(clear), wpabuf_len(clear),
3391 2, addr, len, wrapped) < 0)
3392 goto fail;
3393
3394 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3395 msg);
3396 wpabuf_free(json);
3397 wpabuf_free(clear);
3398 return msg;
3399fail:
3400 wpabuf_free(json);
3401 wpabuf_free(clear);
3402 wpabuf_free(msg);
3403 return NULL;
3404}
3405
3406#endif /* CONFIG_DPP2 */
3407
3408
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003409void dpp_configurator_free(struct dpp_configurator *conf)
3410{
3411 if (!conf)
3412 return;
Hai Shalomc1a21442022-02-04 13:43:00 -08003413 crypto_ec_key_deinit(conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003414 os_free(conf->kid);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003415 os_free(conf->connector);
Hai Shalomc1a21442022-02-04 13:43:00 -08003416 crypto_ec_key_deinit(conf->connector_key);
3417 crypto_ec_key_deinit(conf->pp_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003418 os_free(conf);
3419}
3420
3421
Roshan Pius3a1667e2018-07-03 15:17:14 -07003422int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3423 size_t buflen)
3424{
Hai Shalomc1a21442022-02-04 13:43:00 -08003425 struct wpabuf *key;
3426 int ret = -1;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003427
3428 if (!conf->csign)
3429 return -1;
3430
Hai Shalomc1a21442022-02-04 13:43:00 -08003431 key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3432 if (!key)
Roshan Pius3a1667e2018-07-03 15:17:14 -07003433 return -1;
3434
Hai Shalomc1a21442022-02-04 13:43:00 -08003435 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
Roshan Pius3a1667e2018-07-03 15:17:14 -07003436
Hai Shalomc1a21442022-02-04 13:43:00 -08003437 wpabuf_clear_free(key);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003438 return ret;
3439}
3440
3441
Hai Shalomfdcde762020-04-02 11:19:20 -07003442static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3443{
3444 struct wpabuf *csign_pub = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07003445 const u8 *addr[1];
3446 size_t len[1];
3447 int res;
3448
Hai Shalomc1a21442022-02-04 13:43:00 -08003449 csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
Hai Shalomfdcde762020-04-02 11:19:20 -07003450 if (!csign_pub) {
3451 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3452 return -1;
3453 }
3454
3455 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
3456 addr[0] = wpabuf_head(csign_pub);
3457 len[0] = wpabuf_len(csign_pub);
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003458 res = sha256_vector(1, addr, len, conf->kid_hash);
Hai Shalomfdcde762020-04-02 11:19:20 -07003459 wpabuf_free(csign_pub);
3460 if (res < 0) {
3461 wpa_printf(MSG_DEBUG,
3462 "DPP: Failed to derive kid for C-sign-key");
3463 return -1;
3464 }
3465
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003466 conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3467 NULL);
Hai Shalomfdcde762020-04-02 11:19:20 -07003468 return conf->kid ? 0 : -1;
3469}
3470
3471
Hai Shalom899fcc72020-10-19 14:38:18 -07003472static struct dpp_configurator *
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003473dpp_keygen_configurator(const char *curve, const u8 *privkey,
Hai Shalom899fcc72020-10-19 14:38:18 -07003474 size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003475{
3476 struct dpp_configurator *conf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003477
3478 conf = os_zalloc(sizeof(*conf));
3479 if (!conf)
3480 return NULL;
3481
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003482 conf->curve = dpp_get_curve_name(curve);
3483 if (!conf->curve) {
3484 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3485 os_free(conf);
3486 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003487 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003488
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003489 if (privkey)
3490 conf->csign = dpp_set_keypair(&conf->curve, privkey,
3491 privkey_len);
3492 else
3493 conf->csign = dpp_gen_keypair(conf->curve);
Hai Shalom899fcc72020-10-19 14:38:18 -07003494 if (pp_key)
3495 conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3496 pp_key_len);
3497 else
3498 conf->pp_key = dpp_gen_keypair(conf->curve);
3499 if (!conf->csign || !conf->pp_key)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003500 goto fail;
3501 conf->own = 1;
3502
Hai Shalomfdcde762020-04-02 11:19:20 -07003503 if (dpp_configurator_gen_kid(conf) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003504 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003505 return conf;
3506fail:
3507 dpp_configurator_free(conf);
Hai Shalomfdcde762020-04-02 11:19:20 -07003508 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003509}
3510
3511
3512int dpp_configurator_own_config(struct dpp_authentication *auth,
Roshan Pius3a1667e2018-07-03 15:17:14 -07003513 const char *curve, int ap)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003514{
3515 struct wpabuf *conf_obj;
3516 int ret = -1;
3517
3518 if (!auth->conf) {
3519 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
3520 return -1;
3521 }
3522
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003523 auth->curve = dpp_get_curve_name(curve);
3524 if (!auth->curve) {
3525 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3526 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003527 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003528
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003529 wpa_printf(MSG_DEBUG,
3530 "DPP: Building own configuration/connector with curve %s",
3531 auth->curve->name);
3532
3533 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
3534 if (!auth->own_protocol_key)
3535 return -1;
Hai Shalomc3565922019-10-28 11:58:20 -07003536 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003537 auth->peer_protocol_key = auth->own_protocol_key;
Hai Shalomc3565922019-10-28 11:58:20 -07003538 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003539
Hai Shalom899fcc72020-10-19 14:38:18 -07003540 conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003541 if (!conf_obj) {
3542 wpabuf_free(auth->conf_obj[0].c_sign_key);
3543 auth->conf_obj[0].c_sign_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003544 goto fail;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003545 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003546 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
3547 wpabuf_len(conf_obj));
3548fail:
3549 wpabuf_free(conf_obj);
3550 auth->peer_protocol_key = NULL;
3551 return ret;
3552}
3553
3554
3555static int dpp_compatible_netrole(const char *role1, const char *role2)
3556{
3557 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
3558 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
3559}
3560
3561
3562static int dpp_connector_compatible_group(struct json_token *root,
3563 const char *group_id,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003564 const char *net_role,
3565 bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003566{
3567 struct json_token *groups, *token;
3568
3569 groups = json_get_member(root, "groups");
3570 if (!groups || groups->type != JSON_ARRAY)
3571 return 0;
3572
3573 for (token = groups->child; token; token = token->sibling) {
3574 struct json_token *id, *role;
3575
3576 id = json_get_member(token, "groupId");
3577 if (!id || id->type != JSON_STRING)
3578 continue;
3579
3580 role = json_get_member(token, "netRole");
3581 if (!role || role->type != JSON_STRING)
3582 continue;
3583
3584 if (os_strcmp(id->string, "*") != 0 &&
3585 os_strcmp(group_id, "*") != 0 &&
3586 os_strcmp(id->string, group_id) != 0)
3587 continue;
3588
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003589 if (reconfig && os_strcmp(net_role, "configurator") == 0)
3590 return 1;
3591 if (!reconfig && dpp_compatible_netrole(role->string, net_role))
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003592 return 1;
3593 }
3594
3595 return 0;
3596}
3597
3598
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003599int dpp_connector_match_groups(struct json_token *own_root,
3600 struct json_token *peer_root, bool reconfig)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003601{
3602 struct json_token *groups, *token;
3603
3604 groups = json_get_member(peer_root, "groups");
3605 if (!groups || groups->type != JSON_ARRAY) {
3606 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
3607 return 0;
3608 }
3609
3610 for (token = groups->child; token; token = token->sibling) {
3611 struct json_token *id, *role;
3612
3613 id = json_get_member(token, "groupId");
3614 if (!id || id->type != JSON_STRING) {
3615 wpa_printf(MSG_DEBUG,
3616 "DPP: Missing peer groupId string");
3617 continue;
3618 }
3619
3620 role = json_get_member(token, "netRole");
3621 if (!role || role->type != JSON_STRING) {
3622 wpa_printf(MSG_DEBUG,
3623 "DPP: Missing peer groups::netRole string");
3624 continue;
3625 }
3626 wpa_printf(MSG_DEBUG,
3627 "DPP: peer connector group: groupId='%s' netRole='%s'",
3628 id->string, role->string);
3629 if (dpp_connector_compatible_group(own_root, id->string,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003630 role->string, reconfig)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003631 wpa_printf(MSG_DEBUG,
3632 "DPP: Compatible group/netRole in own connector");
3633 return 1;
3634 }
3635 }
3636
3637 return 0;
3638}
3639
3640
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003641struct json_token * dpp_parse_own_connector(const char *own_connector)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003642{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003643 unsigned char *own_conn;
3644 size_t own_conn_len;
3645 const char *pos, *end;
3646 struct json_token *own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003647
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003648 pos = os_strchr(own_connector, '.');
3649 if (!pos) {
3650 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
3651 return NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003652 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003653 pos++;
3654 end = os_strchr(pos, '.');
3655 if (!end) {
3656 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
3657 return NULL;
3658 }
3659 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
3660 if (!own_conn) {
3661 wpa_printf(MSG_DEBUG,
3662 "DPP: Failed to base64url decode own signedConnector JWS Payload");
3663 return NULL;
3664 }
3665
3666 own_root = json_parse((const char *) own_conn, own_conn_len);
3667 os_free(own_conn);
3668 if (!own_root)
3669 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
3670
3671 return own_root;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003672}
3673
3674
Roshan Pius3a1667e2018-07-03 15:17:14 -07003675enum dpp_status_error
3676dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
3677 const u8 *net_access_key, size_t net_access_key_len,
3678 const u8 *csign_key, size_t csign_key_len,
3679 const u8 *peer_connector, size_t peer_connector_len,
3680 os_time_t *expiry)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003681{
3682 struct json_token *root = NULL, *netkey, *token;
3683 struct json_token *own_root = NULL;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003684 enum dpp_status_error ret = 255, res;
Hai Shalomc1a21442022-02-04 13:43:00 -08003685 struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003686 struct wpabuf *own_key_pub = NULL;
3687 const struct dpp_curve_params *curve, *own_curve;
3688 struct dpp_signed_connector_info info;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003689 size_t Nx_len;
3690 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
3691
3692 os_memset(intro, 0, sizeof(*intro));
3693 os_memset(&info, 0, sizeof(info));
3694 if (expiry)
3695 *expiry = 0;
3696
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003697 own_key = dpp_set_keypair(&own_curve, net_access_key,
3698 net_access_key_len);
3699 if (!own_key) {
3700 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
3701 goto fail;
3702 }
3703
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003704 own_root = dpp_parse_own_connector(own_connector);
3705 if (!own_root)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003706 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003707
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003708 res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
3709 peer_connector, peer_connector_len);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003710 if (res != DPP_STATUS_OK) {
3711 ret = res;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003712 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003713 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003714
3715 root = json_parse((const char *) info.payload, info.payload_len);
3716 if (!root) {
3717 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003718 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003719 goto fail;
3720 }
3721
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003722 if (!dpp_connector_match_groups(own_root, root, false)) {
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003723 wpa_printf(MSG_DEBUG,
3724 "DPP: Peer connector does not include compatible group netrole with own connector");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003725 ret = DPP_STATUS_NO_MATCH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003726 goto fail;
3727 }
3728
3729 token = json_get_member(root, "expiry");
3730 if (!token || token->type != JSON_STRING) {
3731 wpa_printf(MSG_DEBUG,
3732 "DPP: No expiry string found - connector does not expire");
3733 } else {
3734 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
3735 if (dpp_key_expired(token->string, expiry)) {
3736 wpa_printf(MSG_DEBUG,
3737 "DPP: Connector (netAccessKey) has expired");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003738 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003739 goto fail;
3740 }
3741 }
3742
Hai Shalomc1a21442022-02-04 13:43:00 -08003743#ifdef CONFIG_DPP3
3744 token = json_get_member(root, "version");
3745 if (token && token->type == JSON_NUMBER) {
3746 wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
3747 intro->peer_version = token->number;
3748 }
3749#endif /* CONFIG_DPP3 */
3750
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003751 netkey = json_get_member(root, "netAccessKey");
3752 if (!netkey || netkey->type != JSON_OBJECT) {
3753 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
Roshan Pius3a1667e2018-07-03 15:17:14 -07003754 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003755 goto fail;
3756 }
3757
3758 peer_key = dpp_parse_jwk(netkey, &curve);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003759 if (!peer_key) {
3760 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003761 goto fail;
Roshan Pius3a1667e2018-07-03 15:17:14 -07003762 }
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003763 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
3764
3765 if (own_curve != curve) {
3766 wpa_printf(MSG_DEBUG,
3767 "DPP: Mismatching netAccessKey curves (%s != %s)",
3768 own_curve->name, curve->name);
Roshan Pius3a1667e2018-07-03 15:17:14 -07003769 ret = DPP_STATUS_INVALID_CONNECTOR;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003770 goto fail;
3771 }
3772
3773 /* ECDH: N = nk * PK */
Hai Shalomc3565922019-10-28 11:58:20 -07003774 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003775 goto fail;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003776
3777 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3778 Nx, Nx_len);
3779
3780 /* PMK = HKDF(<>, "DPP PMK", N.x) */
3781 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
3782 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
3783 goto fail;
3784 }
3785 intro->pmk_len = curve->hash_len;
3786
3787 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
3788 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
3789 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
3790 goto fail;
3791 }
3792
Roshan Pius3a1667e2018-07-03 15:17:14 -07003793 ret = DPP_STATUS_OK;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003794fail:
Roshan Pius3a1667e2018-07-03 15:17:14 -07003795 if (ret != DPP_STATUS_OK)
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003796 os_memset(intro, 0, sizeof(*intro));
3797 os_memset(Nx, 0, sizeof(Nx));
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003798 os_free(info.payload);
Hai Shalomc1a21442022-02-04 13:43:00 -08003799 crypto_ec_key_deinit(own_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003800 wpabuf_free(own_key_pub);
Hai Shalomc1a21442022-02-04 13:43:00 -08003801 crypto_ec_key_deinit(peer_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003802 json_free(root);
3803 json_free(own_root);
3804 return ret;
3805}
3806
3807
Hai Shalomc1a21442022-02-04 13:43:00 -08003808#ifdef CONFIG_DPP3
3809int dpp_get_connector_version(const char *connector)
3810{
3811 struct json_token *root, *token;
3812 int ver = -1;
3813
3814 root = dpp_parse_own_connector(connector);
3815 if (!root)
3816 return -1;
3817
3818 token = json_get_member(root, "version");
3819 if (token && token->type == JSON_NUMBER)
3820 ver = token->number;
3821
3822 json_free(root);
3823 return ver;
3824}
3825#endif /* CONFIG_DPP3 */
3826
3827
Hai Shalom4fbc08f2020-05-18 12:37:00 -07003828unsigned int dpp_next_id(struct dpp_global *dpp)
Hai Shalom021b0b52019-04-10 11:17:58 -07003829{
3830 struct dpp_bootstrap_info *bi;
3831 unsigned int max_id = 0;
3832
3833 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
3834 if (bi->id > max_id)
3835 max_id = bi->id;
3836 }
3837 return max_id + 1;
3838}
3839
3840
3841static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
3842{
3843 struct dpp_bootstrap_info *bi, *tmp;
3844 int found = 0;
3845
3846 if (!dpp)
3847 return -1;
3848
3849 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
3850 struct dpp_bootstrap_info, list) {
3851 if (id && bi->id != id)
3852 continue;
3853 found = 1;
Hai Shalomfdcde762020-04-02 11:19:20 -07003854#ifdef CONFIG_DPP2
3855 if (dpp->remove_bi)
3856 dpp->remove_bi(dpp->cb_ctx, bi);
3857#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07003858 dl_list_del(&bi->list);
3859 dpp_bootstrap_info_free(bi);
3860 }
3861
3862 if (id == 0)
3863 return 0; /* flush succeeds regardless of entries found */
3864 return found ? 0 : -1;
3865}
3866
3867
3868struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
3869 const char *uri)
3870{
3871 struct dpp_bootstrap_info *bi;
3872
3873 if (!dpp)
3874 return NULL;
3875
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003876 bi = dpp_parse_uri(uri);
Hai Shalom021b0b52019-04-10 11:17:58 -07003877 if (!bi)
3878 return NULL;
3879
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003880 bi->type = DPP_BOOTSTRAP_QR_CODE;
3881 bi->id = dpp_next_id(dpp);
3882 dl_list_add(&dpp->bootstrap, &bi->list);
3883 return bi;
3884}
3885
3886
3887struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
3888 const char *uri)
3889{
3890 struct dpp_bootstrap_info *bi;
3891
3892 if (!dpp)
3893 return NULL;
3894
3895 bi = dpp_parse_uri(uri);
3896 if (!bi)
3897 return NULL;
3898
3899 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07003900 bi->id = dpp_next_id(dpp);
3901 dl_list_add(&dpp->bootstrap, &bi->list);
3902 return bi;
3903}
3904
3905
3906int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
3907{
Hai Shalomfdcde762020-04-02 11:19:20 -07003908 char *mac = NULL, *info = NULL, *curve = NULL;
Hai Shalom021b0b52019-04-10 11:17:58 -07003909 char *key = NULL;
3910 u8 *privkey = NULL;
3911 size_t privkey_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07003912 int ret = -1;
3913 struct dpp_bootstrap_info *bi;
3914
3915 if (!dpp)
3916 return -1;
3917
3918 bi = os_zalloc(sizeof(*bi));
3919 if (!bi)
3920 goto fail;
3921
3922 if (os_strstr(cmd, "type=qrcode"))
3923 bi->type = DPP_BOOTSTRAP_QR_CODE;
3924 else if (os_strstr(cmd, "type=pkex"))
3925 bi->type = DPP_BOOTSTRAP_PKEX;
Ahmed ElArabawy0ff61c52019-12-26 12:38:39 -08003926 else if (os_strstr(cmd, "type=nfc-uri"))
3927 bi->type = DPP_BOOTSTRAP_NFC_URI;
Hai Shalom021b0b52019-04-10 11:17:58 -07003928 else
3929 goto fail;
3930
Hai Shalomfdcde762020-04-02 11:19:20 -07003931 bi->chan = get_param(cmd, " chan=");
Hai Shalom021b0b52019-04-10 11:17:58 -07003932 mac = get_param(cmd, " mac=");
3933 info = get_param(cmd, " info=");
3934 curve = get_param(cmd, " curve=");
3935 key = get_param(cmd, " key=");
3936
3937 if (key) {
3938 privkey_len = os_strlen(key) / 2;
3939 privkey = os_malloc(privkey_len);
3940 if (!privkey ||
3941 hexstr2bin(key, privkey, privkey_len) < 0)
3942 goto fail;
3943 }
3944
Hai Shalomfdcde762020-04-02 11:19:20 -07003945 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
3946 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
3947 dpp_parse_uri_mac(bi, mac) < 0 ||
3948 dpp_parse_uri_info(bi, info) < 0 ||
3949 dpp_gen_uri(bi) < 0)
Hai Shalom021b0b52019-04-10 11:17:58 -07003950 goto fail;
3951
Hai Shalom021b0b52019-04-10 11:17:58 -07003952 bi->id = dpp_next_id(dpp);
3953 dl_list_add(&dpp->bootstrap, &bi->list);
3954 ret = bi->id;
3955 bi = NULL;
3956fail:
3957 os_free(curve);
Hai Shalom021b0b52019-04-10 11:17:58 -07003958 os_free(mac);
3959 os_free(info);
3960 str_clear_free(key);
3961 bin_clear_free(privkey, privkey_len);
3962 dpp_bootstrap_info_free(bi);
3963 return ret;
3964}
3965
3966
3967struct dpp_bootstrap_info *
3968dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
3969{
3970 struct dpp_bootstrap_info *bi;
3971
3972 if (!dpp)
3973 return NULL;
3974
3975 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
3976 if (bi->id == id)
3977 return bi;
3978 }
3979 return NULL;
3980}
3981
3982
3983int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
3984{
3985 unsigned int id_val;
3986
3987 if (os_strcmp(id, "*") == 0) {
3988 id_val = 0;
3989 } else {
3990 id_val = atoi(id);
3991 if (id_val == 0)
3992 return -1;
3993 }
3994
3995 return dpp_bootstrap_del(dpp, id_val);
3996}
3997
3998
Hai Shalom021b0b52019-04-10 11:17:58 -07003999const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4000{
4001 struct dpp_bootstrap_info *bi;
4002
4003 bi = dpp_bootstrap_get_id(dpp, id);
4004 if (!bi)
4005 return NULL;
4006 return bi->uri;
4007}
4008
4009
4010int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4011 char *reply, int reply_size)
4012{
4013 struct dpp_bootstrap_info *bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004014 char pkhash[2 * SHA256_MAC_LEN + 1];
Hai Shalom021b0b52019-04-10 11:17:58 -07004015
4016 bi = dpp_bootstrap_get_id(dpp, id);
4017 if (!bi)
4018 return -1;
Hai Shalom81f62d82019-07-22 12:10:00 -07004019 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4020 SHA256_MAC_LEN);
Hai Shalom021b0b52019-04-10 11:17:58 -07004021 return os_snprintf(reply, reply_size, "type=%s\n"
4022 "mac_addr=" MACSTR "\n"
4023 "info=%s\n"
4024 "num_freq=%u\n"
Hai Shalomfdcde762020-04-02 11:19:20 -07004025 "use_freq=%u\n"
Hai Shalom81f62d82019-07-22 12:10:00 -07004026 "curve=%s\n"
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004027 "pkhash=%s\n"
4028 "version=%d\n",
Hai Shalom021b0b52019-04-10 11:17:58 -07004029 dpp_bootstrap_type_txt(bi->type),
4030 MAC2STR(bi->mac_addr),
4031 bi->info ? bi->info : "",
4032 bi->num_freq,
Hai Shalomfdcde762020-04-02 11:19:20 -07004033 bi->num_freq == 1 ? bi->freq[0] : 0,
Hai Shalom81f62d82019-07-22 12:10:00 -07004034 bi->curve->name,
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004035 pkhash,
4036 bi->version);
Hai Shalom021b0b52019-04-10 11:17:58 -07004037}
4038
4039
Hai Shalomfdcde762020-04-02 11:19:20 -07004040int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4041{
4042 struct dpp_bootstrap_info *bi;
4043
4044 bi = dpp_bootstrap_get_id(dpp, id);
4045 if (!bi)
4046 return -1;
4047
4048 str_clear_free(bi->configurator_params);
4049
4050 if (params) {
4051 bi->configurator_params = os_strdup(params);
4052 return bi->configurator_params ? 0 : -1;
4053 }
4054
4055 bi->configurator_params = NULL;
4056 return 0;
4057}
4058
4059
Hai Shalom021b0b52019-04-10 11:17:58 -07004060void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4061 const u8 *r_bootstrap,
4062 struct dpp_bootstrap_info **own_bi,
4063 struct dpp_bootstrap_info **peer_bi)
4064{
4065 struct dpp_bootstrap_info *bi;
4066
4067 *own_bi = NULL;
4068 *peer_bi = NULL;
4069 if (!dpp)
4070 return;
4071
4072 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4073 if (!*own_bi && bi->own &&
4074 os_memcmp(bi->pubkey_hash, r_bootstrap,
4075 SHA256_MAC_LEN) == 0) {
4076 wpa_printf(MSG_DEBUG,
4077 "DPP: Found matching own bootstrapping information");
4078 *own_bi = bi;
4079 }
4080
4081 if (!*peer_bi && !bi->own &&
4082 os_memcmp(bi->pubkey_hash, i_bootstrap,
4083 SHA256_MAC_LEN) == 0) {
4084 wpa_printf(MSG_DEBUG,
4085 "DPP: Found matching peer bootstrapping information");
4086 *peer_bi = bi;
4087 }
4088
4089 if (*own_bi && *peer_bi)
4090 break;
4091 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004092}
Hai Shalom021b0b52019-04-10 11:17:58 -07004093
Hai Shalomfdcde762020-04-02 11:19:20 -07004094
4095#ifdef CONFIG_DPP2
4096struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4097 const u8 *hash)
4098{
4099 struct dpp_bootstrap_info *bi;
4100
4101 if (!dpp)
4102 return NULL;
4103
4104 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4105 if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4106 SHA256_MAC_LEN) == 0)
4107 return bi;
4108 }
4109
4110 return NULL;
4111}
4112#endif /* CONFIG_DPP2 */
4113
4114
4115static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4116 struct dpp_bootstrap_info *peer_bi)
4117{
4118 unsigned int i, freq = 0;
4119 enum hostapd_hw_mode mode;
4120 u8 op_class, channel;
4121 char chan[20];
4122
Hai Shalom899fcc72020-10-19 14:38:18 -07004123 if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
Hai Shalomfdcde762020-04-02 11:19:20 -07004124 return 0; /* no channel preference/constraint */
4125
4126 for (i = 0; i < peer_bi->num_freq; i++) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004127 if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
Hai Shalomfdcde762020-04-02 11:19:20 -07004128 freq_included(own_bi->freq, own_bi->num_freq,
4129 peer_bi->freq[i])) {
4130 freq = peer_bi->freq[i];
4131 break;
4132 }
4133 }
4134 if (!freq) {
4135 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4136 return -1;
4137 }
4138
4139 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4140 if (mode == NUM_HOSTAPD_MODES) {
4141 wpa_printf(MSG_DEBUG,
4142 "DPP: Could not determine operating class or channel number for %u MHz",
4143 freq);
4144 }
4145
4146 wpa_printf(MSG_DEBUG,
4147 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4148 freq, op_class, channel);
4149 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4150 os_free(own_bi->chan);
4151 own_bi->chan = os_strdup(chan);
4152 own_bi->freq[0] = freq;
4153 own_bi->num_freq = 1;
4154 os_free(peer_bi->chan);
4155 peer_bi->chan = os_strdup(chan);
4156 peer_bi->freq[0] = freq;
4157 peer_bi->num_freq = 1;
4158
4159 return dpp_gen_uri(own_bi);
4160}
4161
4162
4163static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4164 struct dpp_bootstrap_info *peer_bi)
4165{
4166 if (peer_bi->curve == own_bi->curve)
4167 return 0;
4168
4169 wpa_printf(MSG_DEBUG,
4170 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4171
Hai Shalomc1a21442022-02-04 13:43:00 -08004172 crypto_ec_key_deinit(own_bi->pubkey);
Hai Shalomfdcde762020-04-02 11:19:20 -07004173 own_bi->pubkey = NULL;
4174
4175 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4176 dpp_gen_uri(own_bi) < 0)
4177 goto fail;
4178
4179 return 0;
4180fail:
4181 dl_list_del(&own_bi->list);
4182 dpp_bootstrap_info_free(own_bi);
4183 return -1;
4184}
4185
4186
4187int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4188 struct dpp_bootstrap_info *peer_bi)
4189{
4190 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4191 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4192 return -1;
4193 return 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004194}
4195
4196
4197static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4198{
4199 struct dpp_configurator *conf;
4200 unsigned int max_id = 0;
4201
4202 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4203 list) {
4204 if (conf->id > max_id)
4205 max_id = conf->id;
4206 }
4207 return max_id + 1;
4208}
4209
4210
4211int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4212{
4213 char *curve = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07004214 char *key = NULL, *ppkey = NULL;
4215 u8 *privkey = NULL, *pp_key = NULL;
4216 size_t privkey_len = 0, pp_key_len = 0;
Hai Shalom021b0b52019-04-10 11:17:58 -07004217 int ret = -1;
4218 struct dpp_configurator *conf = NULL;
4219
4220 curve = get_param(cmd, " curve=");
4221 key = get_param(cmd, " key=");
Hai Shalom899fcc72020-10-19 14:38:18 -07004222 ppkey = get_param(cmd, " ppkey=");
Hai Shalom021b0b52019-04-10 11:17:58 -07004223
4224 if (key) {
4225 privkey_len = os_strlen(key) / 2;
4226 privkey = os_malloc(privkey_len);
4227 if (!privkey ||
4228 hexstr2bin(key, privkey, privkey_len) < 0)
4229 goto fail;
4230 }
4231
Hai Shalom899fcc72020-10-19 14:38:18 -07004232 if (ppkey) {
Hai Shalom60840252021-02-19 19:02:11 -08004233 pp_key_len = os_strlen(ppkey) / 2;
Hai Shalom899fcc72020-10-19 14:38:18 -07004234 pp_key = os_malloc(pp_key_len);
4235 if (!pp_key ||
4236 hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4237 goto fail;
4238 }
4239
4240 conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4241 pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004242 if (!conf)
4243 goto fail;
4244
4245 conf->id = dpp_next_configurator_id(dpp);
4246 dl_list_add(&dpp->configurator, &conf->list);
4247 ret = conf->id;
4248 conf = NULL;
4249fail:
4250 os_free(curve);
4251 str_clear_free(key);
Hai Shalom899fcc72020-10-19 14:38:18 -07004252 str_clear_free(ppkey);
Hai Shalom021b0b52019-04-10 11:17:58 -07004253 bin_clear_free(privkey, privkey_len);
Hai Shalom899fcc72020-10-19 14:38:18 -07004254 bin_clear_free(pp_key, pp_key_len);
Hai Shalom021b0b52019-04-10 11:17:58 -07004255 dpp_configurator_free(conf);
4256 return ret;
4257}
4258
4259
4260static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4261{
4262 struct dpp_configurator *conf, *tmp;
4263 int found = 0;
4264
4265 if (!dpp)
4266 return -1;
4267
4268 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4269 struct dpp_configurator, list) {
4270 if (id && conf->id != id)
4271 continue;
4272 found = 1;
4273 dl_list_del(&conf->list);
4274 dpp_configurator_free(conf);
4275 }
4276
4277 if (id == 0)
4278 return 0; /* flush succeeds regardless of entries found */
4279 return found ? 0 : -1;
4280}
4281
4282
4283int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4284{
4285 unsigned int id_val;
4286
4287 if (os_strcmp(id, "*") == 0) {
4288 id_val = 0;
4289 } else {
4290 id_val = atoi(id);
4291 if (id_val == 0)
4292 return -1;
4293 }
4294
4295 return dpp_configurator_del(dpp, id_val);
4296}
4297
4298
4299int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4300 char *buf, size_t buflen)
4301{
4302 struct dpp_configurator *conf;
4303
4304 conf = dpp_configurator_get_id(dpp, id);
4305 if (!conf)
4306 return -1;
4307
4308 return dpp_configurator_get_key(conf, buf, buflen);
4309}
4310
4311
Hai Shalom81f62d82019-07-22 12:10:00 -07004312#ifdef CONFIG_DPP2
4313
Hai Shalomfdcde762020-04-02 11:19:20 -07004314int dpp_configurator_from_backup(struct dpp_global *dpp,
4315 struct dpp_asymmetric_key *key)
4316{
4317 struct dpp_configurator *conf;
Hai Shalomc1a21442022-02-04 13:43:00 -08004318 const struct dpp_curve_params *curve, *curve_pp;
Hai Shalomfdcde762020-04-02 11:19:20 -07004319
Hai Shalom899fcc72020-10-19 14:38:18 -07004320 if (!key->csign || !key->pp_key)
Hai Shalomfdcde762020-04-02 11:19:20 -07004321 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08004322
4323 curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
Hai Shalomfdcde762020-04-02 11:19:20 -07004324 if (!curve) {
4325 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4326 return -1;
4327 }
Hai Shalomc1a21442022-02-04 13:43:00 -08004328
4329 curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
4330 if (!curve_pp) {
4331 wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
Hai Shalom899fcc72020-10-19 14:38:18 -07004332 return -1;
Hai Shalomc1a21442022-02-04 13:43:00 -08004333 }
4334
4335 if (curve != curve_pp) {
Hai Shalom899fcc72020-10-19 14:38:18 -07004336 wpa_printf(MSG_INFO,
4337 "DPP: Mismatch in c-sign-key and ppKey groups");
4338 return -1;
4339 }
Hai Shalomfdcde762020-04-02 11:19:20 -07004340
4341 conf = os_zalloc(sizeof(*conf));
4342 if (!conf)
4343 return -1;
4344 conf->curve = curve;
4345 conf->csign = key->csign;
4346 key->csign = NULL;
Hai Shalom899fcc72020-10-19 14:38:18 -07004347 conf->pp_key = key->pp_key;
4348 key->pp_key = NULL;
Hai Shalomfdcde762020-04-02 11:19:20 -07004349 conf->own = 1;
4350 if (dpp_configurator_gen_kid(conf) < 0) {
4351 dpp_configurator_free(conf);
4352 return -1;
4353 }
4354
4355 conf->id = dpp_next_configurator_id(dpp);
4356 dl_list_add(&dpp->configurator, &conf->list);
4357 return conf->id;
4358}
4359
4360
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004361struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4362 const u8 *kid)
Hai Shalom81f62d82019-07-22 12:10:00 -07004363{
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004364 struct dpp_configurator *conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004365
4366 if (!dpp)
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004367 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004368
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004369 dl_list_for_each(conf, &dpp->configurator,
4370 struct dpp_configurator, list) {
4371 if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4372 return conf;
Hai Shalom81f62d82019-07-22 12:10:00 -07004373 }
Hai Shalom4fbc08f2020-05-18 12:37:00 -07004374 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004375}
4376
4377#endif /* CONFIG_DPP2 */
4378
4379
4380struct dpp_global * dpp_global_init(struct dpp_global_config *config)
Hai Shalom021b0b52019-04-10 11:17:58 -07004381{
4382 struct dpp_global *dpp;
4383
4384 dpp = os_zalloc(sizeof(*dpp));
4385 if (!dpp)
4386 return NULL;
Hai Shalom81f62d82019-07-22 12:10:00 -07004387#ifdef CONFIG_DPP2
4388 dpp->cb_ctx = config->cb_ctx;
Hai Shalomfdcde762020-04-02 11:19:20 -07004389 dpp->remove_bi = config->remove_bi;
Hai Shalom81f62d82019-07-22 12:10:00 -07004390#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004391
4392 dl_list_init(&dpp->bootstrap);
4393 dl_list_init(&dpp->configurator);
Hai Shalom81f62d82019-07-22 12:10:00 -07004394#ifdef CONFIG_DPP2
4395 dl_list_init(&dpp->controllers);
4396 dl_list_init(&dpp->tcp_init);
4397#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004398
4399 return dpp;
4400}
4401
4402
4403void dpp_global_clear(struct dpp_global *dpp)
4404{
4405 if (!dpp)
4406 return;
4407
4408 dpp_bootstrap_del(dpp, 0);
4409 dpp_configurator_del(dpp, 0);
Hai Shalom81f62d82019-07-22 12:10:00 -07004410#ifdef CONFIG_DPP2
4411 dpp_tcp_init_flush(dpp);
4412 dpp_relay_flush_controllers(dpp);
4413 dpp_controller_stop(dpp);
4414#endif /* CONFIG_DPP2 */
Hai Shalom021b0b52019-04-10 11:17:58 -07004415}
4416
4417
4418void dpp_global_deinit(struct dpp_global *dpp)
4419{
4420 dpp_global_clear(dpp);
4421 os_free(dpp);
4422}
Hai Shalom81f62d82019-07-22 12:10:00 -07004423
4424
4425#ifdef CONFIG_DPP2
Hai Shalom899fcc72020-10-19 14:38:18 -07004426
Hai Shalomfdcde762020-04-02 11:19:20 -07004427struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
4428{
4429 struct wpabuf *msg;
4430
4431 wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
4432
4433 msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
4434 if (!msg)
4435 return NULL;
4436
4437 /* Responder Bootstrapping Key Hash */
4438 dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
4439 wpa_hexdump_buf(MSG_DEBUG,
4440 "DPP: Presence Announcement frame attributes", msg);
4441 return msg;
4442}
Hai Shalom899fcc72020-10-19 14:38:18 -07004443
4444
4445void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
4446 unsigned int freq, const u8 *hash)
4447{
4448 char hex[SHA256_MAC_LEN * 2 + 1];
4449
4450 wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
4451 wpa_msg(msg_ctx, MSG_INFO,
4452 DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
4453 id, MAC2STR(src), freq, hex);
4454}
4455
Hai Shalom81f62d82019-07-22 12:10:00 -07004456#endif /* CONFIG_DPP2 */