Coverage Report

Created: 2025-04-24 06:18

/src/hostap/src/common/dpp_pkex.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * DPP PKEX functionality
3
 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4
 * Copyright (c) 2018-2020, The Linux Foundation
5
 *
6
 * This software may be distributed under the terms of the BSD license.
7
 * See README for more details.
8
 */
9
10
#include "utils/includes.h"
11
12
#include "utils/common.h"
13
#include "common/wpa_ctrl.h"
14
#include "crypto/aes.h"
15
#include "crypto/aes_siv.h"
16
#include "crypto/crypto.h"
17
#include "dpp.h"
18
#include "dpp_i.h"
19
20
21
#ifdef CONFIG_TESTING_OPTIONS
22
u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
23
u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
24
u8 dpp_pkex_ephemeral_key_override[600];
25
size_t dpp_pkex_ephemeral_key_override_len = 0;
26
#endif /* CONFIG_TESTING_OPTIONS */
27
28
29
static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
30
               bool v2)
31
0
{
32
0
  struct crypto_ec *ec = NULL;
33
0
  struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
34
0
  u8 *Mx, *My;
35
0
  struct wpabuf *msg = NULL;
36
0
  size_t attr_len;
37
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
38
39
0
  wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
40
0
       v2 ? "" : "Version 1 ");
41
42
  /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
43
0
  Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
44
0
        pkex->code_len, pkex->identifier, &ec);
45
0
  if (!Qi)
46
0
    goto fail;
47
48
  /* Generate a random ephemeral keypair x/X */
49
#ifdef CONFIG_TESTING_OPTIONS
50
  if (dpp_pkex_ephemeral_key_override_len) {
51
    const struct dpp_curve_params *tmp_curve;
52
53
    wpa_printf(MSG_INFO,
54
         "DPP: TESTING - override ephemeral key x/X");
55
    pkex->x = dpp_set_keypair(&tmp_curve,
56
            dpp_pkex_ephemeral_key_override,
57
            dpp_pkex_ephemeral_key_override_len);
58
  } else {
59
    pkex->x = dpp_gen_keypair(curve);
60
  }
61
#else /* CONFIG_TESTING_OPTIONS */
62
0
  pkex->x = dpp_gen_keypair(curve);
63
0
#endif /* CONFIG_TESTING_OPTIONS */
64
0
  if (!pkex->x)
65
0
    goto fail;
66
67
  /* M = X + Qi */
68
0
  X = crypto_ec_key_get_public_key(pkex->x);
69
0
  M = crypto_ec_point_init(ec);
70
0
  if (!X || !M)
71
0
    goto fail;
72
0
  crypto_ec_point_debug_print(ec, X, "DPP: X");
73
74
0
  if (crypto_ec_point_add(ec, X, Qi, M))
75
0
    goto fail;
76
0
  crypto_ec_point_debug_print(ec, M, "DPP: M");
77
78
  /* Initiator -> Responder: group, [identifier,] M */
79
0
  attr_len = 4 + 2;
80
0
#ifdef CONFIG_DPP2
81
0
  if (v2)
82
0
    attr_len += 4 + 1;
83
0
#endif /* CONFIG_DPP2 */
84
0
  if (pkex->identifier)
85
0
    attr_len += 4 + os_strlen(pkex->identifier);
86
0
  attr_len += 4 + 2 * curve->prime_len;
87
0
  msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
88
0
          DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
89
0
  if (!msg)
90
0
    goto fail;
91
92
0
#ifdef CONFIG_DPP2
93
0
  if (v2) {
94
    /* Protocol Version */
95
0
    wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
96
0
    wpabuf_put_le16(msg, 1);
97
0
    wpabuf_put_u8(msg, DPP_VERSION);
98
0
  }
99
0
#endif /* CONFIG_DPP2 */
100
101
#ifdef CONFIG_TESTING_OPTIONS
102
  if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
103
    wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
104
    goto skip_finite_cyclic_group;
105
  }
106
#endif /* CONFIG_TESTING_OPTIONS */
107
108
  /* Finite Cyclic Group attribute */
109
0
  wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
110
0
  wpabuf_put_le16(msg, 2);
111
0
  wpabuf_put_le16(msg, curve->ike_group);
112
113
#ifdef CONFIG_TESTING_OPTIONS
114
skip_finite_cyclic_group:
115
#endif /* CONFIG_TESTING_OPTIONS */
116
117
  /* Code Identifier attribute */
118
0
  if (pkex->identifier) {
119
0
    wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
120
0
    wpabuf_put_le16(msg, os_strlen(pkex->identifier));
121
0
    wpabuf_put_str(msg, pkex->identifier);
122
0
  }
123
124
#ifdef CONFIG_TESTING_OPTIONS
125
  if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
126
    wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
127
    goto out;
128
  }
129
#endif /* CONFIG_TESTING_OPTIONS */
130
131
  /* M in Encrypted Key attribute */
132
0
  wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
133
0
  wpabuf_put_le16(msg, 2 * curve->prime_len);
134
135
#ifdef CONFIG_TESTING_OPTIONS
136
  if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
137
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
138
    if (dpp_test_gen_invalid_key(msg, curve) < 0)
139
      goto fail;
140
    goto out;
141
  }
142
#endif /* CONFIG_TESTING_OPTIONS */
143
144
0
  Mx = wpabuf_put(msg, curve->prime_len);
145
0
  My = wpabuf_put(msg, curve->prime_len);
146
0
  if (crypto_ec_point_to_bin(ec, M, Mx, My))
147
0
    goto fail;
148
0
  wpabuf_free(pkex->enc_key);
149
0
  pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len);
150
151
0
  os_memcpy(pkex->Mx, Mx, curve->prime_len);
152
153
0
out:
154
0
  crypto_ec_point_deinit(X, 1);
155
0
  crypto_ec_point_deinit(M, 1);
156
0
  crypto_ec_point_deinit(Qi, 1);
157
0
  crypto_ec_deinit(ec);
158
0
  return msg;
159
0
fail:
160
0
  wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
161
0
  wpabuf_free(msg);
162
0
  msg = NULL;
163
0
  goto out;
