Coverage Report

Created: 2025-04-24 06:18

/src/hostap/src/common/dpp_reconfig.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * DPP reconfiguration
3
 * Copyright (c) 2020, The Linux Foundation
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "utils/includes.h"
10
11
#include "utils/common.h"
12
#include "utils/json.h"
13
#include "crypto/crypto.h"
14
#include "crypto/random.h"
15
#include "crypto/aes.h"
16
#include "crypto/aes_siv.h"
17
#include "dpp.h"
18
#include "dpp_i.h"
19
20
21
#ifdef CONFIG_DPP2
22
23
static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash)
24
0
{
25
0
  if (hash) {
26
0
    wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash");
27
0
    wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH);
28
0
    wpabuf_put_le16(msg, SHA256_MAC_LEN);
29
0
    wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
30
0
  }
31
0
}
32
33
34
struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
35
            size_t csign_key_len,
36
            const u8 *net_access_key,
37
            size_t net_access_key_len,
38
            struct dpp_reconfig_id *id)
39
0
{
40
0
  struct wpabuf *msg = NULL;
41
0
  struct crypto_ec_key *csign = NULL;
42
0
  struct wpabuf *uncomp;
43
0
  u8 hash[SHA256_MAC_LEN];
44
0
  const u8 *addr[1];
45
0
  size_t len[1];
46
0
  int res;
47
0
  size_t attr_len;
48
0
  const struct dpp_curve_params *own_curve;
49
0
  struct crypto_ec_key *own_key;
50
0
  struct wpabuf *a_nonce = NULL, *e_id = NULL;
51
52
0
  wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
53
54
0
  own_key = dpp_set_keypair(&own_curve, net_access_key,
55
0
          net_access_key_len);
56
0
  if (!own_key) {
57
0
    wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
58
0
    goto fail;
59
0
  }
60
61
0
  csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
62
0
  if (!csign) {
63
0
    wpa_printf(MSG_ERROR,
64
0
         "DPP: Failed to parse local C-sign-key information");
65
0
    goto fail;
66
0
  }
67
68
0
  uncomp = crypto_ec_key_get_pubkey_point(csign, 1);
69
0
  crypto_ec_key_deinit(csign);
70
0
  if (!uncomp)
71
0
    goto fail;
72
0
  addr[0] = wpabuf_head(uncomp);
73
0
  len[0] = wpabuf_len(uncomp);
74
0
  wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]);
75
0
  res = sha256_vector(1, addr, len, hash);
76
0
  wpabuf_free(uncomp);
77
0
  if (res < 0)
78
0
    goto fail;
79
0
  wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)",
80
0
        hash, SHA256_MAC_LEN);
81
82
0
  if (dpp_update_reconfig_id(id) < 0) {
83
0
    wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id");
84
0
    goto fail;
85
0
  }
86
87
0
  a_nonce = crypto_ec_key_get_pubkey_point(id->a_nonce, 0);
88
0
  e_id = crypto_ec_key_get_pubkey_point(id->e_prime_id, 0);
89
0
  if (!a_nonce || !e_id)
90
0
    goto fail;
91
92
0
  attr_len = 4 + SHA256_MAC_LEN;
93
0
  attr_len += 4 + 2;
94
0
  attr_len += 4 + wpabuf_len(a_nonce);
95
0
  attr_len += 4 + wpabuf_len(e_id);
96
0
  msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len);
97
0
  if (!msg)
98
0
    goto fail;
99
100
  /* Configurator C-sign key Hash */
101
0
  dpp_build_attr_csign_key_hash(msg, hash);
102
103
  /* Finite Cyclic Group attribute */
104
0
  wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
105
0
       own_curve->ike_group);
106
0
  wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
107
0
  wpabuf_put_le16(msg, 2);
108
0
  wpabuf_put_le16(msg, own_curve->ike_group);
109
110
  /* A-NONCE */
111
0
  wpabuf_put_le16(msg, DPP_ATTR_A_NONCE);
112
0
  wpabuf_put_le16(msg, wpabuf_len(a_nonce));
113
0
  wpabuf_put_buf(msg, a_nonce);
114
115
  /* E'-id */
116
0
  wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID);
117
0
  wpabuf_put_le16(msg, wpabuf_len(e_id));
118
0
  wpabuf_put_buf(msg, e_id);
