• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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