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