164
0
}
165
166
167
static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
168
0
{
169
0
  wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
170
0
}
171
172
173
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
174
        const u8 *own_mac,
175
        const char *identifier, const char *code,
176
        size_t code_len, bool v2)
177
0
{
178
0
  struct dpp_pkex *pkex;
179
180
#ifdef CONFIG_TESTING_OPTIONS
181
  if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
182
    wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
183
         MAC2STR(dpp_pkex_own_mac_override));
184
    own_mac = dpp_pkex_own_mac_override;
185
  }
186
#endif /* CONFIG_TESTING_OPTIONS */
187
188
0
  pkex = os_zalloc(sizeof(*pkex));
189
0
  if (!pkex)
190
0
    return NULL;
191
0
  pkex->msg_ctx = msg_ctx;
192
0
  pkex->initiator = 1;
193
0
  pkex->v2 = v2;
194
0
  pkex->own_bi = bi;
195
0
  os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
196
0
  if (identifier) {
197
0
    pkex->identifier = os_strdup(identifier);
198
0
    if (!pkex->identifier)
199
0
      goto fail;
200
0
  }
201
0
  pkex->code = os_memdup(code, code_len);
202
0
  if (!pkex->code)
203
0
    goto fail;
204
0
  pkex->code_len = code_len;
205
0
  pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
206
0
  if (!pkex->exchange_req)
207
0
    goto fail;
208
0
  return pkex;
209
0
fail:
210
0
  dpp_pkex_free(pkex);
211
0
  return NULL;
212
0
}
213
214
215
static struct wpabuf *
216
dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
217
           enum dpp_status_error status,
218
           const u8 *Nx, const u8 *Ny)
219
0
{
220
0
  struct wpabuf *msg = NULL;
221
0
  size_t attr_len;
222
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
223
224
  /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
225
   * N */
226
0
  attr_len = 4 + 1;
227
0
#ifdef CONFIG_DPP2
228
0
  if (pkex->v2)
229
0
    attr_len += 4 + 1;
230
0
#endif /* CONFIG_DPP2 */
231
0
  if (pkex->identifier)
232
0
    attr_len += 4 + os_strlen(pkex->identifier);
233
0
  attr_len += 4 + 2 * curve->prime_len;
234
0
  msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
235
0
  if (!msg)
236
0
    goto fail;
237
238
#ifdef CONFIG_TESTING_OPTIONS
239
  if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
240
    wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
241
    goto skip_status;
242
  }
243
244
  if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
245
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
246
    status = 255;
247
  }
248
#endif /* CONFIG_TESTING_OPTIONS */
249
250
  /* DPP Status */
251
0
  dpp_build_attr_status(msg, status);
252
253
#ifdef CONFIG_TESTING_OPTIONS
254
skip_status:
255
#endif /* CONFIG_TESTING_OPTIONS */
256
257
0
#ifdef CONFIG_DPP2
258
0
  if (pkex->v2) {
259
    /* Protocol Version */
260
0
    wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
261
0
    wpabuf_put_le16(msg, 1);
262
0
    wpabuf_put_u8(msg, DPP_VERSION);
263
0
  }
264
0
#endif /* CONFIG_DPP2 */
265
266
  /* Code Identifier attribute */
267
0
  if (pkex->identifier) {
268
0
    wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
269
0
    wpabuf_put_le16(msg, os_strlen(pkex->identifier));
270
0
    wpabuf_put_str(msg, pkex->identifier);
271
0
  }
272
273
0
  if (status != DPP_STATUS_OK)
274
0
    goto skip_encrypted_key;
275
276
#ifdef CONFIG_TESTING_OPTIONS
277
  if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
278
    wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
279
    goto skip_encrypted_key;
280
  }
281
#endif /* CONFIG_TESTING_OPTIONS */
282
283
  /* N in Encrypted Key attribute */
284
0
  wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
285
0
  wpabuf_put_le16(msg, 2 * curve->prime_len);
286
287
#ifdef CONFIG_TESTING_OPTIONS
288
  if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
289
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
290
    if (dpp_test_gen_invalid_key(msg, curve) < 0)
291
      goto fail;
292
    goto skip_encrypted_key;
293
  }
294
#endif /* CONFIG_TESTING_OPTIONS */
295
296
0
  wpabuf_put_data(msg, Nx, curve->prime_len);
297
0
  wpabuf_put_data(msg, Ny, curve->prime_len);
298
0
  os_memcpy(pkex->Nx, Nx, curve->prime_len);
299
300
0
skip_encrypted_key:
301
0
  if (status == DPP_STATUS_BAD_GROUP) {
302
    /* Finite Cyclic Group attribute */
303
0
    wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
304
0
    wpabuf_put_le16(msg, 2);
305
0
    wpabuf_put_le16(msg, curve->ike_group);
306
0
  }
307
308
0
  return msg;
309
0
fail:
310
0
  wpabuf_free(msg);
311
0
  return NULL;
312
0
}
313
314
315
static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
316
             const char *identifier)
317
0
{
318
0
  if (!attr_id && identifier) {
319
0
    wpa_printf(MSG_DEBUG,
320
0
         "DPP: No PKEX code identifier received, but expected one");
321
0
    return 0;
322
0
  }
323
324
0
  if (attr_id && !identifier) {
325
0
    wpa_printf(MSG_DEBUG,
326
0
         "DPP: PKEX code identifier received, but not expecting one");
327
0
    return 0;
328
0
  }
329
330
0
  if (attr_id && identifier &&
331
0
      (os_strlen(identifier) != attr_id_len ||
332
0
       os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
333
0
    wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
334
0
    return 0;
335
0
  }
336
337
0
  return 1;
338
0
}
339
340
341
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
342
             struct dpp_bootstrap_info *bi,
343
             const u8 *own_mac,
344
             const u8 *peer_mac,
345
             const char *identifier,
346
             const char *code, size_t code_len,
347
             const u8 *buf, size_t len, bool v2)