119
120
0
  wpa_hexdump_buf(MSG_DEBUG,
121
0
      "DPP: Reconfig Announcement frame attributes", msg);
122
0
fail:
123
0
  wpabuf_free(a_nonce);
124
0
  wpabuf_free(e_id);
125
0
  crypto_ec_key_deinit(own_key);
126
0
  return msg;
127
0
}
128
129
130
static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth)
131
0
{
132
0
  struct wpabuf *msg;
133
0
  size_t attr_len;
134
0
  u8 ver = DPP_VERSION;
135
136
  /* Build DPP Reconfig Authentication Request frame attributes */
137
0
  attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
138
0
    4 + auth->curve->nonce_len;
139
0
  msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len);
140
0
  if (!msg)
141
0
    return NULL;
142
143
  /* Transaction ID */
144
0
  wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
145
0
  wpabuf_put_le16(msg, 1);
146
0
  wpabuf_put_u8(msg, auth->transaction_id);
147
148
#ifdef CONFIG_TESTING_OPTIONS
149
  if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
150
    wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
151
    goto skip_proto_ver;
152
  }
153
  if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
154
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version");
155
    ver = 1;
156
  }
157
#endif /* CONFIG_TESTING_OPTIONS */
158
159
  /* Protocol Version */
160
0
  wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
161
0
  wpabuf_put_le16(msg, 1);
162
0
  wpabuf_put_u8(msg, ver);
163
164
#ifdef CONFIG_TESTING_OPTIONS
165
skip_proto_ver:
166
#endif /* CONFIG_TESTING_OPTIONS */
167
168
  /* DPP Connector */
169
0
  wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
170
0
  wpabuf_put_le16(msg, os_strlen(auth->conf->connector));
171
0
  wpabuf_put_str(msg, auth->conf->connector);
172
173
  /* C-nonce */
174
0
  wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE);
175
0
  wpabuf_put_le16(msg, auth->curve->nonce_len);
176
0
  wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len);
177
178
0
  wpa_hexdump_buf(MSG_DEBUG,
179
0
      "DPP: Reconfig Authentication Request frame attributes",
180
0
      msg);
181
182
0
  return msg;
183
0
}
184
185
186
static int
187
dpp_configurator_build_own_connector(struct dpp_configurator *conf,
188
             const struct dpp_curve_params *curve)
189
0
{
190
0
  struct wpabuf *dppcon = NULL;
191
0
  int ret = -1;
192
193
0
  if (conf->connector)
194
0
    return 0; /* already generated */
195
196
0
  wpa_printf(MSG_DEBUG,
197
0
       "DPP: Sign own Configurator Connector for reconfiguration with curve %s",
198
0
       conf->curve->name);
199
0
  conf->connector_key = dpp_gen_keypair(curve);
200
0
  if (!conf->connector_key)
201
0
    goto fail;
202
203
  /* Connector (JSON dppCon object) */
204
0
  dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3);
205
0
  if (!dppcon)
206
0
    goto fail;
207
0
  json_start_object(dppcon, NULL);
208
0
  json_start_array(dppcon, "groups");
209
0
  json_start_object(dppcon, NULL);
210
0
  json_add_string(dppcon, "groupId", "*");
211
0
  json_value_sep(dppcon);
212
0
  json_add_string(dppcon, "netRole", "configurator");
213
0
  json_end_object(dppcon);
214
0
  json_end_array(dppcon);
215
0
  json_value_sep(dppcon);
216
0
  if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL,
217
0
        curve) < 0) {
218
0
    wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
219
0
    goto fail;
220
0
  }
221
0
  json_end_object(dppcon);
222
0
  wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
223
0
       (const char *) wpabuf_head(dppcon));
224
225
0
  conf->connector = dpp_sign_connector(conf, dppcon);
226
0
  if (!conf->connector)
227
0
    goto fail;
228
0
  wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector);
229
230
0
  ret = 0;
231
0
fail:
232
0
  wpabuf_free(dppcon);
233
0
  return ret;
234
0
}
235
236
237
struct dpp_authentication *
238
dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
239
      struct dpp_configurator *conf, unsigned int freq, u16 group,
240
      const u8 *a_nonce_attr, size_t a_nonce_len,
241
      const u8 *e_id_attr, size_t e_id_len)
