1 /*
2  * DPP functionality shared between hostapd and wpa_supplicant
3  * Copyright (c) 2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2018-2020, The Linux Foundation
5  * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
6  *
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"
12 
13 #include "utils/common.h"
14 #include "utils/base64.h"
15 #include "utils/json.h"
16 #include "utils/ip_addr.h"
17 #include "common/ieee802_11_common.h"
18 #include "common/wpa_ctrl.h"
19 #include "common/gas.h"
20 #include "eap_common/eap_defs.h"
21 #include "crypto/crypto.h"
22 #include "crypto/random.h"
23 #include "crypto/aes.h"
24 #include "crypto/aes_siv.h"
25 #include "drivers/driver.h"
26 #include "dpp.h"
27 #include "dpp_i.h"
28 
29 
30 #ifdef CONFIG_TESTING_OPTIONS
31 #ifdef CONFIG_DPP3
32 int dpp_version_override = 3;
33 #elif defined(CONFIG_DPP2)
34 int dpp_version_override = 2;
35 #else
36 int dpp_version_override = 1;
37 #endif
38 enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
39 #endif /* CONFIG_TESTING_OPTIONS */
40 
41 
dpp_auth_fail(struct dpp_authentication * auth,const char * txt)42 void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
43 {
44           wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
45 }
46 
47 
dpp_alloc_msg(enum dpp_public_action_frame_type type,size_t len)48 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
49                                     size_t len)
50 {
51           struct wpabuf *msg;
52 
53           msg = wpabuf_alloc(8 + len);
54           if (!msg)
55                     return NULL;
56           wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
57           wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
58           wpabuf_put_be24(msg, OUI_WFA);
59           wpabuf_put_u8(msg, DPP_OUI_TYPE);
60           wpabuf_put_u8(msg, 1); /* Crypto Suite */
61           wpabuf_put_u8(msg, type);
62           return msg;
63 }
64 
65 
dpp_get_attr(const u8 * buf,size_t len,u16 req_id,u16 * ret_len)66 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
67 {
68           u16 id, alen;
69           const u8 *pos = buf, *end = buf + len;
70 
71           while (end - pos >= 4) {
72                     id = WPA_GET_LE16(pos);
73                     pos += 2;
74                     alen = WPA_GET_LE16(pos);
75                     pos += 2;
76                     if (alen > end - pos)
77                               return NULL;
78                     if (id == req_id) {
79                               *ret_len = alen;
80                               return pos;
81                     }
82                     pos += alen;
83           }
84 
85           return NULL;
86 }
87 
88 
dpp_get_attr_next(const u8 * prev,const u8 * buf,size_t len,u16 req_id,u16 * ret_len)89 static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
90                                             u16 req_id, u16 *ret_len)
91 {
92           u16 id, alen;
93           const u8 *pos, *end = buf + len;
94 
95           if (!prev)
96                     pos = buf;
97           else
98                     pos = prev + WPA_GET_LE16(prev - 2);
99           while (end - pos >= 4) {
100                     id = WPA_GET_LE16(pos);
101                     pos += 2;
102                     alen = WPA_GET_LE16(pos);
103                     pos += 2;
104                     if (alen > end - pos)
105                               return NULL;
106                     if (id == req_id) {
107                               *ret_len = alen;
108                               return pos;
109                     }
110                     pos += alen;
111           }
112 
113           return NULL;
114 }
115 
116 
dpp_check_attrs(const u8 * buf,size_t len)117 int dpp_check_attrs(const u8 *buf, size_t len)
118 {
119           const u8 *pos, *end;
120           int wrapped_data = 0;
121 
122           pos = buf;
123           end = buf + len;
124           while (end - pos >= 4) {
125                     u16 id, alen;
126 
127                     id = WPA_GET_LE16(pos);
128                     pos += 2;
129                     alen = WPA_GET_LE16(pos);
130                     pos += 2;
131                     wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
132                                  id, alen);
133                     if (alen > end - pos) {
134                               wpa_printf(MSG_DEBUG,
135                                            "DPP: Truncated message - not enough room for the attribute - dropped");
136                               return -1;
137                     }
138                     if (wrapped_data) {
139                               wpa_printf(MSG_DEBUG,
140                                            "DPP: An unexpected attribute included after the Wrapped Data attribute");
141                               return -1;
142                     }
143                     if (id == DPP_ATTR_WRAPPED_DATA)
144                               wrapped_data = 1;
145                     pos += alen;
146           }
147 
148           if (end != pos) {
149                     wpa_printf(MSG_DEBUG,
150                                  "DPP: Unexpected octets (%d) after the last attribute",
151                                  (int) (end - pos));
152                     return -1;
153           }
154 
155           return 0;
156 }
157 
158 
dpp_bootstrap_info_free(struct dpp_bootstrap_info * info)159 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
160 {
161           if (!info)
162                     return;
163           os_free(info->uri);
164           os_free(info->info);
165           os_free(info->chan);
166           os_free(info->host);
167           os_free(info->pk);
168           crypto_ec_key_deinit(info->pubkey);
169           str_clear_free(info->configurator_params);
170           os_free(info);
171 }
172 
173 
dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)174 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
175 {
176           switch (type) {
177           case DPP_BOOTSTRAP_QR_CODE:
178                     return "QRCODE";
179           case DPP_BOOTSTRAP_PKEX:
180                     return "PKEX";
181           case DPP_BOOTSTRAP_NFC_URI:
182                     return "NFC-URI";
183           }
184           return "??";
185 }
186 
187 
dpp_uri_valid_info(const char * info)188 static int dpp_uri_valid_info(const char *info)
189 {
190           while (*info) {
191                     unsigned char val = *info++;
192 
193                     if (val < 0x20 || val > 0x7e || val == 0x3b)
194                               return 0;
195           }
196 
197           return 1;
198 }
199 
200 
dpp_clone_uri(struct dpp_bootstrap_info * bi,const char * uri)201 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
202 {
203           bi->uri = os_strdup(uri);
204           return bi->uri ? 0 : -1;
205 }
206 
207 
dpp_parse_uri_chan_list(struct dpp_bootstrap_info * bi,const char * chan_list)208 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
209                                   const char *chan_list)
210 {
211           const char *pos = chan_list, *pos2;
212           int opclass = -1, channel, freq;
213 
214           while (pos && *pos && *pos != ';') {
215                     pos2 = pos;
216                     while (*pos2 >= '0' && *pos2 <= '9')
217                               pos2++;
218                     if (*pos2 == '/') {
219                               opclass = atoi(pos);
220                               pos = pos2 + 1;
221                     }
222                     if (opclass <= 0)
223                               goto fail;
224                     channel = atoi(pos);
225                     if (channel <= 0)
226                               goto fail;
227                     while (*pos >= '0' && *pos <= '9')
228                               pos++;
229                     freq = ieee80211_chan_to_freq(NULL, opclass, channel);
230                     wpa_printf(MSG_DEBUG,
231                                  "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
232                                  opclass, channel, freq);
233                     bi->channels_listed = true;
234                     if (freq < 0) {
235                               wpa_printf(MSG_DEBUG,
236                                            "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
237                                            opclass, channel);
238                     } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
239                               wpa_printf(MSG_DEBUG,
240                                            "DPP: Too many channels in URI channel-list - ignore list");
241                               bi->num_freq = 0;
242                               break;
243                     } else {
244                               bi->freq[bi->num_freq++] = freq;
245                     }
246 
247                     if (*pos == ';' || *pos == '\0')
248                               break;
249                     if (*pos != ',')
250                               goto fail;
251                     pos++;
252           }
253 
254           return 0;
255 fail:
256           wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
257           return -1;
258 }
259 
260 
dpp_parse_uri_mac(struct dpp_bootstrap_info * bi,const char * mac)261 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
262 {
263           if (!mac)
264                     return 0;
265 
266           if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
267                     wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
268                     return -1;
269           }
270 
271           wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
272 
273           return 0;
274 }
275 
276 
dpp_parse_uri_info(struct dpp_bootstrap_info * bi,const char * info)277 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
278 {
279           const char *end;
280 
281           if (!info)
282                     return 0;
283 
284           end = os_strchr(info, ';');
285           if (!end)
286                     end = info + os_strlen(info);
287           bi->info = os_malloc(end - info + 1);
288           if (!bi->info)
289                     return -1;
290           os_memcpy(bi->info, info, end - info);
291           bi->info[end - info] = '\0';
292           wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
293           if (!dpp_uri_valid_info(bi->info)) {
294                     wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
295                     return -1;
296           }
297 
298           return 0;
299 }
300 
301 
dpp_parse_uri_version(struct dpp_bootstrap_info * bi,const char * version)302 int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
303 {
304 #ifdef CONFIG_DPP2
305           if (!version || DPP_VERSION < 2)
306                     return 0;
307 
308           if (*version == '1')
309                     bi->version = 1;
310           else if (*version == '2')
311                     bi->version = 2;
312           else if (*version == '3')
313                     bi->version = 3;
314           else
315                     wpa_printf(MSG_DEBUG, "DPP: Unknown URI version");
316 
317           wpa_printf(MSG_DEBUG, "DPP: URI version: %d", bi->version);
318 #endif /* CONFIG_DPP2 */
319 
320           return 0;
321 }
322 
323 
dpp_parse_uri_pk(struct dpp_bootstrap_info * bi,const char * info)324 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
325 {
326           u8 *data;
327           size_t data_len;
328           int res;
329           const char *end;
330 
331           end = os_strchr(info, ';');
332           if (!end)
333                     return -1;
334 
335           data = base64_decode(info, end - info, &data_len);
336           if (!data) {
337                     wpa_printf(MSG_DEBUG,
338                                  "DPP: Invalid base64 encoding on URI public-key");
339                     return -1;
340           }
341           wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
342                         data, data_len);
343 
344           res = dpp_get_subject_public_key(bi, data, data_len);
345           os_free(data);
346           return res;
347 }
348 
349 
dpp_parse_uri_supported_curves(struct dpp_bootstrap_info * bi,const char * txt)350 static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
351                                                     const char *txt)
352 {
353           int val;
354 
355           if (!txt)
356                     return 0;
357 
358           val = hex2num(txt[0]);
359           if (val < 0)
360                     return -1;
361           bi->supported_curves = val;
362 
363           val = hex2num(txt[1]);
364           if (val > 0)
365                     bi->supported_curves |= val << 4;
366 
367           wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
368                        bi->supported_curves);
369 
370           return 0;
371 }
372 
373 
dpp_parse_uri_host(struct dpp_bootstrap_info * bi,const char * txt)374 static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt)
375 {
376           const char *end;
377           char *port;
378           struct hostapd_ip_addr addr;
379           char buf[100], *pos;
380 
381           if (!txt)
382                     return 0;
383 
384           end = os_strchr(txt, ';');
385           if (!end)
386                     end = txt + os_strlen(txt);
387           if (end - txt > (int) sizeof(buf) - 1)
388                     return -1;
389           os_memcpy(buf, txt, end - txt);
390           buf[end - txt] = '\0';
391 
392           bi->port = DPP_TCP_PORT;
393 
394           pos = buf;
395           if (*pos == '[') {
396                     pos = &buf[1];
397                     port = os_strchr(pos, ']');
398                     if (!port)
399                               return -1;
400                     *port++ = '\0';
401                     if (*port == ':')
402                               bi->port = atoi(port + 1);
403           }
404 
405           if (hostapd_parse_ip_addr(pos, &addr) < 0) {
406                     if (buf[0] != '[') {
407                               port = os_strrchr(pos, ':');
408                               if (port) {
409                                         *port++ = '\0';
410                                         bi->port = atoi(port);
411                               }
412                     }
413                     if (hostapd_parse_ip_addr(pos, &addr) < 0) {
414                               wpa_printf(MSG_INFO,
415                                            "DPP: Invalid IP address in URI host entry: %s",
416                                            pos);
417                               return -1;
418                     }
419           }
420           os_free(bi->host);
421           bi->host = os_memdup(&addr, sizeof(addr));
422           if (!bi->host)
423                     return -1;
424 
425           wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u",
426                        hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port);
427 
428           return 0;
429 }
430 
431 
dpp_parse_uri(const char * uri)432 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
433 {
434           const char *pos = uri;
435           const char *end;
436           const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
437           const char *version = NULL, *supported_curves = NULL, *host = NULL;
438           struct dpp_bootstrap_info *bi;
439 
440           wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
441 
442           if (os_strncmp(pos, "DPP:", 4) != 0) {
443                     wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
444                     return NULL;
445           }
446           pos += 4;
447 
448           for (;;) {
449                     end = os_strchr(pos, ';');
450                     if (!end)
451                               break;
452 
453                     if (end == pos) {
454                               /* Handle terminating ";;" and ignore unexpected ";"
455                                * for parsing robustness. */
456                               pos++;
457                               continue;
458                     }
459 
460                     if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
461                               chan_list = pos + 2;
462                     else if (pos[0] == 'M' && pos[1] == ':' && !mac)
463                               mac = pos + 2;
464                     else if (pos[0] == 'I' && pos[1] == ':' && !info)
465                               info = pos + 2;
466                     else if (pos[0] == 'K' && pos[1] == ':' && !pk)
467                               pk = pos + 2;
468                     else if (pos[0] == 'V' && pos[1] == ':' && !version)
469                               version = pos + 2;
470                     else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
471                               supported_curves = pos + 2;
472                     else if (pos[0] == 'H' && pos[1] == ':' && !host)
473                               host = pos + 2;
474                     else
475                               wpa_hexdump_ascii(MSG_DEBUG,
476                                                     "DPP: Ignore unrecognized URI parameter",
477                                                     pos, end - pos);
478                     pos = end + 1;
479           }
480 
481           if (!pk) {
482                     wpa_printf(MSG_INFO, "DPP: URI missing public-key");
483                     return NULL;
484           }
485 
486           bi = os_zalloc(sizeof(*bi));
487           if (!bi)
488                     return NULL;
489 
490           if (dpp_clone_uri(bi, uri) < 0 ||
491               dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
492               dpp_parse_uri_mac(bi, mac) < 0 ||
493               dpp_parse_uri_info(bi, info) < 0 ||
494               dpp_parse_uri_version(bi, version) < 0 ||
495               dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
496               dpp_parse_uri_host(bi, host) < 0 ||
497               dpp_parse_uri_pk(bi, pk) < 0) {
498                     dpp_bootstrap_info_free(bi);
499                     bi = NULL;
500           }
501 
502           return bi;
503 }
504 
505 
dpp_build_attr_status(struct wpabuf * msg,enum dpp_status_error status)506 void dpp_build_attr_status(struct wpabuf *msg, enum dpp_status_error status)
507 {
508           wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
509           wpabuf_put_le16(msg, DPP_ATTR_STATUS);
510           wpabuf_put_le16(msg, 1);
511           wpabuf_put_u8(msg, status);
512 }
513 
514 
dpp_build_attr_r_bootstrap_key_hash(struct wpabuf * msg,const u8 * hash)515 void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg, const u8 *hash)
516 {
517           if (hash) {
518                     wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
519                     wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
520                     wpabuf_put_le16(msg, SHA256_MAC_LEN);
521                     wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
522           }
523 }
524 
525 
dpp_channel_ok_init(struct hostapd_hw_modes * own_modes,u16 num_modes,unsigned int freq)526 static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
527                                      u16 num_modes, unsigned int freq)
528 {
529           u16 m;
530           int c, flag;
531 
532           if (!own_modes || !num_modes)
533                     return 1;
534 
535           for (m = 0; m < num_modes; m++) {
536                     for (c = 0; c < own_modes[m].num_channels; c++) {
537                               if ((unsigned int) own_modes[m].channels[c].freq !=
538                                   freq)
539                                         continue;
540                               flag = own_modes[m].channels[c].flag;
541                               if (!(flag & (HOSTAPD_CHAN_DISABLED |
542                                               HOSTAPD_CHAN_NO_IR |
543                                               HOSTAPD_CHAN_RADAR)))
544                                         return 1;
545                     }
546           }
547 
548           wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
549           return 0;
550 }
551 
552 
freq_included(const unsigned int freqs[],unsigned int num,unsigned int freq)553 static int freq_included(const unsigned int freqs[], unsigned int num,
554                                unsigned int freq)
555 {
556           while (num > 0) {
557                     if (freqs[--num] == freq)
558                               return 1;
559           }
560           return 0;
561 }
562 
563 
freq_to_start(unsigned int freqs[],unsigned int num,unsigned int freq)564 static void freq_to_start(unsigned int freqs[], unsigned int num,
565                                 unsigned int freq)
566 {
567           unsigned int i;
568 
569           for (i = 0; i < num; i++) {
570                     if (freqs[i] == freq)
571                               break;
572           }
573           if (i == 0 || i >= num)
574                     return;
575           os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
576           freqs[0] = freq;
577 }
578 
579 
dpp_channel_intersect(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)580 static int dpp_channel_intersect(struct dpp_authentication *auth,
581                                          struct hostapd_hw_modes *own_modes,
582                                          u16 num_modes)
583 {
584           struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
585           unsigned int i, freq;
586 
587           for (i = 0; i < peer_bi->num_freq; i++) {
588                     freq = peer_bi->freq[i];
589                     if (freq_included(auth->freq, auth->num_freq, freq))
590                               continue;
591                     if (dpp_channel_ok_init(own_modes, num_modes, freq))
592                               auth->freq[auth->num_freq++] = freq;
593           }
594           if (!auth->num_freq) {
595                     wpa_printf(MSG_INFO,
596                                  "DPP: No available channels for initiating DPP Authentication");
597                     return -1;
598           }
599           auth->curr_freq = auth->freq[0];
600           return 0;
601 }
602 
603 
dpp_channel_local_list(struct dpp_authentication * auth,struct hostapd_hw_modes * own_modes,u16 num_modes)604 static int dpp_channel_local_list(struct dpp_authentication *auth,
605                                           struct hostapd_hw_modes *own_modes,
606                                           u16 num_modes)
607 {
608           u16 m;
609           int c, flag;
610           unsigned int freq;
611 
612           auth->num_freq = 0;
613 
614           if (!own_modes || !num_modes) {
615                     auth->freq[0] = 2412;
616                     auth->freq[1] = 2437;
617                     auth->freq[2] = 2462;
618                     auth->num_freq = 3;
619                     return 0;
620           }
621 
622           for (m = 0; m < num_modes; m++) {
623                     for (c = 0; c < own_modes[m].num_channels; c++) {
624                               freq = own_modes[m].channels[c].freq;
625                               flag = own_modes[m].channels[c].flag;
626                               if (flag & (HOSTAPD_CHAN_DISABLED |
627                                             HOSTAPD_CHAN_NO_IR |
628                                             HOSTAPD_CHAN_RADAR))
629                                         continue;
630                               if (freq_included(auth->freq, auth->num_freq, freq))
631                                         continue;
632                               auth->freq[auth->num_freq++] = freq;
633                               if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
634                                         m = num_modes;
635                                         break;
636                               }
637                     }
638           }
639 
640           return auth->num_freq == 0 ? -1 : 0;
641 }
642 
643 
dpp_prepare_channel_list(struct dpp_authentication * auth,unsigned int neg_freq,struct hostapd_hw_modes * own_modes,u16 num_modes)644 int dpp_prepare_channel_list(struct dpp_authentication *auth,
645                                    unsigned int neg_freq,
646                                    struct hostapd_hw_modes *own_modes, u16 num_modes)
647 {
648           int res;
649           char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
650           unsigned int i;
651 
652           if (!own_modes) {
653                     if (!neg_freq)
654                               return -1;
655                     auth->num_freq = 1;
656                     auth->freq[0] = neg_freq;
657                     auth->curr_freq = neg_freq;
658                     return 0;
659           }
660 
661           if (auth->peer_bi->num_freq > 0)
662                     res = dpp_channel_intersect(auth, own_modes, num_modes);
663           else
664                     res = dpp_channel_local_list(auth, own_modes, num_modes);
665           if (res < 0)
666                     return res;
667 
668           /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
669            * likely channels first. */
670           freq_to_start(auth->freq, auth->num_freq, 2462);
671           freq_to_start(auth->freq, auth->num_freq, 2412);
672           freq_to_start(auth->freq, auth->num_freq, 2437);
673 
674           auth->freq_idx = 0;
675           auth->curr_freq = auth->freq[0];
676 
677           pos = freqs;
678           end = pos + sizeof(freqs);
679           for (i = 0; i < auth->num_freq; i++) {
680                     res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
681                     if (os_snprintf_error(end - pos, res))
682                               break;
683                     pos += res;
684           }
685           *pos = '\0';
686           wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
687                        freqs);
688 
689           return 0;
690 }
691 
692 
dpp_gen_uri(struct dpp_bootstrap_info * bi)693 int dpp_gen_uri(struct dpp_bootstrap_info *bi)
694 {
695           char macstr[ETH_ALEN * 2 + 10];
696           size_t len;
697           char supp_curves[10];
698           char host[100];
699 
700           len = 4; /* "DPP:" */
701           if (bi->chan)
702                     len += 3 + os_strlen(bi->chan); /* C:...; */
703           if (is_zero_ether_addr(bi->mac_addr))
704                     macstr[0] = '\0';
705           else
706                     os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
707                                   MAC2STR(bi->mac_addr));
708           len += os_strlen(macstr); /* M:...; */
709           if (bi->info)
710                     len += 3 + os_strlen(bi->info); /* I:...; */
711 #ifdef CONFIG_DPP2
712           len += 4; /* V:2; */
713 #endif /* CONFIG_DPP2 */
714           len += 4 + os_strlen(bi->pk); /* K:...;; */
715 
716           if (bi->supported_curves) {
717                     u8 val = bi->supported_curves;
718 
719                     if (val & 0xf0) {
720                               val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
721                               len += os_snprintf(supp_curves, sizeof(supp_curves),
722                                                      "B:%02x;", val);
723                     } else {
724                               len += os_snprintf(supp_curves, sizeof(supp_curves),
725                                                      "B:%x;", val);
726                     }
727           } else {
728                     supp_curves[0] = '\0';
729           }
730 
731           host[0] = '\0';
732           if (bi->host) {
733                     char buf[100];
734                     const char *addr;
735 
736                     addr = hostapd_ip_txt(bi->host, buf, sizeof(buf));
737                     if (!addr)
738                               return -1;
739                     if (bi->port == DPP_TCP_PORT)
740                               len += os_snprintf(host, sizeof(host), "H:%s;", addr);
741                     else if (bi->host->af == AF_INET)
742                               len += os_snprintf(host, sizeof(host), "H:%s:%u;",
743                                                      addr, bi->port);
744                     else
745                               len += os_snprintf(host, sizeof(host), "H:[%s]:%u;",
746                                                      addr, bi->port);
747           }
748 
749           os_free(bi->uri);
750           bi->uri = os_malloc(len + 1);
751           if (!bi->uri)
752                     return -1;
753           os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;",
754                         bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
755                         bi->chan ? ";" : "",
756                         macstr,
757                         bi->info ? "I:" : "", bi->info ? bi->info : "",
758                         bi->info ? ";" : "",
759                         DPP_VERSION == 3 ? "V:3;" :
760                         (DPP_VERSION == 2 ? "V:2;" : ""),
761                         supp_curves,
762                         host,
763                         bi->pk);
764           return 0;
765 }
766 
767 
768 struct dpp_authentication *
dpp_alloc_auth(struct dpp_global * dpp,void * msg_ctx)769 dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx)
770 {
771           struct dpp_authentication *auth;
772 
773           auth = os_zalloc(sizeof(*auth));
774           if (!auth)
775                     return NULL;
776           auth->global = dpp;
777           auth->msg_ctx = msg_ctx;
778           auth->conf_resp_status = 255;
779           return auth;
780 }
781 
782 
dpp_build_conf_req_attr(struct dpp_authentication * auth,const char * json)783 static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
784                                                          const char *json)
785 {
786           size_t nonce_len;
787           size_t json_len, clear_len;
788           struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
789           u8 *wrapped;
790           size_t attr_len;
791 #ifdef CONFIG_DPP3
792           u8 auth_i[DPP_MAX_HASH_LEN];
793 #endif /* CONFIG_DPP3 */
794 
795           wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
796 
797           nonce_len = auth->curve->nonce_len;
798           if (random_get_bytes(auth->e_nonce, nonce_len)) {
799                     wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
800                     goto fail;
801           }
802           wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
803           json_len = os_strlen(json);
804           wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
805 
806           /* { E-nonce, configAttrib }ke */
807           clear_len = 4 + nonce_len + 4 + json_len;
808 #ifdef CONFIG_DPP3
809           if (auth->waiting_new_key) {
810                     pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
811                     if (!pe)
812                               goto fail;
813                     clear_len += 4 + wpabuf_len(pe);
814 
815                     if (dpp_derive_auth_i(auth, auth_i) < 0)
816                               goto fail;
817                     clear_len += 4 + auth->curve->hash_len;
818           }
819 #endif /* CONFIG_DPP3 */
820           clear = wpabuf_alloc(clear_len);
821           attr_len = 4 + clear_len + AES_BLOCK_SIZE;
822 #ifdef CONFIG_TESTING_OPTIONS
823           if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
824                     attr_len += 5;
825 #endif /* CONFIG_TESTING_OPTIONS */
826           msg = wpabuf_alloc(attr_len);
827           if (!clear || !msg)
828                     goto fail;
829 
830 #ifdef CONFIG_TESTING_OPTIONS
831           if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
832                     wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
833                     goto skip_e_nonce;
834           }
835           if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
836                     wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
837                     wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
838                     wpabuf_put_le16(clear, nonce_len - 1);
839                     wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
840                     goto skip_e_nonce;
841           }
842           if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
843                     wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
844                     goto skip_wrapped_data;
845           }
846 #endif /* CONFIG_TESTING_OPTIONS */
847 
848           /* E-nonce */
849           wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
850           wpabuf_put_le16(clear, nonce_len);
851           wpabuf_put_data(clear, auth->e_nonce, nonce_len);
852 
853 #ifdef CONFIG_TESTING_OPTIONS
854 skip_e_nonce:
855           if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
856                     wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
857                     goto skip_conf_attr_obj;
858           }
859 #endif /* CONFIG_TESTING_OPTIONS */
860 
861 #ifdef CONFIG_DPP3
862           if (pe) {
863                     wpa_printf(MSG_DEBUG, "DPP: Pe");
864                     wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
865                     wpabuf_put_le16(clear, wpabuf_len(pe));
866                     wpabuf_put_buf(clear, pe);
867           }
868           if (auth->waiting_new_key) {
869                     wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
870                     wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
871                     wpabuf_put_le16(clear, auth->curve->hash_len);
872                     wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
873           }
874 #endif /* CONFIG_DPP3 */
875 
876           /* configAttrib */
877           wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
878           wpabuf_put_le16(clear, json_len);
879           wpabuf_put_data(clear, json, json_len);
880 
881 #ifdef CONFIG_TESTING_OPTIONS
882 skip_conf_attr_obj:
883 #endif /* CONFIG_TESTING_OPTIONS */
884 
885           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
886           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
887           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
888 
889           /* No AES-SIV AD */
890           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
891           if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
892                                   wpabuf_head(clear), wpabuf_len(clear),
893                                   0, NULL, NULL, wrapped) < 0)
894                     goto fail;
895           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
896                         wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
897 
898 #ifdef CONFIG_TESTING_OPTIONS
899           if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
900                     wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
901                     dpp_build_attr_status(msg, DPP_STATUS_OK);
902           }
903 skip_wrapped_data:
904 #endif /* CONFIG_TESTING_OPTIONS */
905 
906           wpa_hexdump_buf(MSG_DEBUG,
907                               "DPP: Configuration Request frame attributes", msg);
908 out:
909           wpabuf_free(clear);
910           wpabuf_free(pe);
911           return msg;
912 
913 fail:
914           wpabuf_free(msg);
915           msg = NULL;
916           goto out;
917 }
918 
919 
dpp_write_adv_proto(struct wpabuf * buf)920 void dpp_write_adv_proto(struct wpabuf *buf)
921 {
922           /* Advertisement Protocol IE */
923           wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
924           wpabuf_put_u8(buf, 8); /* Length */
925           wpabuf_put_u8(buf, 0x7f);
926           wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
927           wpabuf_put_u8(buf, 5);
928           wpabuf_put_be24(buf, OUI_WFA);
929           wpabuf_put_u8(buf, DPP_OUI_TYPE);
930           wpabuf_put_u8(buf, 0x01);
931 }
932 
933 
dpp_write_gas_query(struct wpabuf * buf,struct wpabuf * query)934 void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
935 {
936           /* GAS Query */
937           wpabuf_put_le16(buf, wpabuf_len(query));
938           wpabuf_put_buf(buf, query);
939 }
940 
941 
dpp_build_conf_req(struct dpp_authentication * auth,const char * json)942 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
943                                            const char *json)
944 {
945           struct wpabuf *buf, *conf_req;
946 
947           conf_req = dpp_build_conf_req_attr(auth, json);
948           if (!conf_req) {
949                     wpa_printf(MSG_DEBUG,
950                                  "DPP: No configuration request data available");
951                     return NULL;
952           }
953 
954           buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
955           if (!buf) {
956                     wpabuf_free(conf_req);
957                     return NULL;
958           }
959 
960           dpp_write_adv_proto(buf);
961           dpp_write_gas_query(buf, conf_req);
962           wpabuf_free(conf_req);
963           wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
964 
965           return buf;
966 }
967 
968 
dpp_build_conf_req_helper(struct dpp_authentication * auth,const char * name,enum dpp_netrole netrole,const char * mud_url,int * opclasses,const char * extra_name,const char * extra_value)969 struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
970                                                     const char *name,
971                                                     enum dpp_netrole netrole,
972                                                     const char *mud_url, int *opclasses,
973                                                     const char *extra_name,
974                                                     const char *extra_value)
975 {
976           size_t len, name_len;
977           const char *tech = "infra";
978           const char *dpp_name;
979           struct wpabuf *buf = NULL, *json = NULL;
980           char *csr = NULL;
981 
982 #ifdef CONFIG_TESTING_OPTIONS
983           if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
984                     static const char *bogus_tech = "knfra";
985 
986                     wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
987                     tech = bogus_tech;
988           }
989 #endif /* CONFIG_TESTING_OPTIONS */
990 
991           dpp_name = name ? name : "Test";
992           name_len = os_strlen(dpp_name);
993 
994           len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
995           if (mud_url && mud_url[0])
996                     len += 10 + os_strlen(mud_url);
997           if (extra_name && extra_value && extra_name[0] && extra_value[0])
998                     len += 10 + os_strlen(extra_name) + os_strlen(extra_value);
999 #ifdef CONFIG_DPP2
1000           if (auth->csr) {
1001                     size_t csr_len;
1002 
1003                     csr = base64_encode_no_lf(wpabuf_head(auth->csr),
1004                                                     wpabuf_len(auth->csr), &csr_len);
1005                     if (!csr)
1006                               goto fail;
1007                     len += 30 + csr_len;
1008           }
1009 #endif /* CONFIG_DPP2 */
1010           json = wpabuf_alloc(len);
1011           if (!json)
1012                     goto fail;
1013 
1014           json_start_object(json, NULL);
1015           if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
1016                     goto fail;
1017           json_value_sep(json);
1018           json_add_string(json, "wi-fi_tech", tech);
1019           json_value_sep(json);
1020           json_add_string(json, "netRole", dpp_netrole_str(netrole));
1021           if (mud_url && mud_url[0]) {
1022                     json_value_sep(json);
1023                     json_add_string(json, "mudurl", mud_url);
1024           }
1025           if (opclasses) {
1026                     int i;
1027 
1028                     json_value_sep(json);
1029                     json_start_array(json, "bandSupport");
1030                     for (i = 0; opclasses[i]; i++)
1031                               wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
1032                     json_end_array(json);
1033           }
1034           if (csr) {
1035                     json_value_sep(json);
1036                     json_add_string(json, "pkcs10", csr);
1037           }
1038           if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
1039                     json_value_sep(json);
1040                     wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
1041           }
1042           json_end_object(json);
1043 
1044           buf = dpp_build_conf_req(auth, wpabuf_head(json));
1045 fail:
1046           wpabuf_free(json);
1047           os_free(csr);
1048 
1049           return buf;
1050 }
1051 
1052 
bin_str_eq(const char * val,size_t len,const char * cmp)1053 static int bin_str_eq(const char *val, size_t len, const char *cmp)
1054 {
1055           return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
1056 }
1057 
1058 
dpp_configuration_alloc(const char * type)1059 struct dpp_configuration * dpp_configuration_alloc(const char *type)
1060 {
1061           struct dpp_configuration *conf;
1062           const char *end;
1063           size_t len;
1064 
1065           conf = os_zalloc(sizeof(*conf));
1066           if (!conf)
1067                     goto fail;
1068 
1069           end = os_strchr(type, ' ');
1070           if (end)
1071                     len = end - type;
1072           else
1073                     len = os_strlen(type);
1074 
1075           if (bin_str_eq(type, len, "psk"))
1076                     conf->akm = DPP_AKM_PSK;
1077           else if (bin_str_eq(type, len, "sae"))
1078                     conf->akm = DPP_AKM_SAE;
1079           else if (bin_str_eq(type, len, "psk-sae") ||
1080                      bin_str_eq(type, len, "psk+sae"))
1081                     conf->akm = DPP_AKM_PSK_SAE;
1082           else if (bin_str_eq(type, len, "sae-dpp") ||
1083                      bin_str_eq(type, len, "dpp+sae"))
1084                     conf->akm = DPP_AKM_SAE_DPP;
1085           else if (bin_str_eq(type, len, "psk-sae-dpp") ||
1086                      bin_str_eq(type, len, "dpp+psk+sae"))
1087                     conf->akm = DPP_AKM_PSK_SAE_DPP;
1088           else if (bin_str_eq(type, len, "dpp"))
1089                     conf->akm = DPP_AKM_DPP;
1090           else if (bin_str_eq(type, len, "dot1x"))
1091                     conf->akm = DPP_AKM_DOT1X;
1092           else
1093                     goto fail;
1094 
1095           return conf;
1096 fail:
1097           dpp_configuration_free(conf);
1098           return NULL;
1099 }
1100 
1101 
dpp_akm_psk(enum dpp_akm akm)1102 int dpp_akm_psk(enum dpp_akm akm)
1103 {
1104           return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1105                     akm == DPP_AKM_PSK_SAE_DPP;
1106 }
1107 
1108 
dpp_akm_sae(enum dpp_akm akm)1109 int dpp_akm_sae(enum dpp_akm akm)
1110 {
1111           return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
1112                     akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1113 }
1114 
1115 
dpp_akm_legacy(enum dpp_akm akm)1116 int dpp_akm_legacy(enum dpp_akm akm)
1117 {
1118           return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
1119                     akm == DPP_AKM_SAE;
1120 }
1121 
1122 
dpp_akm_dpp(enum dpp_akm akm)1123 int dpp_akm_dpp(enum dpp_akm akm)
1124 {
1125           return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
1126                     akm == DPP_AKM_PSK_SAE_DPP;
1127 }
1128 
1129 
dpp_akm_ver2(enum dpp_akm akm)1130 int dpp_akm_ver2(enum dpp_akm akm)
1131 {
1132           return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
1133 }
1134 
1135 
dpp_configuration_valid(const struct dpp_configuration * conf)1136 int dpp_configuration_valid(const struct dpp_configuration *conf)
1137 {
1138           if (conf->ssid_len == 0)
1139                     return 0;
1140           if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
1141                     return 0;
1142           if (dpp_akm_sae(conf->akm) && !conf->passphrase)
1143                     return 0;
1144           return 1;
1145 }
1146 
1147 
dpp_configuration_free(struct dpp_configuration * conf)1148 void dpp_configuration_free(struct dpp_configuration *conf)
1149 {
1150           if (!conf)
1151                     return;
1152           str_clear_free(conf->passphrase);
1153           os_free(conf->group_id);
1154           os_free(conf->csrattrs);
1155           os_free(conf->extra_name);
1156           os_free(conf->extra_value);
1157           bin_clear_free(conf, sizeof(*conf));
1158 }
1159 
1160 
dpp_configuration_parse_helper(struct dpp_authentication * auth,const char * cmd,int idx)1161 static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
1162                                                     const char *cmd, int idx)
1163 {
1164           const char *pos, *end;
1165           struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
1166           struct dpp_configuration *conf = NULL;
1167           size_t len;
1168 
1169           pos = os_strstr(cmd, " conf=sta-");
1170           if (pos) {
1171                     conf_sta = dpp_configuration_alloc(pos + 10);
1172                     if (!conf_sta)
1173                               goto fail;
1174                     conf_sta->netrole = DPP_NETROLE_STA;
1175                     conf = conf_sta;
1176           }
1177 
1178           pos = os_strstr(cmd, " conf=ap-");
1179           if (pos) {
1180                     conf_ap = dpp_configuration_alloc(pos + 9);
1181                     if (!conf_ap)
1182                               goto fail;
1183                     conf_ap->netrole = DPP_NETROLE_AP;
1184                     conf = conf_ap;
1185           }
1186 
1187           pos = os_strstr(cmd, " conf=configurator");
1188           if (pos)
1189                     auth->provision_configurator = 1;
1190 
1191           if (!conf)
1192                     return 0;
1193 
1194           pos = os_strstr(cmd, " ssid=");
1195           if (pos) {
1196                     pos += 6;
1197                     end = os_strchr(pos, ' ');
1198                     conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
1199                     conf->ssid_len /= 2;
1200                     if (conf->ssid_len > sizeof(conf->ssid) ||
1201                         hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
1202                               goto fail;
1203           } else {
1204 #ifdef CONFIG_TESTING_OPTIONS
1205                     /* use a default SSID for legacy testing reasons */
1206                     os_memcpy(conf->ssid, "test", 4);
1207                     conf->ssid_len = 4;
1208 #else /* CONFIG_TESTING_OPTIONS */
1209                     goto fail;
1210 #endif /* CONFIG_TESTING_OPTIONS */
1211           }
1212 
1213           pos = os_strstr(cmd, " ssid_charset=");
1214           if (pos) {
1215                     if (conf_ap) {
1216                               wpa_printf(MSG_INFO,
1217                                            "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
1218                               goto fail;
1219                     }
1220                     conf->ssid_charset = atoi(pos + 14);
1221           }
1222 
1223           pos = os_strstr(cmd, " pass=");
1224           if (pos) {
1225                     size_t pass_len;
1226 
1227                     pos += 6;
1228                     end = os_strchr(pos, ' ');
1229                     pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
1230                     pass_len /= 2;
1231                     if (pass_len > 63 || pass_len < 8)
1232                               goto fail;
1233                     conf->passphrase = os_zalloc(pass_len + 1);
1234                     if (!conf->passphrase ||
1235                         hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
1236                               goto fail;
1237           }
1238 
1239           pos = os_strstr(cmd, " psk=");
1240           if (pos) {
1241                     pos += 5;
1242                     if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
1243                               goto fail;
1244                     conf->psk_set = 1;
1245           }
1246 
1247           pos = os_strstr(cmd, " group_id=");
1248           if (pos) {
1249                     size_t group_id_len;
1250 
1251                     pos += 10;
1252                     end = os_strchr(pos, ' ');
1253                     group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
1254                     conf->group_id = os_malloc(group_id_len + 1);
1255                     if (!conf->group_id)
1256                               goto fail;
1257                     os_memcpy(conf->group_id, pos, group_id_len);
1258                     conf->group_id[group_id_len] = '\0';
1259           }
1260 
1261           pos = os_strstr(cmd, " expiry=");
1262           if (pos) {
1263                     long int val;
1264 
1265                     pos += 8;
1266                     val = strtol(pos, NULL, 0);
1267                     if (val <= 0)
1268                               goto fail;
1269                     conf->netaccesskey_expiry = val;
1270           }
1271 
1272           pos = os_strstr(cmd, " csrattrs=");
1273           if (pos) {
1274                     pos += 10;
1275                     end = os_strchr(pos, ' ');
1276                     len = end ? (size_t) (end - pos) : os_strlen(pos);
1277                     conf->csrattrs = os_zalloc(len + 1);
1278                     if (!conf->csrattrs)
1279                               goto fail;
1280                     os_memcpy(conf->csrattrs, pos, len);
1281           }
1282 
1283           pos = os_strstr(cmd, " conf_extra_name=");
1284           if (pos) {
1285                     pos += 17;
1286                     end = os_strchr(pos, ' ');
1287                     len = end ? (size_t) (end - pos) : os_strlen(pos);
1288                     conf->extra_name = os_zalloc(len + 1);
1289                     if (!conf->extra_name)
1290                               goto fail;
1291                     os_memcpy(conf->extra_name, pos, len);
1292           }
1293 
1294           pos = os_strstr(cmd, " conf_extra_value=");
1295           if (pos) {
1296                     pos += 18;
1297                     end = os_strchr(pos, ' ');
1298                     len = end ? (size_t) (end - pos) : os_strlen(pos);
1299                     len /= 2;
1300                     conf->extra_value = os_zalloc(len + 1);
1301                     if (!conf->extra_value ||
1302                         hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0)
1303                               goto fail;
1304           }
1305 
1306           if (!dpp_configuration_valid(conf))
1307                     goto fail;
1308 
1309           if (idx == 0) {
1310                     auth->conf_sta = conf_sta;
1311                     auth->conf_ap = conf_ap;
1312           } else if (idx == 1) {
1313                     if (!auth->conf_sta)
1314                               auth->conf_sta = conf_sta;
1315                     else
1316                               auth->conf2_sta = conf_sta;
1317                     if (!auth->conf_ap)
1318                               auth->conf_ap = conf_ap;
1319                     else
1320                               auth->conf2_ap = conf_ap;
1321           } else {
1322                     goto fail;
1323           }
1324           return 0;
1325 
1326 fail:
1327           dpp_configuration_free(conf_sta);
1328           dpp_configuration_free(conf_ap);
1329           return -1;
1330 }
1331 
1332 
dpp_configuration_parse(struct dpp_authentication * auth,const char * cmd)1333 static int dpp_configuration_parse(struct dpp_authentication *auth,
1334                                            const char *cmd)
1335 {
1336           const char *pos;
1337           char *tmp;
1338           size_t len;
1339           int res;
1340 
1341           pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
1342           if (!pos)
1343                     return dpp_configuration_parse_helper(auth, cmd, 0);
1344 
1345           len = pos - cmd;
1346           tmp = os_malloc(len + 1);
1347           if (!tmp)
1348                     goto fail;
1349           os_memcpy(tmp, cmd, len);
1350           tmp[len] = '\0';
1351           res = dpp_configuration_parse_helper(auth, tmp, 0);
1352           str_clear_free(tmp);
1353           if (res)
1354                     goto fail;
1355           res = dpp_configuration_parse_helper(auth, cmd + len, 1);
1356           if (res)
1357                     goto fail;
1358           return 0;
1359 fail:
1360           dpp_configuration_free(auth->conf_sta);
1361           dpp_configuration_free(auth->conf2_sta);
1362           dpp_configuration_free(auth->conf_ap);
1363           dpp_configuration_free(auth->conf2_ap);
1364           return -1;
1365 }
1366 
1367 
1368 static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global * dpp,unsigned int id)1369 dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
1370 {
1371           struct dpp_configurator *conf;
1372 
1373           if (!dpp)
1374                     return NULL;
1375 
1376           dl_list_for_each(conf, &dpp->configurator,
1377                                struct dpp_configurator, list) {
1378                     if (conf->id == id)
1379                               return conf;
1380           }
1381           return NULL;
1382 }
1383 
1384 
dpp_set_configurator(struct dpp_authentication * auth,const char * cmd)1385 int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd)
1386 {
1387           const char *pos;
1388           char *tmp = NULL;
1389           int ret = -1;
1390 
1391           if (!cmd || auth->configurator_set)
1392                     return 0;
1393           auth->configurator_set = 1;
1394 
1395           if (cmd[0] != ' ') {
1396                     size_t len;
1397 
1398                     len = os_strlen(cmd);
1399                     tmp = os_malloc(len + 2);
1400                     if (!tmp)
1401                               goto fail;
1402                     tmp[0] = ' ';
1403                     os_memcpy(tmp + 1, cmd, len + 1);
1404                     cmd = tmp;
1405           }
1406 
1407           wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
1408 
1409           if (os_strstr(cmd, " conf=query")) {
1410                     auth->configurator_set = 0;
1411                     auth->use_config_query = true;
1412                     ret = 0;
1413                     goto fail;
1414           }
1415 
1416           pos = os_strstr(cmd, " configurator=");
1417           if (!auth->conf && pos) {
1418                     pos += 14;
1419                     auth->conf = dpp_configurator_get_id(auth->global, atoi(pos));
1420                     if (!auth->conf) {
1421                               wpa_printf(MSG_INFO,
1422                                            "DPP: Could not find the specified configurator");
1423                               goto fail;
1424                     }
1425           }
1426 
1427           pos = os_strstr(cmd, " conn_status=");
1428           if (pos) {
1429                     pos += 13;
1430                     auth->send_conn_status = atoi(pos);
1431           }
1432 
1433           pos = os_strstr(cmd, " akm_use_selector=");
1434           if (pos) {
1435                     pos += 18;
1436                     auth->akm_use_selector = atoi(pos);
1437           }
1438 
1439           if (dpp_configuration_parse(auth, cmd) < 0) {
1440                     wpa_msg(auth->msg_ctx, MSG_INFO,
1441                               "DPP: Failed to set configurator parameters");
1442                     goto fail;
1443           }
1444           ret = 0;
1445 fail:
1446           os_free(tmp);
1447           return ret;
1448 }
1449 
1450 
dpp_auth_deinit(struct dpp_authentication * auth)1451 void dpp_auth_deinit(struct dpp_authentication *auth)
1452 {
1453           unsigned int i;
1454 
1455           if (!auth)
1456                     return;
1457           dpp_configuration_free(auth->conf_ap);
1458           dpp_configuration_free(auth->conf2_ap);
1459           dpp_configuration_free(auth->conf_sta);
1460           dpp_configuration_free(auth->conf2_sta);
1461           crypto_ec_key_deinit(auth->own_protocol_key);
1462           crypto_ec_key_deinit(auth->peer_protocol_key);
1463           crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
1464           wpabuf_free(auth->req_msg);
1465           wpabuf_free(auth->resp_msg);
1466           wpabuf_free(auth->conf_req);
1467           wpabuf_free(auth->reconfig_req_msg);
1468           wpabuf_free(auth->reconfig_resp_msg);
1469           for (i = 0; i < auth->num_conf_obj; i++) {
1470                     struct dpp_config_obj *conf = &auth->conf_obj[i];
1471 
1472                     os_free(conf->connector);
1473                     wpabuf_free(conf->c_sign_key);
1474                     wpabuf_free(conf->certbag);
1475                     wpabuf_free(conf->certs);
1476                     wpabuf_free(conf->cacert);
1477                     os_free(conf->server_name);
1478                     wpabuf_free(conf->pp_key);
1479           }
1480 #ifdef CONFIG_DPP2
1481           dpp_free_asymmetric_key(auth->conf_key_pkg);
1482           os_free(auth->csrattrs);
1483           wpabuf_free(auth->csr);
1484           wpabuf_free(auth->priv_key);
1485           wpabuf_free(auth->cacert);
1486           wpabuf_free(auth->certbag);
1487           os_free(auth->trusted_eap_server_name);
1488           wpabuf_free(auth->conf_resp_tcp);
1489 #endif /* CONFIG_DPP2 */
1490           wpabuf_free(auth->net_access_key);
1491           dpp_bootstrap_info_free(auth->tmp_own_bi);
1492           if (auth->tmp_peer_bi) {
1493                     dl_list_del(&auth->tmp_peer_bi->list);
1494                     dpp_bootstrap_info_free(auth->tmp_peer_bi);
1495           }
1496           os_free(auth->e_name);
1497           os_free(auth->e_mud_url);
1498           os_free(auth->e_band_support);
1499 #ifdef CONFIG_TESTING_OPTIONS
1500           os_free(auth->config_obj_override);
1501           os_free(auth->discovery_override);
1502           os_free(auth->groups_override);
1503 #endif /* CONFIG_TESTING_OPTIONS */
1504           bin_clear_free(auth, sizeof(*auth));
1505 }
1506 
1507 
1508 static struct wpabuf *
dpp_build_conf_start(struct dpp_authentication * auth,struct dpp_configuration * conf,size_t tailroom)1509 dpp_build_conf_start(struct dpp_authentication *auth,
1510                          struct dpp_configuration *conf, size_t tailroom)
1511 {
1512           struct wpabuf *buf;
1513 
1514 #ifdef CONFIG_TESTING_OPTIONS
1515           if (auth->discovery_override)
1516                     tailroom += os_strlen(auth->discovery_override);
1517 #endif /* CONFIG_TESTING_OPTIONS */
1518 
1519           buf = wpabuf_alloc(200 + tailroom);
1520           if (!buf)
1521                     return NULL;
1522           json_start_object(buf, NULL);
1523           json_add_string(buf, "wi-fi_tech", "infra");
1524           json_value_sep(buf);
1525 #ifdef CONFIG_TESTING_OPTIONS
1526           if (auth->discovery_override) {
1527                     wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
1528                                  auth->discovery_override);
1529                     wpabuf_put_str(buf, "\"discovery\":");
1530                     wpabuf_put_str(buf, auth->discovery_override);
1531                     json_value_sep(buf);
1532                     return buf;
1533           }
1534 #endif /* CONFIG_TESTING_OPTIONS */
1535           json_start_object(buf, "discovery");
1536           if (((!conf->ssid_charset || auth->peer_version < 2) &&
1537                json_add_string_escape(buf, "ssid", conf->ssid,
1538                                             conf->ssid_len) < 0) ||
1539               ((conf->ssid_charset && auth->peer_version >= 2) &&
1540                json_add_base64url(buf, "ssid64", conf->ssid,
1541                                         conf->ssid_len) < 0)) {
1542                     wpabuf_free(buf);
1543                     return NULL;
1544           }
1545           if (conf->ssid_charset > 0) {
1546                     json_value_sep(buf);
1547                     json_add_int(buf, "ssid_charset", conf->ssid_charset);
1548           }
1549           json_end_object(buf);
1550           json_value_sep(buf);
1551 
1552           return buf;
1553 }
1554 
1555 
dpp_build_jwk(struct wpabuf * buf,const char * name,struct crypto_ec_key * key,const char * kid,const struct dpp_curve_params * curve)1556 int dpp_build_jwk(struct wpabuf *buf, const char *name,
1557                       struct crypto_ec_key *key, const char *kid,
1558                       const struct dpp_curve_params *curve)
1559 {
1560           struct wpabuf *pub;
1561           const u8 *pos;
1562           int ret = -1;
1563 
1564           pub = crypto_ec_key_get_pubkey_point(key, 0);
1565           if (!pub)
1566                     goto fail;
1567 
1568           json_start_object(buf, name);
1569           json_add_string(buf, "kty", "EC");
1570           json_value_sep(buf);
1571           json_add_string(buf, "crv", curve->jwk_crv);
1572           json_value_sep(buf);
1573           pos = wpabuf_head(pub);
1574           if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
1575                     goto fail;
1576           json_value_sep(buf);
1577           pos += curve->prime_len;
1578           if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
1579                     goto fail;
1580           if (kid) {
1581                     json_value_sep(buf);
1582                     json_add_string(buf, "kid", kid);
1583           }
1584           json_end_object(buf);
1585           ret = 0;
1586 fail:
1587           wpabuf_free(pub);
1588           return ret;
1589 }
1590 
1591 
dpp_build_legacy_cred_params(struct wpabuf * buf,struct dpp_configuration * conf)1592 static void dpp_build_legacy_cred_params(struct wpabuf *buf,
1593                                                    struct dpp_configuration *conf)
1594 {
1595           if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
1596                     json_add_string_escape(buf, "pass", conf->passphrase,
1597                                                os_strlen(conf->passphrase));
1598           } else if (conf->psk_set) {
1599                     char psk[2 * sizeof(conf->psk) + 1];
1600 
1601                     wpa_snprintf_hex(psk, sizeof(psk),
1602                                          conf->psk, sizeof(conf->psk));
1603                     json_add_string(buf, "psk_hex", psk);
1604                     forced_memzero(psk, sizeof(psk));
1605           }
1606 }
1607 
1608 
dpp_netrole_str(enum dpp_netrole netrole)1609 const char * dpp_netrole_str(enum dpp_netrole netrole)
1610 {
1611           switch (netrole) {
1612           case DPP_NETROLE_STA:
1613                     return "sta";
1614           case DPP_NETROLE_AP:
1615                     return "ap";
1616           case DPP_NETROLE_CONFIGURATOR:
1617                     return "configurator";
1618           default:
1619                     return "??";
1620           }
1621 }
1622 
1623 
dpp_supports_curve(const char * curve,struct dpp_bootstrap_info * bi)1624 static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi)
1625 {
1626           enum dpp_bootstrap_supported_curves idx;
1627 
1628           if (!bi || !bi->supported_curves)
1629                     return true; /* no support indication available */
1630 
1631           if (os_strcmp(curve, "prime256v1") == 0)
1632                     idx = DPP_BOOTSTRAP_CURVE_P_256;
1633           else if (os_strcmp(curve, "secp384r1") == 0)
1634                     idx = DPP_BOOTSTRAP_CURVE_P_384;
1635           else if (os_strcmp(curve, "secp521r1") == 0)
1636                     idx = DPP_BOOTSTRAP_CURVE_P_521;
1637           else if (os_strcmp(curve, "brainpoolP256r1") == 0)
1638                     idx = DPP_BOOTSTRAP_CURVE_BP_256;
1639           else if (os_strcmp(curve, "brainpoolP384r1") == 0)
1640                     idx = DPP_BOOTSTRAP_CURVE_BP_384;
1641           else if (os_strcmp(curve, "brainpoolP512r1") == 0)
1642                     idx = DPP_BOOTSTRAP_CURVE_BP_512;
1643           else
1644                     return true;
1645 
1646           return bi->supported_curves & BIT(idx);
1647 }
1648 
1649 
1650 static struct wpabuf *
dpp_build_conf_obj_dpp(struct dpp_authentication * auth,struct dpp_configuration * conf)1651 dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
1652                            struct dpp_configuration *conf)
1653 {
1654           struct wpabuf *buf = NULL;
1655           char *signed_conn = NULL;
1656           size_t tailroom;
1657           const struct dpp_curve_params *curve; /* C-sign-key curve */
1658           const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
1659           struct wpabuf *dppcon = NULL;
1660           size_t extra_len = 1000;
1661           int incl_legacy;
1662           enum dpp_akm akm;
1663           const char *akm_str;
1664 
1665           if (!auth->conf) {
1666                     wpa_printf(MSG_INFO,
1667                                  "DPP: No configurator specified - cannot generate DPP config object");
1668                     goto fail;
1669           }
1670           curve = auth->conf->curve;
1671           if (dpp_akm_dpp(conf->akm) &&
1672               !dpp_supports_curve(curve->name, auth->peer_bi)) {
1673                     wpa_printf(MSG_DEBUG,
1674                                  "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object",
1675                                  curve->name);
1676                     goto fail;
1677           }
1678           if (auth->new_curve && auth->new_key_received)
1679                     nak_curve = auth->new_curve;
1680           else
1681                     nak_curve = auth->curve;
1682           if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) {
1683                     wpa_printf(MSG_DEBUG,
1684                                  "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object",
1685                                  nak_curve->name);
1686                     goto fail;
1687           }
1688 
1689           akm = conf->akm;
1690           if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
1691                     wpa_printf(MSG_DEBUG,
1692                                  "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
1693                     akm = DPP_AKM_DPP;
1694           }
1695 
1696 #ifdef CONFIG_TESTING_OPTIONS
1697           if (auth->groups_override)
1698                     extra_len += os_strlen(auth->groups_override);
1699 #endif /* CONFIG_TESTING_OPTIONS */
1700 
1701           if (conf->group_id)
1702                     extra_len += os_strlen(conf->group_id);
1703 
1704           /* Connector (JSON dppCon object) */
1705           dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
1706           if (!dppcon)
1707                     goto fail;
1708 #ifdef CONFIG_TESTING_OPTIONS
1709           if (auth->groups_override) {
1710                     wpabuf_put_u8(dppcon, '{');
1711                     if (auth->groups_override) {
1712                               wpa_printf(MSG_DEBUG,
1713                                            "DPP: TESTING - groups override: '%s'",
1714                                            auth->groups_override);
1715                               wpabuf_put_str(dppcon, "\"groups\":");
1716                               wpabuf_put_str(dppcon, auth->groups_override);
1717                               json_value_sep(dppcon);
1718                     }
1719                     goto skip_groups;
1720           }
1721 #endif /* CONFIG_TESTING_OPTIONS */
1722           json_start_object(dppcon, NULL);
1723           json_start_array(dppcon, "groups");
1724           json_start_object(dppcon, NULL);
1725           json_add_string(dppcon, "groupId",
1726                               conf->group_id ? conf->group_id : "*");
1727           json_value_sep(dppcon);
1728           json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
1729           json_end_object(dppcon);
1730           json_end_array(dppcon);
1731           json_value_sep(dppcon);
1732 #ifdef CONFIG_TESTING_OPTIONS
1733 skip_groups:
1734 #endif /* CONFIG_TESTING_OPTIONS */
1735           if (!auth->peer_protocol_key) {
1736                     wpa_printf(MSG_DEBUG,
1737                                  "DPP: No peer protocol key available to build netAccessKey JWK");
1738                     goto fail;
1739           }
1740 #ifdef CONFIG_DPP3
1741           if (auth->conf->net_access_key_curve &&
1742               auth->curve != auth->conf->net_access_key_curve &&
1743               !auth->new_key_received) {
1744                     if (!dpp_supports_curve(auth->conf->net_access_key_curve->name,
1745                                                   auth->peer_bi)) {
1746                               wpa_printf(MSG_DEBUG,
1747                                            "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object",
1748                                            auth->conf->net_access_key_curve->name);
1749                               goto fail;
1750                     }
1751                     wpa_printf(MSG_DEBUG,
1752                                  "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
1753                                  auth->curve->name,
1754                                  auth->conf->net_access_key_curve->name,
1755                                  auth->waiting_new_key ?
1756                                  "the required key not received" :
1757                                  "request a new key");
1758                     if (auth->waiting_new_key)
1759                               auth->waiting_new_key = false; /* failed */
1760                     else
1761                               auth->waiting_new_key = true;
1762                     goto fail;
1763           }
1764 #endif /* CONFIG_DPP3 */
1765           if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
1766                                 nak_curve) < 0) {
1767                     wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
1768                     goto fail;
1769           }
1770           if (conf->netaccesskey_expiry) {
1771                     struct os_tm tm;
1772                     char expiry[30];
1773 
1774                     if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
1775                               wpa_printf(MSG_DEBUG,
1776                                            "DPP: Failed to generate expiry string");
1777                               goto fail;
1778                     }
1779                     os_snprintf(expiry, sizeof(expiry),
1780                                   "%04u-%02u-%02uT%02u:%02u:%02uZ",
1781                                   tm.year, tm.month, tm.day,
1782                                   tm.hour, tm.min, tm.sec);
1783                     json_value_sep(dppcon);
1784                     json_add_string(dppcon, "expiry", expiry);
1785           }
1786 #ifdef CONFIG_DPP3
1787           json_value_sep(dppcon);
1788           json_add_int(dppcon, "version", auth->peer_version);
1789 #endif /* CONFIG_DPP3 */
1790           json_end_object(dppcon);
1791           wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
1792                        (const char *) wpabuf_head(dppcon));
1793 
1794           signed_conn = dpp_sign_connector(auth->conf, dppcon);
1795           if (!signed_conn)
1796                     goto fail;
1797 
1798           incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
1799           tailroom = 1000;
1800           tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
1801           tailroom += os_strlen(signed_conn);
1802           if (incl_legacy)
1803                     tailroom += 1000;
1804           if (akm == DPP_AKM_DOT1X) {
1805                     if (auth->certbag)
1806                               tailroom += 2 * wpabuf_len(auth->certbag);
1807                     if (auth->cacert)
1808                               tailroom += 2 * wpabuf_len(auth->cacert);
1809                     if (auth->trusted_eap_server_name)
1810                               tailroom += os_strlen(auth->trusted_eap_server_name);
1811                     tailroom += 1000;
1812           }
1813           if (conf->extra_name && conf->extra_value)
1814                     tailroom += 10 + os_strlen(conf->extra_name) +
1815                               os_strlen(conf->extra_value);
1816           buf = dpp_build_conf_start(auth, conf, tailroom);
1817           if (!buf)
1818                     goto fail;
1819 
1820           if (auth->akm_use_selector && dpp_akm_ver2(akm))
1821                     akm_str = dpp_akm_selector_str(akm);
1822           else
1823                     akm_str = dpp_akm_str(akm);
1824           json_start_object(buf, "cred");
1825           json_add_string(buf, "akm", akm_str);
1826           json_value_sep(buf);
1827           if (incl_legacy) {
1828                     dpp_build_legacy_cred_params(buf, conf);
1829                     json_value_sep(buf);
1830           }
1831           if (akm == DPP_AKM_DOT1X) {
1832                     json_start_object(buf, "entCreds");
1833                     if (!auth->certbag)
1834                               goto fail;
1835                     json_add_base64(buf, "certBag", wpabuf_head(auth->certbag),
1836                                         wpabuf_len(auth->certbag));
1837                     if (auth->cacert) {
1838                               json_value_sep(buf);
1839                               json_add_base64(buf, "caCert",
1840                                                   wpabuf_head(auth->cacert),
1841                                                   wpabuf_len(auth->cacert));
1842                     }
1843                     if (auth->trusted_eap_server_name) {
1844                               json_value_sep(buf);
1845                               json_add_string(buf, "trustedEapServerName",
1846                                                   auth->trusted_eap_server_name);
1847                     }
1848                     json_value_sep(buf);
1849                     json_start_array(buf, "eapMethods");
1850                     wpabuf_printf(buf, "%d", EAP_TYPE_TLS);
1851                     json_end_array(buf);
1852                     json_end_object(buf);
1853                     json_value_sep(buf);
1854           }
1855           wpabuf_put_str(buf, "\"signedConnector\":\"");
1856           wpabuf_put_str(buf, signed_conn);
1857           wpabuf_put_str(buf, "\"");
1858           json_value_sep(buf);
1859           if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
1860                                 curve) < 0) {
1861                     wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
1862                     goto fail;
1863           }
1864 #ifdef CONFIG_DPP2
1865           if (auth->peer_version >= 2 && auth->conf->pp_key) {
1866                     json_value_sep(buf);
1867                     if (dpp_build_jwk(buf, "ppKey", auth->conf->pp_key, NULL,
1868                                           curve) < 0) {
1869                               wpa_printf(MSG_DEBUG, "DPP: Failed to build ppKey JWK");
1870                               goto fail;
1871                     }
1872           }
1873 #endif /* CONFIG_DPP2 */
1874 
1875           json_end_object(buf);
1876           if (conf->extra_name && conf->extra_value) {
1877                     json_value_sep(buf);
1878                     wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1879                                     conf->extra_value);
1880           }
1881           json_end_object(buf);
1882 
1883           wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
1884                                     wpabuf_head(buf), wpabuf_len(buf));
1885 
1886 #ifdef CONFIG_DPP3
1887           if (!auth->conf->net_access_key_curve) {
1888                     /* All netAccessKey values used in the network will have to be
1889                      * from the same curve for network introduction to work, so
1890                      * hardcode the first used netAccessKey curve for consecutive
1891                      * operations if there was no explicit configuration of which
1892                      * curve to use. */
1893                     wpa_printf(MSG_DEBUG,
1894                                  "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
1895                                  nak_curve->name);
1896                     auth->conf->net_access_key_curve = nak_curve;
1897           }
1898 #endif /* CONFIG_DPP3 */
1899 
1900 out:
1901           os_free(signed_conn);
1902           wpabuf_free(dppcon);
1903           return buf;
1904 fail:
1905           wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
1906           wpabuf_free(buf);
1907           buf = NULL;
1908           goto out;
1909 }
1910 
1911 
1912 static struct wpabuf *
dpp_build_conf_obj_legacy(struct dpp_authentication * auth,struct dpp_configuration * conf)1913 dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
1914                                 struct dpp_configuration *conf)
1915 {
1916           struct wpabuf *buf;
1917           const char *akm_str;
1918           size_t len = 1000;
1919 
1920           if (conf->extra_name && conf->extra_value)
1921                     len += 10 + os_strlen(conf->extra_name) +
1922                               os_strlen(conf->extra_value);
1923           buf = dpp_build_conf_start(auth, conf, len);
1924           if (!buf)
1925                     return NULL;
1926 
1927           if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
1928                     akm_str = dpp_akm_selector_str(conf->akm);
1929           else
1930                     akm_str = dpp_akm_str(conf->akm);
1931           json_start_object(buf, "cred");
1932           json_add_string(buf, "akm", akm_str);
1933           json_value_sep(buf);
1934           dpp_build_legacy_cred_params(buf, conf);
1935           json_end_object(buf);
1936           if (conf->extra_name && conf->extra_value) {
1937                     json_value_sep(buf);
1938                     wpabuf_printf(buf, "\"%s\":%s", conf->extra_name,
1939                                     conf->extra_value);
1940           }
1941           json_end_object(buf);
1942 
1943           wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
1944                                     wpabuf_head(buf), wpabuf_len(buf));
1945 
1946           return buf;
1947 }
1948 
1949 
dpp_get_peer_bi_id(struct dpp_authentication * auth)1950 static int dpp_get_peer_bi_id(struct dpp_authentication *auth)
1951 {
1952           struct dpp_bootstrap_info *bi;
1953 
1954           if (auth->peer_bi)
1955                     return auth->peer_bi->id;
1956           if (auth->tmp_peer_bi)
1957                     return auth->tmp_peer_bi->id;
1958 
1959           bi = os_zalloc(sizeof(*bi));
1960           if (!bi)
1961                     return -1;
1962           bi->id = dpp_next_id(auth->global);
1963           dl_list_add(&auth->global->bootstrap, &bi->list);
1964           auth->tmp_peer_bi = bi;
1965           return bi->id;
1966 }
1967 
1968 
1969 static struct wpabuf *
dpp_build_conf_obj(struct dpp_authentication * auth,enum dpp_netrole netrole,int idx,bool cert_req)1970 dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
1971                        int idx, bool cert_req)
1972 {
1973           struct dpp_configuration *conf = NULL;
1974 
1975 #ifdef CONFIG_TESTING_OPTIONS
1976           if (auth->config_obj_override) {
1977                     if (idx != 0)
1978                               return NULL;
1979                     wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
1980                     return wpabuf_alloc_copy(auth->config_obj_override,
1981                                                    os_strlen(auth->config_obj_override));
1982           }
1983 #endif /* CONFIG_TESTING_OPTIONS */
1984 
1985           if (idx == 0) {
1986                     if (netrole == DPP_NETROLE_STA)
1987                               conf = auth->conf_sta;
1988                     else if (netrole == DPP_NETROLE_AP)
1989                               conf = auth->conf_ap;
1990           } else if (idx == 1) {
1991                     if (netrole == DPP_NETROLE_STA)
1992                               conf = auth->conf2_sta;
1993                     else if (netrole == DPP_NETROLE_AP)
1994                               conf = auth->conf2_ap;
1995           }
1996           if (!conf) {
1997                     if (idx == 0) {
1998                               if (auth->use_config_query) {
1999                                         wpa_printf(MSG_DEBUG,
2000                                                      "DPP: No configuration available for Enrollee(%s) - waiting for configuration",
2001                                                      dpp_netrole_str(netrole));
2002                                         auth->waiting_config = true;
2003                                         dpp_get_peer_bi_id(auth);
2004                                         return NULL;
2005                               }
2006                               wpa_printf(MSG_DEBUG,
2007                                            "DPP: No configuration available for Enrollee(%s) - reject configuration request",
2008                                            dpp_netrole_str(netrole));
2009                     }
2010                     return NULL;
2011           }
2012 
2013           if (conf->akm == DPP_AKM_DOT1X) {
2014                     if (!auth->conf) {
2015                               wpa_printf(MSG_DEBUG,
2016                                            "DPP: No Configurator data available");
2017                               return NULL;
2018                     }
2019                     if (!cert_req && !auth->certbag) {
2020                               wpa_printf(MSG_DEBUG,
2021                                            "DPP: No certificate data available for dot1x configuration");
2022                               return NULL;
2023                     }
2024                     return dpp_build_conf_obj_dpp(auth, conf);
2025           }
2026           if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf))
2027                     return dpp_build_conf_obj_dpp(auth, conf);
2028           return dpp_build_conf_obj_legacy(auth, conf);
2029 }
2030 
2031 
2032 struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication * auth,const u8 * e_nonce,u16 e_nonce_len,enum dpp_netrole netrole,bool cert_req)2033 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
2034                         u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
2035 {
2036           struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
2037           size_t clear_len, attr_len;
2038           struct wpabuf *clear = NULL, *msg = NULL;
2039           u8 *wrapped;
2040           const u8 *addr[1];
2041           size_t len[1];
2042           enum dpp_status_error status;
2043 
2044           if (auth->force_conf_resp_status != DPP_STATUS_OK) {
2045                     status = auth->force_conf_resp_status;
2046                     goto forced_status;
2047           }
2048 
2049           if (netrole == DPP_NETROLE_CONFIGURATOR) {
2050 #ifdef CONFIG_DPP2
2051                     env_data = dpp_build_enveloped_data(auth);
2052 #endif /* CONFIG_DPP2 */
2053           } else {
2054                     conf = dpp_build_conf_obj(auth, netrole, 0, cert_req);
2055                     if (conf) {
2056                               wpa_hexdump_ascii(MSG_DEBUG,
2057                                                     "DPP: configurationObject JSON",
2058                                                     wpabuf_head(conf), wpabuf_len(conf));
2059                               conf2 = dpp_build_conf_obj(auth, netrole, 1, cert_req);
2060                     }
2061           }
2062 
2063           if (!conf && auth->waiting_config)
2064                     return NULL;
2065           if (conf || env_data)
2066                     status = DPP_STATUS_OK;
2067           else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
2068                      auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
2069                     status = DPP_STATUS_CSR_NEEDED;
2070 #ifdef CONFIG_DPP3
2071           else if (auth->waiting_new_key)
2072                     status = DPP_STATUS_NEW_KEY_NEEDED;
2073 #endif /* CONFIG_DPP3 */
2074           else
2075                     status = DPP_STATUS_CONFIGURE_FAILURE;
2076 forced_status:
2077           auth->conf_resp_status = status;
2078 
2079           /* { E-nonce, configurationObject[, sendConnStatus]}ke */
2080           clear_len = 4 + e_nonce_len;
2081           if (conf)
2082                     clear_len += 4 + wpabuf_len(conf);
2083           if (conf2)
2084                     clear_len += 4 + wpabuf_len(conf2);
2085           if (env_data)
2086                     clear_len += 4 + wpabuf_len(env_data);
2087           if (auth->peer_version >= 2 && auth->send_conn_status &&
2088               netrole == DPP_NETROLE_STA)
2089                     clear_len += 4;
2090           if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2091               auth->conf_sta->csrattrs)
2092                     clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
2093 #ifdef CONFIG_DPP3
2094           if (status == DPP_STATUS_NEW_KEY_NEEDED) {
2095                     struct crypto_ec_key *new_pc;
2096 
2097                     clear_len += 6; /* Finite Cyclic Group attribute */
2098 
2099                     wpa_printf(MSG_DEBUG,
2100                                  "DPP: Generate a new own protocol key for the curve %s",
2101                                  auth->conf->net_access_key_curve->name);
2102                     new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
2103                     if (!new_pc) {
2104                               wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
2105                               return NULL;
2106                     }
2107                     pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
2108                     if (!pc) {
2109                               crypto_ec_key_deinit(new_pc);
2110                               return NULL;
2111                     }
2112                     crypto_ec_key_deinit(auth->own_protocol_key);
2113                     auth->own_protocol_key = new_pc;
2114                     auth->new_curve = auth->conf->net_access_key_curve;
2115                     clear_len += 4 + wpabuf_len(pc);
2116           }
2117 #endif /* CONFIG_DPP3 */
2118           clear = wpabuf_alloc(clear_len);
2119           attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
2120 #ifdef CONFIG_TESTING_OPTIONS
2121           if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
2122                     attr_len += 5;
2123 #endif /* CONFIG_TESTING_OPTIONS */
2124           msg = wpabuf_alloc(attr_len);
2125           if (!clear || !msg)
2126                     goto fail;
2127 
2128 #ifdef CONFIG_TESTING_OPTIONS
2129           if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
2130                     wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2131                     goto skip_e_nonce;
2132           }
2133           if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
2134                     wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
2135                     wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2136                     wpabuf_put_le16(clear, e_nonce_len);
2137                     wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
2138                     wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
2139                     goto skip_e_nonce;
2140           }
2141           if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
2142                     wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2143                     goto skip_wrapped_data;
2144           }
2145 #endif /* CONFIG_TESTING_OPTIONS */
2146 
2147           /* E-nonce */
2148           wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2149           wpabuf_put_le16(clear, e_nonce_len);
2150           wpabuf_put_data(clear, e_nonce, e_nonce_len);
2151 
2152 #ifdef CONFIG_TESTING_OPTIONS
2153 skip_e_nonce:
2154           if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
2155                     wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
2156                     goto skip_config_obj;
2157           }
2158 #endif /* CONFIG_TESTING_OPTIONS */
2159 
2160           if (conf) {
2161                     wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2162                     wpabuf_put_le16(clear, wpabuf_len(conf));
2163                     wpabuf_put_buf(clear, conf);
2164           }
2165           if (auth->peer_version >= 2 && conf2) {
2166                     wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
2167                     wpabuf_put_le16(clear, wpabuf_len(conf2));
2168                     wpabuf_put_buf(clear, conf2);
2169           } else if (conf2) {
2170                     wpa_printf(MSG_DEBUG,
2171                                  "DPP: Second Config Object available, but peer does not support more than one");
2172           }
2173           if (env_data) {
2174                     wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
2175                     wpabuf_put_le16(clear, wpabuf_len(env_data));
2176                     wpabuf_put_buf(clear, env_data);
2177           }
2178 
2179           if (auth->peer_version >= 2 && auth->send_conn_status &&
2180               netrole == DPP_NETROLE_STA && status == DPP_STATUS_OK) {
2181                     wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
2182                     wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
2183                     wpabuf_put_le16(clear, 0);
2184           }
2185 
2186           if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
2187               auth->conf_sta->csrattrs) {
2188                     auth->waiting_csr = true;
2189                     wpa_printf(MSG_DEBUG, "DPP: CSR Attributes Request");
2190                     wpabuf_put_le16(clear, DPP_ATTR_CSR_ATTR_REQ);
2191                     wpabuf_put_le16(clear, os_strlen(auth->conf_sta->csrattrs));
2192                     wpabuf_put_str(clear, auth->conf_sta->csrattrs);
2193           }
2194 
2195 #ifdef CONFIG_DPP3
2196           if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
2197               auth->conf->net_access_key_curve) {
2198                     u16 ike_group = auth->conf->net_access_key_curve->ike_group;
2199 
2200                     /* Finite Cyclic Group attribute */
2201                     wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
2202                                  ike_group);
2203                     wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
2204                     wpabuf_put_le16(clear, 2);
2205                     wpabuf_put_le16(clear, ike_group);
2206 
2207                     if (pc) {
2208                               wpa_printf(MSG_DEBUG, "DPP: Pc");
2209                               wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
2210                               wpabuf_put_le16(clear, wpabuf_len(pc));
2211                               wpabuf_put_buf(clear, pc);
2212                     }
2213           }
2214 #endif /* CONFIG_DPP3 */
2215 
2216 #ifdef CONFIG_TESTING_OPTIONS
2217 skip_config_obj:
2218           if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
2219                     wpa_printf(MSG_INFO, "DPP: TESTING - Status");
2220                     goto skip_status;
2221           }
2222           if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
2223                     wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
2224                     status = 255;
2225           }
2226 #endif /* CONFIG_TESTING_OPTIONS */
2227 
2228           /* DPP Status */
2229           dpp_build_attr_status(msg, status);
2230 
2231 #ifdef CONFIG_TESTING_OPTIONS
2232 skip_status:
2233 #endif /* CONFIG_TESTING_OPTIONS */
2234 
2235           addr[0] = wpabuf_head(msg);
2236           len[0] = wpabuf_len(msg);
2237           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
2238 
2239           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2240           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2241           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2242 
2243           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2244           if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2245                                   wpabuf_head(clear), wpabuf_len(clear),
2246                                   1, addr, len, wrapped) < 0)
2247                     goto fail;
2248           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2249                         wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2250 
2251 #ifdef CONFIG_TESTING_OPTIONS
2252           if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
2253                     wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
2254                     dpp_build_attr_status(msg, DPP_STATUS_OK);
2255           }
2256 skip_wrapped_data:
2257 #endif /* CONFIG_TESTING_OPTIONS */
2258 
2259           wpa_hexdump_buf(MSG_DEBUG,
2260                               "DPP: Configuration Response attributes", msg);
2261 out:
2262           wpabuf_clear_free(conf);
2263           wpabuf_clear_free(conf2);
2264           wpabuf_clear_free(env_data);
2265           wpabuf_clear_free(clear);
2266           wpabuf_free(pc);
2267 
2268           return msg;
2269 fail:
2270           wpabuf_free(msg);
2271           msg = NULL;
2272           goto out;
2273 }
2274 
2275 
2276 struct wpabuf *
dpp_conf_req_rx(struct dpp_authentication * auth,const u8 * attr_start,size_t attr_len)2277 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
2278                     size_t attr_len)
2279 {
2280           const u8 *wrapped_data, *e_nonce, *config_attr;
2281           u16 wrapped_data_len, e_nonce_len, config_attr_len;
2282           u8 *unwrapped = NULL;
2283           size_t unwrapped_len = 0;
2284           struct wpabuf *resp = NULL;
2285           struct json_token *root = NULL, *token;
2286           enum dpp_netrole netrole;
2287           struct wpabuf *cert_req = NULL;
2288 #ifdef CONFIG_DPP3
2289           const u8 *i_proto;
2290           u16 i_proto_len;
2291 #endif /* CONFIG_DPP3 */
2292 
2293 #ifdef CONFIG_TESTING_OPTIONS
2294           if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
2295                     wpa_printf(MSG_INFO,
2296                                  "DPP: TESTING - stop at Config Request");
2297                     return NULL;
2298           }
2299 #endif /* CONFIG_TESTING_OPTIONS */
2300 
2301           if (dpp_check_attrs(attr_start, attr_len) < 0) {
2302                     dpp_auth_fail(auth, "Invalid attribute in config request");
2303                     return NULL;
2304           }
2305 
2306           wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
2307                                             &wrapped_data_len);
2308           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
2309                     dpp_auth_fail(auth,
2310                                     "Missing or invalid required Wrapped Data attribute");
2311                     return NULL;
2312           }
2313 
2314           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2315                         wrapped_data, wrapped_data_len);
2316           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
2317           unwrapped = os_malloc(unwrapped_len);
2318           if (!unwrapped)
2319                     return NULL;
2320           if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
2321                                   wrapped_data, wrapped_data_len,
2322                                   0, NULL, NULL, unwrapped) < 0) {
2323                     dpp_auth_fail(auth, "AES-SIV decryption failed");
2324                     goto fail;
2325           }
2326           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
2327                         unwrapped, unwrapped_len);
2328 
2329           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
2330                     dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
2331                     goto fail;
2332           }
2333 
2334           e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
2335                                      DPP_ATTR_ENROLLEE_NONCE,
2336                                      &e_nonce_len);
2337           if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
2338                     dpp_auth_fail(auth,
2339                                     "Missing or invalid Enrollee Nonce attribute");
2340                     goto fail;
2341           }
2342           wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
2343           os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
2344 
2345 #ifdef CONFIG_DPP3
2346           i_proto = dpp_get_attr(unwrapped, unwrapped_len,
2347                                      DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
2348           if (i_proto && !auth->waiting_new_key) {
2349                     dpp_auth_fail(auth,
2350                                     "Enrollee included a new protocol key even though one was not expected");
2351                     goto fail;
2352           }
2353           if (i_proto) {
2354                     struct crypto_ec_key *pe;
2355                     u8 auth_i[DPP_MAX_HASH_LEN];
2356                     const u8 *rx_auth_i;
2357                     u16 rx_auth_i_len;
2358 
2359                     wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
2360                                   i_proto, i_proto_len);
2361 
2362                     pe = dpp_set_pubkey_point(auth->own_protocol_key,
2363                                                     i_proto, i_proto_len);
2364                     if (!pe) {
2365                               dpp_auth_fail(auth,
2366                                               "Invalid Initiator Protocol Key (Pe)");
2367                               goto fail;
2368                     }
2369                     dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
2370                     crypto_ec_key_deinit(auth->peer_protocol_key);
2371                     auth->peer_protocol_key = pe;
2372                     auth->new_key_received = true;
2373                     auth->waiting_new_key = false;
2374 
2375                     if (dpp_derive_auth_i(auth, auth_i) < 0)
2376                               goto fail;
2377 
2378                     rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
2379                                                    DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
2380                     if (!rx_auth_i) {
2381                               dpp_auth_fail(auth,
2382                                               "Missing Initiator Authentication Tag");
2383                               goto fail;
2384                     }
2385                     if (rx_auth_i_len != auth->curve->hash_len ||
2386                         os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
2387                               dpp_auth_fail(auth,
2388                                               "Mismatch in Initiator Authenticating Tag");
2389                               wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
2390                                             rx_auth_i, rx_auth_i_len);
2391                               wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
2392                                             auth_i, auth->curve->hash_len);
2393                               goto fail;
2394                     }
2395           }
2396 #endif /* CONFIG_DPP3 */
2397 
2398           config_attr = dpp_get_attr(unwrapped, unwrapped_len,
2399                                            DPP_ATTR_CONFIG_ATTR_OBJ,
2400                                            &config_attr_len);
2401           if (!config_attr) {
2402                     dpp_auth_fail(auth,
2403                                     "Missing or invalid Config Attributes attribute");
2404                     goto fail;
2405           }
2406           wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
2407                                 config_attr, config_attr_len);
2408 
2409           root = json_parse((const char *) config_attr, config_attr_len);
2410           if (!root) {
2411                     dpp_auth_fail(auth, "Could not parse Config Attributes");
2412                     goto fail;
2413           }
2414 
2415           token = json_get_member(root, "name");
2416           if (!token || token->type != JSON_STRING) {
2417                     dpp_auth_fail(auth, "No Config Attributes - name");
2418                     goto fail;
2419           }
2420           wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
2421           os_free(auth->e_name);
2422           auth->e_name = os_strdup(token->string);
2423 
2424           token = json_get_member(root, "wi-fi_tech");
2425           if (!token || token->type != JSON_STRING) {
2426                     dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
2427                     goto fail;
2428           }
2429           wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
2430           if (os_strcmp(token->string, "infra") != 0) {
2431                     wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
2432                                  token->string);
2433                     dpp_auth_fail(auth, "Unsupported wi-fi_tech");
2434                     goto fail;
2435           }
2436 
2437           token = json_get_member(root, "netRole");
2438           if (!token || token->type != JSON_STRING) {
2439                     dpp_auth_fail(auth, "No Config Attributes - netRole");
2440                     goto fail;
2441           }
2442           wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
2443           if (os_strcmp(token->string, "sta") == 0) {
2444                     netrole = DPP_NETROLE_STA;
2445           } else if (os_strcmp(token->string, "ap") == 0) {
2446                     netrole = DPP_NETROLE_AP;
2447           } else if (os_strcmp(token->string, "configurator") == 0) {
2448                     netrole = DPP_NETROLE_CONFIGURATOR;
2449           } else {
2450                     wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
2451                                  token->string);
2452                     dpp_auth_fail(auth, "Unsupported netRole");
2453                     goto fail;
2454           }
2455           auth->e_netrole = netrole;
2456 
2457           token = json_get_member(root, "mudurl");
2458           if (token && token->type == JSON_STRING) {
2459                     wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
2460                     wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s",
2461                               token->string);
2462                     os_free(auth->e_mud_url);
2463                     auth->e_mud_url = os_strdup(token->string);
2464           }
2465 
2466           token = json_get_member(root, "bandSupport");
2467           if (token && token->type == JSON_ARRAY) {
2468                     int *opclass = NULL;
2469                     char txt[200], *pos, *end;
2470                     int i, res;
2471 
2472                     wpa_printf(MSG_DEBUG, "DPP: bandSupport");
2473                     token = token->child;
2474                     while (token) {
2475                               if (token->type != JSON_NUMBER) {
2476                                         wpa_printf(MSG_DEBUG,
2477                                                      "DPP: Invalid bandSupport array member type");
2478                               } else {
2479                                         wpa_printf(MSG_DEBUG,
2480                                                      "DPP: Supported global operating class: %d",
2481                                                      token->number);
2482                                         int_array_add_unique(&opclass, token->number);
2483                               }
2484                               token = token->sibling;
2485                     }
2486 
2487                     txt[0] = '\0';
2488                     pos = txt;
2489                     end = txt + sizeof(txt);
2490                     for (i = 0; opclass && opclass[i]; i++) {
2491                               res = os_snprintf(pos, end - pos, "%s%d",
2492                                                     pos == txt ? "" : ",", opclass[i]);
2493                               if (os_snprintf_error(end - pos, res)) {
2494                                         *pos = '\0';
2495                                         break;
2496                               }
2497                               pos += res;
2498                     }
2499                     os_free(auth->e_band_support);
2500                     auth->e_band_support = opclass;
2501                     wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s",
2502                               txt);
2503           }
2504 
2505 #ifdef CONFIG_DPP2
2506           cert_req = json_get_member_base64(root, "pkcs10");
2507           if (cert_req) {
2508                     char *txt;
2509                     int id;
2510 
2511                     wpa_hexdump_buf(MSG_DEBUG, "DPP: CertificateRequest", cert_req);
2512                     if (dpp_validate_csr(auth, cert_req) < 0) {
2513                               wpa_printf(MSG_DEBUG, "DPP: CSR is not valid");
2514                               auth->force_conf_resp_status = DPP_STATUS_CSR_BAD;
2515                               goto cont;
2516                     }
2517 
2518                     id = dpp_get_peer_bi_id(auth);
2519                     if (id < 0)
2520                               goto fail;
2521 
2522                     wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA");
2523                     txt = base64_encode_no_lf(wpabuf_head(cert_req),
2524                                                     wpabuf_len(cert_req), NULL);
2525                     if (!txt)
2526                               goto fail;
2527 
2528                     wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_CSR "peer=%d csr=%s",
2529                               id, txt);
2530                     os_free(txt);
2531                     auth->waiting_csr = false;
2532                     auth->waiting_cert = true;
2533                     goto fail;
2534           }
2535 cont:
2536 #endif /* CONFIG_DPP2 */
2537 
2538           resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
2539                                            cert_req);
2540 
2541 fail:
2542           wpabuf_free(cert_req);
2543           json_free(root);
2544           os_free(unwrapped);
2545           return resp;
2546 }
2547 
2548 
dpp_parse_cred_legacy(struct dpp_config_obj * conf,struct json_token * cred)2549 static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
2550                                          struct json_token *cred)
2551 {
2552           struct json_token *pass, *psk_hex;
2553 
2554           wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
2555 
2556           pass = json_get_member(cred, "pass");
2557           psk_hex = json_get_member(cred, "psk_hex");
2558 
2559           if (pass && pass->type == JSON_STRING) {
2560                     size_t len = os_strlen(pass->string);
2561 
2562                     wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
2563                                               pass->string, len);
2564                     if (len < 8 || len > 63)
2565                               return -1;
2566                     os_strlcpy(conf->passphrase, pass->string,
2567                                  sizeof(conf->passphrase));
2568           } else if (psk_hex && psk_hex->type == JSON_STRING) {
2569                     if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
2570                               wpa_printf(MSG_DEBUG,
2571                                            "DPP: Unexpected psk_hex with akm=sae");
2572                               return -1;
2573                     }
2574                     if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
2575                         hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
2576                               wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
2577                               return -1;
2578                     }
2579                     wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
2580                                         conf->psk, PMK_LEN);
2581                     conf->psk_set = 1;
2582           } else {
2583                     wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
2584                     return -1;
2585           }
2586 
2587           if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
2588                     wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
2589                     return -1;
2590           }
2591 
2592           return 0;
2593 }
2594 
2595 
dpp_parse_jwk(struct json_token * jwk,const struct dpp_curve_params ** key_curve)2596 struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
2597                                              const struct dpp_curve_params **key_curve)
2598 {
2599           struct json_token *token;
2600           const struct dpp_curve_params *curve;
2601           struct wpabuf *x = NULL, *y = NULL;
2602           struct crypto_ec_key *key = NULL;
2603 
2604           token = json_get_member(jwk, "kty");
2605           if (!token || token->type != JSON_STRING) {
2606                     wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
2607                     goto fail;
2608           }
2609           if (os_strcmp(token->string, "EC") != 0) {
2610                     wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
2611                                  token->string);
2612                     goto fail;
2613           }
2614 
2615           token = json_get_member(jwk, "crv");
2616           if (!token || token->type != JSON_STRING) {
2617                     wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
2618                     goto fail;
2619           }
2620           curve = dpp_get_curve_jwk_crv(token->string);
2621           if (!curve) {
2622                     wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
2623                                  token->string);
2624                     goto fail;
2625           }
2626 
2627           x = json_get_member_base64url(jwk, "x");
2628           if (!x) {
2629                     wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
2630                     goto fail;
2631           }
2632           wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
2633           if (wpabuf_len(x) != curve->prime_len) {
2634                     wpa_printf(MSG_DEBUG,
2635                                  "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
2636                                  (unsigned int) wpabuf_len(x),
2637                                  (unsigned int) curve->prime_len, curve->name);
2638                     goto fail;
2639           }
2640 
2641           y = json_get_member_base64url(jwk, "y");
2642           if (!y) {
2643                     wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
2644                     goto fail;
2645           }
2646           wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
2647           if (wpabuf_len(y) != curve->prime_len) {
2648                     wpa_printf(MSG_DEBUG,
2649                                  "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
2650                                  (unsigned int) wpabuf_len(y),
2651                                  (unsigned int) curve->prime_len, curve->name);
2652                     goto fail;
2653           }
2654 
2655           key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
2656                                             wpabuf_head(y), wpabuf_len(x));
2657           if (!key)
2658                     goto fail;
2659 
2660           *key_curve = curve;
2661 
2662 fail:
2663           wpabuf_free(x);
2664           wpabuf_free(y);
2665 
2666           return key;
2667 }
2668 
2669 
dpp_key_expired(const char * timestamp,os_time_t * expiry)2670 int dpp_key_expired(const char *timestamp, os_time_t *expiry)
2671 {
2672           struct os_time now;
2673           unsigned int year, month, day, hour, min, sec;
2674           os_time_t utime;
2675           const char *pos;
2676 
2677           /* ISO 8601 date and time:
2678            * <date>T<time>
2679            * YYYY-MM-DDTHH:MM:SSZ
2680            * YYYY-MM-DDTHH:MM:SS+03:00
2681            */
2682           if (os_strlen(timestamp) < 19) {
2683                     wpa_printf(MSG_DEBUG,
2684                                  "DPP: Too short timestamp - assume expired key");
2685                     return 1;
2686           }
2687           if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
2688                        &year, &month, &day, &hour, &min, &sec) != 6) {
2689                     wpa_printf(MSG_DEBUG,
2690                                  "DPP: Failed to parse expiration day - assume expired key");
2691                     return 1;
2692           }
2693 
2694           if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
2695                     wpa_printf(MSG_DEBUG,
2696                                  "DPP: Invalid date/time information - assume expired key");
2697                     return 1;
2698           }
2699 
2700           pos = timestamp + 19;
2701           if (*pos == 'Z' || *pos == '\0') {
2702                     /* In UTC - no need to adjust */
2703           } else if (*pos == '-' || *pos == '+') {
2704                     int items;
2705 
2706                     /* Adjust local time to UTC */
2707                     items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
2708                     if (items < 1) {
2709                               wpa_printf(MSG_DEBUG,
2710                                            "DPP: Invalid time zone designator (%s) - assume expired key",
2711                                            pos);
2712                               return 1;
2713                     }
2714                     if (*pos == '-')
2715                               utime += 3600 * hour;
2716                     if (*pos == '+')
2717                               utime -= 3600 * hour;
2718                     if (items > 1) {
2719                               if (*pos == '-')
2720                                         utime += 60 * min;
2721                               if (*pos == '+')
2722                                         utime -= 60 * min;
2723                     }
2724           } else {
2725                     wpa_printf(MSG_DEBUG,
2726                                  "DPP: Invalid time zone designator (%s) - assume expired key",
2727                                  pos);
2728                     return 1;
2729           }
2730           if (expiry)
2731                     *expiry = utime;
2732 
2733           if (os_get_time(&now) < 0) {
2734                     wpa_printf(MSG_DEBUG,
2735                                  "DPP: Cannot get current time - assume expired key");
2736                     return 1;
2737           }
2738 
2739           if (now.sec > utime) {
2740                     wpa_printf(MSG_DEBUG, "DPP: Key has expired (%jd < %jd)",
2741                                  (intmax_t)utime, (intmax_t)now.sec);
2742                     return 1;
2743           }
2744 
2745           return 0;
2746 }
2747 
2748 
dpp_parse_connector(struct dpp_authentication * auth,struct dpp_config_obj * conf,const unsigned char * payload,u16 payload_len)2749 static int dpp_parse_connector(struct dpp_authentication *auth,
2750                                      struct dpp_config_obj *conf,
2751                                      const unsigned char *payload,
2752                                      u16 payload_len)
2753 {
2754           struct json_token *root, *groups, *netkey, *token;
2755           int ret = -1;
2756           struct crypto_ec_key *key = NULL;
2757           const struct dpp_curve_params *curve;
2758           unsigned int rules = 0;
2759 
2760           root = json_parse((const char *) payload, payload_len);
2761           if (!root) {
2762                     wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
2763                     goto fail;
2764           }
2765 
2766           groups = json_get_member(root, "groups");
2767           if (!groups || groups->type != JSON_ARRAY) {
2768                     wpa_printf(MSG_DEBUG, "DPP: No groups array found");
2769                     goto skip_groups;
2770           }
2771           for (token = groups->child; token; token = token->sibling) {
2772                     struct json_token *id, *role;
2773 
2774                     id = json_get_member(token, "groupId");
2775                     if (!id || id->type != JSON_STRING) {
2776                               wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
2777                               goto fail;
2778                     }
2779 
2780                     role = json_get_member(token, "netRole");
2781                     if (!role || role->type != JSON_STRING) {
2782                               wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
2783                               goto fail;
2784                     }
2785                     wpa_printf(MSG_DEBUG,
2786                                  "DPP: connector group: groupId='%s' netRole='%s'",
2787                                  id->string, role->string);
2788                     rules++;
2789           }
2790 skip_groups:
2791 
2792           if (!rules) {
2793                     wpa_printf(MSG_DEBUG,
2794                                  "DPP: Connector includes no groups");
2795                     goto fail;
2796           }
2797 
2798           token = json_get_member(root, "expiry");
2799           if (!token || token->type != JSON_STRING) {
2800                     wpa_printf(MSG_DEBUG,
2801                                  "DPP: No expiry string found - connector does not expire");
2802           } else {
2803                     wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
2804                     if (dpp_key_expired(token->string,
2805                                             &auth->net_access_key_expiry)) {
2806                               wpa_printf(MSG_DEBUG,
2807                                            "DPP: Connector (netAccessKey) has expired");
2808                               goto fail;
2809                     }
2810           }
2811 
2812           netkey = json_get_member(root, "netAccessKey");
2813           if (!netkey || netkey->type != JSON_OBJECT) {
2814                     wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
2815                     goto fail;
2816           }
2817 
2818           key = dpp_parse_jwk(netkey, &curve);
2819           if (!key)
2820                     goto fail;
2821           dpp_debug_print_key("DPP: Received netAccessKey", key);
2822 
2823           if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
2824                     wpa_printf(MSG_DEBUG,
2825                                  "DPP: netAccessKey in connector does not match own protocol key");
2826 #ifdef CONFIG_TESTING_OPTIONS
2827                     if (auth->ignore_netaccesskey_mismatch) {
2828                               wpa_printf(MSG_DEBUG,
2829                                            "DPP: TESTING - skip netAccessKey mismatch");
2830                     } else {
2831                               goto fail;
2832                     }
2833 #else /* CONFIG_TESTING_OPTIONS */
2834                     goto fail;
2835 #endif /* CONFIG_TESTING_OPTIONS */
2836           }
2837 
2838           ret = 0;
2839 fail:
2840           crypto_ec_key_deinit(key);
2841           json_free(root);
2842           return ret;
2843 }
2844 
2845 
dpp_copy_csign(struct dpp_config_obj * conf,struct crypto_ec_key * csign)2846 static void dpp_copy_csign(struct dpp_config_obj *conf,
2847                                  struct crypto_ec_key *csign)
2848 {
2849           struct wpabuf *c_sign_key;
2850 
2851           c_sign_key = crypto_ec_key_get_subject_public_key(csign);
2852           if (!c_sign_key)
2853                     return;
2854 
2855           wpabuf_free(conf->c_sign_key);
2856           conf->c_sign_key = c_sign_key;
2857 }
2858 
2859 
dpp_copy_ppkey(struct dpp_config_obj * conf,struct crypto_ec_key * ppkey)2860 static void dpp_copy_ppkey(struct dpp_config_obj *conf,
2861                                  struct crypto_ec_key *ppkey)
2862 {
2863           struct wpabuf *pp_key;
2864 
2865           pp_key = crypto_ec_key_get_subject_public_key(ppkey);
2866           if (!pp_key)
2867                     return;
2868 
2869           wpabuf_free(conf->pp_key);
2870           conf->pp_key = pp_key;
2871 }
2872 
2873 
dpp_copy_netaccesskey(struct dpp_authentication * auth,struct dpp_config_obj * conf)2874 static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
2875                                           struct dpp_config_obj *conf)
2876 {
2877           struct wpabuf *net_access_key;
2878           struct crypto_ec_key *own_key;
2879 
2880           own_key = auth->own_protocol_key;
2881 #ifdef CONFIG_DPP2
2882           if (auth->reconfig_connector_key == DPP_CONFIG_REUSEKEY &&
2883               auth->reconfig_old_protocol_key)
2884                     own_key = auth->reconfig_old_protocol_key;
2885 #endif /* CONFIG_DPP2 */
2886 
2887           net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
2888           if (!net_access_key)
2889                     return;
2890 
2891           wpabuf_free(auth->net_access_key);
2892           auth->net_access_key = net_access_key;
2893 }
2894 
2895 
dpp_parse_cred_dpp(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)2896 static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
2897                                     struct dpp_config_obj *conf,
2898                                     struct json_token *cred)
2899 {
2900           struct dpp_signed_connector_info info;
2901           struct json_token *token, *csign, *ppkey;
2902           int ret = -1;
2903           struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
2904           const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
2905           const char *signed_connector;
2906 
2907           os_memset(&info, 0, sizeof(info));
2908 
2909           if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
2910                     wpa_printf(MSG_DEBUG,
2911                                  "DPP: Legacy credential included in Connector credential");
2912                     if (dpp_parse_cred_legacy(conf, cred) < 0)
2913                               return -1;
2914           }
2915 
2916           wpa_printf(MSG_DEBUG, "DPP: Connector credential");
2917 
2918           csign = json_get_member(cred, "csign");
2919           if (!csign || csign->type != JSON_OBJECT) {
2920                     wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
2921                     goto fail;
2922           }
2923 
2924           csign_pub = dpp_parse_jwk(csign, &key_curve);
2925           if (!csign_pub) {
2926                     wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
2927                     goto fail;
2928           }
2929           dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
2930 
2931           ppkey = json_get_member(cred, "ppKey");
2932           if (ppkey && ppkey->type == JSON_OBJECT) {
2933                     pp_pub = dpp_parse_jwk(ppkey, &pp_curve);
2934                     if (!pp_pub) {
2935                               wpa_printf(MSG_DEBUG, "DPP: Failed to parse ppKey JWK");
2936                               goto fail;
2937                     }
2938                     dpp_debug_print_key("DPP: Received ppKey", pp_pub);
2939                     if (key_curve != pp_curve) {
2940                               wpa_printf(MSG_DEBUG,
2941                                            "DPP: C-sign-key and ppKey do not use the same curve");
2942                               goto fail;
2943                     }
2944           }
2945 
2946           token = json_get_member(cred, "signedConnector");
2947           if (!token || token->type != JSON_STRING) {
2948                     wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
2949                     goto fail;
2950           }
2951           wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
2952                                 token->string, os_strlen(token->string));
2953           signed_connector = token->string;
2954 
2955           if (os_strchr(signed_connector, '"') ||
2956               os_strchr(signed_connector, '\n')) {
2957                     wpa_printf(MSG_DEBUG,
2958                                  "DPP: Unexpected character in signedConnector");
2959                     goto fail;
2960           }
2961 
2962           if (dpp_process_signed_connector(&info, csign_pub,
2963                                                    signed_connector) != DPP_STATUS_OK)
2964                     goto fail;
2965 
2966           if (dpp_parse_connector(auth, conf,
2967                                         info.payload, info.payload_len) < 0) {
2968                     wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
2969                     goto fail;
2970           }
2971 
2972           os_free(conf->connector);
2973           conf->connector = os_strdup(signed_connector);
2974 
2975           dpp_copy_csign(conf, csign_pub);
2976           if (pp_pub)
2977                     dpp_copy_ppkey(conf, pp_pub);
2978           if (dpp_akm_dpp(conf->akm) || auth->peer_version >= 2)
2979                     dpp_copy_netaccesskey(auth, conf);
2980 
2981           ret = 0;
2982 fail:
2983           crypto_ec_key_deinit(csign_pub);
2984           crypto_ec_key_deinit(pp_pub);
2985           os_free(info.payload);
2986           return ret;
2987 }
2988 
2989 
2990 #ifdef CONFIG_DPP2
dpp_parse_cred_dot1x(struct dpp_authentication * auth,struct dpp_config_obj * conf,struct json_token * cred)2991 static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
2992                                         struct dpp_config_obj *conf,
2993                                         struct json_token *cred)
2994 {
2995           struct json_token *ent, *name;
2996 
2997           ent = json_get_member(cred, "entCreds");
2998           if (!ent || ent->type != JSON_OBJECT) {
2999                     dpp_auth_fail(auth, "No entCreds in JSON");
3000                     return -1;
3001           }
3002 
3003           conf->certbag = json_get_member_base64(ent, "certBag");
3004           if (!conf->certbag) {
3005                     dpp_auth_fail(auth, "No certBag in JSON");
3006                     return -1;
3007           }
3008           wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
3009           conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
3010           if (!conf->certs) {
3011                     dpp_auth_fail(auth, "No certificates in certBag");
3012                     return -1;
3013           }
3014 
3015           conf->cacert = json_get_member_base64(ent, "caCert");
3016           if (conf->cacert)
3017                     wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received caCert",
3018                                         conf->cacert);
3019 
3020           name = json_get_member(ent, "trustedEapServerName");
3021           if (name &&
3022               (name->type != JSON_STRING ||
3023                has_ctrl_char((const u8 *) name->string,
3024                                  os_strlen(name->string)))) {
3025                     dpp_auth_fail(auth,
3026                                     "Invalid trustedEapServerName type in JSON");
3027                     return -1;
3028           }
3029           if (name && name->string) {
3030                     wpa_printf(MSG_DEBUG, "DPP: Received trustedEapServerName: %s",
3031                                  name->string);
3032                     conf->server_name = os_strdup(name->string);
3033                     if (!conf->server_name)
3034                               return -1;
3035           }
3036 
3037           return 0;
3038 }
3039 #endif /* CONFIG_DPP2 */
3040 
3041 
dpp_akm_str(enum dpp_akm akm)3042 const char * dpp_akm_str(enum dpp_akm akm)
3043 {
3044           switch (akm) {
3045           case DPP_AKM_DPP:
3046                     return "dpp";
3047           case DPP_AKM_PSK:
3048                     return "psk";
3049           case DPP_AKM_SAE:
3050                     return "sae";
3051           case DPP_AKM_PSK_SAE:
3052                     return "psk+sae";
3053           case DPP_AKM_SAE_DPP:
3054                     return "dpp+sae";
3055           case DPP_AKM_PSK_SAE_DPP:
3056                     return "dpp+psk+sae";
3057           case DPP_AKM_DOT1X:
3058                     return "dot1x";
3059           default:
3060                     return "??";
3061           }
3062 }
3063 
3064 
dpp_akm_selector_str(enum dpp_akm akm)3065 const char * dpp_akm_selector_str(enum dpp_akm akm)
3066 {
3067           switch (akm) {
3068           case DPP_AKM_DPP:
3069                     return "506F9A02";
3070           case DPP_AKM_PSK:
3071                     return "000FAC02+000FAC06";
3072           case DPP_AKM_SAE:
3073                     return "000FAC08";
3074           case DPP_AKM_PSK_SAE:
3075                     return "000FAC02+000FAC06+000FAC08";
3076           case DPP_AKM_SAE_DPP:
3077                     return "506F9A02+000FAC08";
3078           case DPP_AKM_PSK_SAE_DPP:
3079                     return "506F9A02+000FAC08+000FAC02+000FAC06";
3080           case DPP_AKM_DOT1X:
3081                     return "000FAC01+000FAC05";
3082           default:
3083                     return "??";
3084           }
3085 }
3086 
3087 
dpp_akm_from_str(const char * akm)3088 static enum dpp_akm dpp_akm_from_str(const char *akm)
3089 {
3090           const char *pos;
3091           int dpp = 0, psk = 0, sae = 0, dot1x = 0;
3092 
3093           if (os_strcmp(akm, "psk") == 0)
3094                     return DPP_AKM_PSK;
3095           if (os_strcmp(akm, "sae") == 0)
3096                     return DPP_AKM_SAE;
3097           if (os_strcmp(akm, "psk+sae") == 0)
3098                     return DPP_AKM_PSK_SAE;
3099           if (os_strcmp(akm, "dpp") == 0)
3100                     return DPP_AKM_DPP;
3101           if (os_strcmp(akm, "dpp+sae") == 0)
3102                     return DPP_AKM_SAE_DPP;
3103           if (os_strcmp(akm, "dpp+psk+sae") == 0)
3104                     return DPP_AKM_PSK_SAE_DPP;
3105           if (os_strcmp(akm, "dot1x") == 0)
3106                     return DPP_AKM_DOT1X;
3107 
3108           pos = akm;
3109           while (*pos) {
3110                     if (os_strlen(pos) < 8)
3111                               break;
3112                     if (os_strncasecmp(pos, "506F9A02", 8) == 0)
3113                               dpp = 1;
3114                     else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
3115                               psk = 1;
3116                     else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
3117                               psk = 1;
3118                     else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
3119                               sae = 1;
3120                     else if (os_strncasecmp(pos, "000FAC01", 8) == 0)
3121                               dot1x = 1;
3122                     else if (os_strncasecmp(pos, "000FAC05", 8) == 0)
3123                               dot1x = 1;
3124                     pos += 8;
3125                     if (*pos != '+')
3126                               break;
3127                     pos++;
3128           }
3129 
3130           if (dpp && psk && sae)
3131                     return DPP_AKM_PSK_SAE_DPP;
3132           if (dpp && sae)
3133                     return DPP_AKM_SAE_DPP;
3134           if (dpp)
3135                     return DPP_AKM_DPP;
3136           if (psk && sae)
3137                     return DPP_AKM_PSK_SAE;
3138           if (sae)
3139                     return DPP_AKM_SAE;
3140           if (psk)
3141                     return DPP_AKM_PSK;
3142           if (dot1x)
3143                     return DPP_AKM_DOT1X;
3144 
3145           return DPP_AKM_UNKNOWN;
3146 }
3147 
3148 
dpp_parse_conf_obj(struct dpp_authentication * auth,const u8 * conf_obj,u16 conf_obj_len)3149 static int dpp_parse_conf_obj(struct dpp_authentication *auth,
3150                                     const u8 *conf_obj, u16 conf_obj_len)
3151 {
3152           int ret = -1;
3153           struct json_token *root, *token, *discovery, *cred;
3154           struct dpp_config_obj *conf;
3155           struct wpabuf *ssid64 = NULL;
3156           int legacy;
3157 
3158           root = json_parse((const char *) conf_obj, conf_obj_len);
3159           if (!root)
3160                     return -1;
3161           if (root->type != JSON_OBJECT) {
3162                     dpp_auth_fail(auth, "JSON root is not an object");
3163                     goto fail;
3164           }
3165 
3166           token = json_get_member(root, "wi-fi_tech");
3167           if (!token || token->type != JSON_STRING) {
3168                     dpp_auth_fail(auth, "No wi-fi_tech string value found");
3169                     goto fail;
3170           }
3171           if (os_strcmp(token->string, "infra") != 0) {
3172                     wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
3173                                  token->string);
3174                     dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
3175                     goto fail;
3176           }
3177 
3178           discovery = json_get_member(root, "discovery");
3179           if (!discovery || discovery->type != JSON_OBJECT) {
3180                     dpp_auth_fail(auth, "No discovery object in JSON");
3181                     goto fail;
3182           }
3183 
3184           ssid64 = json_get_member_base64url(discovery, "ssid64");
3185           if (ssid64) {
3186                     wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
3187                                           wpabuf_head(ssid64), wpabuf_len(ssid64));
3188                     if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
3189                               dpp_auth_fail(auth, "Too long discovery::ssid64 value");
3190                               goto fail;
3191                     }
3192           } else {
3193                     token = json_get_member(discovery, "ssid");
3194                     if (!token || token->type != JSON_STRING) {
3195                               dpp_auth_fail(auth,
3196                                               "No discovery::ssid string value found");
3197                               goto fail;
3198                     }
3199                     wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
3200                                           token->string, os_strlen(token->string));
3201                     if (os_strlen(token->string) > SSID_MAX_LEN) {
3202                               dpp_auth_fail(auth,
3203                                               "Too long discovery::ssid string value");
3204                               goto fail;
3205                     }
3206           }
3207 
3208           if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
3209                     wpa_printf(MSG_DEBUG,
3210                                  "DPP: No room for this many Config Objects - ignore this one");
3211                     ret = 0;
3212                     goto fail;
3213           }
3214           conf = &auth->conf_obj[auth->num_conf_obj++];
3215 
3216           if (ssid64) {
3217                     conf->ssid_len = wpabuf_len(ssid64);
3218                     os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
3219           } else {
3220                     conf->ssid_len = os_strlen(token->string);
3221                     os_memcpy(conf->ssid, token->string, conf->ssid_len);
3222           }
3223 
3224           token = json_get_member(discovery, "ssid_charset");
3225           if (token && token->type == JSON_NUMBER) {
3226                     conf->ssid_charset = token->number;
3227                     wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
3228                                  conf->ssid_charset);
3229           }
3230 
3231           cred = json_get_member(root, "cred");
3232           if (!cred || cred->type != JSON_OBJECT) {
3233                     dpp_auth_fail(auth, "No cred object in JSON");
3234                     goto fail;
3235           }
3236 
3237           token = json_get_member(cred, "akm");
3238           if (!token || token->type != JSON_STRING) {
3239                     dpp_auth_fail(auth, "No cred::akm string value found");
3240                     goto fail;
3241           }
3242           conf->akm = dpp_akm_from_str(token->string);
3243 
3244           legacy = dpp_akm_legacy(conf->akm);
3245           if (legacy && auth->peer_version >= 2) {
3246                     struct json_token *csign, *s_conn;
3247 
3248                     csign = json_get_member(cred, "csign");
3249                     s_conn = json_get_member(cred, "signedConnector");
3250                     if (csign && csign->type == JSON_OBJECT &&
3251                         s_conn && s_conn->type == JSON_STRING)
3252                               legacy = 0;
3253           }
3254           if (legacy) {
3255                     if (dpp_parse_cred_legacy(conf, cred) < 0)
3256                               goto fail;
3257           } else if (dpp_akm_dpp(conf->akm) ||
3258                        (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) {
3259                     if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
3260                               goto fail;
3261 #ifdef CONFIG_DPP2
3262           } else if (conf->akm == DPP_AKM_DOT1X) {
3263                     if (dpp_parse_cred_dot1x(auth, conf, cred) < 0 ||
3264                         dpp_parse_cred_dpp(auth, conf, cred) < 0)
3265                               goto fail;
3266 #endif /* CONFIG_DPP2 */
3267           } else {
3268                     wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
3269                                  token->string);
3270                     dpp_auth_fail(auth, "Unsupported akm");
3271                     goto fail;
3272           }
3273 
3274           wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
3275           ret = 0;
3276 fail:
3277           wpabuf_free(ssid64);
3278           json_free(root);
3279           return ret;
3280 }
3281 
3282 
3283 #ifdef CONFIG_DPP2
dpp_get_csr_attrs(const u8 * attrs,size_t attrs_len,size_t * len)3284 static u8 * dpp_get_csr_attrs(const u8 *attrs, size_t attrs_len, size_t *len)
3285 {
3286           const u8 *b64;
3287           u16 b64_len;
3288 
3289           b64 = dpp_get_attr(attrs, attrs_len, DPP_ATTR_CSR_ATTR_REQ, &b64_len);
3290           if (!b64)
3291                     return NULL;
3292           return base64_decode((const char *) b64, b64_len, len);
3293 }
3294 #endif /* CONFIG_DPP2 */
3295 
3296 
dpp_conf_resp_rx(struct dpp_authentication * auth,const struct wpabuf * resp)3297 int dpp_conf_resp_rx(struct dpp_authentication *auth,
3298                          const struct wpabuf *resp)
3299 {
3300           const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
3301           u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
3302           const u8 *env_data;
3303           u16 env_data_len;
3304           const u8 *addr[1];
3305           size_t len[1];
3306           u8 *unwrapped = NULL;
3307           size_t unwrapped_len = 0;
3308           int ret = -1;
3309 
3310           auth->conf_resp_status = 255;
3311 
3312           if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
3313                     dpp_auth_fail(auth, "Invalid attribute in config response");
3314                     return -1;
3315           }
3316 
3317           wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3318                                             DPP_ATTR_WRAPPED_DATA,
3319                                             &wrapped_data_len);
3320           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3321                     dpp_auth_fail(auth,
3322                                     "Missing or invalid required Wrapped Data attribute");
3323                     return -1;
3324           }
3325 
3326           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3327                         wrapped_data, wrapped_data_len);
3328           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3329           unwrapped = os_malloc(unwrapped_len);
3330           if (!unwrapped)
3331                     return -1;
3332 
3333           addr[0] = wpabuf_head(resp);
3334           len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
3335           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
3336 
3337           if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3338                                   wrapped_data, wrapped_data_len,
3339                                   1, addr, len, unwrapped) < 0) {
3340                     dpp_auth_fail(auth, "AES-SIV decryption failed");
3341                     goto fail;
3342           }
3343           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3344                         unwrapped, unwrapped_len);
3345 
3346           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3347                     dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3348                     goto fail;
3349           }
3350 
3351           e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3352                                      DPP_ATTR_ENROLLEE_NONCE,
3353                                      &e_nonce_len);
3354           if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3355                     dpp_auth_fail(auth,
3356                                     "Missing or invalid Enrollee Nonce attribute");
3357                     goto fail;
3358           }
3359           wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3360           if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3361                     dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3362                     goto fail;
3363           }
3364 
3365           status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
3366                                     DPP_ATTR_STATUS, &status_len);
3367           if (!status || status_len < 1) {
3368                     dpp_auth_fail(auth,
3369                                     "Missing or invalid required DPP Status attribute");
3370                     goto fail;
3371           }
3372           auth->conf_resp_status = status[0];
3373           wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3374 #ifdef CONFIG_DPP2
3375           if (status[0] == DPP_STATUS_CSR_NEEDED) {
3376                     u8 *csrattrs;
3377                     size_t csrattrs_len;
3378 
3379                     wpa_printf(MSG_DEBUG, "DPP: Configurator requested CSR");
3380 
3381                     csrattrs = dpp_get_csr_attrs(unwrapped, unwrapped_len,
3382                                                        &csrattrs_len);
3383                     if (!csrattrs) {
3384                               dpp_auth_fail(auth,
3385                                               "Missing or invalid CSR Attributes Request attribute");
3386                               goto fail;
3387                     }
3388                     wpa_hexdump(MSG_DEBUG, "DPP: CsrAttrs", csrattrs, csrattrs_len);
3389                     os_free(auth->csrattrs);
3390                     auth->csrattrs = csrattrs;
3391                     auth->csrattrs_len = csrattrs_len;
3392                     ret = -2;
3393                     goto fail;
3394           }
3395 #endif /* CONFIG_DPP2 */
3396 #ifdef CONFIG_DPP3
3397           if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
3398                     const u8 *fcgroup, *r_proto;
3399                     u16 fcgroup_len, r_proto_len;
3400                     u16 group;
3401                     const struct dpp_curve_params *curve;
3402                     struct crypto_ec_key *new_pe;
3403                     struct crypto_ec_key *pc;
3404 
3405                     fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
3406                                                DPP_ATTR_FINITE_CYCLIC_GROUP,
3407                                                &fcgroup_len);
3408                     if (!fcgroup || fcgroup_len != 2) {
3409                               dpp_auth_fail(auth,
3410                                               "Missing or invalid required Finite Cyclic Group attribute");
3411                               goto fail;
3412                     }
3413                     group = WPA_GET_LE16(fcgroup);
3414 
3415                     wpa_printf(MSG_DEBUG,
3416                                  "DPP: Configurator requested a new protocol key from group %u",
3417                                  group);
3418                     curve = dpp_get_curve_ike_group(group);
3419                     if (!curve) {
3420                               dpp_auth_fail(auth,
3421                                               "Unsupported group for new protocol key");
3422                               goto fail;
3423                     }
3424 
3425                     new_pe = dpp_gen_keypair(curve);
3426                     if (!new_pe) {
3427                               dpp_auth_fail(auth,
3428                                               "Failed to generate a new protocol key");
3429                               goto fail;
3430                     }
3431 
3432                     crypto_ec_key_deinit(auth->own_protocol_key);
3433                     auth->own_protocol_key = new_pe;
3434                     auth->new_curve = curve;
3435 
3436                     r_proto = dpp_get_attr(unwrapped, unwrapped_len,
3437                                                DPP_ATTR_R_PROTOCOL_KEY,
3438                                                &r_proto_len);
3439                     if (!r_proto) {
3440                               dpp_auth_fail(auth,
3441                                               "Missing required Responder Protocol Key attribute (Pc)");
3442                               goto fail;
3443                     }
3444                     wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
3445                                   r_proto, r_proto_len);
3446 
3447                     pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
3448                     if (!pc) {
3449                               dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
3450                               goto fail;
3451                     }
3452                     dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
3453 
3454                     crypto_ec_key_deinit(auth->peer_protocol_key);
3455                     auth->peer_protocol_key = pc;
3456 
3457                     auth->waiting_new_key = true;
3458                     ret = -3;
3459                     goto fail;
3460           }
3461 #endif /* CONFIG_DPP3 */
3462           if (status[0] != DPP_STATUS_OK) {
3463                     dpp_auth_fail(auth, "Configurator rejected configuration");
3464                     goto fail;
3465           }
3466 
3467           env_data = dpp_get_attr(unwrapped, unwrapped_len,
3468                                         DPP_ATTR_ENVELOPED_DATA, &env_data_len);
3469 #ifdef CONFIG_DPP2
3470           if (env_data &&
3471               dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
3472                     goto fail;
3473 #endif /* CONFIG_DPP2 */
3474 
3475           conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
3476                                         &conf_obj_len);
3477           if (!conf_obj && !env_data) {
3478                     dpp_auth_fail(auth,
3479                                     "Missing required Configuration Object attribute");
3480                     goto fail;
3481           }
3482           while (conf_obj) {
3483                     wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
3484                                           conf_obj, conf_obj_len);
3485                     if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
3486                               goto fail;
3487                     conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
3488                                                        DPP_ATTR_CONFIG_OBJ,
3489                                                        &conf_obj_len);
3490           }
3491 
3492 #ifdef CONFIG_DPP2
3493           status = dpp_get_attr(unwrapped, unwrapped_len,
3494                                     DPP_ATTR_SEND_CONN_STATUS, &status_len);
3495           if (status) {
3496                     wpa_printf(MSG_DEBUG,
3497                                  "DPP: Configurator requested connection status result");
3498                     auth->conn_status_requested = 1;
3499           }
3500 #endif /* CONFIG_DPP2 */
3501 
3502           ret = 0;
3503 
3504 fail:
3505           os_free(unwrapped);
3506           return ret;
3507 }
3508 
3509 
3510 #ifdef CONFIG_DPP2
3511 
dpp_conf_result_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)3512 enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
3513                                                    const u8 *hdr,
3514                                                    const u8 *attr_start, size_t attr_len)
3515 {
3516           const u8 *wrapped_data, *status, *e_nonce;
3517           u16 wrapped_data_len, status_len, e_nonce_len;
3518           const u8 *addr[2];
3519           size_t len[2];
3520           u8 *unwrapped = NULL;
3521           size_t unwrapped_len = 0;
3522           enum dpp_status_error ret = 256;
3523 
3524           wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3525                                             &wrapped_data_len);
3526           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3527                     dpp_auth_fail(auth,
3528                                     "Missing or invalid required Wrapped Data attribute");
3529                     goto fail;
3530           }
3531           wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3532                         wrapped_data, wrapped_data_len);
3533 
3534           attr_len = wrapped_data - 4 - attr_start;
3535 
3536           addr[0] = hdr;
3537           len[0] = DPP_HDR_LEN;
3538           addr[1] = attr_start;
3539           len[1] = attr_len;
3540           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3541           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3542           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3543                         wrapped_data, wrapped_data_len);
3544           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3545           unwrapped = os_malloc(unwrapped_len);
3546           if (!unwrapped)
3547                     goto fail;
3548           if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3549                                   wrapped_data, wrapped_data_len,
3550                                   2, addr, len, unwrapped) < 0) {
3551                     dpp_auth_fail(auth, "AES-SIV decryption failed");
3552                     goto fail;
3553           }
3554           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3555                         unwrapped, unwrapped_len);
3556 
3557           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3558                     dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3559                     goto fail;
3560           }
3561 
3562           e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3563                                      DPP_ATTR_ENROLLEE_NONCE,
3564                                      &e_nonce_len);
3565           if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3566                     dpp_auth_fail(auth,
3567                                     "Missing or invalid Enrollee Nonce attribute");
3568                     goto fail;
3569           }
3570           wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3571           if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3572                     dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3573                     wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3574                                   auth->e_nonce, e_nonce_len);
3575                     goto fail;
3576           }
3577 
3578           status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
3579                                     &status_len);
3580           if (!status || status_len < 1) {
3581                     dpp_auth_fail(auth,
3582                                     "Missing or invalid required DPP Status attribute");
3583                     goto fail;
3584           }
3585           wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3586           ret = status[0];
3587 
3588 fail:
3589           bin_clear_free(unwrapped, unwrapped_len);
3590           return ret;
3591 }
3592 
3593 
dpp_build_conf_result(struct dpp_authentication * auth,enum dpp_status_error status)3594 struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
3595                                               enum dpp_status_error status)
3596 {
3597           struct wpabuf *msg, *clear;
3598           size_t nonce_len, clear_len, attr_len;
3599           const u8 *addr[2];
3600           size_t len[2];
3601           u8 *wrapped;
3602 
3603           nonce_len = auth->curve->nonce_len;
3604           clear_len = 5 + 4 + nonce_len;
3605           attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3606           clear = wpabuf_alloc(clear_len);
3607           msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
3608           if (!clear || !msg)
3609                     goto fail;
3610 
3611           /* DPP Status */
3612           dpp_build_attr_status(clear, status);
3613 
3614           /* E-nonce */
3615           wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3616           wpabuf_put_le16(clear, nonce_len);
3617           wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3618 
3619           /* OUI, OUI type, Crypto Suite, DPP frame type */
3620           addr[0] = wpabuf_head_u8(msg) + 2;
3621           len[0] = 3 + 1 + 1 + 1;
3622           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3623 
3624           /* Attributes before Wrapped Data (none) */
3625           addr[1] = wpabuf_put(msg, 0);
3626           len[1] = 0;
3627           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3628 
3629           /* Wrapped Data */
3630           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3631           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3632           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3633 
3634           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3635           if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3636                                   wpabuf_head(clear), wpabuf_len(clear),
3637                                   2, addr, len, wrapped) < 0)
3638                     goto fail;
3639 
3640           wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
3641           wpabuf_free(clear);
3642           return msg;
3643 fail:
3644           wpabuf_free(clear);
3645           wpabuf_free(msg);
3646           return NULL;
3647 }
3648 
3649 
valid_channel_list(const char * val)3650 static int valid_channel_list(const char *val)
3651 {
3652           while (*val) {
3653                     if (!((*val >= '0' && *val <= '9') ||
3654                           *val == '/' || *val == ','))
3655                               return 0;
3656                     val++;
3657           }
3658 
3659           return 1;
3660 }
3661 
3662 
dpp_conn_status_result_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,u8 * ssid,size_t * ssid_len,char ** channel_list)3663 enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
3664                                                             const u8 *hdr,
3665                                                             const u8 *attr_start,
3666                                                             size_t attr_len,
3667                                                             u8 *ssid, size_t *ssid_len,
3668                                                             char **channel_list)
3669 {
3670           const u8 *wrapped_data, *status, *e_nonce;
3671           u16 wrapped_data_len, status_len, e_nonce_len;
3672           const u8 *addr[2];
3673           size_t len[2];
3674           u8 *unwrapped = NULL;
3675           size_t unwrapped_len = 0;
3676           enum dpp_status_error ret = 256;
3677           struct json_token *root = NULL, *token;
3678           struct wpabuf *ssid64;
3679 
3680           *ssid_len = 0;
3681           *channel_list = NULL;
3682 
3683           wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3684                                             &wrapped_data_len);
3685           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3686                     dpp_auth_fail(auth,
3687                                     "Missing or invalid required Wrapped Data attribute");
3688                     goto fail;
3689           }
3690           wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3691                         wrapped_data, wrapped_data_len);
3692 
3693           attr_len = wrapped_data - 4 - attr_start;
3694 
3695           addr[0] = hdr;
3696           len[0] = DPP_HDR_LEN;
3697           addr[1] = attr_start;
3698           len[1] = attr_len;
3699           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3700           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3701           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3702                         wrapped_data, wrapped_data_len);
3703           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3704           unwrapped = os_malloc(unwrapped_len);
3705           if (!unwrapped)
3706                     goto fail;
3707           if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
3708                                   wrapped_data, wrapped_data_len,
3709                                   2, addr, len, unwrapped) < 0) {
3710                     dpp_auth_fail(auth, "AES-SIV decryption failed");
3711                     goto fail;
3712           }
3713           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3714                         unwrapped, unwrapped_len);
3715 
3716           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
3717                     dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
3718                     goto fail;
3719           }
3720 
3721           e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
3722                                      DPP_ATTR_ENROLLEE_NONCE,
3723                                      &e_nonce_len);
3724           if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
3725                     dpp_auth_fail(auth,
3726                                     "Missing or invalid Enrollee Nonce attribute");
3727                     goto fail;
3728           }
3729           wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
3730           if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
3731                     dpp_auth_fail(auth, "Enrollee Nonce mismatch");
3732                     wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
3733                                   auth->e_nonce, e_nonce_len);
3734                     goto fail;
3735           }
3736 
3737           status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
3738                                     &status_len);
3739           if (!status) {
3740                     dpp_auth_fail(auth,
3741                                     "Missing required DPP Connection Status attribute");
3742                     goto fail;
3743           }
3744           wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3745                                 status, status_len);
3746 
3747           root = json_parse((const char *) status, status_len);
3748           if (!root) {
3749                     dpp_auth_fail(auth, "Could not parse connStatus");
3750                     goto fail;
3751           }
3752 
3753           ssid64 = json_get_member_base64url(root, "ssid64");
3754           if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
3755                     *ssid_len = wpabuf_len(ssid64);
3756                     os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
3757           }
3758           wpabuf_free(ssid64);
3759 
3760           token = json_get_member(root, "channelList");
3761           if (token && token->type == JSON_STRING &&
3762               valid_channel_list(token->string))
3763                     *channel_list = os_strdup(token->string);
3764 
3765           token = json_get_member(root, "result");
3766           if (!token || token->type != JSON_NUMBER) {
3767                     dpp_auth_fail(auth, "No connStatus - result");
3768                     goto fail;
3769           }
3770           wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
3771           ret = token->number;
3772 
3773 fail:
3774           json_free(root);
3775           bin_clear_free(unwrapped, unwrapped_len);
3776           return ret;
3777 }
3778 
3779 
dpp_build_conn_status(enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)3780 struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
3781                                               const u8 *ssid, size_t ssid_len,
3782                                               const char *channel_list)
3783 {
3784           struct wpabuf *json;
3785 
3786           json = wpabuf_alloc(1000);
3787           if (!json)
3788                     return NULL;
3789           json_start_object(json, NULL);
3790           json_add_int(json, "result", result);
3791           if (ssid) {
3792                     json_value_sep(json);
3793                     if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0) {
3794                               wpabuf_free(json);
3795                               return NULL;
3796                     }
3797           }
3798           if (channel_list) {
3799                     json_value_sep(json);
3800                     json_add_string(json, "channelList", channel_list);
3801           }
3802           json_end_object(json);
3803           wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
3804                                 wpabuf_head(json), wpabuf_len(json));
3805 
3806           return json;
3807 }
3808 
3809 
dpp_build_conn_status_result(struct dpp_authentication * auth,enum dpp_status_error result,const u8 * ssid,size_t ssid_len,const char * channel_list)3810 struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
3811                                                        enum dpp_status_error result,
3812                                                        const u8 *ssid, size_t ssid_len,
3813                                                        const char *channel_list)
3814 {
3815           struct wpabuf *msg = NULL, *clear = NULL, *json;
3816           size_t nonce_len, clear_len, attr_len;
3817           const u8 *addr[2];
3818           size_t len[2];
3819           u8 *wrapped;
3820 
3821           json = dpp_build_conn_status(result, ssid, ssid_len, channel_list);
3822           if (!json)
3823                     return NULL;
3824 
3825           nonce_len = auth->curve->nonce_len;
3826           clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
3827           attr_len = 4 + clear_len + AES_BLOCK_SIZE;
3828           clear = wpabuf_alloc(clear_len);
3829           msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
3830           if (!clear || !msg)
3831                     goto fail;
3832 
3833           /* E-nonce */
3834           wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
3835           wpabuf_put_le16(clear, nonce_len);
3836           wpabuf_put_data(clear, auth->e_nonce, nonce_len);
3837 
3838           /* DPP Connection Status */
3839           wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
3840           wpabuf_put_le16(clear, wpabuf_len(json));
3841           wpabuf_put_buf(clear, json);
3842 
3843           /* OUI, OUI type, Crypto Suite, DPP frame type */
3844           addr[0] = wpabuf_head_u8(msg) + 2;
3845           len[0] = 3 + 1 + 1 + 1;
3846           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3847 
3848           /* Attributes before Wrapped Data (none) */
3849           addr[1] = wpabuf_put(msg, 0);
3850           len[1] = 0;
3851           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3852 
3853           /* Wrapped Data */
3854           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3855           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3856           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
3857 
3858           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
3859           if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3860                                   wpabuf_head(clear), wpabuf_len(clear),
3861                                   2, addr, len, wrapped) < 0)
3862                     goto fail;
3863 
3864           wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
3865                               msg);
3866           wpabuf_free(json);
3867           wpabuf_free(clear);
3868           return msg;
3869 fail:
3870           wpabuf_free(json);
3871           wpabuf_free(clear);
3872           wpabuf_free(msg);
3873           return NULL;
3874 }
3875 
3876 #endif /* CONFIG_DPP2 */
3877 
3878 
dpp_configurator_free(struct dpp_configurator * conf)3879 void dpp_configurator_free(struct dpp_configurator *conf)
3880 {
3881           if (!conf)
3882                     return;
3883           crypto_ec_key_deinit(conf->csign);
3884           os_free(conf->kid);
3885           os_free(conf->connector);
3886           crypto_ec_key_deinit(conf->connector_key);
3887           crypto_ec_key_deinit(conf->pp_key);
3888           os_free(conf);
3889 }
3890 
3891 
dpp_configurator_get_key(const struct dpp_configurator * conf,char * buf,size_t buflen)3892 int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
3893                                    size_t buflen)
3894 {
3895           struct wpabuf *key;
3896           int ret = -1;
3897 
3898           if (!conf->csign)
3899                     return -1;
3900 
3901           key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
3902           if (!key)
3903                     return -1;
3904 
3905           ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
3906 
3907           wpabuf_clear_free(key);
3908           return ret;
3909 }
3910 
3911 
dpp_configurator_gen_kid(struct dpp_configurator * conf)3912 static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
3913 {
3914           struct wpabuf *csign_pub = NULL;
3915           const u8 *addr[1];
3916           size_t len[1];
3917           int res;
3918 
3919           csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
3920           if (!csign_pub) {
3921                     wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
3922                     return -1;
3923           }
3924 
3925           /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
3926           addr[0] = wpabuf_head(csign_pub);
3927           len[0] = wpabuf_len(csign_pub);
3928           res = sha256_vector(1, addr, len, conf->kid_hash);
3929           wpabuf_free(csign_pub);
3930           if (res < 0) {
3931                     wpa_printf(MSG_DEBUG,
3932                                  "DPP: Failed to derive kid for C-sign-key");
3933                     return -1;
3934           }
3935 
3936           conf->kid = base64_url_encode(conf->kid_hash, sizeof(conf->kid_hash),
3937                                               NULL);
3938           return conf->kid ? 0 : -1;
3939 }
3940 
3941 
3942 static struct dpp_configurator *
dpp_keygen_configurator(const char * curve,const u8 * privkey,size_t privkey_len,const u8 * pp_key,size_t pp_key_len)3943 dpp_keygen_configurator(const char *curve, const u8 *privkey,
3944                               size_t privkey_len, const u8 *pp_key, size_t pp_key_len)
3945 {
3946           struct dpp_configurator *conf;
3947 
3948           conf = os_zalloc(sizeof(*conf));
3949           if (!conf)
3950                     return NULL;
3951 
3952           conf->curve = dpp_get_curve_name(curve);
3953           if (!conf->curve) {
3954                     wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3955                     os_free(conf);
3956                     return NULL;
3957           }
3958 
3959           if (privkey)
3960                     conf->csign = dpp_set_keypair(&conf->curve, privkey,
3961                                                         privkey_len);
3962           else
3963                     conf->csign = dpp_gen_keypair(conf->curve);
3964           if (pp_key)
3965                     conf->pp_key = dpp_set_keypair(&conf->curve, pp_key,
3966                                                          pp_key_len);
3967           else
3968                     conf->pp_key = dpp_gen_keypair(conf->curve);
3969           if (!conf->csign || !conf->pp_key)
3970                     goto fail;
3971           conf->own = 1;
3972 
3973           if (dpp_configurator_gen_kid(conf) < 0)
3974                     goto fail;
3975           return conf;
3976 fail:
3977           dpp_configurator_free(conf);
3978           return NULL;
3979 }
3980 
3981 
dpp_configurator_own_config(struct dpp_authentication * auth,const char * curve,int ap)3982 int dpp_configurator_own_config(struct dpp_authentication *auth,
3983                                         const char *curve, int ap)
3984 {
3985           struct wpabuf *conf_obj;
3986           int ret = -1;
3987 
3988           if (!auth->conf) {
3989                     wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
3990                     return -1;
3991           }
3992 
3993           auth->curve = dpp_get_curve_name(curve);
3994           if (!auth->curve) {
3995                     wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve);
3996                     return -1;
3997           }
3998 
3999           wpa_printf(MSG_DEBUG,
4000                        "DPP: Building own configuration/connector with curve %s",
4001                        auth->curve->name);
4002 
4003           auth->own_protocol_key = dpp_gen_keypair(auth->curve);
4004           if (!auth->own_protocol_key)
4005                     return -1;
4006           dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
4007           auth->peer_protocol_key = auth->own_protocol_key;
4008           dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
4009 
4010           conf_obj = dpp_build_conf_obj(auth, ap, 0, NULL);
4011           if (!conf_obj) {
4012                     wpabuf_free(auth->conf_obj[0].c_sign_key);
4013                     auth->conf_obj[0].c_sign_key = NULL;
4014                     goto fail;
4015           }
4016           ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
4017                                          wpabuf_len(conf_obj));
4018 fail:
4019           wpabuf_free(conf_obj);
4020           auth->peer_protocol_key = NULL;
4021           return ret;
4022 }
4023 
4024 
dpp_compatible_netrole(const char * role1,const char * role2)4025 static int dpp_compatible_netrole(const char *role1, const char *role2)
4026 {
4027           return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
4028                     (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
4029 }
4030 
4031 
dpp_connector_compatible_group(struct json_token * root,const char * group_id,const char * net_role,bool reconfig)4032 static int dpp_connector_compatible_group(struct json_token *root,
4033                                                     const char *group_id,
4034                                                     const char *net_role,
4035                                                     bool reconfig)
4036 {
4037           struct json_token *groups, *token;
4038 
4039           groups = json_get_member(root, "groups");
4040           if (!groups || groups->type != JSON_ARRAY)
4041                     return 0;
4042 
4043           for (token = groups->child; token; token = token->sibling) {
4044                     struct json_token *id, *role;
4045 
4046                     id = json_get_member(token, "groupId");
4047                     if (!id || id->type != JSON_STRING)
4048                               continue;
4049 
4050                     role = json_get_member(token, "netRole");
4051                     if (!role || role->type != JSON_STRING)
4052                               continue;
4053 
4054                     if (os_strcmp(id->string, "*") != 0 &&
4055                         os_strcmp(group_id, "*") != 0 &&
4056                         os_strcmp(id->string, group_id) != 0)
4057                               continue;
4058 
4059                     if (reconfig && os_strcmp(net_role, "configurator") == 0)
4060                               return 1;
4061                     if (!reconfig && dpp_compatible_netrole(role->string, net_role))
4062                               return 1;
4063           }
4064 
4065           return 0;
4066 }
4067 
4068 
dpp_connector_match_groups(struct json_token * own_root,struct json_token * peer_root,bool reconfig)4069 int dpp_connector_match_groups(struct json_token *own_root,
4070                                      struct json_token *peer_root, bool reconfig)
4071 {
4072           struct json_token *groups, *token;
4073 
4074           groups = json_get_member(peer_root, "groups");
4075           if (!groups || groups->type != JSON_ARRAY) {
4076                     wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
4077                     return 0;
4078           }
4079 
4080           for (token = groups->child; token; token = token->sibling) {
4081                     struct json_token *id, *role;
4082 
4083                     id = json_get_member(token, "groupId");
4084                     if (!id || id->type != JSON_STRING) {
4085                               wpa_printf(MSG_DEBUG,
4086                                            "DPP: Missing peer groupId string");
4087                               continue;
4088                     }
4089 
4090                     role = json_get_member(token, "netRole");
4091                     if (!role || role->type != JSON_STRING) {
4092                               wpa_printf(MSG_DEBUG,
4093                                            "DPP: Missing peer groups::netRole string");
4094                               continue;
4095                     }
4096                     wpa_printf(MSG_DEBUG,
4097                                  "DPP: peer connector group: groupId='%s' netRole='%s'",
4098                                  id->string, role->string);
4099                     if (dpp_connector_compatible_group(own_root, id->string,
4100                                                                role->string, reconfig)) {
4101                               wpa_printf(MSG_DEBUG,
4102                                            "DPP: Compatible group/netRole in own connector");
4103                               return 1;
4104                     }
4105           }
4106 
4107           return 0;
4108 }
4109 
4110 
dpp_parse_own_connector(const char * own_connector)4111 struct json_token * dpp_parse_own_connector(const char *own_connector)
4112 {
4113           unsigned char *own_conn;
4114           size_t own_conn_len;
4115           const char *pos, *end;
4116           struct json_token *own_root;
4117 
4118           pos = os_strchr(own_connector, '.');
4119           if (!pos) {
4120                     wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
4121                     return NULL;
4122           }
4123           pos++;
4124           end = os_strchr(pos, '.');
4125           if (!end) {
4126                     wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
4127                     return NULL;
4128           }
4129           own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
4130           if (!own_conn) {
4131                     wpa_printf(MSG_DEBUG,
4132                                  "DPP: Failed to base64url decode own signedConnector JWS Payload");
4133                     return NULL;
4134           }
4135 
4136           own_root = json_parse((const char *) own_conn, own_conn_len);
4137           os_free(own_conn);
4138           if (!own_root)
4139                     wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
4140 
4141           return own_root;
4142 }
4143 
4144 
4145 enum dpp_status_error
dpp_peer_intro(struct dpp_introduction * intro,const char * own_connector,const u8 * net_access_key,size_t net_access_key_len,const u8 * csign_key,size_t csign_key_len,const u8 * peer_connector,size_t peer_connector_len,os_time_t * expiry,u8 * peer_key_hash)4146 dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
4147                  const u8 *net_access_key, size_t net_access_key_len,
4148                  const u8 *csign_key, size_t csign_key_len,
4149                  const u8 *peer_connector, size_t peer_connector_len,
4150                  os_time_t *expiry, u8 *peer_key_hash)
4151 {
4152           struct json_token *root = NULL, *netkey, *token;
4153           struct json_token *own_root = NULL;
4154           enum dpp_status_error ret = 255, res;
4155           struct crypto_ec_key *own_key = NULL;
4156           struct wpabuf *own_key_pub = NULL;
4157           const struct dpp_curve_params *curve, *own_curve;
4158           struct dpp_signed_connector_info info;
4159           size_t Nx_len;
4160           u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
4161 
4162           os_memset(intro, 0, sizeof(*intro));
4163           os_memset(&info, 0, sizeof(info));
4164           if (expiry)
4165                     *expiry = 0;
4166 
4167           own_key = dpp_set_keypair(&own_curve, net_access_key,
4168                                           net_access_key_len);
4169           if (!own_key) {
4170                     wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
4171                     goto fail;
4172           }
4173 
4174           own_root = dpp_parse_own_connector(own_connector);
4175           if (!own_root)
4176                     goto fail;
4177 
4178           res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
4179                                                    peer_connector, peer_connector_len);
4180           if (res != DPP_STATUS_OK) {
4181                     ret = res;
4182                     goto fail;
4183           }
4184 
4185           root = json_parse((const char *) info.payload, info.payload_len);
4186           if (!root) {
4187                     wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
4188                     ret = DPP_STATUS_INVALID_CONNECTOR;
4189                     goto fail;
4190           }
4191 
4192           if (!dpp_connector_match_groups(own_root, root, false)) {
4193                     wpa_printf(MSG_DEBUG,
4194                                  "DPP: Peer connector does not include compatible group netrole with own connector");
4195                     ret = DPP_STATUS_NO_MATCH;
4196                     goto fail;
4197           }
4198 
4199           token = json_get_member(root, "expiry");
4200           if (!token || token->type != JSON_STRING) {
4201                     wpa_printf(MSG_DEBUG,
4202                                  "DPP: No expiry string found - connector does not expire");
4203           } else {
4204                     wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
4205                     if (dpp_key_expired(token->string, expiry)) {
4206                               wpa_printf(MSG_DEBUG,
4207                                            "DPP: Connector (netAccessKey) has expired");
4208                               ret = DPP_STATUS_INVALID_CONNECTOR;
4209                               goto fail;
4210                     }
4211           }
4212 
4213 #ifdef CONFIG_DPP3
4214           token = json_get_member(root, "version");
4215           if (token && token->type == JSON_NUMBER) {
4216                     wpa_printf(MSG_DEBUG, "DPP: version = %d", token->number);
4217                     intro->peer_version = token->number;
4218           }
4219 #endif /* CONFIG_DPP3 */
4220 
4221           netkey = json_get_member(root, "netAccessKey");
4222           if (!netkey || netkey->type != JSON_OBJECT) {
4223                     wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
4224                     ret = DPP_STATUS_INVALID_CONNECTOR;
4225                     goto fail;
4226           }
4227 
4228           intro->peer_key = dpp_parse_jwk(netkey, &curve);
4229           if (!intro->peer_key) {
4230                     ret = DPP_STATUS_INVALID_CONNECTOR;
4231                     goto fail;
4232           }
4233           dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
4234 
4235           if (own_curve != curve) {
4236                     wpa_printf(MSG_DEBUG,
4237                                  "DPP: Mismatching netAccessKey curves (%s != %s)",
4238                                  own_curve->name, curve->name);
4239                     ret = DPP_STATUS_INVALID_CONNECTOR;
4240                     goto fail;
4241           }
4242 
4243           /* ECDH: N = nk * PK */
4244           if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
4245                     goto fail;
4246 
4247           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
4248                               Nx, Nx_len);
4249 
4250           /* PMK = HKDF(<>, "DPP PMK", N.x) */
4251           if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
4252                     wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
4253                     goto fail;
4254           }
4255           intro->pmk_len = curve->hash_len;
4256 
4257           /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
4258           if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
4259               0) {
4260                     wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
4261                     goto fail;
4262           }
4263 
4264 #ifdef CONFIG_DPP3
4265           if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
4266                                  &intro->aead_id) < 0) {
4267                     wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
4268                                  curve->ike_group);
4269                     goto fail;
4270           }
4271 #endif /* CONFIG_DPP3 */
4272 
4273           if (peer_key_hash)
4274                     dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
4275 
4276           ret = DPP_STATUS_OK;
4277 fail:
4278           if (ret != DPP_STATUS_OK)
4279                     dpp_peer_intro_deinit(intro);
4280           os_memset(Nx, 0, sizeof(Nx));
4281           os_free(info.payload);
4282           crypto_ec_key_deinit(own_key);
4283           wpabuf_free(own_key_pub);
4284           json_free(root);
4285           json_free(own_root);
4286           return ret;
4287 }
4288 
4289 
dpp_peer_intro_deinit(struct dpp_introduction * intro)4290 void dpp_peer_intro_deinit(struct dpp_introduction *intro)
4291 {
4292           if (!intro)
4293                     return;
4294 
4295           crypto_ec_key_deinit(intro->peer_key);
4296           os_memset(intro, 0, sizeof(*intro));
4297 }
4298 
4299 
4300 #ifdef CONFIG_DPP3
dpp_get_connector_version(const char * connector)4301 int dpp_get_connector_version(const char *connector)
4302 {
4303           struct json_token *root, *token;
4304           int ver = -1;
4305 
4306           root = dpp_parse_own_connector(connector);
4307           if (!root)
4308                     return -1;
4309 
4310           token = json_get_member(root, "version");
4311           if (token && token->type == JSON_NUMBER)
4312                     ver = token->number;
4313 
4314           json_free(root);
4315           return ver;
4316 }
4317 #endif /* CONFIG_DPP3 */
4318 
4319 
dpp_next_id(struct dpp_global * dpp)4320 unsigned int dpp_next_id(struct dpp_global *dpp)
4321 {
4322           struct dpp_bootstrap_info *bi;
4323           unsigned int max_id = 0;
4324 
4325           dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4326                     if (bi->id > max_id)
4327                               max_id = bi->id;
4328           }
4329           return max_id + 1;
4330 }
4331 
4332 
dpp_bootstrap_del(struct dpp_global * dpp,unsigned int id)4333 static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
4334 {
4335           struct dpp_bootstrap_info *bi, *tmp;
4336           int found = 0;
4337 
4338           if (!dpp)
4339                     return -1;
4340 
4341           dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
4342                                     struct dpp_bootstrap_info, list) {
4343                     if (id && bi->id != id)
4344                               continue;
4345                     found = 1;
4346 #ifdef CONFIG_DPP2
4347                     if (dpp->remove_bi)
4348                               dpp->remove_bi(dpp->cb_ctx, bi);
4349 #endif /* CONFIG_DPP2 */
4350                     dl_list_del(&bi->list);
4351                     dpp_bootstrap_info_free(bi);
4352           }
4353 
4354           if (id == 0)
4355                     return 0; /* flush succeeds regardless of entries found */
4356           return found ? 0 : -1;
4357 }
4358 
4359 
dpp_add_qr_code(struct dpp_global * dpp,const char * uri)4360 struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
4361                                                       const char *uri)
4362 {
4363           struct dpp_bootstrap_info *bi;
4364 
4365           if (!dpp)
4366                     return NULL;
4367 
4368           bi = dpp_parse_uri(uri);
4369           if (!bi)
4370                     return NULL;
4371 
4372           bi->type = DPP_BOOTSTRAP_QR_CODE;
4373           bi->id = dpp_next_id(dpp);
4374           dl_list_add(&dpp->bootstrap, &bi->list);
4375           return bi;
4376 }
4377 
4378 
dpp_add_nfc_uri(struct dpp_global * dpp,const char * uri)4379 struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
4380                                                       const char *uri)
4381 {
4382           struct dpp_bootstrap_info *bi;
4383 
4384           if (!dpp)
4385                     return NULL;
4386 
4387           bi = dpp_parse_uri(uri);
4388           if (!bi)
4389                     return NULL;
4390 
4391           bi->type = DPP_BOOTSTRAP_NFC_URI;
4392           bi->id = dpp_next_id(dpp);
4393           dl_list_add(&dpp->bootstrap, &bi->list);
4394           return bi;
4395 }
4396 
4397 
dpp_parse_supported_curves_list(struct dpp_bootstrap_info * bi,char * txt)4398 static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
4399                                                      char *txt)
4400 {
4401           char *token, *context = NULL;
4402           u8 curves = 0;
4403 
4404           if (!txt)
4405                     return 0;
4406 
4407           while ((token = str_token(txt, ":", &context))) {
4408                     if (os_strcmp(token, "P-256") == 0) {
4409                               curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
4410                     } else if (os_strcmp(token, "P-384") == 0) {
4411                               curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
4412                     } else if (os_strcmp(token, "P-521") == 0) {
4413                               curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
4414                     } else if (os_strcmp(token, "BP-256") == 0) {
4415                               curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
4416                     } else if (os_strcmp(token, "BP-384") == 0) {
4417                               curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
4418                     } else if (os_strcmp(token, "BP-512") == 0) {
4419                               curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
4420                     } else {
4421                               wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
4422                                            token);
4423                               return -1;
4424                     }
4425           }
4426           bi->supported_curves = curves;
4427 
4428           wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
4429                        bi->supported_curves);
4430 
4431           return 0;
4432 }
4433 
4434 
dpp_bootstrap_gen(struct dpp_global * dpp,const char * cmd)4435 int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
4436 {
4437           char *mac = NULL, *info = NULL, *curve = NULL;
4438           char *key = NULL, *supported_curves = NULL, *host = NULL;
4439           u8 *privkey = NULL;
4440           size_t privkey_len = 0;
4441           int ret = -1;
4442           struct dpp_bootstrap_info *bi;
4443 
4444           if (!dpp)
4445                     return -1;
4446 
4447           bi = os_zalloc(sizeof(*bi));
4448           if (!bi)
4449                     goto fail;
4450 
4451           if (os_strstr(cmd, "type=qrcode"))
4452                     bi->type = DPP_BOOTSTRAP_QR_CODE;
4453           else if (os_strstr(cmd, "type=pkex"))
4454                     bi->type = DPP_BOOTSTRAP_PKEX;
4455           else if (os_strstr(cmd, "type=nfc-uri"))
4456                     bi->type = DPP_BOOTSTRAP_NFC_URI;
4457           else
4458                     goto fail;
4459 
4460           bi->chan = get_param(cmd, " chan=");
4461           mac = get_param(cmd, " mac=");
4462           info = get_param(cmd, " info=");
4463           curve = get_param(cmd, " curve=");
4464           key = get_param(cmd, " key=");
4465           supported_curves = get_param(cmd, " supported_curves=");
4466           host = get_param(cmd, " host=");
4467 
4468           if (key) {
4469                     privkey_len = os_strlen(key) / 2;
4470                     privkey = os_malloc(privkey_len);
4471                     if (!privkey ||
4472                         hexstr2bin(key, privkey, privkey_len) < 0)
4473                               goto fail;
4474           }
4475 
4476           if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
4477               dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
4478               dpp_parse_uri_mac(bi, mac) < 0 ||
4479               dpp_parse_uri_info(bi, info) < 0 ||
4480               dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
4481               dpp_parse_uri_host(bi, host) < 0 ||
4482               dpp_gen_uri(bi) < 0)
4483                     goto fail;
4484 
4485           bi->id = dpp_next_id(dpp);
4486           dl_list_add(&dpp->bootstrap, &bi->list);
4487           ret = bi->id;
4488           bi = NULL;
4489 fail:
4490           os_free(curve);
4491           os_free(mac);
4492           os_free(info);
4493           str_clear_free(key);
4494           os_free(supported_curves);
4495           os_free(host);
4496           bin_clear_free(privkey, privkey_len);
4497           dpp_bootstrap_info_free(bi);
4498           return ret;
4499 }
4500 
4501 
4502 struct dpp_bootstrap_info *
dpp_bootstrap_get_id(struct dpp_global * dpp,unsigned int id)4503 dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
4504 {
4505           struct dpp_bootstrap_info *bi;
4506 
4507           if (!dpp)
4508                     return NULL;
4509 
4510           dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4511                     if (bi->id == id)
4512                               return bi;
4513           }
4514           return NULL;
4515 }
4516 
4517 
dpp_bootstrap_remove(struct dpp_global * dpp,const char * id)4518 int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
4519 {
4520           unsigned int id_val;
4521 
4522           if (os_strcmp(id, "*") == 0) {
4523                     id_val = 0;
4524           } else {
4525                     id_val = atoi(id);
4526                     if (id_val == 0)
4527                               return -1;
4528           }
4529 
4530           return dpp_bootstrap_del(dpp, id_val);
4531 }
4532 
4533 
dpp_bootstrap_get_uri(struct dpp_global * dpp,unsigned int id)4534 const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
4535 {
4536           struct dpp_bootstrap_info *bi;
4537 
4538           bi = dpp_bootstrap_get_id(dpp, id);
4539           if (!bi)
4540                     return NULL;
4541           return bi->uri;
4542 }
4543 
4544 
dpp_bootstrap_info(struct dpp_global * dpp,int id,char * reply,int reply_size)4545 int dpp_bootstrap_info(struct dpp_global *dpp, int id,
4546                            char *reply, int reply_size)
4547 {
4548           struct dpp_bootstrap_info *bi;
4549           char pkhash[2 * SHA256_MAC_LEN + 1];
4550           char supp_curves[100];
4551           char host[100];
4552           int ret;
4553 
4554           bi = dpp_bootstrap_get_id(dpp, id);
4555           if (!bi)
4556                     return -1;
4557           wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
4558                                SHA256_MAC_LEN);
4559 
4560           supp_curves[0] = '\0';
4561           if (bi->supported_curves) {
4562                     size_t i;
4563                     char *pos = supp_curves;
4564                     char *end = &supp_curves[sizeof(supp_curves)];
4565                     const char *curve[6] = { "P-256", "P-384", "P-521",
4566                                                    "BP-256", "BP-384", "BP-512" };
4567 
4568                     ret = os_snprintf(pos, end - pos, "supp_curves=");
4569                     if (os_snprintf_error(end - pos, ret))
4570                               return -1;
4571                     pos += ret;
4572 
4573                     for (i = 0; i < ARRAY_SIZE(curve); i++) {
4574                               if (!(bi->supported_curves & BIT(i)))
4575                                         continue;
4576                               ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
4577                               if (os_snprintf_error(end - pos, ret))
4578                                         return -1;
4579                               pos += ret;
4580                     }
4581 
4582                     if (pos[-1] == ':')
4583                               pos[-1] = '\n';
4584                     else
4585                               supp_curves[0] = '\0';
4586           }
4587 
4588           host[0] = '\0';
4589           if (bi->host) {
4590                     char buf[100];
4591 
4592                     ret = os_snprintf(host, sizeof(host), "host=%s %u\n",
4593                                           hostapd_ip_txt(bi->host, buf, sizeof(buf)),
4594                                           bi->port);
4595                     if (os_snprintf_error(sizeof(host), ret))
4596                               return -1;
4597           }
4598 
4599           return os_snprintf(reply, reply_size, "type=%s\n"
4600                                  "mac_addr=" MACSTR "\n"
4601                                  "info=%s\n"
4602                                  "num_freq=%u\n"
4603                                  "use_freq=%u\n"
4604                                  "curve=%s\n"
4605                                  "pkhash=%s\n"
4606                                  "version=%d\n%s%s",
4607                                  dpp_bootstrap_type_txt(bi->type),
4608                                  MAC2STR(bi->mac_addr),
4609                                  bi->info ? bi->info : "",
4610                                  bi->num_freq,
4611                                  bi->num_freq == 1 ? bi->freq[0] : 0,
4612                                  bi->curve->name,
4613                                  pkhash,
4614                                  bi->version,
4615                                  supp_curves,
4616                                  host);
4617 }
4618 
4619 
dpp_bootstrap_set(struct dpp_global * dpp,int id,const char * params)4620 int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params)
4621 {
4622           struct dpp_bootstrap_info *bi;
4623 
4624           bi = dpp_bootstrap_get_id(dpp, id);
4625           if (!bi)
4626                     return -1;
4627 
4628           str_clear_free(bi->configurator_params);
4629 
4630           if (params) {
4631                     bi->configurator_params = os_strdup(params);
4632                     return bi->configurator_params ? 0 : -1;
4633           }
4634 
4635           bi->configurator_params = NULL;
4636           return 0;
4637 }
4638 
4639 
dpp_bootstrap_find_pair(struct dpp_global * dpp,const u8 * i_bootstrap,const u8 * r_bootstrap,struct dpp_bootstrap_info ** own_bi,struct dpp_bootstrap_info ** peer_bi)4640 void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
4641                                    const u8 *r_bootstrap,
4642                                    struct dpp_bootstrap_info **own_bi,
4643                                    struct dpp_bootstrap_info **peer_bi)
4644 {
4645           struct dpp_bootstrap_info *bi;
4646 
4647           *own_bi = NULL;
4648           *peer_bi = NULL;
4649           if (!dpp)
4650                     return;
4651 
4652           dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4653                     if (!*own_bi && bi->own &&
4654                         os_memcmp(bi->pubkey_hash, r_bootstrap,
4655                                     SHA256_MAC_LEN) == 0) {
4656                               wpa_printf(MSG_DEBUG,
4657                                            "DPP: Found matching own bootstrapping information");
4658                               *own_bi = bi;
4659                     }
4660 
4661                     if (!*peer_bi && !bi->own &&
4662                         os_memcmp(bi->pubkey_hash, i_bootstrap,
4663                                     SHA256_MAC_LEN) == 0) {
4664                               wpa_printf(MSG_DEBUG,
4665                                            "DPP: Found matching peer bootstrapping information");
4666                               *peer_bi = bi;
4667                     }
4668 
4669                     if (*own_bi && *peer_bi)
4670                               break;
4671           }
4672 }
4673 
4674 
4675 #ifdef CONFIG_DPP2
dpp_bootstrap_find_chirp(struct dpp_global * dpp,const u8 * hash)4676 struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
4677                                                                  const u8 *hash)
4678 {
4679           struct dpp_bootstrap_info *bi;
4680 
4681           if (!dpp)
4682                     return NULL;
4683 
4684           dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
4685                     if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash,
4686                                                     SHA256_MAC_LEN) == 0)
4687                               return bi;
4688           }
4689 
4690           return NULL;
4691 }
4692 #endif /* CONFIG_DPP2 */
4693 
4694 
dpp_nfc_update_bi_channel(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4695 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
4696                                              struct dpp_bootstrap_info *peer_bi)
4697 {
4698           unsigned int i, freq = 0;
4699           enum hostapd_hw_mode mode;
4700           u8 op_class, channel;
4701           char chan[20];
4702 
4703           if (peer_bi->num_freq == 0 && !peer_bi->channels_listed)
4704                     return 0; /* no channel preference/constraint */
4705 
4706           for (i = 0; i < peer_bi->num_freq; i++) {
4707                     if ((own_bi->num_freq == 0 && !own_bi->channels_listed) ||
4708                         freq_included(own_bi->freq, own_bi->num_freq,
4709                                           peer_bi->freq[i])) {
4710                               freq = peer_bi->freq[i];
4711                               break;
4712                     }
4713           }
4714           if (!freq) {
4715                     wpa_printf(MSG_DEBUG, "DPP: No common channel found");
4716                     return -1;
4717           }
4718 
4719           mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
4720           if (mode == NUM_HOSTAPD_MODES) {
4721                     wpa_printf(MSG_DEBUG,
4722                                  "DPP: Could not determine operating class or channel number for %u MHz",
4723                                  freq);
4724           }
4725 
4726           wpa_printf(MSG_DEBUG,
4727                        "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
4728                        freq, op_class, channel);
4729           os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
4730           os_free(own_bi->chan);
4731           own_bi->chan = os_strdup(chan);
4732           own_bi->freq[0] = freq;
4733           own_bi->num_freq = 1;
4734           os_free(peer_bi->chan);
4735           peer_bi->chan = os_strdup(chan);
4736           peer_bi->freq[0] = freq;
4737           peer_bi->num_freq = 1;
4738 
4739           return dpp_gen_uri(own_bi);
4740 }
4741 
4742 
dpp_nfc_update_bi_key(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4743 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
4744                                          struct dpp_bootstrap_info *peer_bi)
4745 {
4746           if (peer_bi->curve == own_bi->curve)
4747                     return 0;
4748 
4749           wpa_printf(MSG_DEBUG,
4750                        "DPP: Update own bootstrapping key to match peer curve from NFC handover");
4751 
4752           crypto_ec_key_deinit(own_bi->pubkey);
4753           own_bi->pubkey = NULL;
4754 
4755           if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
4756               dpp_gen_uri(own_bi) < 0)
4757                     goto fail;
4758 
4759           return 0;
4760 fail:
4761           dl_list_del(&own_bi->list);
4762           dpp_bootstrap_info_free(own_bi);
4763           return -1;
4764 }
4765 
4766 
dpp_nfc_update_bi(struct dpp_bootstrap_info * own_bi,struct dpp_bootstrap_info * peer_bi)4767 int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
4768                           struct dpp_bootstrap_info *peer_bi)
4769 {
4770           if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
4771               dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
4772                     return -1;
4773           return 0;
4774 }
4775 
4776 
dpp_next_configurator_id(struct dpp_global * dpp)4777 static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
4778 {
4779           struct dpp_configurator *conf;
4780           unsigned int max_id = 0;
4781 
4782           dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
4783                                list) {
4784                     if (conf->id > max_id)
4785                               max_id = conf->id;
4786           }
4787           return max_id + 1;
4788 }
4789 
4790 
dpp_configurator_add(struct dpp_global * dpp,const char * cmd)4791 int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
4792 {
4793           char *curve;
4794           char *key = NULL, *ppkey = NULL;
4795           u8 *privkey = NULL, *pp_key = NULL;
4796           size_t privkey_len = 0, pp_key_len = 0;
4797           int ret = -1;
4798           struct dpp_configurator *conf = NULL;
4799           const struct dpp_curve_params *net_access_key_curve = NULL;
4800 
4801           curve = get_param(cmd, " net_access_key_curve=");
4802           if (curve) {
4803                     net_access_key_curve = dpp_get_curve_name(curve);
4804                     if (!net_access_key_curve) {
4805                               wpa_printf(MSG_DEBUG,
4806                                            "DPP: Unsupported net_access_key_curve: %s",
4807                                            curve);
4808                               goto fail;
4809                     }
4810                     os_free(curve);
4811           }
4812 
4813           curve = get_param(cmd, " curve=");
4814           key = get_param(cmd, " key=");
4815           ppkey = get_param(cmd, " ppkey=");
4816 
4817           if (key) {
4818                     privkey_len = os_strlen(key) / 2;
4819                     privkey = os_malloc(privkey_len);
4820                     if (!privkey ||
4821                         hexstr2bin(key, privkey, privkey_len) < 0)
4822                               goto fail;
4823           }
4824 
4825           if (ppkey) {
4826                     pp_key_len = os_strlen(ppkey) / 2;
4827                     pp_key = os_malloc(pp_key_len);
4828                     if (!pp_key ||
4829                         hexstr2bin(ppkey, pp_key, pp_key_len) < 0)
4830                               goto fail;
4831           }
4832 
4833           conf = dpp_keygen_configurator(curve, privkey, privkey_len,
4834                                                pp_key, pp_key_len);
4835           if (!conf)
4836                     goto fail;
4837 
4838           conf->net_access_key_curve = net_access_key_curve;
4839           conf->id = dpp_next_configurator_id(dpp);
4840           dl_list_add(&dpp->configurator, &conf->list);
4841           ret = conf->id;
4842           conf = NULL;
4843 fail:
4844           os_free(curve);
4845           str_clear_free(key);
4846           str_clear_free(ppkey);
4847           bin_clear_free(privkey, privkey_len);
4848           bin_clear_free(pp_key, pp_key_len);
4849           dpp_configurator_free(conf);
4850           return ret;
4851 }
4852 
4853 
dpp_configurator_set(struct dpp_global * dpp,const char * cmd)4854 int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
4855 {
4856           unsigned int id;
4857           struct dpp_configurator *conf;
4858           char *curve;
4859 
4860           id = atoi(cmd);
4861           conf = dpp_configurator_get_id(dpp, id);
4862           if (!conf)
4863                     return -1;
4864 
4865           curve = get_param(cmd, " net_access_key_curve=");
4866           if (curve) {
4867                     const struct dpp_curve_params *net_access_key_curve;
4868 
4869                     net_access_key_curve = dpp_get_curve_name(curve);
4870                     os_free(curve);
4871                     if (!net_access_key_curve)
4872                               return -1;
4873                     conf->net_access_key_curve = net_access_key_curve;
4874           }
4875 
4876           return 0;
4877 }
4878 
4879 
dpp_configurator_del(struct dpp_global * dpp,unsigned int id)4880 static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
4881 {
4882           struct dpp_configurator *conf, *tmp;
4883           int found = 0;
4884 
4885           if (!dpp)
4886                     return -1;
4887 
4888           dl_list_for_each_safe(conf, tmp, &dpp->configurator,
4889                                     struct dpp_configurator, list) {
4890                     if (id && conf->id != id)
4891                               continue;
4892                     found = 1;
4893                     dl_list_del(&conf->list);
4894                     dpp_configurator_free(conf);
4895           }
4896 
4897           if (id == 0)
4898                     return 0; /* flush succeeds regardless of entries found */
4899           return found ? 0 : -1;
4900 }
4901 
4902 
dpp_configurator_remove(struct dpp_global * dpp,const char * id)4903 int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
4904 {
4905           unsigned int id_val;
4906 
4907           if (os_strcmp(id, "*") == 0) {
4908                     id_val = 0;
4909           } else {
4910                     id_val = atoi(id);
4911                     if (id_val == 0)
4912                               return -1;
4913           }
4914 
4915           return dpp_configurator_del(dpp, id_val);
4916 }
4917 
4918 
dpp_configurator_get_key_id(struct dpp_global * dpp,unsigned int id,char * buf,size_t buflen)4919 int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
4920                                         char *buf, size_t buflen)
4921 {
4922           struct dpp_configurator *conf;
4923 
4924           conf = dpp_configurator_get_id(dpp, id);
4925           if (!conf)
4926                     return -1;
4927 
4928           return dpp_configurator_get_key(conf, buf, buflen);
4929 }
4930 
4931 
4932 #ifdef CONFIG_DPP2
4933 
dpp_configurator_from_backup(struct dpp_global * dpp,struct dpp_asymmetric_key * key)4934 int dpp_configurator_from_backup(struct dpp_global *dpp,
4935                                          struct dpp_asymmetric_key *key)
4936 {
4937           struct dpp_configurator *conf;
4938           const struct dpp_curve_params *curve, *curve_pp;
4939 
4940           if (!key->csign || !key->pp_key)
4941                     return -1;
4942 
4943           curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
4944           if (!curve) {
4945                     wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
4946                     return -1;
4947           }
4948 
4949           curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
4950           if (!curve_pp) {
4951                     wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
4952                     return -1;
4953           }
4954 
4955           if (curve != curve_pp) {
4956                     wpa_printf(MSG_INFO,
4957                                  "DPP: Mismatch in c-sign-key and ppKey groups");
4958                     return -1;
4959           }
4960 
4961           conf = os_zalloc(sizeof(*conf));
4962           if (!conf)
4963                     return -1;
4964           conf->curve = curve;
4965           conf->csign = key->csign;
4966           key->csign = NULL;
4967           conf->pp_key = key->pp_key;
4968           key->pp_key = NULL;
4969           conf->own = 1;
4970           if (dpp_configurator_gen_kid(conf) < 0) {
4971                     dpp_configurator_free(conf);
4972                     return -1;
4973           }
4974 
4975           conf->id = dpp_next_configurator_id(dpp);
4976           dl_list_add(&dpp->configurator, &conf->list);
4977           return conf->id;
4978 }
4979 
4980 
dpp_configurator_find_kid(struct dpp_global * dpp,const u8 * kid)4981 struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp,
4982                                                                 const u8 *kid)
4983 {
4984           struct dpp_configurator *conf;
4985 
4986           if (!dpp)
4987                     return NULL;
4988 
4989           dl_list_for_each(conf, &dpp->configurator,
4990                                struct dpp_configurator, list) {
4991                     if (os_memcmp(conf->kid_hash, kid, SHA256_MAC_LEN) == 0)
4992                               return conf;
4993           }
4994           return NULL;
4995 }
4996 
4997 #endif /* CONFIG_DPP2 */
4998 
4999 
dpp_global_init(struct dpp_global_config * config)5000 struct dpp_global * dpp_global_init(struct dpp_global_config *config)
5001 {
5002           struct dpp_global *dpp;
5003 
5004           dpp = os_zalloc(sizeof(*dpp));
5005           if (!dpp)
5006                     return NULL;
5007 #ifdef CONFIG_DPP2
5008           dpp->cb_ctx = config->cb_ctx;
5009           dpp->remove_bi = config->remove_bi;
5010 #endif /* CONFIG_DPP2 */
5011 
5012           dl_list_init(&dpp->bootstrap);
5013           dl_list_init(&dpp->configurator);
5014 #ifdef CONFIG_DPP2
5015           dl_list_init(&dpp->controllers);
5016           dl_list_init(&dpp->tcp_init);
5017           dpp->relay_sock = -1;
5018 #endif /* CONFIG_DPP2 */
5019 
5020           return dpp;
5021 }
5022 
5023 
dpp_global_clear(struct dpp_global * dpp)5024 void dpp_global_clear(struct dpp_global *dpp)
5025 {
5026           if (!dpp)
5027                     return;
5028 
5029           dpp_bootstrap_del(dpp, 0);
5030           dpp_configurator_del(dpp, 0);
5031 #ifdef CONFIG_DPP2
5032           dpp_tcp_init_flush(dpp);
5033           dpp_relay_flush_controllers(dpp);
5034           dpp_controller_stop(dpp);
5035 #endif /* CONFIG_DPP2 */
5036 }
5037 
5038 
dpp_global_deinit(struct dpp_global * dpp)5039 void dpp_global_deinit(struct dpp_global *dpp)
5040 {
5041           dpp_global_clear(dpp);
5042           os_free(dpp);
5043 }
5044 
5045 
dpp_notify_auth_success(struct dpp_authentication * auth,int initiator)5046 void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
5047 {
5048           u8 hash[SHA256_MAC_LEN];
5049           char hex[SHA256_MAC_LEN * 2 + 1];
5050 
5051           if (auth->peer_protocol_key) {
5052                     dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
5053                     wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
5054           } else {
5055                     hex[0] = '\0';
5056           }
5057           wpa_msg(auth->msg_ctx, MSG_INFO,
5058                     DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d",
5059                     initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1,
5060                     auth->peer_bi ? (int) auth->peer_bi->id : -1);
5061 }
5062 
5063 
5064 #ifdef CONFIG_DPP2
5065 
dpp_build_presence_announcement(struct dpp_bootstrap_info * bi)5066 struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi)
5067 {
5068           struct wpabuf *msg;
5069 
5070           wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame");
5071 
5072           msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN);
5073           if (!msg)
5074                     return NULL;
5075 
5076           /* Responder Bootstrapping Key Hash */
5077           dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp);
5078           wpa_hexdump_buf(MSG_DEBUG,
5079                               "DPP: Presence Announcement frame attributes", msg);
5080           return msg;
5081 }
5082 
5083 
dpp_notify_chirp_received(void * msg_ctx,int id,const u8 * src,unsigned int freq,const u8 * hash)5084 void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src,
5085                                         unsigned int freq, const u8 *hash)
5086 {
5087           char hex[SHA256_MAC_LEN * 2 + 1];
5088 
5089           wpa_snprintf_hex(hex, sizeof(hex), hash, SHA256_MAC_LEN);
5090           wpa_msg(msg_ctx, MSG_INFO,
5091                     DPP_EVENT_CHIRP_RX "id=%d src=" MACSTR " freq=%u hash=%s",
5092                     id, MAC2STR(src), freq, hex);
5093 }
5094 
5095 #endif /* CONFIG_DPP2 */
5096 
5097 
5098 #ifdef CONFIG_DPP3
5099 
dpp_build_pb_announcement(struct dpp_bootstrap_info * bi)5100 struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi)
5101 {
5102           struct wpabuf *msg;
5103           const u8 *r_hash = bi->pubkey_hash_chirp;
5104 #ifdef CONFIG_TESTING_OPTIONS
5105           u8 test_hash[SHA256_MAC_LEN];
5106 #endif /* CONFIG_TESTING_OPTIONS */
5107 
5108           wpa_printf(MSG_DEBUG,
5109                        "DPP: Build Push Button Presence Announcement frame");
5110 
5111           msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT,
5112                                   4 + SHA256_MAC_LEN);
5113           if (!msg)
5114                     return NULL;
5115 
5116 #ifdef CONFIG_TESTING_OPTIONS
5117           if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) {
5118                     wpa_printf(MSG_INFO,
5119                                  "DPP: TESTING - invalid R-Bootstrap Key Hash");
5120                     os_memcpy(test_hash, r_hash, SHA256_MAC_LEN);
5121                     test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5122                     r_hash = test_hash;
5123           }
5124 #endif /* CONFIG_TESTING_OPTIONS */
5125 
5126           /* Responder Bootstrapping Key Hash */
5127           dpp_build_attr_r_bootstrap_key_hash(msg, r_hash);
5128           wpa_hexdump_buf(MSG_DEBUG,
5129                               "DPP: Push Button Presence Announcement frame attributes",
5130                               msg);
5131           return msg;
5132 }
5133 
5134 
dpp_build_pb_announcement_resp(struct dpp_bootstrap_info * bi,const u8 * e_hash,const u8 * c_nonce,size_t c_nonce_len)5135 struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi,
5136                                                          const u8 *e_hash,
5137                                                          const u8 *c_nonce,
5138                                                          size_t c_nonce_len)
5139 {
5140           struct wpabuf *msg;
5141           const u8 *i_hash = bi->pubkey_hash_chirp;
5142 #ifdef CONFIG_TESTING_OPTIONS
5143           u8 test_hash[SHA256_MAC_LEN];
5144 #endif /* CONFIG_TESTING_OPTIONS */
5145 
5146           wpa_printf(MSG_DEBUG,
5147                        "DPP: Build Push Button Presence Announcement Response frame");
5148 
5149           msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP,
5150                                   2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len);
5151           if (!msg)
5152                     return NULL;
5153 
5154 #ifdef CONFIG_TESTING_OPTIONS
5155           if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) {
5156                     wpa_printf(MSG_INFO,
5157                                  "DPP: TESTING - invalid I-Bootstrap Key Hash");
5158                     os_memcpy(test_hash, i_hash, SHA256_MAC_LEN);
5159                     test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5160                     i_hash = test_hash;
5161           } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) {
5162                     wpa_printf(MSG_INFO,
5163                                  "DPP: TESTING - invalid R-Bootstrap Key Hash");
5164                     os_memcpy(test_hash, e_hash, SHA256_MAC_LEN);
5165                     test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
5166                     e_hash = test_hash;
5167           }
5168 #endif /* CONFIG_TESTING_OPTIONS */
5169 
5170           /* Initiator Bootstrapping Key Hash */
5171           wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
5172           wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
5173           wpabuf_put_le16(msg, SHA256_MAC_LEN);
5174           wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN);
5175 
5176           /* Responder Bootstrapping Key Hash */
5177           dpp_build_attr_r_bootstrap_key_hash(msg, e_hash);
5178 
5179           /* Configurator Nonce */
5180           wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
5181           wpabuf_put_le16(msg, c_nonce_len);
5182           wpabuf_put_data(msg, c_nonce, c_nonce_len);
5183 
5184           wpa_hexdump_buf(MSG_DEBUG,
5185                               "DPP: Push Button Presence Announcement Response frame attributes",
5186                               msg);
5187           return msg;
5188 }
5189 
5190 #endif /* CONFIG_DPP3 */
5191