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
23static 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
34struct 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);
122fail:
123	wpabuf_free(a_nonce);
124	wpabuf_free(e_id);
125	crypto_ec_key_deinit(own_key);
126	return msg;
127}
128
129
130static 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
170static int
171dpp_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;
215fail:
216	wpabuf_free(dppcon);
217	return ret;
218}
219
220
221struct dpp_authentication *
222dpp_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
303out:
304	return auth;
305fail:
306	dpp_auth_deinit(auth);
307	auth = NULL;
308	goto out;
309}
310
311
312static 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;
411out:
412	wpabuf_free(clear);
413	wpabuf_free(pr);
414	return res;
415fail:
416	wpabuf_free(msg);
417	goto out;
418}
419
420
421struct dpp_authentication *
422dpp_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
542out:
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;
549fail:
550	dpp_auth_deinit(auth);
551	auth = NULL;
552	goto out;
553}
554
555
556struct wpabuf *
557dpp_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
637out:
638	wpabuf_free(clear);
639	return msg;
640fail:
641	wpabuf_free(msg);
642	msg = NULL;
643	goto out;
644}
645
646
647struct wpabuf *
648dpp_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
819out:
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;
826fail:
827	wpabuf_free(conf);
828	conf = NULL;
829	goto out;
830}
831
832
833int 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;
949fail:
950	bin_clear_free(unwrapped, unwrapped_len);
951	return res;
952}
953
954#endif /* CONFIG_DPP2 */
955