242
0
{
243
0
  struct dpp_authentication *auth;
244
0
  const struct dpp_curve_params *curve;
245
0
  struct crypto_ec_key *a_nonce, *e_prime_id;
246
0
  struct crypto_ec_point *e_id;
247
248
0
  curve = dpp_get_curve_ike_group(group);
249
0
  if (!curve) {
250
0
    wpa_printf(MSG_DEBUG,
251
0
         "DPP: Unsupported group %u - cannot reconfigure",
252
0
         group);
253
0
    return NULL;
254
0
  }
255
256
0
  if (!a_nonce_attr) {
257
0
    wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute");
258
0
    return NULL;
259
0
  }
260
0
  wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len);
261
0
  a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len);
262
0
  if (!a_nonce) {
263
0
    wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE");
264
0
    return NULL;
265
0
  }
266
0
  dpp_debug_print_key("A-NONCE", a_nonce);
267
268
0
  if (!e_id_attr) {
269
0
    wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute");
270
0
    return NULL;
271
0
  }
272
0
  e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
273
0
  if (!e_prime_id) {
274
0
    wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
275
0
    crypto_ec_key_deinit(a_nonce);
276
0
    return NULL;
277
0
  }
278
0
  dpp_debug_print_key("E'-id", e_prime_id);
279
0
  e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
280
0
  crypto_ec_key_deinit(a_nonce);
281
0
  crypto_ec_key_deinit(e_prime_id);
282
0
  if (!e_id) {
283
0
    wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
284
0
    return NULL;
285
0
  }
286
  /* TODO: could use E-id to determine whether reconfiguration with this
287
   * Enrollee has already been started and is waiting for updated
288
   * configuration instead of replying again before such configuration
289
   * becomes available */
290
0
  crypto_ec_point_deinit(e_id, 1);
291
292
0
  auth = dpp_alloc_auth(dpp, msg_ctx);
293
0
  if (!auth)
294
0
    return NULL;
295
296
0
  auth->conf = conf;
297
0
  auth->reconfig = 1;
298
0
  auth->initiator = 1;
299
0
  auth->waiting_auth_resp = 1;
300
0
  auth->allowed_roles = DPP_CAPAB_CONFIGURATOR;
301
0
  auth->configurator = 1;
302
0
  auth->curve = curve;
303
0
  auth->transaction_id = 1;
304
0
  if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
305
0
    goto fail;
306
307
0
  if (dpp_configurator_build_own_connector(conf, curve) < 0)
308
0
    goto fail;
309
310
0
  if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) {
311
0
    wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce");
312
0
    goto fail;
313
0
  }
314
315
0
  auth->reconfig_req_msg = dpp_reconfig_build_req(auth);
316
0
  if (!auth->reconfig_req_msg)
317
0
    goto fail;
318
319
0
out:
320
0
  return auth;
321
0
fail:
322
0
  dpp_auth_deinit(auth);
323
0
  auth = NULL;
324
0
  goto out;
325
0
}
326
327
328
static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
329
           const char *own_connector,
330
           struct wpabuf *conn_status)
331
0
{
332
0
  struct wpabuf *msg = NULL, *clear, *pr = NULL;
333
0
  u8 *attr_start, *attr_end;
334
0
  size_t clear_len, attr_len, len[2];
335
0
  const u8 *addr[2];
336
0
  u8 *wrapped;
337
0
  int res = -1;
338
339
  /* Build DPP Reconfig Authentication Response frame attributes */
340
0
  clear_len = 4 + auth->curve->nonce_len +
341
0
    4 + wpabuf_len(conn_status);
342
0
  clear = wpabuf_alloc(clear_len);
343
0
  if (!clear)
344
0
    goto fail;
345
346
  /* C-nonce (wrapped) */
347
0
  wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
348
0
  wpabuf_put_le16(clear, auth->curve->nonce_len);
349
0
  wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
350
351
  /* Connection Status (wrapped) */
352
0
  wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
353
0
  wpabuf_put_le16(clear, wpabuf_len(conn_status));
354
0
  wpabuf_put_buf(clear, conn_status);
355
356
0
  pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
357
0
  if (!pr)
358
0
    goto fail;
359
360
0
  attr_len = 4 + 1 + 4 + 1 +
361
0
    4 + os_strlen(own_connector) +
362
0
    4 + auth->curve->nonce_len +
363
0
    4 + wpabuf_len(pr) +
364
0
    4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
365
0
  msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len);
366
0
  if (!msg)
367
0
    goto fail;
