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