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