348
0
{
349
0
  const u8 *attr_group, *attr_id, *attr_key;
350
0
  u16 attr_group_len, attr_id_len, attr_key_len;
351
0
  const struct dpp_curve_params *curve = bi->curve;
352
0
  u16 ike_group;
353
0
  struct dpp_pkex *pkex = NULL;
354
0
  struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
355
0
    *N = NULL, *Y = NULL;
356
0
  struct crypto_ec *ec = NULL;
357
0
  u8 *x_coord = NULL, *y_coord = NULL;
358
0
  u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
359
0
  size_t Kx_len;
360
0
  int res;
361
0
  u8 peer_version = 0;
362
363
0
  if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
364
0
    wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
365
0
      "PKEX counter t limit reached - ignore message");
366
0
    return NULL;
367
0
  }
368
369
0
#ifdef CONFIG_DPP2
370
0
  if (v2) {
371
0
    const u8 *version;
372
0
    u16 version_len;
373
374
0
    version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
375
0
               &version_len);
376
0
    if (!version || version_len < 1 || version[0] == 0) {
377
0
      wpa_msg(msg_ctx, MSG_INFO,
378
0
        "Missing or invalid Protocol Version attribute");
379
0
      return NULL;
380
0
    }
381
0
    peer_version = version[0];
382
0
    wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
383
0
         peer_version);
384
0
  }
385
0
#endif /* CONFIG_DPP2 */
386
387
#ifdef CONFIG_TESTING_OPTIONS
388
  if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
389
    wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
390
         MAC2STR(dpp_pkex_peer_mac_override));
391
    peer_mac = dpp_pkex_peer_mac_override;
392
  }
393
  if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
394
    wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
395
         MAC2STR(dpp_pkex_own_mac_override));
396
    own_mac = dpp_pkex_own_mac_override;
397
  }
398
#endif /* CONFIG_TESTING_OPTIONS */
399
400
0
  attr_id_len = 0;
401
0
  attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
402
0
             &attr_id_len);
403
0
  if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
404
0
    return NULL;
405
406
0
  attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
407
0
          &attr_group_len);
408
0
  if (!attr_group || attr_group_len != 2) {
409
0
    wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
410
0
      "Missing or invalid Finite Cyclic Group attribute");
411
0
    return NULL;
412
0
  }
413
0
  ike_group = WPA_GET_LE16(attr_group);
414
0
  if (ike_group != curve->ike_group) {
415
0
    wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
416
0
      "Mismatching PKEX curve: peer=%u own=%u",
417
0
      ike_group, curve->ike_group);
418
0
    pkex = os_zalloc(sizeof(*pkex));
419
0
    if (!pkex)
420
0
      goto fail;
421
0
    pkex->v2 = v2;
422
0
    pkex->peer_version = peer_version;
423
0
    pkex->own_bi = bi;
424
0
    pkex->failed = 1;
425
0
    pkex->exchange_resp = dpp_pkex_build_exchange_resp(
426
0
      pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
427
0
    if (!pkex->exchange_resp)
428
0
      goto fail;
429
0
    return pkex;
430
0
  }
431
432
  /* M in Encrypted Key attribute */
433
0
  attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
434
0
        &attr_key_len);
435
0
  if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
436
0
      attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
437
0
    wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
438
0
      "Missing Encrypted Key attribute");
439
0
    return NULL;
440
0
  }
441
442
  /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
443
0
  Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
444
0
        identifier, &ec);
445
0
  if (!Qi)
446
0
    goto fail;
447
448
  /* X' = M - Qi */
449
0
  X = crypto_ec_point_init(ec);
450
0
  M = crypto_ec_point_from_bin(ec, attr_key);
451
0
  if (!X || !M ||
452
0
      crypto_ec_point_is_at_infinity(ec, M) ||
453
0
      !crypto_ec_point_is_on_curve(ec, M) ||
454
0
      crypto_ec_point_invert(ec, Qi) ||
455
0
      crypto_ec_point_add(ec, M, Qi, X) ||
456
0
      crypto_ec_point_is_at_infinity(ec, X) ||
457
0
      !crypto_ec_point_is_on_curve(ec, X)) {
458
0
    wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
459
0
      "Invalid Encrypted Key value");
460
0
    bi->pkex_t++;
461
0
    goto fail;
462
0
  }
463
0
  crypto_ec_point_debug_print(ec, M, "DPP: M");
464
0
  crypto_ec_point_debug_print(ec, X, "DPP: X'");
465
466
0
  pkex = os_zalloc(sizeof(*pkex));
467
0
  if (!pkex)
468
0
    goto fail;
469
0
  pkex->v2 = v2;
470
0
  pkex->peer_version = peer_version;
471
0
  pkex->t = bi->pkex_t;
472
0
  pkex->msg_ctx = msg_ctx;
473
0
  pkex->own_bi = bi;
474
0
  if (own_mac)
475
0
    os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
476
0
  if (peer_mac)
477
0
    os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
478
0
  if (identifier) {
479
0
    pkex->identifier = os_strdup(identifier);
480
0
    if (!pkex->identifier)
481
0
      goto fail;
482
0
  }
483
0
  pkex->code = os_memdup(code, code_len);
484
0
  if (!pkex->code)
485
0
    goto fail;
486
0
  pkex->code_len = code_len;
487
488
0
  os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
489
490
0
  x_coord = os_malloc(curve->prime_len);
491
0
  y_coord = os_malloc(curve->prime_len);
492
0
  if (!x_coord || !y_coord ||
493
0
      crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
494
0
    goto fail;
495
496
0
  pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
497
0
          y_coord, crypto_ec_prime_len(ec));
498
0
  if (!pkex->x)
499
0
    goto fail;
500
501
  /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
502
0
  Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
503
0
        identifier, NULL);
504
0
  if (!Qr)
505
0
    goto fail;
506
507
  /* Generate a random ephemeral keypair y/Y */
508
#ifdef CONFIG_TESTING_OPTIONS
509
  if (dpp_pkex_ephemeral_key_override_len) {
510
    const struct dpp_curve_params *tmp_curve;
511
512
    wpa_printf(MSG_INFO,
513
         "DPP: TESTING - override ephemeral key y/Y");
514
    pkex->y = dpp_set_keypair(&tmp_curve,
515
            dpp_pkex_ephemeral_key_override,
516
            dpp_pkex_ephemeral_key_override_len);
517
  } else {
518
    pkex->y = dpp_gen_keypair(curve);
519
  }
