xref: /freebsd/contrib/wpa/src/common/dpp_reconfig.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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