368
369
0
  attr_start = wpabuf_put(msg, 0);
370
371
  /* Transaction ID */
372
0
  wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
373
0
  wpabuf_put_le16(msg, 1);
374
0
  wpabuf_put_u8(msg, auth->transaction_id);
375
376
  /* Protocol Version */
377
0
  wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
378
0
  wpabuf_put_le16(msg, 1);
379
0
  wpabuf_put_u8(msg, DPP_VERSION);
380
381
  /* R-Connector */
382
0
  wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
383
0
  wpabuf_put_le16(msg, os_strlen(own_connector));
384
0
  wpabuf_put_str(msg, own_connector);
385
386
  /* E-nonce */
387
0
  wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE);
388
0
  wpabuf_put_le16(msg, auth->curve->nonce_len);
389
0
  wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len);
390
391
  /* Responder Protocol Key (Pr) */
392
0
  wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
393
0
  wpabuf_put_le16(msg, wpabuf_len(pr));
394
0
  wpabuf_put_buf(msg, pr);
395
396
0
  attr_end = wpabuf_put(msg, 0);
397
398
  /* OUI, OUI type, Crypto Suite, DPP frame type */
399
0
  addr[0] = wpabuf_head_u8(msg) + 2;
400
0
  len[0] = 3 + 1 + 1 + 1;
401
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
402
403
  /* Attributes before Wrapped Data */
404
0
  addr[1] = attr_start;
405
0
  len[1] = attr_end - attr_start;
406
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
407
408
  /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */
409
0
  wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
410
0
  wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
411
0
  wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
412
413
0
  wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
414
0
  if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
415
0
          wpabuf_head(clear), wpabuf_len(clear),
416
0
          2, addr, len, wrapped) < 0)
417
0
    goto fail;
418
419
0
  wpa_hexdump_buf(MSG_DEBUG,
420
0
      "DPP: Reconfig Authentication Response frame attributes",
421
0
      msg);
422
423
0
  wpabuf_free(auth->reconfig_resp_msg);
424
0
  auth->reconfig_resp_msg = msg;
425
426
0
  res = 0;
427
0
out:
428
0
  wpabuf_free(clear);
429
0
  wpabuf_free(pr);
430
0
  return res;
431
0
fail:
432
0
  wpabuf_free(msg);
433
0
  goto out;
434
0
}
435
436
437
struct dpp_authentication *
438
dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx,
439
       const char *own_connector,
440
       const u8 *net_access_key, size_t net_access_key_len,
441
       const u8 *csign_key, size_t csign_key_len,
442
       unsigned int freq, const u8 *hdr,
443
       const u8 *attr_start, size_t attr_len)
444
0
{
445
0
  struct dpp_authentication *auth = NULL;
446
0
  const u8 *trans_id, *version, *i_connector, *c_nonce;
447
0
  u16 trans_id_len, version_len, i_connector_len, c_nonce_len;
448
0
  struct dpp_signed_connector_info info;
449
0
  enum dpp_status_error res;
450
0
  struct json_token *root = NULL, *own_root = NULL, *token;
451
0
  unsigned char *own_conn = NULL;
452
0
  struct wpabuf *conn_status = NULL;
453
454
0
  os_memset(&info, 0, sizeof(info));
455
456
0
  trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
457
0
             &trans_id_len);
458
0
  if (!trans_id || trans_id_len != 1) {
459
0
    wpa_printf(MSG_DEBUG,
460
0
         "DPP: Peer did not include Transaction ID");
461
0
    goto fail;
462
0
  }
463
464
0
  version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
465
0
             &version_len);
466
0
  if (!version || version_len < 1 || version[0] < 2) {
467
0
    wpa_printf(MSG_DEBUG,
468
0
         "DPP: Missing or invalid Protocol Version attribute");
469
0
    goto fail;
470
0
  }
471
472
0
  i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
473
0
             &i_connector_len);
474
0
  if (!i_connector) {
475
0
    wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute");
476
0
    goto fail;
477
0
  }
478
0
  wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector",
479
0
        i_connector, i_connector_len);
480
481
0
  c_nonce = dpp_get_attr(attr_start, attr_len,
482
0
             DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
483
0
  if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) {
484
0
    wpa_printf(MSG_DEBUG,
485
0
         "DPP: Missing or invalid C-nonce attribute");
486
0
    goto fail;
487
0
  }