520
#else /* CONFIG_TESTING_OPTIONS */
521
0
  pkex->y = dpp_gen_keypair(curve);
522
0
#endif /* CONFIG_TESTING_OPTIONS */
523
0
  if (!pkex->y)
524
0
    goto fail;
525
526
  /* N = Y + Qr */
527
0
  Y = crypto_ec_key_get_public_key(pkex->y);
528
0
  if (!Y)
529
0
    goto fail;
530
0
  crypto_ec_point_debug_print(ec, Y, "DPP: Y");
531
532
0
  N = crypto_ec_point_init(ec);
533
0
  if (!N ||
534
0
      crypto_ec_point_add(ec, Y, Qr, N) ||
535
0
      crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
536
0
    goto fail;
537
0
  crypto_ec_point_debug_print(ec, N, "DPP: N");
538
539
0
  pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
540
0
                 x_coord, y_coord);
541
0
  if (!pkex->exchange_resp)
542
0
    goto fail;
543
544
  /* K = y * X' */
545
0
  if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
546
0
    goto fail;
547
548
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
549
0
      Kx, Kx_len);
550
551
  /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
552
0
  res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
553
0
        pkex->v2 ? NULL : pkex->own_mac,
554
0
        pkex->peer_version, DPP_VERSION,
555
0
        pkex->Mx, curve->prime_len,
556
0
        pkex->Nx, curve->prime_len, pkex->code,
557
0
        pkex->code_len, Kx, Kx_len, pkex->z,
558
0
        curve->hash_len);
559
0
  os_memset(Kx, 0, Kx_len);
560
0
  if (res < 0)
561
0
    goto fail;
562
563
0
  pkex->exchange_done = 1;
564
565
0
out:
566
0
  os_free(x_coord);
567
0
  os_free(y_coord);
568
0
  crypto_ec_point_deinit(Qi, 1);
569
0
  crypto_ec_point_deinit(Qr, 1);
570
0
  crypto_ec_point_deinit(M, 1);
571
0
  crypto_ec_point_deinit(N, 1);
572
0
  crypto_ec_point_deinit(X, 1);
573
0
  crypto_ec_point_deinit(Y, 1);
574
0
  crypto_ec_deinit(ec);
575
0
  return pkex;
576
0
fail:
577
0
  wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
578
0
  dpp_pkex_free(pkex);
579
0
  pkex = NULL;
580
0
  goto out;
581
0
}
582
583
584
static struct wpabuf *
585
dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
586
         const struct wpabuf *A_pub, const u8 *u)
587
0
{
588
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
589
0
  struct wpabuf *msg = NULL;
590
0
  size_t clear_len, attr_len;
591
0
  struct wpabuf *clear = NULL;
592
0
  u8 *wrapped;
593
0
  u8 octet;
594
0
  const u8 *addr[2];
595
0
  size_t len[2];
596
597
  /* {A, u, [bootstrapping info]}z */
598
0
  clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
599
0
  clear = wpabuf_alloc(clear_len);
600
0
  attr_len = 4 + clear_len + AES_BLOCK_SIZE;
601
#ifdef CONFIG_TESTING_OPTIONS
602
  if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
603
    attr_len += 5;
604
#endif /* CONFIG_TESTING_OPTIONS */
605
0
  msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
606
0
  if (!clear || !msg)
607
0
    goto fail;
608
609
#ifdef CONFIG_TESTING_OPTIONS
610
  if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
611
    wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
612
    goto skip_bootstrap_key;
613
  }
614
  if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
615
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
616
    wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
617
    wpabuf_put_le16(clear, 2 * curve->prime_len);
618
    if (dpp_test_gen_invalid_key(clear, curve) < 0)
619
      goto fail;
620
    goto skip_bootstrap_key;
621
  }
622
#endif /* CONFIG_TESTING_OPTIONS */
623
624
  /* A in Bootstrap Key attribute */
625
0
  wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
626
0
  wpabuf_put_le16(clear, wpabuf_len(A_pub));
627
0
  wpabuf_put_buf(clear, A_pub);
628
629
#ifdef CONFIG_TESTING_OPTIONS
630
skip_bootstrap_key:
631
  if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
632
    wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
633
    goto skip_i_auth_tag;
634
  }
635
  if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
636
    wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
637
    wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
638
    wpabuf_put_le16(clear, curve->hash_len);
639
    wpabuf_put_data(clear, u, curve->hash_len - 1);
640
    wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
641
    goto skip_i_auth_tag;
642
  }
643
#endif /* CONFIG_TESTING_OPTIONS */
644
645
  /* u in I-Auth tag attribute */
646
0
  wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
647
0
  wpabuf_put_le16(clear, curve->hash_len);
648
0
  wpabuf_put_data(clear, u, curve->hash_len);
649
650
#ifdef CONFIG_TESTING_OPTIONS
651
skip_i_auth_tag:
652
  if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
653
    wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
654
    goto skip_wrapped_data;
655
  }
656
#endif /* CONFIG_TESTING_OPTIONS */
657
658
0
  addr[0] = wpabuf_head_u8(msg) + 2;
659
0
  len[0] = DPP_HDR_LEN;
660
0
  octet = 0;
661
0
  addr[1] = &octet;
662
0
  len[1] = sizeof(octet);
663
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
664
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
665
666
0
  wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
667
0
  wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
668
0
  wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
669
670
0
  wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
671
0
  if (aes_siv_encrypt(pkex->z, curve->hash_len,
672
0
          wpabuf_head(clear), wpabuf_len(clear),
673
0
          2, addr, len, wrapped) < 0)
674
0
    goto fail;
675
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
676
0
        wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
677
678
#ifdef CONFIG_TESTING_OPTIONS
679
  if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
680
    wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
681
    dpp_build_attr_status(msg, DPP_STATUS_OK);
682
  }
683
skip_wrapped_data:
684
#endif /* CONFIG_TESTING_OPTIONS */
685
686
0
out:
687
0
  wpabuf_free(clear);
688
0
  return msg;
689
690
0
fail:
691
0
  wpabuf_free(msg);
692
0
  msg = NULL;
693
0
  goto out;
694
0
}
695
696
697
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
698
            const u8 *peer_mac,
