Coverage Report

Created: 2024-05-20 06:26

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