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 
dpp_pkex_build_exchange_req(struct dpp_pkex * pkex,bool v2)29 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
30                                                                bool v2)
31 {
32           struct crypto_ec *ec = NULL;
33           struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL;
34           u8 *Mx, *My;
35           struct wpabuf *msg = NULL;
36           size_t attr_len;
37           const struct dpp_curve_params *curve = pkex->own_bi->curve;
38 
39           wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
40                        v2 ? "" : "Version 1 ");
41 
42           /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
43           Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
44                                         pkex->code_len, pkex->identifier, &ec);
45           if (!Qi)
46                     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           pkex->x = dpp_gen_keypair(curve);
63 #endif /* CONFIG_TESTING_OPTIONS */
64           if (!pkex->x)
65                     goto fail;
66 
67           /* M = X + Qi */
68           X = crypto_ec_key_get_public_key(pkex->x);
69           M = crypto_ec_point_init(ec);
70           if (!X || !M)
71                     goto fail;
72           crypto_ec_point_debug_print(ec, X, "DPP: X");
73 
74           if (crypto_ec_point_add(ec, X, Qi, M))
75                     goto fail;
76           crypto_ec_point_debug_print(ec, M, "DPP: M");
77 
78           /* Initiator -> Responder: group, [identifier,] M */
79           attr_len = 4 + 2;
80 #ifdef CONFIG_DPP2
81           if (v2)
82                     attr_len += 4 + 1;
83 #endif /* CONFIG_DPP2 */
84           if (pkex->identifier)
85                     attr_len += 4 + os_strlen(pkex->identifier);
86           attr_len += 4 + 2 * curve->prime_len;
87           msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
88                                   DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
89           if (!msg)
90                     goto fail;
91 
92 #ifdef CONFIG_DPP2
93           if (v2) {
94                     /* Protocol Version */
95                     wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
96                     wpabuf_put_le16(msg, 1);
97                     wpabuf_put_u8(msg, DPP_VERSION);
98           }
99 #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           wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
110           wpabuf_put_le16(msg, 2);
111           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           if (pkex->identifier) {
119                     wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
120                     wpabuf_put_le16(msg, os_strlen(pkex->identifier));
121                     wpabuf_put_str(msg, pkex->identifier);
122           }
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           wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
133           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           Mx = wpabuf_put(msg, curve->prime_len);
145           My = wpabuf_put(msg, curve->prime_len);
146           if (crypto_ec_point_to_bin(ec, M, Mx, My))
147                     goto fail;
148           wpabuf_free(pkex->enc_key);
149           pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len);
150 
151           os_memcpy(pkex->Mx, Mx, curve->prime_len);
152 
153 out:
154           crypto_ec_point_deinit(X, 1);
155           crypto_ec_point_deinit(M, 1);
156           crypto_ec_point_deinit(Qi, 1);
157           crypto_ec_deinit(ec);
158           return msg;
159 fail:
160           wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
161           wpabuf_free(msg);
162           msg = NULL;
163           goto out;
164 }
165 
166 
dpp_pkex_fail(struct dpp_pkex * pkex,const char * txt)167 static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
168 {
169           wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
170 }
171 
172 
dpp_pkex_init(void * msg_ctx,struct dpp_bootstrap_info * bi,const u8 * own_mac,const char * identifier,const char * code,size_t code_len,bool v2)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 {
178           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           pkex = os_zalloc(sizeof(*pkex));
189           if (!pkex)
190                     return NULL;
191           pkex->msg_ctx = msg_ctx;
192           pkex->initiator = 1;
193           pkex->v2 = v2;
194           pkex->own_bi = bi;
195           os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
196           if (identifier) {
197                     pkex->identifier = os_strdup(identifier);
198                     if (!pkex->identifier)
199                               goto fail;
200           }
201           pkex->code = os_memdup(code, code_len);
202           if (!pkex->code)
203                     goto fail;
204           pkex->code_len = code_len;
205           pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
206           if (!pkex->exchange_req)
207                     goto fail;
208           return pkex;
209 fail:
210           dpp_pkex_free(pkex);
211           return NULL;
212 }
213 
214 
215 static struct wpabuf *
dpp_pkex_build_exchange_resp(struct dpp_pkex * pkex,enum dpp_status_error status,const u8 * Nx,const u8 * Ny)216 dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
217                                    enum dpp_status_error status,
218                                    const u8 *Nx, const u8 *Ny)
219 {
220           struct wpabuf *msg = NULL;
221           size_t attr_len;
222           const struct dpp_curve_params *curve = pkex->own_bi->curve;
223 
224           /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
225            * N */
226           attr_len = 4 + 1;
227 #ifdef CONFIG_DPP2
228           if (pkex->v2)
229                     attr_len += 4 + 1;
230 #endif /* CONFIG_DPP2 */
231           if (pkex->identifier)
232                     attr_len += 4 + os_strlen(pkex->identifier);
233           attr_len += 4 + 2 * curve->prime_len;
234           msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
235           if (!msg)
236                     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           dpp_build_attr_status(msg, status);
252 
253 #ifdef CONFIG_TESTING_OPTIONS
254 skip_status:
255 #endif /* CONFIG_TESTING_OPTIONS */
256 
257 #ifdef CONFIG_DPP2
258           if (pkex->v2) {
259                     /* Protocol Version */
260                     wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
261                     wpabuf_put_le16(msg, 1);
262                     wpabuf_put_u8(msg, DPP_VERSION);
263           }
264 #endif /* CONFIG_DPP2 */
265 
266           /* Code Identifier attribute */
267           if (pkex->identifier) {
268                     wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
269                     wpabuf_put_le16(msg, os_strlen(pkex->identifier));
270                     wpabuf_put_str(msg, pkex->identifier);
271           }
272 
273           if (status != DPP_STATUS_OK)
274                     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           wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
285           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           wpabuf_put_data(msg, Nx, curve->prime_len);
297           wpabuf_put_data(msg, Ny, curve->prime_len);
298           os_memcpy(pkex->Nx, Nx, curve->prime_len);
299 
300 skip_encrypted_key:
301           if (status == DPP_STATUS_BAD_GROUP) {
302                     /* Finite Cyclic Group attribute */
303                     wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
304                     wpabuf_put_le16(msg, 2);
305                     wpabuf_put_le16(msg, curve->ike_group);
306           }
307 
308           return msg;
309 fail:
310           wpabuf_free(msg);
311           return NULL;
312 }
313 
314 
dpp_pkex_identifier_match(const u8 * attr_id,u16 attr_id_len,const char * identifier)315 static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
316                                              const char *identifier)
317 {
318           if (!attr_id && identifier) {
319                     wpa_printf(MSG_DEBUG,
320                                  "DPP: No PKEX code identifier received, but expected one");
321                     return 0;
322           }
323 
324           if (attr_id && !identifier) {
325                     wpa_printf(MSG_DEBUG,
326                                  "DPP: PKEX code identifier received, but not expecting one");
327                     return 0;
328           }
329 
330           if (attr_id && identifier &&
331               (os_strlen(identifier) != attr_id_len ||
332                os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
333                     wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
334                     return 0;
335           }
336 
337           return 1;
338 }
339 
340 
dpp_pkex_rx_exchange_req(void * msg_ctx,struct dpp_bootstrap_info * bi,const u8 * own_mac,const u8 * peer_mac,const char * identifier,const char * code,size_t code_len,const u8 * buf,size_t len,bool v2)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 {
349           const u8 *attr_group, *attr_id, *attr_key;
350           u16 attr_group_len, attr_id_len, attr_key_len;
351           const struct dpp_curve_params *curve = bi->curve;
352           u16 ike_group;
353           struct dpp_pkex *pkex = NULL;
354           struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
355                     *N = NULL, *Y = NULL;
356           struct crypto_ec *ec = NULL;
357           u8 *x_coord = NULL, *y_coord = NULL;
358           u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
359           size_t Kx_len;
360           int res;
361           u8 peer_version = 0;
362 
363           if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
364                     wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
365                               "PKEX counter t limit reached - ignore message");
366                     return NULL;
367           }
368 
369 #ifdef CONFIG_DPP2
370           if (v2) {
371                     const u8 *version;
372                     u16 version_len;
373 
374                     version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
375                                                &version_len);
376                     if (!version || version_len < 1 || version[0] == 0) {
377                               wpa_msg(msg_ctx, MSG_INFO,
378                                         "Missing or invalid Protocol Version attribute");
379                               return NULL;
380                     }
381                     peer_version = version[0];
382                     wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
383                                  peer_version);
384           }
385 #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           attr_id_len = 0;
401           attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
402                                      &attr_id_len);
403           if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
404                     return NULL;
405 
406           attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
407                                           &attr_group_len);
408           if (!attr_group || attr_group_len != 2) {
409                     wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
410                               "Missing or invalid Finite Cyclic Group attribute");
411                     return NULL;
412           }
413           ike_group = WPA_GET_LE16(attr_group);
414           if (ike_group != curve->ike_group) {
415                     wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
416                               "Mismatching PKEX curve: peer=%u own=%u",
417                               ike_group, curve->ike_group);
418                     pkex = os_zalloc(sizeof(*pkex));
419                     if (!pkex)
420                               goto fail;
421                     pkex->v2 = v2;
422                     pkex->peer_version = peer_version;
423                     pkex->own_bi = bi;
424                     pkex->failed = 1;
425                     pkex->exchange_resp = dpp_pkex_build_exchange_resp(
426                               pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
427                     if (!pkex->exchange_resp)
428                               goto fail;
429                     return pkex;
430           }
431 
432           /* M in Encrypted Key attribute */
433           attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
434                                         &attr_key_len);
435           if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
436               attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
437                     wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
438                               "Missing Encrypted Key attribute");
439                     return NULL;
440           }
441 
442           /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
443           Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len,
444                                         identifier, &ec);
445           if (!Qi)
446                     goto fail;
447 
448           /* X' = M - Qi */
449           X = crypto_ec_point_init(ec);
450           M = crypto_ec_point_from_bin(ec, attr_key);
451           if (!X || !M ||
452               crypto_ec_point_is_at_infinity(ec, M) ||
453               !crypto_ec_point_is_on_curve(ec, M) ||
454               crypto_ec_point_invert(ec, Qi) ||
455               crypto_ec_point_add(ec, M, Qi, X) ||
456               crypto_ec_point_is_at_infinity(ec, X) ||
457               !crypto_ec_point_is_on_curve(ec, X)) {
458                     wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
459                               "Invalid Encrypted Key value");
460                     bi->pkex_t++;
461                     goto fail;
462           }
463           crypto_ec_point_debug_print(ec, M, "DPP: M");
464           crypto_ec_point_debug_print(ec, X, "DPP: X'");
465 
466           pkex = os_zalloc(sizeof(*pkex));
467           if (!pkex)
468                     goto fail;
469           pkex->v2 = v2;
470           pkex->peer_version = peer_version;
471           pkex->t = bi->pkex_t;
472           pkex->msg_ctx = msg_ctx;
473           pkex->own_bi = bi;
474           if (own_mac)
475                     os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
476           if (peer_mac)
477                     os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
478           if (identifier) {
479                     pkex->identifier = os_strdup(identifier);
480                     if (!pkex->identifier)
481                               goto fail;
482           }
483           pkex->code = os_memdup(code, code_len);
484           if (!pkex->code)
485                     goto fail;
486           pkex->code_len = code_len;
487 
488           os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
489 
490           x_coord = os_malloc(curve->prime_len);
491           y_coord = os_malloc(curve->prime_len);
492           if (!x_coord || !y_coord ||
493               crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
494                     goto fail;
495 
496           pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
497                                                   y_coord, crypto_ec_prime_len(ec));
498           if (!pkex->x)
499                     goto fail;
500 
501           /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
502           Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len,
503                                         identifier, NULL);
504           if (!Qr)
505                     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           pkex->y = dpp_gen_keypair(curve);
522 #endif /* CONFIG_TESTING_OPTIONS */
523           if (!pkex->y)
524                     goto fail;
525 
526           /* N = Y + Qr */
527           Y = crypto_ec_key_get_public_key(pkex->y);
528           if (!Y)
529                     goto fail;
530           crypto_ec_point_debug_print(ec, Y, "DPP: Y");
531 
532           N = crypto_ec_point_init(ec);
533           if (!N ||
534               crypto_ec_point_add(ec, Y, Qr, N) ||
535               crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
536                     goto fail;
537           crypto_ec_point_debug_print(ec, N, "DPP: N");
538 
539           pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
540                                                                          x_coord, y_coord);
541           if (!pkex->exchange_resp)
542                     goto fail;
543 
544           /* K = y * X' */
545           if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
546                     goto fail;
547 
548           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
549                               Kx, Kx_len);
550 
551           /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
552           res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
553                                         pkex->v2 ? NULL : pkex->own_mac,
554                                         pkex->peer_version, DPP_VERSION,
555                                         pkex->Mx, curve->prime_len,
556                                         pkex->Nx, curve->prime_len, pkex->code,
557                                         pkex->code_len,     Kx, Kx_len, pkex->z,
558                                         curve->hash_len);
559           os_memset(Kx, 0, Kx_len);
560           if (res < 0)
561                     goto fail;
562 
563           pkex->exchange_done = 1;
564 
565 out:
566           os_free(x_coord);
567           os_free(y_coord);
568           crypto_ec_point_deinit(Qi, 1);
569           crypto_ec_point_deinit(Qr, 1);
570           crypto_ec_point_deinit(M, 1);
571           crypto_ec_point_deinit(N, 1);
572           crypto_ec_point_deinit(X, 1);
573           crypto_ec_point_deinit(Y, 1);
574           crypto_ec_deinit(ec);
575           return pkex;
576 fail:
577           wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
578           dpp_pkex_free(pkex);
579           pkex = NULL;
580           goto out;
581 }
582 
583 
584 static struct wpabuf *
dpp_pkex_build_commit_reveal_req(struct dpp_pkex * pkex,const struct wpabuf * A_pub,const u8 * u)585 dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
586                                          const struct wpabuf *A_pub, const u8 *u)
587 {
588           const struct dpp_curve_params *curve = pkex->own_bi->curve;
589           struct wpabuf *msg = NULL;
590           size_t clear_len, attr_len;
591           struct wpabuf *clear = NULL;
592           u8 *wrapped;
593           u8 octet;
594           const u8 *addr[2];
595           size_t len[2];
596 
597           /* {A, u, [bootstrapping info]}z */
598           clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
599           clear = wpabuf_alloc(clear_len);
600           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           msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
606           if (!clear || !msg)
607                     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           wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
626           wpabuf_put_le16(clear, wpabuf_len(A_pub));
627           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           wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
647           wpabuf_put_le16(clear, curve->hash_len);
648           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           addr[0] = wpabuf_head_u8(msg) + 2;
659           len[0] = DPP_HDR_LEN;
660           octet = 0;
661           addr[1] = &octet;
662           len[1] = sizeof(octet);
663           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
664           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
665 
666           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
667           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
668           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
669 
670           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
671           if (aes_siv_encrypt(pkex->z, curve->hash_len,
672                                   wpabuf_head(clear), wpabuf_len(clear),
673                                   2, addr, len, wrapped) < 0)
674                     goto fail;
675           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
676                         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 out:
687           wpabuf_free(clear);
688           return msg;
689 
690 fail:
691           wpabuf_free(msg);
692           msg = NULL;
693           goto out;
694 }
695 
696 
dpp_pkex_rx_exchange_resp(struct dpp_pkex * pkex,const u8 * peer_mac,const u8 * buf,size_t buflen)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 {
701           const u8 *attr_status, *attr_id, *attr_key, *attr_group;
702           u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
703           struct crypto_ec *ec = NULL;
704           struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
705           const struct dpp_curve_params *curve = pkex->own_bi->curve;
706           struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
707           u8 *x_coord = NULL, *y_coord = NULL;
708           size_t Jx_len, Kx_len;
709           u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
710           const u8 *addr[4];
711           size_t len[4];
712           size_t num_elem;
713           u8 u[DPP_MAX_HASH_LEN];
714           int res;
715 
716           if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
717                     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 #ifdef CONFIG_DPP2
735           if (pkex->v2) {
736                     const u8 *version;
737                     u16 version_len;
738 
739                     version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
740                                                &version_len);
741                     if (!version || version_len < 1 || version[0] == 0) {
742                     dpp_pkex_fail(pkex,
743                                     "Missing or invalid Protocol Version attribute");
744                               return NULL;
745                     }
746                     pkex->peer_version = version[0];
747                     wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
748                                  pkex->peer_version);
749           }
750 #endif /* CONFIG_DPP2 */
751 
752           if (peer_mac)
753                     os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
754 
755           attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
756                                            &attr_status_len);
757           if (!attr_status || attr_status_len != 1) {
758                     dpp_pkex_fail(pkex, "No DPP Status attribute");
759                     return NULL;
760           }
761           wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
762 
763           if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
764                     attr_group = dpp_get_attr(buf, buflen,
765                                                     DPP_ATTR_FINITE_CYCLIC_GROUP,
766                                                     &attr_group_len);
767                     if (attr_group && attr_group_len == 2) {
768                               wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
769                                         "Peer indicated mismatching PKEX group - proposed %u",
770                                         WPA_GET_LE16(attr_group));
771                               return NULL;
772                     }
773           }
774 
775           if (attr_status[0] != DPP_STATUS_OK) {
776                     dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
777                     return NULL;
778           }
779 
780           attr_id_len = 0;
781           attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
782                                      &attr_id_len);
783           if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
784                                                pkex->identifier)) {
785                     dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
786                     return NULL;
787           }
788 
789           /* N in Encrypted Key attribute */
790           attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
791                                         &attr_key_len);
792           if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
793                     dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
794                     return NULL;
795           }
796 
797           /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
798           Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
799                                         pkex->code, pkex->code_len, pkex->identifier,
800                                         &ec);
801           if (!Qr)
802                     goto fail;
803 
804           /* Y' = N - Qr */
805           Y = crypto_ec_point_init(ec);
806           N = crypto_ec_point_from_bin(ec, attr_key);
807           if (!Y || !N ||
808               crypto_ec_point_is_at_infinity(ec, N) ||
809               !crypto_ec_point_is_on_curve(ec, N) ||
810               crypto_ec_point_invert(ec, Qr) ||
811               crypto_ec_point_add(ec, N, Qr, Y) ||
812               crypto_ec_point_is_at_infinity(ec, Y) ||
813               !crypto_ec_point_is_on_curve(ec, Y)) {
814                     dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
815                     pkex->t++;
816                     goto fail;
817           }
818           crypto_ec_point_debug_print(ec, N, "DPP: N");
819           crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
820 
821           pkex->exchange_done = 1;
822 
823           /* ECDH: J = a * Y' */
824           x_coord = os_malloc(curve->prime_len);
825           y_coord = os_malloc(curve->prime_len);
826           if (!x_coord || !y_coord ||
827               crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
828                     goto fail;
829           pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
830                                                   curve->prime_len);
831           if (!pkex->y)
832                     goto fail;
833           if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
834                     goto fail;
835 
836           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
837                               Jx, Jx_len);
838 
839           /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
840           A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
841           Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
842           X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
843           if (!A_pub || !Y_pub || !X_pub)
844                     goto fail;
845           num_elem = 0;
846           if (!pkex->v2) {
847                     addr[num_elem] = pkex->own_mac;
848                     len[num_elem] = ETH_ALEN;
849                     num_elem++;
850           }
851           addr[num_elem] = wpabuf_head(A_pub);
852           len[num_elem] = wpabuf_len(A_pub) / 2;
853           num_elem++;
854           addr[num_elem] = wpabuf_head(Y_pub);
855           len[num_elem] = wpabuf_len(Y_pub) / 2;
856           num_elem++;
857           addr[num_elem] = wpabuf_head(X_pub);
858           len[num_elem] = wpabuf_len(X_pub) / 2;
859           num_elem++;
860           if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
861               < 0)
862                     goto fail;
863           wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
864 
865           /* K = x * Y' */
866           if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
867                     goto fail;
868 
869           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
870                               Kx, Kx_len);
871 
872           /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
873           res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
874                                         pkex->v2 ? NULL : pkex->peer_mac,
875                                         DPP_VERSION, pkex->peer_version,
876                                         pkex->Mx, curve->prime_len,
877                                         attr_key /* N.x */, attr_key_len / 2,
878                                         pkex->code, pkex->code_len, Kx, Kx_len,
879                                         pkex->z, curve->hash_len);
880           os_memset(Kx, 0, Kx_len);
881           if (res < 0)
882                     goto fail;
883 
884           msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
885           if (!msg)
886                     goto fail;
887 
888 out:
889           wpabuf_free(A_pub);
890           wpabuf_free(X_pub);
891           wpabuf_free(Y_pub);
892           os_free(x_coord);
893           os_free(y_coord);
894           crypto_ec_point_deinit(Qr, 1);
895           crypto_ec_point_deinit(Y, 1);
896           crypto_ec_point_deinit(N, 1);
897           crypto_ec_deinit(ec);
898           return msg;
899 fail:
900           wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
901           goto out;
902 }
903 
904 
905 static struct wpabuf *
dpp_pkex_build_commit_reveal_resp(struct dpp_pkex * pkex,const struct wpabuf * B_pub,const u8 * v)906 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
907                                           const struct wpabuf *B_pub, const u8 *v)
908 {
909           const struct dpp_curve_params *curve = pkex->own_bi->curve;
910           struct wpabuf *msg = NULL;
911           const u8 *addr[2];
912           size_t len[2];
913           u8 octet;
914           u8 *wrapped;
915           struct wpabuf *clear = NULL;
916           size_t clear_len, attr_len;
917 
918           /* {B, v [bootstrapping info]}z */
919           clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
920           clear = wpabuf_alloc(clear_len);
921           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           msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
927           if (!clear || !msg)
928                     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           wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
947           wpabuf_put_le16(clear, wpabuf_len(B_pub));
948           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           wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
968           wpabuf_put_le16(clear, curve->hash_len);
969           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           addr[0] = wpabuf_head_u8(msg) + 2;
980           len[0] = DPP_HDR_LEN;
981           octet = 1;
982           addr[1] = &octet;
983           len[1] = sizeof(octet);
984           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
985           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
986 
987           wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
988           wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
989           wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
990 
991           wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
992           if (aes_siv_encrypt(pkex->z, curve->hash_len,
993                                   wpabuf_head(clear), wpabuf_len(clear),
994                                   2, addr, len, wrapped) < 0)
995                     goto fail;
996           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
997                         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 out:
1008           wpabuf_free(clear);
1009           return msg;
1010 
1011 fail:
1012           wpabuf_free(msg);
1013           msg = NULL;
1014           goto out;
1015 }
1016 
1017 
dpp_pkex_rx_commit_reveal_req(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)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 {
1022           const struct dpp_curve_params *curve = pkex->own_bi->curve;
1023           size_t Jx_len, Lx_len;
1024           u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
1025           u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1026           const u8 *wrapped_data, *b_key, *peer_u;
1027           u16 wrapped_data_len, b_key_len, peer_u_len = 0;
1028           const u8 *addr[4];
1029           size_t len[4];
1030           size_t num_elem;
1031           u8 octet;
1032           u8 *unwrapped = NULL;
1033           size_t unwrapped_len = 0;
1034           struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
1035           struct wpabuf *B_pub = NULL;
1036           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           if (!pkex->exchange_done || pkex->failed ||
1048               pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
1049                     goto fail;
1050 
1051           wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1052                                             &wrapped_data_len);
1053           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1054                     dpp_pkex_fail(pkex,
1055                                     "Missing or invalid required Wrapped Data attribute");
1056                     goto fail;
1057           }
1058 
1059           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1060                         wrapped_data, wrapped_data_len);
1061           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1062           unwrapped = os_malloc(unwrapped_len);
1063           if (!unwrapped)
1064                     goto fail;
1065 
1066           addr[0] = hdr;
1067           len[0] = DPP_HDR_LEN;
1068           octet = 0;
1069           addr[1] = &octet;
1070           len[1] = sizeof(octet);
1071           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1072           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1073 
1074           if (aes_siv_decrypt(pkex->z, curve->hash_len,
1075                                   wrapped_data, wrapped_data_len,
1076                                   2, addr, len, unwrapped) < 0) {
1077                     dpp_pkex_fail(pkex,
1078                                     "AES-SIV decryption failed - possible PKEX code mismatch");
1079                     pkex->failed = 1;
1080                     pkex->t++;
1081                     goto fail;
1082           }
1083           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1084                         unwrapped, unwrapped_len);
1085 
1086           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1087                     dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1088                     goto fail;
1089           }
1090 
1091           b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1092                                    &b_key_len);
1093           if (!b_key || b_key_len != 2 * curve->prime_len) {
1094                     dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1095                     goto fail;
1096           }
1097           pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1098                                                                       b_key_len);
1099           if (!pkex->peer_bootstrap_key) {
1100                     dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1101                     goto fail;
1102           }
1103           dpp_debug_print_key("DPP: Peer bootstrap public key",
1104                                   pkex->peer_bootstrap_key);
1105 
1106           /* ECDH: J' = y * A' */
1107           if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
1108                     goto fail;
1109 
1110           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
1111                               Jx, Jx_len);
1112 
1113           /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
1114           A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1115           Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1116           X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1117           if (!A_pub || !Y_pub || !X_pub)
1118                     goto fail;
1119           num_elem = 0;
1120           if (!pkex->v2) {
1121                     addr[num_elem] = pkex->peer_mac;
1122                     len[num_elem] = ETH_ALEN;
1123                     num_elem++;
1124           }
1125           addr[num_elem] = wpabuf_head(A_pub);
1126           len[num_elem] = wpabuf_len(A_pub) / 2;
1127           num_elem++;
1128           addr[num_elem] = wpabuf_head(Y_pub);
1129           len[num_elem] = wpabuf_len(Y_pub) / 2;
1130           num_elem++;
1131           addr[num_elem] = wpabuf_head(X_pub);
1132           len[num_elem] = wpabuf_len(X_pub) / 2;
1133           num_elem++;
1134           if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
1135               < 0)
1136                     goto fail;
1137 
1138           peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1139                                     &peer_u_len);
1140           if (!peer_u || peer_u_len != curve->hash_len ||
1141               os_memcmp(peer_u, u, curve->hash_len) != 0) {
1142                     dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
1143                     wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
1144                                   u, curve->hash_len);
1145                     wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
1146                     pkex->t++;
1147                     goto fail;
1148           }
1149           wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
1150 
1151           /* ECDH: L = b * X' */
1152           if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
1153                     goto fail;
1154 
1155           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1156                               Lx, Lx_len);
1157 
1158           /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
1159           B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
1160           if (!B_pub)
1161                     goto fail;
1162           num_elem = 0;
1163           if (!pkex->v2) {
1164                     addr[num_elem] = pkex->own_mac;
1165                     len[num_elem] = ETH_ALEN;
1166                     num_elem++;
1167           }
1168           addr[num_elem] = wpabuf_head(B_pub);
1169           len[num_elem] = wpabuf_len(B_pub) / 2;
1170           num_elem++;
1171           addr[num_elem] = wpabuf_head(X_pub);
1172           len[num_elem] = wpabuf_len(X_pub) / 2;
1173           num_elem++;
1174           addr[num_elem] = wpabuf_head(Y_pub);
1175           len[num_elem] = wpabuf_len(Y_pub) / 2;
1176           num_elem++;
1177           if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1178               < 0)
1179                     goto fail;
1180           wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
1181 
1182           msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
1183           if (!msg)
1184                     goto fail;
1185 
1186 out:
1187           os_free(unwrapped);
1188           wpabuf_free(A_pub);
1189           wpabuf_free(B_pub);
1190           wpabuf_free(X_pub);
1191           wpabuf_free(Y_pub);
1192           return msg;
1193 fail:
1194           wpa_printf(MSG_DEBUG,
1195                        "DPP: PKEX Commit-Reveal Request processing failed");
1196           goto out;
1197 }
1198 
1199 
dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex * pkex,const u8 * hdr,const u8 * buf,size_t buflen)1200 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
1201                                            const u8 *buf, size_t buflen)
1202 {
1203           const struct dpp_curve_params *curve = pkex->own_bi->curve;
1204           const u8 *wrapped_data, *b_key, *peer_v;
1205           u16 wrapped_data_len, b_key_len, peer_v_len = 0;
1206           const u8 *addr[4];
1207           size_t len[4];
1208           size_t num_elem;
1209           u8 octet;
1210           u8 *unwrapped = NULL;
1211           size_t unwrapped_len = 0;
1212           int ret = -1;
1213           u8 v[DPP_MAX_HASH_LEN];
1214           size_t Lx_len;
1215           u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
1216           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           if (!pkex->exchange_done || pkex->failed ||
1228               pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
1229                     goto fail;
1230 
1231           wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
1232                                             &wrapped_data_len);
1233           if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1234                     dpp_pkex_fail(pkex,
1235                                     "Missing or invalid required Wrapped Data attribute");
1236                     goto fail;
1237           }
1238 
1239           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1240                         wrapped_data, wrapped_data_len);
1241           unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1242           unwrapped = os_malloc(unwrapped_len);
1243           if (!unwrapped)
1244                     goto fail;
1245 
1246           addr[0] = hdr;
1247           len[0] = DPP_HDR_LEN;
1248           octet = 1;
1249           addr[1] = &octet;
1250           len[1] = sizeof(octet);
1251           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1252           wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1253 
1254           if (aes_siv_decrypt(pkex->z, curve->hash_len,
1255                                   wrapped_data, wrapped_data_len,
1256                                   2, addr, len, unwrapped) < 0) {
1257                     dpp_pkex_fail(pkex,
1258                                     "AES-SIV decryption failed - possible PKEX code mismatch");
1259                     pkex->t++;
1260                     goto fail;
1261           }
1262           wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1263                         unwrapped, unwrapped_len);
1264 
1265           if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1266                     dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
1267                     goto fail;
1268           }
1269 
1270           b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
1271                                    &b_key_len);
1272           if (!b_key || b_key_len != 2 * curve->prime_len) {
1273                     dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
1274                     goto fail;
1275           }
1276           pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
1277                                                                       b_key_len);
1278           if (!pkex->peer_bootstrap_key) {
1279                     dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
1280                     goto fail;
1281           }
1282           dpp_debug_print_key("DPP: Peer bootstrap public key",
1283                                   pkex->peer_bootstrap_key);
1284 
1285           /* ECDH: L' = x * B' */
1286           if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
1287                     goto fail;
1288 
1289           wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
1290                               Lx, Lx_len);
1291 
1292           /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
1293           B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
1294           X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
1295           Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
1296           if (!B_pub || !X_pub || !Y_pub)
1297                     goto fail;
1298           num_elem = 0;
1299           if (!pkex->v2) {
1300                     addr[num_elem] = pkex->peer_mac;
1301                     len[num_elem] = ETH_ALEN;
1302                     num_elem++;
1303           }
1304           addr[num_elem] = wpabuf_head(B_pub);
1305           len[num_elem] = wpabuf_len(B_pub) / 2;
1306           num_elem++;
1307           addr[num_elem] = wpabuf_head(X_pub);
1308           len[num_elem] = wpabuf_len(X_pub) / 2;
1309           num_elem++;
1310           addr[num_elem] = wpabuf_head(Y_pub);
1311           len[num_elem] = wpabuf_len(Y_pub) / 2;
1312           num_elem++;
1313           if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
1314               < 0)
1315                     goto fail;
1316 
1317           peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
1318                                     &peer_v_len);
1319           if (!peer_v || peer_v_len != curve->hash_len ||
1320               os_memcmp(peer_v, v, curve->hash_len) != 0) {
1321                     dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
1322                     wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
1323                                   v, curve->hash_len);
1324                     wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
1325                     pkex->t++;
1326                     goto fail;
1327           }
1328           wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
1329 
1330           ret = 0;
1331 out:
1332           wpabuf_free(B_pub);
1333           wpabuf_free(X_pub);
1334           wpabuf_free(Y_pub);
1335           os_free(unwrapped);
1336           return ret;
1337 fail:
1338           goto out;
1339 }
1340 
1341 
1342 struct dpp_bootstrap_info *
dpp_pkex_finish(struct dpp_global * dpp,struct dpp_pkex * pkex,const u8 * peer,unsigned int freq)1343 dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
1344                     unsigned int freq)
1345 {
1346           struct dpp_bootstrap_info *bi;
1347 
1348           bi = os_zalloc(sizeof(*bi));
1349           if (!bi)
1350                     return NULL;
1351           bi->id = dpp_next_id(dpp);
1352           bi->type = DPP_BOOTSTRAP_PKEX;
1353           if (peer)
1354                     os_memcpy(bi->mac_addr, peer, ETH_ALEN);
1355           if (freq) {
1356                     bi->num_freq = 1;
1357                     bi->freq[0] = freq;
1358           }
1359           bi->curve = pkex->own_bi->curve;
1360           bi->pubkey = pkex->peer_bootstrap_key;
1361           pkex->peer_bootstrap_key = NULL;
1362           if (dpp_bootstrap_key_hash(bi) < 0) {
1363                     dpp_bootstrap_info_free(bi);
1364                     return NULL;
1365           }
1366           os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash,
1367                       SHA256_MAC_LEN);
1368           dpp_pkex_free(pkex);
1369           dl_list_add(&dpp->bootstrap, &bi->list);
1370           return bi;
1371 }
1372 
1373 
dpp_pkex_free(struct dpp_pkex * pkex)1374 void dpp_pkex_free(struct dpp_pkex *pkex)
1375 {
1376           if (!pkex)
1377                     return;
1378 
1379           os_free(pkex->identifier);
1380           os_free(pkex->code);
1381           crypto_ec_key_deinit(pkex->x);
1382           crypto_ec_key_deinit(pkex->y);
1383           crypto_ec_key_deinit(pkex->peer_bootstrap_key);
1384           wpabuf_free(pkex->exchange_req);
1385           wpabuf_free(pkex->exchange_resp);
1386           wpabuf_free(pkex->enc_key);
1387           os_free(pkex);
1388 }
1389