699
            const u8 *buf, size_t buflen)
700
0
{
701
0
  const u8 *attr_status, *attr_id, *attr_key, *attr_group;
702
0
  u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
703
0
  struct crypto_ec *ec = NULL;
704
0
  struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
705
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
706
0
  struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
707
0
  u8 *x_coord = NULL, *y_coord = NULL;
708
0
  size_t Jx_len, Kx_len;
709
0
  u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
710
0
  const u8 *addr[4];
711
0
  size_t len[4];
712
0
  size_t num_elem;
713
0
  u8 u[DPP_MAX_HASH_LEN];
714
0
  int res;
715
716
0
  if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
717
0
    return NULL;
718
719
#ifdef CONFIG_TESTING_OPTIONS
720
  if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
721
    wpa_printf(MSG_INFO,
722
         "DPP: TESTING - stop at PKEX Exchange Response");
723
    pkex->failed = 1;
724
    return NULL;
725
  }
726
727
  if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
728
    wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
729
         MAC2STR(dpp_pkex_peer_mac_override));
730
    peer_mac = dpp_pkex_peer_mac_override;
731
  }
732
#endif /* CONFIG_TESTING_OPTIONS */
733
734
0
#ifdef CONFIG_DPP2
735
0
  if (pkex->v2) {
736
0
    const u8 *version;
737
0
    u16 version_len;
738
739
0
    version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
740
0
               &version_len);
741
0
    if (!version || version_len < 1 || version[0] == 0) {
742
0
    dpp_pkex_fail(pkex,
743
0
            "Missing or invalid Protocol Version attribute");
744
0
      return NULL;
745
0
    }
746
0
    pkex->peer_version = version[0];
747
0
    wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
748
0
         pkex->peer_version);
749
0
  }
750
0
#endif /* CONFIG_DPP2 */
751
752
0
  if (peer_mac)
753
0
    os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
754
755
0
  attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
756
0
           &attr_status_len);
757
0
  if (!attr_status || attr_status_len != 1) {
758
0
    dpp_pkex_fail(pkex, "No DPP Status attribute");
759
0
    return NULL;
760
0
  }
761
0
  wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
762
763
0
  if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
764
0
    attr_group = dpp_get_attr(buf, buflen,
765
0
            DPP_ATTR_FINITE_CYCLIC_GROUP,
766
0
            &attr_group_len);
767
0
    if (attr_group && attr_group_len == 2) {
768
0
      wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
769
0
        "Peer indicated mismatching PKEX group - proposed %u",
770
0
        WPA_GET_LE16(attr_group));
771
0
      return NULL;
772
0
    }
773
0
  }
774
775
0
  if (attr_status[0] != DPP_STATUS_OK) {
776
0
    dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
777
0
    return NULL;
778
0
  }
779
780
0
  attr_id_len = 0;
781
0
  attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
782
0
             &attr_id_len);
783
0
  if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
784
0
               pkex->identifier)) {
785
0
    dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
786
0
    return NULL;
787
0
  }
788
789
  /* N in Encrypted Key attribute */
790
0
  attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
791
0
        &attr_key_len);
792
0
  if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
793
0
    dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
794
0
    return NULL;
795
0
  }
796
797
  /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
798
0
  Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
799
0
        pkex->code, pkex->code_len, pkex->identifier,
800
0
        &ec);
801
0
  if (!Qr)
802
0
    goto fail;
803
804
  /* Y' = N - Qr */
805
0
  Y = crypto_ec_point_init(ec);
806
0
  N = crypto_ec_point_from_bin(ec, attr_key);
807
0
  if (!Y || !N ||
808
0
      crypto_ec_point_is_at_infinity(ec, N) ||
809
0
      !crypto_ec_point_is_on_curve(ec, N) ||
810
0
      crypto_ec_point_invert(ec, Qr) ||
811
0
      crypto_ec_point_add(ec, N, Qr, Y) ||
812
0
      crypto_ec_point_is_at_infinity(ec, Y) ||
813
0
      !crypto_ec_point_is_on_curve(ec, Y)) {
814
0
    dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
815
0
    pkex->t++;
816
0
    goto fail;
817
0
  }
818
0
  crypto_ec_point_debug_print(ec, N, "DPP: N");
819
0
  crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
820
821
0
  pkex->exchange_done = 1;
822
823
  /* ECDH: J = a * Y' */
824
0
  x_coord = os_malloc(curve->prime_len);
825
0
  y_coord = os_malloc(curve->prime_len);
826
0
  if (!x_coord || !y_coord ||
827
0
      crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
828
0
    goto fail;
829
0
  pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
830
0
          curve->prime_len);
831
0
  if (!pkex->y)
832
0
    goto fail;
833
0
  if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
834
0
    goto fail;
835
836
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
837
0
      Jx, Jx_len);
838
839
  /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
840
0
  A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
841
0
  Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
842
0
  X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
843
0
  if (!A_pub || !Y_pub || !X_pub)
844
0
    goto fail;
845
0
  num_elem = 0;
846
0
  if (!pkex->v2) {
847
0
    addr[num_elem] = pkex->own_mac;
848
0
    len[num_elem] = ETH_ALEN;
849
0
    num_elem++;
850
0
  }
851
0
  addr[num_elem] = wpabuf_head(A_pub);
852
0
  len[num_elem] = wpabuf_len(A_pub) / 2;
853
0
  num_elem++;
854
0
  addr[num_elem] = wpabuf_head(Y_pub);
855
0
  len[num_elem] = wpabuf_len(Y_pub) / 2;
856
0
  num_elem++;
857
0
  addr[num_elem] = wpabuf_head(X_pub);
858
0
  len[num_elem] = wpabuf_len(X_pub) / 2;
859
0
  num_elem++;
860
0
  if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
861
0
      < 0)
862
0
    goto fail;
863
0
  wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
864
865
  /* K = x * Y' */
866
0
  if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
867
0
    goto fail;
868
869
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
870
0
      Kx, Kx_len);
871
872
  /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
873
0
  res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
874
0
        pkex->v2 ? NULL : pkex->peer_mac,
875
0
        DPP_VERSION, pkex->peer_version,
876
0
        pkex->Mx, curve->prime_len,
