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