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