488
0
  wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
489
490
0
  res = dpp_check_signed_connector(&info, csign_key, csign_key_len,
491
0
           i_connector, i_connector_len);
492
0
  if (res != DPP_STATUS_OK) {
493
0
    wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector");
494
0
    goto fail;
495
0
  }
496
497
0
  root = json_parse((const char *) info.payload, info.payload_len);
498
0
  own_root = dpp_parse_own_connector(own_connector);
499
0
  if (!root || !own_root ||
500
0
      !dpp_connector_match_groups(own_root, root, true)) {
501
0
    wpa_printf(MSG_DEBUG,
502
0
         "DPP: I-Connector does not include compatible group netrole with own connector");
503
0
    goto fail;
504
0
  }
505
506
0
  token = json_get_member(root, "expiry");
507
0
  if (token && token->type == JSON_STRING &&
508
0
      dpp_key_expired(token->string, NULL)) {
509
0
    wpa_printf(MSG_DEBUG,
510
0
         "DPP: I-Connector (netAccessKey) has expired");
511
0
    goto fail;
512
0
  }
513
514
0
  token = json_get_member(root, "netAccessKey");
515
0
  if (!token || token->type != JSON_OBJECT) {
516
0
    wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
517
0
    goto fail;
518
0
  }
519
520
0
  auth = dpp_alloc_auth(dpp, msg_ctx);
521
0
  if (!auth)
522
0
    return NULL;
523
524
0
  auth->reconfig = 1;
525
0
  auth->allowed_roles = DPP_CAPAB_ENROLLEE;
526
0
  if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0)
527
0
    goto fail;
528
529
0
  auth->transaction_id = trans_id[0];
530
531
0
  auth->peer_version = version[0];
532
0
  wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
533
0
       auth->peer_version);
534
535
0
  os_memcpy(auth->c_nonce, c_nonce, c_nonce_len);
536
537
0
  if (dpp_reconfig_derive_ke_responder(auth, net_access_key,
538
0
               net_access_key_len, token) < 0)
539
0
    goto fail;
540
541
0
  if (c_nonce_len != auth->curve->nonce_len) {
542
0
    wpa_printf(MSG_DEBUG,
543
0
         "DPP: Unexpected C-nonce length %u (curve nonce len %zu)",
544
0
         c_nonce_len, auth->curve->nonce_len);
545
0
    goto fail;
546
0
  }
547
548
  /* Build Connection Status object */
549
  /* TODO: Get appropriate result value */
550
  /* TODO: ssid64 and channelList */
551
0
  conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL);
552
0
  if (!conn_status)
553
0
    goto fail;
554
555
0
  if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0)
556
0
    goto fail;
557
558
0
out:
559
0
  os_free(info.payload);
560
0
  os_free(own_conn);
561
0
  json_free(root);
562
0
  json_free(own_root);
563
0
  wpabuf_free(conn_status);
564
0
  return auth;
565
0
fail:
566
0
  dpp_auth_deinit(auth);
567
0
  auth = NULL;
568
0
  goto out;
569
0
}
570
571
572
static struct wpabuf *
573
dpp_reconfig_build_conf(struct dpp_authentication *auth)
574
0
{
575
0
  struct wpabuf *msg = NULL, *clear;
576
0
  u8 *attr_start, *attr_end;
577
0
  size_t clear_len, attr_len, len[2];
578
0
  const u8 *addr[2];
579
0
  u8 *wrapped;
580
0
  u8 flags;
581
582
  /* Build DPP Reconfig Authentication Confirm frame attributes */
583
0
  clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) +
584
0
    4 + 1;
585
0
  clear = wpabuf_alloc(clear_len);
586
0
  if (!clear)
587
0
    goto fail;
588
589
  /* Transaction ID */
590
0
  wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID);
591
0
  wpabuf_put_le16(clear, 1);
592
0
  wpabuf_put_u8(clear, auth->transaction_id);
593
594
  /* Protocol Version */
595
0
  wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION);
596
0
  wpabuf_put_le16(clear, 1);
597
0
  wpabuf_put_u8(clear, auth->peer_version);
598
599
  /* C-nonce (wrapped) */
600
0
  wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE);
601
0
  wpabuf_put_le16(clear, auth->curve->nonce_len);
602
0
  wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len);
603
604
  /* E-nonce (wrapped) */
605
0
  wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