877
0
        attr_key /* N.x */, attr_key_len / 2,
878
0
        pkex->code, pkex->code_len, Kx, Kx_len,
879
0
        pkex->z, curve->hash_len);
880
0
  os_memset(Kx, 0, Kx_len);
881
0
  if (res < 0)
882
0
    goto fail;
883
884
0
  msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
885
0
  if (!msg)
886
0
    goto fail;
887
888
0
out:
889
0
  wpabuf_free(A_pub);
890
0
  wpabuf_free(X_pub);
891
0
  wpabuf_free(Y_pub);
892
0
  os_free(x_coord);
893
0
  os_free(y_coord);
894
0
  crypto_ec_point_deinit(Qr, 1);
895
0
  crypto_ec_point_deinit(Y, 1);
896
0
  crypto_ec_point_deinit(N, 1);
897
0
  crypto_ec_deinit(ec);
898
0
  return msg;
899
0
fail:
900
0
  wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
901
0
  goto out;
902
0
}
903
904
905
static struct wpabuf *
906
dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
907
          const struct wpabuf *B_pub, const u8 *v)
908
0
{
909
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
910
0
  struct wpabuf *msg = NULL;
911
0
  const u8 *addr[2];
912
0
  size_t len[2];
913
0
  u8 octet;
914
0
  u8 *wrapped;
915
0
  struct wpabuf *clear = NULL;
916
0
  size_t clear_len, attr_len;
917
918
  /* {B, v [bootstrapping info]}z */
919
0
  clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
920
0
  clear = wpabuf_alloc(clear_len);
921
0
  attr_len = 4 + clear_len + AES_BLOCK_SIZE;
922
#ifdef CONFIG_TESTING_OPTIONS
923
  if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
924
    attr_len += 5;
925
#endif /* CONFIG_TESTING_OPTIONS */
926
0
  msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
927
0
  if (!clear || !msg)
928
0
    goto fail;
929
930
#ifdef CONFIG_TESTING_OPTIONS
931
  if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
932
    wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
933
    goto skip_bootstrap_key;
934
  }
935
  if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
936
    wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
937
    wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
938
    wpabuf_put_le16(clear, 2 * curve->prime_len);
939
    if (dpp_test_gen_invalid_key(clear, curve) < 0)
940
      goto fail;
941
    goto skip_bootstrap_key;
942
  }
943
#endif /* CONFIG_TESTING_OPTIONS */
944
945
  /* B in Bootstrap Key attribute */
946
0
  wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
947
0
  wpabuf_put_le16(clear, wpabuf_len(B_pub));
948
0
  wpabuf_put_buf(clear, B_pub);
949
950
#ifdef CONFIG_TESTING_OPTIONS
951
skip_bootstrap_key:
952
  if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
953
    wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
954
    goto skip_r_auth_tag;
955
  }
956
  if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
957
    wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
958
    wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
959
    wpabuf_put_le16(clear, curve->hash_len);
960
    wpabuf_put_data(clear, v, curve->hash_len - 1);
961
    wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
962
    goto skip_r_auth_tag;
963
  }
964
#endif /* CONFIG_TESTING_OPTIONS */
965
966
  /* v in R-Auth tag attribute */
967
0
  wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
968
0
  wpabuf_put_le16(clear, curve->hash_len);
969
0
  wpabuf_put_data(clear, v, curve->hash_len);
970
971
#ifdef CONFIG_TESTING_OPTIONS
972
skip_r_auth_tag:
973
  if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
974
    wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
975
    goto skip_wrapped_data;
976
  }
977
#endif /* CONFIG_TESTING_OPTIONS */
978
979
0
  addr[0] = wpabuf_head_u8(msg) + 2;
980
0
  len[0] = DPP_HDR_LEN;
981
0
  octet = 1;
982
0
  addr[1] = &octet;
983
0
  len[1] = sizeof(octet);
984
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
985
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
986
987
0
  wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
988
0
  wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
989
0
  wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
990
991
0
  wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
992
0
  if (aes_siv_encrypt(pkex->z, curve->hash_len,
993
0
          wpabuf_head(clear), wpabuf_len(clear),
994
0
          2, addr, len, wrapped) < 0)
995
0
    goto fail;
996
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
997
0
        wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
998
999
#ifdef CONFIG_TESTING_OPTIONS
1000
  if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
1001
    wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1002
    dpp_build_attr_status(msg, DPP_STATUS_OK);
1003
  }
1004
skip_wrapped_data:
1005
#endif /* CONFIG_TESTING_OPTIONS */
1006
1007
0
out:
1008
0
  wpabuf_free(clear);
1009
0
  return msg;
1010
1011
0
fail:
1012
0
  wpabuf_free(msg);
1013
0
  msg = NULL;
1014
0
  goto out;
1015
0
}
1016
1017
1018
struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
1019
                const u8 *hdr,
1020
                const u8 *buf, size_t buflen)
1021
0
{
1022
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
1023
0
  size_t Jx_len, Lx_len;
1024
0
  u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
1025
0
  u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1026
0
  const u8 *wrapped_data, *b_key, *peer_u;
1027
0
  u16 wrapped_data_len, b_key_len, peer_u_len = 0;
1028
0
  const u8 *addr[4];
1029
0
  size_t len[4];
1030
0
  size_t num_elem;
1031
0
  u8 octet;
1032
0
  u8 *unwrapped = NULL;
1033
0
  size_t unwrapped_len = 0;
1034
0
  struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1035
0
  struct wpabuf *B_pub = NULL;
1036
0
  u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
1037
1038
#ifdef CONFIG_TESTING_OPTIONS
1039
  if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
1040
    wpa_printf(MSG_INFO,
1041
         "DPP: TESTING - stop at PKEX CR Request");
1042
    pkex->failed = 1;
1043
    return NULL;
1044
  }
1045
#endif /* CONFIG_TESTING_OPTIONS */
1046
1047
0
  if (!pkex->exchange_done || pkex->failed ||
1048
0
      pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
1049
0
    goto fail;
1050
1051
0
  wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1052
0
            &wrapped_data_len);
1053
0
  if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1054
0
    dpp_pkex_fail(pkex,
1055
0
            "Missing or invalid required Wrapped Data attribute");
