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