606
0
  wpabuf_put_le16(clear, auth->curve->nonce_len);
607
0
  wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len);
608
609
  /* Reconfig-Flags (wrapped) */
610
0
  flags = DPP_CONFIG_REPLACEKEY;
611
0
  wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS);
612
0
  wpabuf_put_le16(clear, 1);
613
0
  wpabuf_put_u8(clear, flags);
614
615
0
  attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE;
616
0
  attr_len += 4 + 1;
617
0
  msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len);
618
0
  if (!msg)
619
0
    goto fail;
620
621
0
  attr_start = wpabuf_put(msg, 0);
622
623
  /* DPP Status */
624
0
  dpp_build_attr_status(msg, DPP_STATUS_OK);
625
626
0
  attr_end = wpabuf_put(msg, 0);
627
628
  /* OUI, OUI type, Crypto Suite, DPP frame type */
629
0
  addr[0] = wpabuf_head_u8(msg) + 2;
630
0
  len[0] = 3 + 1 + 1 + 1;
631
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
632
633
  /* Attributes before Wrapped Data */
634
0
  addr[1] = attr_start;
635
0
  len[1] = attr_end - attr_start;
636
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
637
638
  /* Wrapped Data */
639
0
  wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
640
0
  wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
641
0
  wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
642
643
0
  wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
644
0
  if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
645
0
          wpabuf_head(clear), wpabuf_len(clear),
646
0
          2, addr, len, wrapped) < 0)
647
0
    goto fail;
648
649
0
  wpa_hexdump_buf(MSG_DEBUG,
650
0
      "DPP: Reconfig Authentication Confirm frame attributes",
651
0
      msg);
652
653
0
out:
654
0
  wpabuf_free(clear);
655
0
  return msg;
656
0
fail:
657
0
  wpabuf_free(msg);
658
0
  msg = NULL;
659
0
  goto out;
660
0
}
661
662
663
struct wpabuf *
664
dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
665
       const u8 *attr_start, size_t attr_len)
666
0
{
667
0
  const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data,
668
0
    *c_nonce, *e_nonce, *conn_status;
669
0
  u16 trans_id_len, version_len, r_connector_len, r_proto_len,
670
0
    wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len;
671
0
  struct wpabuf *conf = NULL;
672
0
  char *signed_connector = NULL;
673
0
  struct dpp_signed_connector_info info;
674
0
  enum dpp_status_error res;
675
0
  struct json_token *root = NULL, *token, *conn_status_json = NULL;
676
0
  const u8 *addr[2];
677
0
  size_t len[2];
678
0
  u8 *unwrapped = NULL;
679
0
  size_t unwrapped_len = 0;
680
681
0
  os_memset(&info, 0, sizeof(info));
682
683
0
  if (!auth->reconfig || !auth->configurator)
684
0
    goto fail;
685
686
0
  wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
687
0
            &wrapped_data_len);
688
0
  if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
689
0
    dpp_auth_fail(auth,
690
0
            "Missing or invalid required Wrapped Data attribute");
691
0
    goto fail;
692
0
  }
693
0
  wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
694
0
        wrapped_data, wrapped_data_len);
695
0
  attr_len = wrapped_data - 4 - attr_start;
696
697
0
  trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID,
698
0
             &trans_id_len);
699
0
  if (!trans_id || trans_id_len != 1) {
700
0
    dpp_auth_fail(auth, "Peer did not include Transaction ID");
701
0
    goto fail;
702
0
  }
703
0
  if (trans_id[0] != auth->transaction_id) {
704
0
    dpp_auth_fail(auth, "Transaction ID mismatch");
705
0
    goto fail;
706
0
  }
707
708
0
  version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
709
0
             &version_len);
710
0
  if (!version || version_len < 1 || version[0] < 2) {
711
0
    dpp_auth_fail(auth,
712
0
            "Missing or invalid Protocol Version attribute");
713
0
    goto fail;
714
0
  }
715
0
  auth->peer_version = version[0];
716
0
  wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
717
0
       auth->peer_version);
718
719
0
  r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR,
720
0
           &r_connector_len);
721
0
  if (!r_connector) {
722
0
    dpp_auth_fail(auth, " Missing R-Connector attribute");
723
0
    goto fail;
724
0
  }
725
0
  wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector",
726
0
        r_connector, r_connector_len);