1056
0
    goto fail;
1057
0
  }
1058
1059
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1060
0
        wrapped_data, wrapped_data_len);
1061
0
  unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1062
0
  unwrapped = os_malloc(unwrapped_len);
1063
0
  if (!unwrapped)
1064
0
    goto fail;
1065
1066
0
  addr[0] = hdr;
1067
0
  len[0] = DPP_HDR_LEN;
1068
0
  octet = 0;
1069
0
  addr[1] = &octet;
1070
0
  len[1] = sizeof(octet);
1071
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1072
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1073
1074
0
  if (aes_siv_decrypt(pkex->z, curve->hash_len,
1075
0
          wrapped_data, wrapped_data_len,
1076
0
          2, addr, len, unwrapped) < 0) {
1077
0
    dpp_pkex_fail(pkex,
1078
0
            "AES-SIV decryption failed - possible PKEX code mismatch");
1079
0
    pkex->failed = 1;
1080
0
    pkex->t++;
1081
0
    goto fail;
1082
0
  }
1083
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1084
0
        unwrapped, unwrapped_len);
1085
1086
0
  if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1087
0
    dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1088
0
    goto fail;
1089
0
  }
1090
1091
0
  b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1092
0
           &b_key_len);
1093
0
  if (!b_key || b_key_len != 2 * curve->prime_len) {
1094
0
    dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1095
0
    goto fail;
1096
0
  }
1097
0
  pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1098
0
              b_key_len);
1099
0
  if (!pkex->peer_bootstrap_key) {
1100
0
    dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1101
0
    goto fail;
1102
0
  }
1103
0
  dpp_debug_print_key("DPP: Peer bootstrap public key",
1104
0
          pkex->peer_bootstrap_key);
1105
1106
  /* ECDH: J' = y * A' */
1107
0
  if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1108
0
    goto fail;
1109
1110
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1111
0
      Jx, Jx_len);
1112
1113
  /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
1114
0
  A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1115
0
  Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1116
0
  X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1117
0
  if (!A_pub || !Y_pub || !X_pub)
1118
0
    goto fail;
1119
0
  num_elem = 0;
1120
0
  if (!pkex->v2) {
1121
0
    addr[num_elem] = pkex->peer_mac;
1122
0
    len[num_elem] = ETH_ALEN;
1123
0
    num_elem++;
1124
0
  }
1125
0
  addr[num_elem] = wpabuf_head(A_pub);
1126
0
  len[num_elem] = wpabuf_len(A_pub) / 2;
1127
0
  num_elem++;
1128
0
  addr[num_elem] = wpabuf_head(Y_pub);
1129
0
  len[num_elem] = wpabuf_len(Y_pub) / 2;
1130
0
  num_elem++;
1131
0
  addr[num_elem] = wpabuf_head(X_pub);
1132
0
  len[num_elem] = wpabuf_len(X_pub) / 2;
1133
0
  num_elem++;
1134
0
  if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
1135
0
      < 0)
1136
0
    goto fail;
1137
1138
0
  peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1139
0
            &peer_u_len);
1140
0
  if (!peer_u || peer_u_len != curve->hash_len ||
1141
0
      os_memcmp(peer_u, u, curve->hash_len) != 0) {
1142
0
    dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1143
0
    wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1144
0
          u, curve->hash_len);
1145
0
    wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1146
0
    pkex->t++;
1147
0
    goto fail;
1148
0
  }
1149
0
  wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1150
1151
  /* ECDH: L = b * X' */
1152
0
  if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1153
0
    goto fail;
1154
1155
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1156
0
      Lx, Lx_len);
1157
1158
  /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
1159
0
  B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
1160
0
  if (!B_pub)
1161
0
    goto fail;
1162
0
  num_elem = 0;
1163
0
  if (!pkex->v2) {
1164
0
    addr[num_elem] = pkex->own_mac;
1165
0
    len[num_elem] = ETH_ALEN;
1166
0
    num_elem++;
1167
0
  }
1168
0
  addr[num_elem] = wpabuf_head(B_pub);
1169
0
  len[num_elem] = wpabuf_len(B_pub) / 2;
1170
0
  num_elem++;
1171
0
  addr[num_elem] = wpabuf_head(X_pub);
1172
0
  len[num_elem] = wpabuf_len(X_pub) / 2;
1173
0
  num_elem++;
1174
0
  addr[num_elem] = wpabuf_head(Y_pub);
1175
0
  len[num_elem] = wpabuf_len(Y_pub) / 2;
1176
0
  num_elem++;
1177
0
  if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1178
0
      < 0)
1179
0
    goto fail;
1180
0
  wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1181
1182
0
  msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1183
0
  if (!msg)
1184
0
    goto fail;
1185
1186
0
out:
1187
0
  os_free(unwrapped);
1188
0
  wpabuf_free(A_pub);
1189
0
  wpabuf_free(B_pub);
1190
0
  wpabuf_free(X_pub);
1191
0
  wpabuf_free(Y_pub);
1192
0
  return msg;
1193
0
fail:
1194
0
  wpa_printf(MSG_DEBUG,
1195
0
       "DPP: PKEX Commit-Reveal Request processing failed");
1196
0
  goto out;
1197
0
}
1198
1199
1200
int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1201
           const u8 *buf, size_t buflen)
1202
0
{
1203
0
  const struct dpp_curve_params *curve = pkex->own_bi->curve;
1204
0
  const u8 *wrapped_data, *b_key, *peer_v;
1205
0
  u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1206
0
  const u8 *addr[4];
1207
0
  size_t len[4];
1208
0
  size_t num_elem;
1209
0
  u8 octet;
1210
0
  u8 *unwrapped = NULL;
1211
0
  size_t unwrapped_len = 0;
1212
0
  int ret = -1;
1213
0
  u8 v[DPP_MAX_HASH_LEN];
1214
0
  size_t Lx_len;
1215
0
  u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1216
0
  struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1217
1218
#ifdef CONFIG_TESTING_OPTIONS
1219
  if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
1220
    wpa_printf(MSG_INFO,
1221
         "DPP: TESTING - stop at PKEX CR Response");
1222
    pkex->failed = 1;
1223
    goto fail;
1224
  }
1225
#endif /* CONFIG_TESTING_OPTIONS */
1226
1227
0
  if (!pkex->exchange_done || pkex->failed ||
1228
0
      pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1229
0
    goto fail;
1230
1231
0
  wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1232
0
            &wrapped_data_len);
1233
0
  if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1234
0
    dpp_pkex_fail(pkex,
1235
0
            "Missing or invalid required Wrapped Data attribute");
1236
0
    goto fail;
1237
0
  }
1238
1239
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1240
0
        wrapped_data, wrapped_data_len);
1241
0
  unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1242
0
  unwrapped = os_malloc(unwrapped_len);
1243
0
  if (!unwrapped)
1244
0
    goto fail;
1245
1246
0
  addr[0] = hdr;
1247
0
  len[0] = DPP_HDR_LEN;
1248
0
  octet = 1;
1249
0
  addr[1] = &octet;
1250
0
  len[1] = sizeof(octet);
1251
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1252
0
  wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1253
1254
0
  if (aes_siv_decrypt(pkex->z, curve->hash_len,
1255
0
          wrapped_data, wrapped_data_len,
1256
0
          2, addr, len, unwrapped) < 0) {
1257
0
    dpp_pkex_fail(pkex,
1258
0
            "AES-SIV decryption failed - possible PKEX code mismatch");
1259
0
    pkex->t++;
1260
0
    goto fail;
1261
0
  }
1262
0
  wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1263
0
        unwrapped, unwrapped_len);
1264
1265
0
  if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1266
0
    dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1267
0
    goto fail;
1268
0
  }
1269
1270
0
  b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1271
0
           &b_key_len);
1272
0
  if (!b_key || b_key_len != 2 * curve->prime_len) {
1273
0
    dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1274
0
    goto fail;
1275
0
  }
1276
0
  pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1277
0
              b_key_len);
1278
0
  if (!pkex->peer_bootstrap_key) {
1279
0
    dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1280
0
    goto fail;
1281
0
  }
1282
0
  dpp_debug_print_key("DPP: Peer bootstrap public key",
1283
0
          pkex->peer_bootstrap_key);
1284
1285
  /* ECDH: L' = x * B' */
1286
0
  if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1287
0
    goto fail;
1288
1289
0
  wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1290
0
      Lx, Lx_len);
1291
1292
  /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
1293
0
  B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1294
0
  X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1295
0
  Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1296
0
  if (!B_pub || !X_pub || !Y_pub)
1297
0
    goto fail;
1298
0
  num_elem = 0;
1299
0
  if (!pkex->v2) {
1300
0
    addr[num_elem] = pkex->peer_mac;
1301
0
    len[num_elem] = ETH_ALEN;
1302
0
    num_elem++;
1303
0
  }
1304
0
  addr[num_elem] = wpabuf_head(B_pub);
1305
0
  len[num_elem] = wpabuf_len(B_pub) / 2;
1306
0
  num_elem++;
1307
0
  addr[num_elem] = wpabuf_head(X_pub);
1308
0
  len[num_elem] = wpabuf_len(X_pub) / 2;
1309
0
  num_elem++;
1310
0
  addr[num_elem] = wpabuf_head(Y_pub);
1311
0
  len[num_elem] = wpabuf_len(Y_pub) / 2;
1312
0
  num_elem++;
1313
0
  if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1314
0
      < 0)
1315
0
    goto fail;
1316
1317
0
  peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1318
0
            &peer_v_len);
1319
0
  if (!peer_v || peer_v_len != curve->hash_len ||
1320
0
      os_memcmp(peer_v, v, curve->hash_len) != 0) {
1321
0
    dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1322
0
    wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1323
0
          v, curve->hash_len);
1324
0
    wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1325
0
    pkex->t++;
1326
0
    goto fail;
1327
0
  }
1328
0
  wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1329
1330
0
  ret = 0;
1331
0
out:
1332
0
  wpabuf_free(B_pub);
1333
0
  wpabuf_free(X_pub);
1334
0
  wpabuf_free(Y_pub);
1335
0
  os_free(unwrapped);
1336
0
  return ret;
1337
0
fail:
1338
0
  goto out;
1339
0
}
1340
1341
1342
struct dpp_bootstrap_info *
1343
dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1344
    unsigned int freq)
1345
0
{
1346
0
  struct dpp_bootstrap_info *bi;
1347
1348
0
  bi = os_zalloc(sizeof(*bi));
1349
0
  if (!bi)
1350
0
    return NULL;
1351
0
  bi->id = dpp_next_id(dpp);
1352
0
  bi->type = DPP_BOOTSTRAP_PKEX;
1353
0
  if (peer)
1354
0
    os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1355
0
  if (freq) {
1356
0
    bi->num_freq = 1;
1357
0
    bi->freq[0] = freq;
1358
0
  }
1359
0
  bi->curve = pkex->own_bi->curve;
1360
0
  bi->pubkey = pkex->peer_bootstrap_key;
1361
0
  pkex->peer_bootstrap_key = NULL;
1362
0
  if (dpp_bootstrap_key_hash(bi) < 0) {
1363
0
    dpp_bootstrap_info_free(bi);
1364
0
    return NULL;
1365
0
  }
1366
0
  os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash,
1367
0
      SHA256_MAC_LEN);
1368
0
  dpp_pkex_free(pkex);
1369
0
  dl_list_add(&dpp->bootstrap, &bi->list);
1370
0
  return bi;
1371
0
}
1372
1373
1374
void dpp_pkex_free(struct dpp_pkex *pkex)
1375
0
{
1376
0
  if (!pkex)
1377
0
    return;
1378
1379
0
  os_free(pkex->identifier);
1380
0
  os_free(pkex->code);
1381
0
  crypto_ec_key_deinit(pkex->x);
1382
0
  crypto_ec_key_deinit(pkex->y);
1383
0
  crypto_ec_key_deinit(pkex->peer_bootstrap_key);
1384
0
  wpabuf_free(pkex->exchange_req);
1385
0
  wpabuf_free(pkex->exchange_resp);
1386
0
  wpabuf_free(pkex->enc_key);
1387
0
  os_free(pkex);
1388
0
}