727
728
0
  e_nonce = dpp_get_attr(attr_start, attr_len,
729
0
             DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
730
0
  if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
731
0
    dpp_auth_fail(auth, "Missing or invalid E-nonce");
732
0
    goto fail;
733
0
  }
734
0
  wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
735
0
  os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
736
737
0
  r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
738
0
             &r_proto_len);
739
0
  if (!r_proto) {
740
0
    dpp_auth_fail(auth,
741
0
            "Missing required Responder Protocol Key attribute");
742
0
    goto fail;
743
0
  }
744
0
  wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
745
0
        r_proto, r_proto_len);
746
747
0
  signed_connector = os_malloc(r_connector_len + 1);
748
0
  if (!signed_connector)
749
0
    goto fail;
750
0
  os_memcpy(signed_connector, r_connector, r_connector_len);
751
0
  signed_connector[r_connector_len] = '\0';
752
753
0
  res = dpp_process_signed_connector(&info, auth->conf->csign,
754
0
             signed_connector);
755
0
  if (res != DPP_STATUS_OK) {
756
0
    dpp_auth_fail(auth, "Invalid R-Connector");
757
0
    goto fail;
758
0
  }
759
760
0
  root = json_parse((const char *) info.payload, info.payload_len);
761
0
  if (!root) {
762
0
    dpp_auth_fail(auth, "Invalid Connector payload");
763
0
    goto fail;
764
0
  }
765
766
  /* Do not check netAccessKey expiration for reconfiguration to allow
767
   * expired Connector to be updated. */
768
769
0
  token = json_get_member(root, "netAccessKey");
770
0
  if (!token || token->type != JSON_OBJECT) {
771
0
    dpp_auth_fail(auth, "No netAccessKey object found");
772
0
    goto fail;
773
0
  }
774
775
0
  if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len,
776
0
               token) < 0)
777
0
    goto fail;
778
779
0
  addr[0] = hdr;
780
0
  len[0] = DPP_HDR_LEN;
781
0
  addr[1] = attr_start;
782
0
  len[1] = attr_len;
783
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
784
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
785
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
786
0
        wrapped_data, wrapped_data_len);
787
0
  unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
788
0
  unwrapped = os_malloc(unwrapped_len);
789
0
  if (!unwrapped)
790
0
    goto fail;
791
0
  if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
792
0
          wrapped_data, wrapped_data_len,
793
0
          2, addr, len, unwrapped) < 0) {
794
0
    dpp_auth_fail(auth, "AES-SIV decryption failed");
795
0
    goto fail;
796
0
  }
797
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
798
0
        unwrapped, unwrapped_len);
799
800
0
  if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
801
0
    dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
802
0
    goto fail;
803
0
  }
804
805
0
  c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
806
0
             DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
807
0
  if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
808
0
      os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
809
0
    dpp_auth_fail(auth, "Missing or invalid C-nonce");
810
0
    goto fail;
811
0
  }
812
0
  wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
813
814
0
  conn_status = dpp_get_attr(unwrapped, unwrapped_len,
815
0
           DPP_ATTR_CONN_STATUS, &conn_status_len);
816
0
  if (!conn_status) {
817
0
    dpp_auth_fail(auth, "Missing Connection Status attribute");
818
0
    goto fail;
819
0
  }
820
0
  wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus",
821
0
        conn_status, conn_status_len);
822
823
0
  conn_status_json = json_parse((const char *) conn_status,
824
0
              conn_status_len);
825
0
  if (!conn_status_json) {
826
0
    dpp_auth_fail(auth, "Could not parse connStatus");
827
0
    goto fail;
828
0
  }
829
  /* TODO: use connStatus information */
830
831
0
  conf = dpp_reconfig_build_conf(auth);
832
0
  if (conf)
833
0
    auth->reconfig_success = true;
834
835
0
out:
836
0
  json_free(root);
837
0
  json_free(conn_status_json);
838
0
  bin_clear_free(unwrapped, unwrapped_len);
839
0
  os_free(info.payload);
840
0
  os_free(signed_connector);
841
0
  return conf;
842
0
fail:
843
0
  wpabuf_free(conf);
844
0
  conf = NULL;
845
0
  goto out;
846
0
}
847
848
849
int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
850
            const u8 *attr_start, size_t attr_len)
851
0
{
852
0
  const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce,
853
0
    *reconfig_flags, *status;
854
0
  u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len,
855
0
    e_nonce_len, reconfig_flags_len, status_len;
856
0
  const u8 *addr[2];
857
0
  size_t len[2];
858
0
  u8 *unwrapped = NULL;
859
0
  size_t unwrapped_len = 0;
860
0
  int res = -1;
861
0
  u8 flags;
862
863
0
  if (!auth->reconfig || auth->configurator)
864
0
    goto fail;
865
866
0
  wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
867
0
            &wrapped_data_len);
868
0
  if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
869
0
    dpp_auth_fail(auth,
870
0
            "Missing or invalid required Wrapped Data attribute");
871
0
    goto fail;
872
0
  }
873
0
  wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
874
0
        wrapped_data, wrapped_data_len);
875
0
  attr_len = wrapped_data - 4 - attr_start;
876
877
0
  status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
878
0
            &status_len);
879
0
  if (!status || status_len < 1) {
880
0
    dpp_auth_fail(auth,
881
0
            "Missing or invalid required DPP Status attribute");
882
0
    goto fail;
883
0
  }
884
0
  wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
885
0
  if (status[0] != DPP_STATUS_OK) {
886
0
    dpp_auth_fail(auth,
887
0
            "Reconfiguration did not complete successfully");
888
0
    goto fail;
889
0
  }
890
891
0
  addr[0] = hdr;
892
0
  len[0] = DPP_HDR_LEN;
893
0
  addr[1] = attr_start;
894
0
  len[1] = attr_len;
895
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
896
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
897
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
898
0
        wrapped_data, wrapped_data_len);
899
0
  unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
900
0
  unwrapped = os_malloc(unwrapped_len);
901
0
  if (!unwrapped)
902
0
    goto fail;
903
0
  if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
904
0
          wrapped_data, wrapped_data_len,
905
0
          2, addr, len, unwrapped) < 0) {
906
0
    dpp_auth_fail(auth, "AES-SIV decryption failed");
907
0
    goto fail;
908
0
  }
909
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
910
0
        unwrapped, unwrapped_len);
911
912
0
  if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
913
0
    dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
914
0
    goto fail;
915
0
  }
916
917
0
  trans_id = dpp_get_attr(unwrapped, unwrapped_len,
918
0
        DPP_ATTR_TRANSACTION_ID, &trans_id_len);
919
0
  if (!trans_id || trans_id_len != 1 ||
920
0
      trans_id[0] != auth->transaction_id) {
921
0
    dpp_auth_fail(auth,
922
0
            "Peer did not include valid Transaction ID");
923
0
    goto fail;
924
0
  }
925
926
0
  version = dpp_get_attr(unwrapped, unwrapped_len,
927
0
             DPP_ATTR_PROTOCOL_VERSION, &version_len);
928
0
  if (!version || version_len < 1 || version[0] != DPP_VERSION) {
929
0
    dpp_auth_fail(auth,
930
0
            "Missing or invalid Protocol Version attribute");
931
0
    goto fail;
932
0
  }
933
934
0
  c_nonce = dpp_get_attr(unwrapped, unwrapped_len,
935
0
             DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len);
936
0
  if (!c_nonce || c_nonce_len != auth->curve->nonce_len ||
937
0
      os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) {
938
0
    dpp_auth_fail(auth, "Missing or invalid C-nonce");
939
0
    goto fail;
940
0
  }
941
0
  wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len);
942
943
0
  e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
944
0
             DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len);
945
0
  if (!e_nonce || e_nonce_len != auth->curve->nonce_len ||
946
0
      os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
947
0
    dpp_auth_fail(auth, "Missing or invalid E-nonce");
948
0
    goto fail;
949
0
  }
950
0
  wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len);
951
952
0
  reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len,
953
0
              DPP_ATTR_RECONFIG_FLAGS,
954
0
              &reconfig_flags_len);
955
0
  if (!reconfig_flags || reconfig_flags_len < 1) {
956
0
    dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags");
957
0
    goto fail;
958
0
  }
959
0
  flags = reconfig_flags[0] & BIT(0);
960
0
  wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags);
961
0
  auth->reconfig_connector_key = flags;
962
963
0
  auth->reconfig_success = true;
964
0
  res = 0;
965
0
fail:
966
0
  bin_clear_free(unwrapped, unwrapped_len);
967
0
  return res;
968
0
}
969
970
#endif /* CONFIG_DPP2 */