1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert * DPP authentication exchange
3c1d255d3SCy Schubert * Copyright (c) 2017, Qualcomm Atheros, Inc.
4c1d255d3SCy Schubert * Copyright (c) 2018-2020, The Linux Foundation
5c1d255d3SCy Schubert *
6c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license.
7c1d255d3SCy Schubert * See README for more details.
8c1d255d3SCy Schubert */
9c1d255d3SCy Schubert
10c1d255d3SCy Schubert #include "utils/includes.h"
11c1d255d3SCy Schubert
12c1d255d3SCy Schubert #include "utils/common.h"
13c1d255d3SCy Schubert #include "common/ieee802_11_common.h"
14c1d255d3SCy Schubert #include "common/wpa_ctrl.h"
15c1d255d3SCy Schubert #include "crypto/aes.h"
16c1d255d3SCy Schubert #include "crypto/aes_siv.h"
17c1d255d3SCy Schubert #include "crypto/random.h"
18c1d255d3SCy Schubert #include "dpp.h"
19c1d255d3SCy Schubert #include "dpp_i.h"
20c1d255d3SCy Schubert
21c1d255d3SCy Schubert
22c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
23c1d255d3SCy Schubert u8 dpp_protocol_key_override[600];
24c1d255d3SCy Schubert size_t dpp_protocol_key_override_len = 0;
25c1d255d3SCy Schubert u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
26c1d255d3SCy Schubert size_t dpp_nonce_override_len = 0;
27c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
28c1d255d3SCy Schubert
29c1d255d3SCy Schubert
dpp_build_attr_i_bootstrap_key_hash(struct wpabuf * msg,const u8 * hash)30c1d255d3SCy Schubert static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
31c1d255d3SCy Schubert const u8 *hash)
32c1d255d3SCy Schubert {
33c1d255d3SCy Schubert if (hash) {
34c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
35c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
36c1d255d3SCy Schubert wpabuf_put_le16(msg, SHA256_MAC_LEN);
37c1d255d3SCy Schubert wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
38c1d255d3SCy Schubert }
39c1d255d3SCy Schubert }
40c1d255d3SCy Schubert
41c1d255d3SCy Schubert
dpp_auth_success(struct dpp_authentication * auth)42c1d255d3SCy Schubert static void dpp_auth_success(struct dpp_authentication *auth)
43c1d255d3SCy Schubert {
44c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
45c1d255d3SCy Schubert "DPP: Authentication success - clear temporary keys");
46c1d255d3SCy Schubert os_memset(auth->Mx, 0, sizeof(auth->Mx));
47c1d255d3SCy Schubert auth->Mx_len = 0;
48c1d255d3SCy Schubert os_memset(auth->Nx, 0, sizeof(auth->Nx));
49c1d255d3SCy Schubert auth->Nx_len = 0;
50c1d255d3SCy Schubert os_memset(auth->Lx, 0, sizeof(auth->Lx));
51c1d255d3SCy Schubert auth->Lx_len = 0;
52c1d255d3SCy Schubert os_memset(auth->k1, 0, sizeof(auth->k1));
53c1d255d3SCy Schubert os_memset(auth->k2, 0, sizeof(auth->k2));
54c1d255d3SCy Schubert
55c1d255d3SCy Schubert auth->auth_success = 1;
56c1d255d3SCy Schubert }
57c1d255d3SCy Schubert
58c1d255d3SCy Schubert
dpp_auth_build_req(struct dpp_authentication * auth,const struct wpabuf * pi,size_t nonce_len,const u8 * r_pubkey_hash,const u8 * i_pubkey_hash,unsigned int neg_freq)59c1d255d3SCy Schubert static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
60c1d255d3SCy Schubert const struct wpabuf *pi,
61c1d255d3SCy Schubert size_t nonce_len,
62c1d255d3SCy Schubert const u8 *r_pubkey_hash,
63c1d255d3SCy Schubert const u8 *i_pubkey_hash,
64c1d255d3SCy Schubert unsigned int neg_freq)
65c1d255d3SCy Schubert {
66c1d255d3SCy Schubert struct wpabuf *msg;
67c1d255d3SCy Schubert u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
68c1d255d3SCy Schubert u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
69c1d255d3SCy Schubert u8 *pos;
70c1d255d3SCy Schubert const u8 *addr[2];
71c1d255d3SCy Schubert size_t len[2], siv_len, attr_len;
72c1d255d3SCy Schubert u8 *attr_start, *attr_end;
73c1d255d3SCy Schubert
74c1d255d3SCy Schubert /* Build DPP Authentication Request frame attributes */
75c1d255d3SCy Schubert attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
76c1d255d3SCy Schubert 4 + sizeof(wrapped_data);
77c1d255d3SCy Schubert if (neg_freq > 0)
78c1d255d3SCy Schubert attr_len += 4 + 2;
79c1d255d3SCy Schubert #ifdef CONFIG_DPP2
80c1d255d3SCy Schubert attr_len += 5;
81c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
82c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
83c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
84c1d255d3SCy Schubert attr_len += 5;
85c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
86c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
87c1d255d3SCy Schubert if (!msg)
88c1d255d3SCy Schubert return NULL;
89c1d255d3SCy Schubert
90c1d255d3SCy Schubert attr_start = wpabuf_put(msg, 0);
91c1d255d3SCy Schubert
92c1d255d3SCy Schubert /* Responder Bootstrapping Key Hash */
93c1d255d3SCy Schubert dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
94c1d255d3SCy Schubert
95c1d255d3SCy Schubert /* Initiator Bootstrapping Key Hash */
96c1d255d3SCy Schubert dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
97c1d255d3SCy Schubert
98c1d255d3SCy Schubert /* Initiator Protocol Key */
99c1d255d3SCy Schubert if (pi) {
100c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
101c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(pi));
102c1d255d3SCy Schubert wpabuf_put_buf(msg, pi);
103c1d255d3SCy Schubert }
104c1d255d3SCy Schubert
105c1d255d3SCy Schubert /* Channel */
106c1d255d3SCy Schubert if (neg_freq > 0) {
107c1d255d3SCy Schubert u8 op_class, channel;
108c1d255d3SCy Schubert
109c1d255d3SCy Schubert if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
110c1d255d3SCy Schubert &channel) ==
111c1d255d3SCy Schubert NUM_HOSTAPD_MODES) {
112c1d255d3SCy Schubert wpa_printf(MSG_INFO,
113c1d255d3SCy Schubert "DPP: Unsupported negotiation frequency request: %d",
114c1d255d3SCy Schubert neg_freq);
115c1d255d3SCy Schubert wpabuf_free(msg);
116c1d255d3SCy Schubert return NULL;
117c1d255d3SCy Schubert }
118c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
119c1d255d3SCy Schubert wpabuf_put_le16(msg, 2);
120c1d255d3SCy Schubert wpabuf_put_u8(msg, op_class);
121c1d255d3SCy Schubert wpabuf_put_u8(msg, channel);
122c1d255d3SCy Schubert }
123c1d255d3SCy Schubert
124c1d255d3SCy Schubert #ifdef CONFIG_DPP2
125c1d255d3SCy Schubert /* Protocol Version */
126c1d255d3SCy Schubert if (DPP_VERSION > 1) {
127c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
128c1d255d3SCy Schubert wpabuf_put_le16(msg, 1);
129c1d255d3SCy Schubert wpabuf_put_u8(msg, DPP_VERSION);
130c1d255d3SCy Schubert }
131c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
132c1d255d3SCy Schubert
133c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
134c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
135c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
136c1d255d3SCy Schubert goto skip_wrapped_data;
137c1d255d3SCy Schubert }
138c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
139c1d255d3SCy Schubert
140c1d255d3SCy Schubert /* Wrapped data ({I-nonce, I-capabilities}k1) */
141c1d255d3SCy Schubert pos = clear;
142c1d255d3SCy Schubert
143c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
144c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
145c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
146c1d255d3SCy Schubert goto skip_i_nonce;
147c1d255d3SCy Schubert }
148c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
149c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
150c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
151c1d255d3SCy Schubert pos += 2;
152c1d255d3SCy Schubert WPA_PUT_LE16(pos, nonce_len - 1);
153c1d255d3SCy Schubert pos += 2;
154c1d255d3SCy Schubert os_memcpy(pos, auth->i_nonce, nonce_len - 1);
155c1d255d3SCy Schubert pos += nonce_len - 1;
156c1d255d3SCy Schubert goto skip_i_nonce;
157c1d255d3SCy Schubert }
158c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
159c1d255d3SCy Schubert
160c1d255d3SCy Schubert /* I-nonce */
161c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
162c1d255d3SCy Schubert pos += 2;
163c1d255d3SCy Schubert WPA_PUT_LE16(pos, nonce_len);
164c1d255d3SCy Schubert pos += 2;
165c1d255d3SCy Schubert os_memcpy(pos, auth->i_nonce, nonce_len);
166c1d255d3SCy Schubert pos += nonce_len;
167c1d255d3SCy Schubert
168c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
169c1d255d3SCy Schubert skip_i_nonce:
170c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
171c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
172c1d255d3SCy Schubert goto skip_i_capab;
173c1d255d3SCy Schubert }
174c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
175c1d255d3SCy Schubert
176c1d255d3SCy Schubert /* I-capabilities */
177c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
178c1d255d3SCy Schubert pos += 2;
179c1d255d3SCy Schubert WPA_PUT_LE16(pos, 1);
180c1d255d3SCy Schubert pos += 2;
181c1d255d3SCy Schubert auth->i_capab = auth->allowed_roles;
182c1d255d3SCy Schubert *pos++ = auth->i_capab;
183c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
184c1d255d3SCy Schubert if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
185c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
186c1d255d3SCy Schubert pos[-1] = 0;
187c1d255d3SCy Schubert }
188c1d255d3SCy Schubert skip_i_capab:
189c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
190c1d255d3SCy Schubert
191c1d255d3SCy Schubert attr_end = wpabuf_put(msg, 0);
192c1d255d3SCy Schubert
193c1d255d3SCy Schubert /* OUI, OUI type, Crypto Suite, DPP frame type */
194c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2;
195c1d255d3SCy Schubert len[0] = 3 + 1 + 1 + 1;
196c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
197c1d255d3SCy Schubert
198c1d255d3SCy Schubert /* Attributes before Wrapped Data */
199c1d255d3SCy Schubert addr[1] = attr_start;
200c1d255d3SCy Schubert len[1] = attr_end - attr_start;
201c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
202c1d255d3SCy Schubert
203c1d255d3SCy Schubert siv_len = pos - clear;
204c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
205c1d255d3SCy Schubert if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
206c1d255d3SCy Schubert 2, addr, len, wrapped_data) < 0) {
207c1d255d3SCy Schubert wpabuf_free(msg);
208c1d255d3SCy Schubert return NULL;
209c1d255d3SCy Schubert }
210c1d255d3SCy Schubert siv_len += AES_BLOCK_SIZE;
211c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
212c1d255d3SCy Schubert wrapped_data, siv_len);
213c1d255d3SCy Schubert
214c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
215c1d255d3SCy Schubert wpabuf_put_le16(msg, siv_len);
216c1d255d3SCy Schubert wpabuf_put_data(msg, wrapped_data, siv_len);
217c1d255d3SCy Schubert
218c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
219c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
220c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
221c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK);
222c1d255d3SCy Schubert }
223c1d255d3SCy Schubert skip_wrapped_data:
224c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
225c1d255d3SCy Schubert
226c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG,
227c1d255d3SCy Schubert "DPP: Authentication Request frame attributes", msg);
228c1d255d3SCy Schubert
229c1d255d3SCy Schubert return msg;
230c1d255d3SCy Schubert }
231c1d255d3SCy Schubert
232c1d255d3SCy Schubert
dpp_auth_build_resp(struct dpp_authentication * auth,enum dpp_status_error status,const struct wpabuf * pr,size_t nonce_len,const u8 * r_pubkey_hash,const u8 * i_pubkey_hash,const u8 * r_nonce,const u8 * i_nonce,const u8 * wrapped_r_auth,size_t wrapped_r_auth_len,const u8 * siv_key)233c1d255d3SCy Schubert static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
234c1d255d3SCy Schubert enum dpp_status_error status,
235c1d255d3SCy Schubert const struct wpabuf *pr,
236c1d255d3SCy Schubert size_t nonce_len,
237c1d255d3SCy Schubert const u8 *r_pubkey_hash,
238c1d255d3SCy Schubert const u8 *i_pubkey_hash,
239c1d255d3SCy Schubert const u8 *r_nonce, const u8 *i_nonce,
240c1d255d3SCy Schubert const u8 *wrapped_r_auth,
241c1d255d3SCy Schubert size_t wrapped_r_auth_len,
242c1d255d3SCy Schubert const u8 *siv_key)
243c1d255d3SCy Schubert {
244c1d255d3SCy Schubert struct wpabuf *msg;
245c1d255d3SCy Schubert #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
246c1d255d3SCy Schubert 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
247c1d255d3SCy Schubert u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
248c1d255d3SCy Schubert u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
249c1d255d3SCy Schubert const u8 *addr[2];
250c1d255d3SCy Schubert size_t len[2], siv_len, attr_len;
251c1d255d3SCy Schubert u8 *attr_start, *attr_end, *pos;
252c1d255d3SCy Schubert
253c1d255d3SCy Schubert auth->waiting_auth_conf = 1;
254c1d255d3SCy Schubert auth->auth_resp_status = status;
255c1d255d3SCy Schubert auth->auth_resp_tries = 0;
256c1d255d3SCy Schubert
257c1d255d3SCy Schubert /* Build DPP Authentication Response frame attributes */
258c1d255d3SCy Schubert attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
259c1d255d3SCy Schubert 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
260c1d255d3SCy Schubert #ifdef CONFIG_DPP2
261c1d255d3SCy Schubert attr_len += 5;
262c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
263c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
264c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
265c1d255d3SCy Schubert attr_len += 5;
266c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
267c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
268c1d255d3SCy Schubert if (!msg)
269c1d255d3SCy Schubert return NULL;
270c1d255d3SCy Schubert
271c1d255d3SCy Schubert attr_start = wpabuf_put(msg, 0);
272c1d255d3SCy Schubert
273c1d255d3SCy Schubert /* DPP Status */
274c1d255d3SCy Schubert if (status != 255)
275c1d255d3SCy Schubert dpp_build_attr_status(msg, status);
276c1d255d3SCy Schubert
277c1d255d3SCy Schubert /* Responder Bootstrapping Key Hash */
278c1d255d3SCy Schubert dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
279c1d255d3SCy Schubert
280c1d255d3SCy Schubert /* Initiator Bootstrapping Key Hash (mutual authentication) */
281c1d255d3SCy Schubert dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
282c1d255d3SCy Schubert
283c1d255d3SCy Schubert /* Responder Protocol Key */
284c1d255d3SCy Schubert if (pr) {
285c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
286c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(pr));
287c1d255d3SCy Schubert wpabuf_put_buf(msg, pr);
288c1d255d3SCy Schubert }
289c1d255d3SCy Schubert
290c1d255d3SCy Schubert #ifdef CONFIG_DPP2
291c1d255d3SCy Schubert /* Protocol Version */
292c1d255d3SCy Schubert if (auth->peer_version >= 2) {
293c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
294c1d255d3SCy Schubert wpabuf_put_le16(msg, 1);
295c1d255d3SCy Schubert wpabuf_put_u8(msg, DPP_VERSION);
296c1d255d3SCy Schubert }
297c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
298c1d255d3SCy Schubert
299c1d255d3SCy Schubert attr_end = wpabuf_put(msg, 0);
300c1d255d3SCy Schubert
301c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
302c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
303c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
304c1d255d3SCy Schubert goto skip_wrapped_data;
305c1d255d3SCy Schubert }
306c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
307c1d255d3SCy Schubert
308c1d255d3SCy Schubert /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
309c1d255d3SCy Schubert pos = clear;
310c1d255d3SCy Schubert
311c1d255d3SCy Schubert if (r_nonce) {
312c1d255d3SCy Schubert /* R-nonce */
313c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
314c1d255d3SCy Schubert pos += 2;
315c1d255d3SCy Schubert WPA_PUT_LE16(pos, nonce_len);
316c1d255d3SCy Schubert pos += 2;
317c1d255d3SCy Schubert os_memcpy(pos, r_nonce, nonce_len);
318c1d255d3SCy Schubert pos += nonce_len;
319c1d255d3SCy Schubert }
320c1d255d3SCy Schubert
321c1d255d3SCy Schubert if (i_nonce) {
322c1d255d3SCy Schubert /* I-nonce */
323c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
324c1d255d3SCy Schubert pos += 2;
325c1d255d3SCy Schubert WPA_PUT_LE16(pos, nonce_len);
326c1d255d3SCy Schubert pos += 2;
327c1d255d3SCy Schubert os_memcpy(pos, i_nonce, nonce_len);
328c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
329c1d255d3SCy Schubert if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
330c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
331c1d255d3SCy Schubert pos[nonce_len / 2] ^= 0x01;
332c1d255d3SCy Schubert }
333c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
334c1d255d3SCy Schubert pos += nonce_len;
335c1d255d3SCy Schubert }
336c1d255d3SCy Schubert
337c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
338c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
339c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
340c1d255d3SCy Schubert goto skip_r_capab;
341c1d255d3SCy Schubert }
342c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
343c1d255d3SCy Schubert
344c1d255d3SCy Schubert /* R-capabilities */
345c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
346c1d255d3SCy Schubert pos += 2;
347c1d255d3SCy Schubert WPA_PUT_LE16(pos, 1);
348c1d255d3SCy Schubert pos += 2;
349c1d255d3SCy Schubert auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
350c1d255d3SCy Schubert DPP_CAPAB_ENROLLEE;
351c1d255d3SCy Schubert *pos++ = auth->r_capab;
352c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
353c1d255d3SCy Schubert if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
354c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
355c1d255d3SCy Schubert pos[-1] = 0;
356c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
357c1d255d3SCy Schubert wpa_printf(MSG_INFO,
358c1d255d3SCy Schubert "DPP: TESTING - incompatible R-capabilities");
359c1d255d3SCy Schubert if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
360c1d255d3SCy Schubert (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
361c1d255d3SCy Schubert pos[-1] = 0;
362c1d255d3SCy Schubert else
363c1d255d3SCy Schubert pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
364c1d255d3SCy Schubert DPP_CAPAB_CONFIGURATOR;
365c1d255d3SCy Schubert }
366c1d255d3SCy Schubert skip_r_capab:
367c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
368c1d255d3SCy Schubert
369c1d255d3SCy Schubert if (wrapped_r_auth) {
370c1d255d3SCy Schubert /* {R-auth}ke */
371c1d255d3SCy Schubert WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
372c1d255d3SCy Schubert pos += 2;
373c1d255d3SCy Schubert WPA_PUT_LE16(pos, wrapped_r_auth_len);
374c1d255d3SCy Schubert pos += 2;
375c1d255d3SCy Schubert os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
376c1d255d3SCy Schubert pos += wrapped_r_auth_len;
377c1d255d3SCy Schubert }
378c1d255d3SCy Schubert
379c1d255d3SCy Schubert /* OUI, OUI type, Crypto Suite, DPP frame type */
380c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2;
381c1d255d3SCy Schubert len[0] = 3 + 1 + 1 + 1;
382c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
383c1d255d3SCy Schubert
384c1d255d3SCy Schubert /* Attributes before Wrapped Data */
385c1d255d3SCy Schubert addr[1] = attr_start;
386c1d255d3SCy Schubert len[1] = attr_end - attr_start;
387c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
388c1d255d3SCy Schubert
389c1d255d3SCy Schubert siv_len = pos - clear;
390c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
391c1d255d3SCy Schubert if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
392c1d255d3SCy Schubert 2, addr, len, wrapped_data) < 0) {
393c1d255d3SCy Schubert wpabuf_free(msg);
394c1d255d3SCy Schubert return NULL;
395c1d255d3SCy Schubert }
396c1d255d3SCy Schubert siv_len += AES_BLOCK_SIZE;
397c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
398c1d255d3SCy Schubert wrapped_data, siv_len);
399c1d255d3SCy Schubert
400c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
401c1d255d3SCy Schubert wpabuf_put_le16(msg, siv_len);
402c1d255d3SCy Schubert wpabuf_put_data(msg, wrapped_data, siv_len);
403c1d255d3SCy Schubert
404c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
405c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
406c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
407c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK);
408c1d255d3SCy Schubert }
409c1d255d3SCy Schubert skip_wrapped_data:
410c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
411c1d255d3SCy Schubert
412c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG,
413c1d255d3SCy Schubert "DPP: Authentication Response frame attributes", msg);
414c1d255d3SCy Schubert return msg;
415c1d255d3SCy Schubert }
416c1d255d3SCy Schubert
417c1d255d3SCy Schubert
dpp_auth_build_resp_ok(struct dpp_authentication * auth)418c1d255d3SCy Schubert static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
419c1d255d3SCy Schubert {
420c1d255d3SCy Schubert size_t nonce_len;
421c1d255d3SCy Schubert size_t secret_len;
422c1d255d3SCy Schubert struct wpabuf *msg, *pr = NULL;
423c1d255d3SCy Schubert u8 r_auth[4 + DPP_MAX_HASH_LEN];
424c1d255d3SCy Schubert u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
425c1d255d3SCy Schubert size_t wrapped_r_auth_len;
426c1d255d3SCy Schubert int ret = -1;
427c1d255d3SCy Schubert const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
428c1d255d3SCy Schubert enum dpp_status_error status = DPP_STATUS_OK;
429c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
430c1d255d3SCy Schubert u8 test_hash[SHA256_MAC_LEN];
431c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
432c1d255d3SCy Schubert
433c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
434c1d255d3SCy Schubert if (!auth->own_bi)
435c1d255d3SCy Schubert return -1;
436c1d255d3SCy Schubert
437c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
438c1d255d3SCy Schubert if (dpp_nonce_override_len > 0) {
439c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
440c1d255d3SCy Schubert nonce_len = dpp_nonce_override_len;
441c1d255d3SCy Schubert os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
442c1d255d3SCy Schubert } else {
443c1d255d3SCy Schubert nonce_len = auth->curve->nonce_len;
444c1d255d3SCy Schubert if (random_get_bytes(auth->r_nonce, nonce_len)) {
445c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
446c1d255d3SCy Schubert "DPP: Failed to generate R-nonce");
447c1d255d3SCy Schubert goto fail;
448c1d255d3SCy Schubert }
449c1d255d3SCy Schubert }
450c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
451c1d255d3SCy Schubert nonce_len = auth->curve->nonce_len;
452c1d255d3SCy Schubert if (random_get_bytes(auth->r_nonce, nonce_len)) {
453c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
454c1d255d3SCy Schubert goto fail;
455c1d255d3SCy Schubert }
456c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
457c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
458c1d255d3SCy Schubert
459*4b72b91aSCy Schubert crypto_ec_key_deinit(auth->own_protocol_key);
460c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
461c1d255d3SCy Schubert if (dpp_protocol_key_override_len) {
462c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve;
463c1d255d3SCy Schubert
464c1d255d3SCy Schubert wpa_printf(MSG_INFO,
465c1d255d3SCy Schubert "DPP: TESTING - override protocol key");
466c1d255d3SCy Schubert auth->own_protocol_key = dpp_set_keypair(
467c1d255d3SCy Schubert &tmp_curve, dpp_protocol_key_override,
468c1d255d3SCy Schubert dpp_protocol_key_override_len);
469c1d255d3SCy Schubert } else {
470c1d255d3SCy Schubert auth->own_protocol_key = dpp_gen_keypair(auth->curve);
471c1d255d3SCy Schubert }
472c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
473c1d255d3SCy Schubert auth->own_protocol_key = dpp_gen_keypair(auth->curve);
474c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
475c1d255d3SCy Schubert if (!auth->own_protocol_key)
476c1d255d3SCy Schubert goto fail;
477c1d255d3SCy Schubert
478*4b72b91aSCy Schubert pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
479c1d255d3SCy Schubert if (!pr)
480c1d255d3SCy Schubert goto fail;
481c1d255d3SCy Schubert
482c1d255d3SCy Schubert /* ECDH: N = pR * PI */
483c1d255d3SCy Schubert if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
484c1d255d3SCy Schubert auth->Nx, &secret_len) < 0)
485c1d255d3SCy Schubert goto fail;
486c1d255d3SCy Schubert
487c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
488c1d255d3SCy Schubert auth->Nx, auth->secret_len);
489c1d255d3SCy Schubert auth->Nx_len = auth->secret_len;
490c1d255d3SCy Schubert
491c1d255d3SCy Schubert if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
492c1d255d3SCy Schubert auth->curve->hash_len) < 0)
493c1d255d3SCy Schubert goto fail;
494c1d255d3SCy Schubert
495c1d255d3SCy Schubert if (auth->own_bi && auth->peer_bi) {
496c1d255d3SCy Schubert /* Mutual authentication */
497c1d255d3SCy Schubert if (dpp_auth_derive_l_responder(auth) < 0)
498c1d255d3SCy Schubert goto fail;
499c1d255d3SCy Schubert }
500c1d255d3SCy Schubert
501c1d255d3SCy Schubert if (dpp_derive_bk_ke(auth) < 0)
502c1d255d3SCy Schubert goto fail;
503c1d255d3SCy Schubert
504c1d255d3SCy Schubert /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
505c1d255d3SCy Schubert WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
506c1d255d3SCy Schubert WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
507c1d255d3SCy Schubert if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
508c1d255d3SCy Schubert goto fail;
509c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
510c1d255d3SCy Schubert if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
511c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
512c1d255d3SCy Schubert r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
513c1d255d3SCy Schubert }
514c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
515c1d255d3SCy Schubert if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
516c1d255d3SCy Schubert r_auth, 4 + auth->curve->hash_len,
517c1d255d3SCy Schubert 0, NULL, NULL, wrapped_r_auth) < 0)
518c1d255d3SCy Schubert goto fail;
519c1d255d3SCy Schubert wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
520c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
521c1d255d3SCy Schubert wrapped_r_auth, wrapped_r_auth_len);
522c1d255d3SCy Schubert w_r_auth = wrapped_r_auth;
523c1d255d3SCy Schubert
524c1d255d3SCy Schubert r_pubkey_hash = auth->own_bi->pubkey_hash;
525c1d255d3SCy Schubert if (auth->peer_bi)
526c1d255d3SCy Schubert i_pubkey_hash = auth->peer_bi->pubkey_hash;
527c1d255d3SCy Schubert else
528c1d255d3SCy Schubert i_pubkey_hash = NULL;
529c1d255d3SCy Schubert
530c1d255d3SCy Schubert i_nonce = auth->i_nonce;
531c1d255d3SCy Schubert r_nonce = auth->r_nonce;
532c1d255d3SCy Schubert
533c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
534c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
535c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
536c1d255d3SCy Schubert r_pubkey_hash = NULL;
537c1d255d3SCy Schubert } else if (dpp_test ==
538c1d255d3SCy Schubert DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
539c1d255d3SCy Schubert wpa_printf(MSG_INFO,
540c1d255d3SCy Schubert "DPP: TESTING - invalid R-Bootstrap Key Hash");
541c1d255d3SCy Schubert os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
542c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
543c1d255d3SCy Schubert r_pubkey_hash = test_hash;
544c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
545c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
546c1d255d3SCy Schubert i_pubkey_hash = NULL;
547c1d255d3SCy Schubert } else if (dpp_test ==
548c1d255d3SCy Schubert DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
549c1d255d3SCy Schubert wpa_printf(MSG_INFO,
550c1d255d3SCy Schubert "DPP: TESTING - invalid I-Bootstrap Key Hash");
551c1d255d3SCy Schubert if (i_pubkey_hash)
552c1d255d3SCy Schubert os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
553c1d255d3SCy Schubert else
554c1d255d3SCy Schubert os_memset(test_hash, 0, SHA256_MAC_LEN);
555c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
556c1d255d3SCy Schubert i_pubkey_hash = test_hash;
557c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
558c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
559c1d255d3SCy Schubert wpabuf_free(pr);
560c1d255d3SCy Schubert pr = NULL;
561c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
562c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
563c1d255d3SCy Schubert wpabuf_free(pr);
564c1d255d3SCy Schubert pr = wpabuf_alloc(2 * auth->curve->prime_len);
565c1d255d3SCy Schubert if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
566c1d255d3SCy Schubert goto fail;
567c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
568c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
569c1d255d3SCy Schubert w_r_auth = NULL;
570c1d255d3SCy Schubert wrapped_r_auth_len = 0;
571c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
572c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
573c1d255d3SCy Schubert status = 255;
574c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
575c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
576c1d255d3SCy Schubert status = 254;
577c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
578c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
579c1d255d3SCy Schubert r_nonce = NULL;
580c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
581c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
582c1d255d3SCy Schubert i_nonce = NULL;
583c1d255d3SCy Schubert }
584c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
585c1d255d3SCy Schubert
586c1d255d3SCy Schubert msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
587c1d255d3SCy Schubert r_pubkey_hash, i_pubkey_hash,
588c1d255d3SCy Schubert r_nonce, i_nonce,
589c1d255d3SCy Schubert w_r_auth, wrapped_r_auth_len,
590c1d255d3SCy Schubert auth->k2);
591c1d255d3SCy Schubert if (!msg)
592c1d255d3SCy Schubert goto fail;
593c1d255d3SCy Schubert wpabuf_free(auth->resp_msg);
594c1d255d3SCy Schubert auth->resp_msg = msg;
595c1d255d3SCy Schubert ret = 0;
596c1d255d3SCy Schubert fail:
597c1d255d3SCy Schubert wpabuf_free(pr);
598c1d255d3SCy Schubert return ret;
599c1d255d3SCy Schubert }
600c1d255d3SCy Schubert
601c1d255d3SCy Schubert
dpp_auth_build_resp_status(struct dpp_authentication * auth,enum dpp_status_error status)602c1d255d3SCy Schubert static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
603c1d255d3SCy Schubert enum dpp_status_error status)
604c1d255d3SCy Schubert {
605c1d255d3SCy Schubert struct wpabuf *msg;
606c1d255d3SCy Schubert const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
607c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
608c1d255d3SCy Schubert u8 test_hash[SHA256_MAC_LEN];
609c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
610c1d255d3SCy Schubert
611c1d255d3SCy Schubert if (!auth->own_bi)
612c1d255d3SCy Schubert return -1;
613c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
614c1d255d3SCy Schubert
615c1d255d3SCy Schubert r_pubkey_hash = auth->own_bi->pubkey_hash;
616c1d255d3SCy Schubert if (auth->peer_bi)
617c1d255d3SCy Schubert i_pubkey_hash = auth->peer_bi->pubkey_hash;
618c1d255d3SCy Schubert else
619c1d255d3SCy Schubert i_pubkey_hash = NULL;
620c1d255d3SCy Schubert
621c1d255d3SCy Schubert i_nonce = auth->i_nonce;
622c1d255d3SCy Schubert
623c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
624c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
625c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
626c1d255d3SCy Schubert r_pubkey_hash = NULL;
627c1d255d3SCy Schubert } else if (dpp_test ==
628c1d255d3SCy Schubert DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
629c1d255d3SCy Schubert wpa_printf(MSG_INFO,
630c1d255d3SCy Schubert "DPP: TESTING - invalid R-Bootstrap Key Hash");
631c1d255d3SCy Schubert os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
632c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
633c1d255d3SCy Schubert r_pubkey_hash = test_hash;
634c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
635c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
636c1d255d3SCy Schubert i_pubkey_hash = NULL;
637c1d255d3SCy Schubert } else if (dpp_test ==
638c1d255d3SCy Schubert DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
639c1d255d3SCy Schubert wpa_printf(MSG_INFO,
640c1d255d3SCy Schubert "DPP: TESTING - invalid I-Bootstrap Key Hash");
641c1d255d3SCy Schubert if (i_pubkey_hash)
642c1d255d3SCy Schubert os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
643c1d255d3SCy Schubert else
644c1d255d3SCy Schubert os_memset(test_hash, 0, SHA256_MAC_LEN);
645c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
646c1d255d3SCy Schubert i_pubkey_hash = test_hash;
647c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
648c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
649c1d255d3SCy Schubert status = 255;
650c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
651c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
652c1d255d3SCy Schubert i_nonce = NULL;
653c1d255d3SCy Schubert }
654c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
655c1d255d3SCy Schubert
656c1d255d3SCy Schubert msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
657c1d255d3SCy Schubert r_pubkey_hash, i_pubkey_hash,
658c1d255d3SCy Schubert NULL, i_nonce, NULL, 0, auth->k1);
659c1d255d3SCy Schubert if (!msg)
660c1d255d3SCy Schubert return -1;
661c1d255d3SCy Schubert wpabuf_free(auth->resp_msg);
662c1d255d3SCy Schubert auth->resp_msg = msg;
663c1d255d3SCy Schubert return 0;
664c1d255d3SCy Schubert }
665c1d255d3SCy Schubert
666c1d255d3SCy Schubert
667c1d255d3SCy Schubert struct dpp_authentication *
dpp_auth_req_rx(struct dpp_global * dpp,void * msg_ctx,u8 dpp_allowed_roles,int qr_mutual,struct dpp_bootstrap_info * peer_bi,struct dpp_bootstrap_info * own_bi,unsigned int freq,const u8 * hdr,const u8 * attr_start,size_t attr_len)668c1d255d3SCy Schubert dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
669c1d255d3SCy Schubert int qr_mutual, struct dpp_bootstrap_info *peer_bi,
670c1d255d3SCy Schubert struct dpp_bootstrap_info *own_bi,
671c1d255d3SCy Schubert unsigned int freq, const u8 *hdr, const u8 *attr_start,
672c1d255d3SCy Schubert size_t attr_len)
673c1d255d3SCy Schubert {
674*4b72b91aSCy Schubert struct crypto_ec_key *pi = NULL;
675c1d255d3SCy Schubert size_t secret_len;
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 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
681c1d255d3SCy Schubert *channel;
682c1d255d3SCy Schubert u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
683c1d255d3SCy Schubert i_bootstrap_len, channel_len;
684c1d255d3SCy Schubert struct dpp_authentication *auth = NULL;
685c1d255d3SCy Schubert #ifdef CONFIG_DPP2
686c1d255d3SCy Schubert const u8 *version;
687c1d255d3SCy Schubert u16 version_len;
688c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
689c1d255d3SCy Schubert
690c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
691c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
692c1d255d3SCy Schubert wpa_printf(MSG_INFO,
693c1d255d3SCy Schubert "DPP: TESTING - stop at Authentication Request");
694c1d255d3SCy Schubert return NULL;
695c1d255d3SCy Schubert }
696c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
697c1d255d3SCy Schubert
698c1d255d3SCy Schubert wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
699c1d255d3SCy Schubert &wrapped_data_len);
700c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
701c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
702c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute");
703c1d255d3SCy Schubert return NULL;
704c1d255d3SCy Schubert }
705c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
706c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
707c1d255d3SCy Schubert attr_len = wrapped_data - 4 - attr_start;
708c1d255d3SCy Schubert
709c1d255d3SCy Schubert auth = dpp_alloc_auth(dpp, msg_ctx);
710c1d255d3SCy Schubert if (!auth)
711c1d255d3SCy Schubert goto fail;
712c1d255d3SCy Schubert if (peer_bi && peer_bi->configurator_params &&
713c1d255d3SCy Schubert dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
714c1d255d3SCy Schubert goto fail;
715c1d255d3SCy Schubert auth->peer_bi = peer_bi;
716c1d255d3SCy Schubert auth->own_bi = own_bi;
717c1d255d3SCy Schubert auth->curve = own_bi->curve;
718c1d255d3SCy Schubert auth->curr_freq = freq;
719c1d255d3SCy Schubert
720c1d255d3SCy Schubert auth->peer_version = 1; /* default to the first version */
721c1d255d3SCy Schubert #ifdef CONFIG_DPP2
722c1d255d3SCy Schubert version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
723c1d255d3SCy Schubert &version_len);
724c1d255d3SCy Schubert if (version && DPP_VERSION > 1) {
725c1d255d3SCy Schubert if (version_len < 1 || version[0] == 0) {
726c1d255d3SCy Schubert dpp_auth_fail(auth,
727c1d255d3SCy Schubert "Invalid Protocol Version attribute");
728c1d255d3SCy Schubert goto fail;
729c1d255d3SCy Schubert }
730c1d255d3SCy Schubert auth->peer_version = version[0];
731c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
732c1d255d3SCy Schubert auth->peer_version);
733c1d255d3SCy Schubert }
734c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
735c1d255d3SCy Schubert
736c1d255d3SCy Schubert channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
737c1d255d3SCy Schubert &channel_len);
738c1d255d3SCy Schubert if (channel) {
739c1d255d3SCy Schubert int neg_freq;
740c1d255d3SCy Schubert
741c1d255d3SCy Schubert if (channel_len < 2) {
742c1d255d3SCy Schubert dpp_auth_fail(auth, "Too short Channel attribute");
743c1d255d3SCy Schubert goto fail;
744c1d255d3SCy Schubert }
745c1d255d3SCy Schubert
746c1d255d3SCy Schubert neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
747c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
748c1d255d3SCy Schubert "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
749c1d255d3SCy Schubert channel[0], channel[1], neg_freq);
750c1d255d3SCy Schubert if (neg_freq < 0) {
751c1d255d3SCy Schubert dpp_auth_fail(auth,
752c1d255d3SCy Schubert "Unsupported Channel attribute value");
753c1d255d3SCy Schubert goto fail;
754c1d255d3SCy Schubert }
755c1d255d3SCy Schubert
756c1d255d3SCy Schubert if (auth->curr_freq != (unsigned int) neg_freq) {
757c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
758c1d255d3SCy Schubert "DPP: Changing negotiation channel from %u MHz to %u MHz",
759c1d255d3SCy Schubert freq, neg_freq);
760c1d255d3SCy Schubert auth->curr_freq = neg_freq;
761c1d255d3SCy Schubert }
762c1d255d3SCy Schubert }
763c1d255d3SCy Schubert
764c1d255d3SCy Schubert i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
765c1d255d3SCy Schubert &i_proto_len);
766c1d255d3SCy Schubert if (!i_proto) {
767c1d255d3SCy Schubert dpp_auth_fail(auth,
768c1d255d3SCy Schubert "Missing required Initiator Protocol Key attribute");
769c1d255d3SCy Schubert goto fail;
770c1d255d3SCy Schubert }
771c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
772c1d255d3SCy Schubert i_proto, i_proto_len);
773c1d255d3SCy Schubert
774c1d255d3SCy Schubert /* M = bR * PI */
775c1d255d3SCy Schubert pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
776c1d255d3SCy Schubert if (!pi) {
777c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
778c1d255d3SCy Schubert goto fail;
779c1d255d3SCy Schubert }
780c1d255d3SCy Schubert dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
781c1d255d3SCy Schubert
782c1d255d3SCy Schubert if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
783c1d255d3SCy Schubert goto fail;
784c1d255d3SCy Schubert auth->secret_len = secret_len;
785c1d255d3SCy Schubert
786c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
787c1d255d3SCy Schubert auth->Mx, auth->secret_len);
788c1d255d3SCy Schubert auth->Mx_len = auth->secret_len;
789c1d255d3SCy Schubert
790c1d255d3SCy Schubert if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
791c1d255d3SCy Schubert auth->curve->hash_len) < 0)
792c1d255d3SCy Schubert goto fail;
793c1d255d3SCy Schubert
794c1d255d3SCy Schubert addr[0] = hdr;
795c1d255d3SCy Schubert len[0] = DPP_HDR_LEN;
796c1d255d3SCy Schubert addr[1] = attr_start;
797c1d255d3SCy Schubert len[1] = attr_len;
798c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
799c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
800c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
801c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
802c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
803c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len);
804c1d255d3SCy Schubert if (!unwrapped)
805c1d255d3SCy Schubert goto fail;
806c1d255d3SCy Schubert if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
807c1d255d3SCy Schubert wrapped_data, wrapped_data_len,
808c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) {
809c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
810c1d255d3SCy Schubert goto fail;
811c1d255d3SCy Schubert }
812c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
813c1d255d3SCy Schubert unwrapped, unwrapped_len);
814c1d255d3SCy Schubert
815c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
816c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
817c1d255d3SCy Schubert goto fail;
818c1d255d3SCy Schubert }
819c1d255d3SCy Schubert
820c1d255d3SCy Schubert i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
821c1d255d3SCy Schubert &i_nonce_len);
822c1d255d3SCy Schubert if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
823c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid I-nonce");
824c1d255d3SCy Schubert goto fail;
825c1d255d3SCy Schubert }
826c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
827c1d255d3SCy Schubert os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
828c1d255d3SCy Schubert
829c1d255d3SCy Schubert i_capab = dpp_get_attr(unwrapped, unwrapped_len,
830c1d255d3SCy Schubert DPP_ATTR_I_CAPABILITIES,
831c1d255d3SCy Schubert &i_capab_len);
832c1d255d3SCy Schubert if (!i_capab || i_capab_len < 1) {
833c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid I-capabilities");
834c1d255d3SCy Schubert goto fail;
835c1d255d3SCy Schubert }
836c1d255d3SCy Schubert auth->i_capab = i_capab[0];
837c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
838c1d255d3SCy Schubert
839c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
840c1d255d3SCy Schubert unwrapped = NULL;
841c1d255d3SCy Schubert
842c1d255d3SCy Schubert switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
843c1d255d3SCy Schubert case DPP_CAPAB_ENROLLEE:
844c1d255d3SCy Schubert if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
845c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
846c1d255d3SCy Schubert "DPP: Local policy does not allow Configurator role");
847c1d255d3SCy Schubert goto not_compatible;
848c1d255d3SCy Schubert }
849c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
850c1d255d3SCy Schubert auth->configurator = 1;
851c1d255d3SCy Schubert break;
852c1d255d3SCy Schubert case DPP_CAPAB_CONFIGURATOR:
853c1d255d3SCy Schubert if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
854c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
855c1d255d3SCy Schubert "DPP: Local policy does not allow Enrollee role");
856c1d255d3SCy Schubert goto not_compatible;
857c1d255d3SCy Schubert }
858c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
859c1d255d3SCy Schubert auth->configurator = 0;
860c1d255d3SCy Schubert break;
861c1d255d3SCy Schubert case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
862c1d255d3SCy Schubert if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
863c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
864c1d255d3SCy Schubert auth->configurator = 0;
865c1d255d3SCy Schubert } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
866c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
867c1d255d3SCy Schubert auth->configurator = 1;
868c1d255d3SCy Schubert } else {
869c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
870c1d255d3SCy Schubert "DPP: Local policy does not allow Configurator/Enrollee role");
871c1d255d3SCy Schubert goto not_compatible;
872c1d255d3SCy Schubert }
873c1d255d3SCy Schubert break;
874c1d255d3SCy Schubert default:
875c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
876c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO,
877c1d255d3SCy Schubert DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
878c1d255d3SCy Schubert auth->i_capab & DPP_CAPAB_ROLE_MASK);
879c1d255d3SCy Schubert goto fail;
880c1d255d3SCy Schubert }
881c1d255d3SCy Schubert
882c1d255d3SCy Schubert auth->peer_protocol_key = pi;
883c1d255d3SCy Schubert pi = NULL;
884c1d255d3SCy Schubert if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
885c1d255d3SCy Schubert char hex[SHA256_MAC_LEN * 2 + 1];
886c1d255d3SCy Schubert
887c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
888c1d255d3SCy Schubert "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
889c1d255d3SCy Schubert if (dpp_auth_build_resp_status(auth,
890c1d255d3SCy Schubert DPP_STATUS_RESPONSE_PENDING) < 0)
891c1d255d3SCy Schubert goto fail;
892c1d255d3SCy Schubert i_bootstrap = dpp_get_attr(attr_start, attr_len,
893c1d255d3SCy Schubert DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
894c1d255d3SCy Schubert &i_bootstrap_len);
895c1d255d3SCy Schubert if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
896c1d255d3SCy Schubert auth->response_pending = 1;
897c1d255d3SCy Schubert os_memcpy(auth->waiting_pubkey_hash,
898c1d255d3SCy Schubert i_bootstrap, i_bootstrap_len);
899c1d255d3SCy Schubert wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
900c1d255d3SCy Schubert i_bootstrap_len);
901c1d255d3SCy Schubert } else {
902c1d255d3SCy Schubert hex[0] = '\0';
903c1d255d3SCy Schubert }
904c1d255d3SCy Schubert
905c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
906c1d255d3SCy Schubert "%s", hex);
907c1d255d3SCy Schubert return auth;
908c1d255d3SCy Schubert }
909c1d255d3SCy Schubert if (dpp_auth_build_resp_ok(auth) < 0)
910c1d255d3SCy Schubert goto fail;
911c1d255d3SCy Schubert
912c1d255d3SCy Schubert return auth;
913c1d255d3SCy Schubert
914c1d255d3SCy Schubert not_compatible:
915c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
916c1d255d3SCy Schubert "i-capab=0x%02x", auth->i_capab);
917c1d255d3SCy Schubert if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
918c1d255d3SCy Schubert auth->configurator = 1;
919c1d255d3SCy Schubert else
920c1d255d3SCy Schubert auth->configurator = 0;
921c1d255d3SCy Schubert auth->peer_protocol_key = pi;
922c1d255d3SCy Schubert pi = NULL;
923c1d255d3SCy Schubert if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
924c1d255d3SCy Schubert goto fail;
925c1d255d3SCy Schubert
926c1d255d3SCy Schubert auth->remove_on_tx_status = 1;
927c1d255d3SCy Schubert return auth;
928c1d255d3SCy Schubert fail:
929c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
930*4b72b91aSCy Schubert crypto_ec_key_deinit(pi);
931c1d255d3SCy Schubert dpp_auth_deinit(auth);
932c1d255d3SCy Schubert return NULL;
933c1d255d3SCy Schubert }
934c1d255d3SCy Schubert
935c1d255d3SCy Schubert
dpp_notify_new_qr_code(struct dpp_authentication * auth,struct dpp_bootstrap_info * peer_bi)936c1d255d3SCy Schubert int dpp_notify_new_qr_code(struct dpp_authentication *auth,
937c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi)
938c1d255d3SCy Schubert {
939c1d255d3SCy Schubert if (!auth || !auth->response_pending ||
940c1d255d3SCy Schubert os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
941c1d255d3SCy Schubert SHA256_MAC_LEN) != 0)
942c1d255d3SCy Schubert return 0;
943c1d255d3SCy Schubert
944c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
945c1d255d3SCy Schubert "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
946c1d255d3SCy Schubert MACSTR, MAC2STR(auth->peer_mac_addr));
947c1d255d3SCy Schubert auth->peer_bi = peer_bi;
948c1d255d3SCy Schubert
949c1d255d3SCy Schubert if (dpp_auth_build_resp_ok(auth) < 0)
950c1d255d3SCy Schubert return -1;
951c1d255d3SCy Schubert
952c1d255d3SCy Schubert return 1;
953c1d255d3SCy Schubert }
954c1d255d3SCy Schubert
955c1d255d3SCy Schubert
dpp_auth_build_conf(struct dpp_authentication * auth,enum dpp_status_error status)956c1d255d3SCy Schubert static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
957c1d255d3SCy Schubert enum dpp_status_error status)
958c1d255d3SCy Schubert {
959c1d255d3SCy Schubert struct wpabuf *msg;
960c1d255d3SCy Schubert u8 i_auth[4 + DPP_MAX_HASH_LEN];
961c1d255d3SCy Schubert size_t i_auth_len;
962c1d255d3SCy Schubert u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
963c1d255d3SCy Schubert size_t r_nonce_len;
964c1d255d3SCy Schubert const u8 *addr[2];
965c1d255d3SCy Schubert size_t len[2], attr_len;
966c1d255d3SCy Schubert u8 *wrapped_i_auth;
967c1d255d3SCy Schubert u8 *wrapped_r_nonce;
968c1d255d3SCy Schubert u8 *attr_start, *attr_end;
969c1d255d3SCy Schubert const u8 *r_pubkey_hash, *i_pubkey_hash;
970c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
971c1d255d3SCy Schubert u8 test_hash[SHA256_MAC_LEN];
972c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
973c1d255d3SCy Schubert
974c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
975c1d255d3SCy Schubert
976c1d255d3SCy Schubert i_auth_len = 4 + auth->curve->hash_len;
977c1d255d3SCy Schubert r_nonce_len = 4 + auth->curve->nonce_len;
978c1d255d3SCy Schubert /* Build DPP Authentication Confirmation frame attributes */
979c1d255d3SCy Schubert attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
980c1d255d3SCy Schubert 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
981c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
982c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
983c1d255d3SCy Schubert attr_len += 5;
984c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
985c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
986c1d255d3SCy Schubert if (!msg)
987c1d255d3SCy Schubert goto fail;
988c1d255d3SCy Schubert
989c1d255d3SCy Schubert attr_start = wpabuf_put(msg, 0);
990c1d255d3SCy Schubert
991c1d255d3SCy Schubert r_pubkey_hash = auth->peer_bi->pubkey_hash;
992c1d255d3SCy Schubert if (auth->own_bi)
993c1d255d3SCy Schubert i_pubkey_hash = auth->own_bi->pubkey_hash;
994c1d255d3SCy Schubert else
995c1d255d3SCy Schubert i_pubkey_hash = NULL;
996c1d255d3SCy Schubert
997c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
998c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
999c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
1000c1d255d3SCy Schubert goto skip_status;
1001c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
1002c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
1003c1d255d3SCy Schubert status = 254;
1004c1d255d3SCy Schubert }
1005c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1006c1d255d3SCy Schubert
1007c1d255d3SCy Schubert /* DPP Status */
1008c1d255d3SCy Schubert dpp_build_attr_status(msg, status);
1009c1d255d3SCy Schubert
1010c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1011c1d255d3SCy Schubert skip_status:
1012c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
1013c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
1014c1d255d3SCy Schubert r_pubkey_hash = NULL;
1015c1d255d3SCy Schubert } else if (dpp_test ==
1016c1d255d3SCy Schubert DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
1017c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1018c1d255d3SCy Schubert "DPP: TESTING - invalid R-Bootstrap Key Hash");
1019c1d255d3SCy Schubert os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
1020c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1021c1d255d3SCy Schubert r_pubkey_hash = test_hash;
1022c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
1023c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
1024c1d255d3SCy Schubert i_pubkey_hash = NULL;
1025c1d255d3SCy Schubert } else if (dpp_test ==
1026c1d255d3SCy Schubert DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
1027c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1028c1d255d3SCy Schubert "DPP: TESTING - invalid I-Bootstrap Key Hash");
1029c1d255d3SCy Schubert if (i_pubkey_hash)
1030c1d255d3SCy Schubert os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
1031c1d255d3SCy Schubert else
1032c1d255d3SCy Schubert os_memset(test_hash, 0, SHA256_MAC_LEN);
1033c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1034c1d255d3SCy Schubert i_pubkey_hash = test_hash;
1035c1d255d3SCy Schubert }
1036c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1037c1d255d3SCy Schubert
1038c1d255d3SCy Schubert /* Responder Bootstrapping Key Hash */
1039c1d255d3SCy Schubert dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
1040c1d255d3SCy Schubert
1041c1d255d3SCy Schubert /* Initiator Bootstrapping Key Hash (mutual authentication) */
1042c1d255d3SCy Schubert dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
1043c1d255d3SCy Schubert
1044c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1045c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
1046c1d255d3SCy Schubert goto skip_wrapped_data;
1047c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
1048c1d255d3SCy Schubert i_auth_len = 0;
1049c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1050c1d255d3SCy Schubert
1051c1d255d3SCy Schubert attr_end = wpabuf_put(msg, 0);
1052c1d255d3SCy Schubert
1053c1d255d3SCy Schubert /* OUI, OUI type, Crypto Suite, DPP frame type */
1054c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2;
1055c1d255d3SCy Schubert len[0] = 3 + 1 + 1 + 1;
1056c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1057c1d255d3SCy Schubert
1058c1d255d3SCy Schubert /* Attributes before Wrapped Data */
1059c1d255d3SCy Schubert addr[1] = attr_start;
1060c1d255d3SCy Schubert len[1] = attr_end - attr_start;
1061c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1062c1d255d3SCy Schubert
1063c1d255d3SCy Schubert if (status == DPP_STATUS_OK) {
1064c1d255d3SCy Schubert /* I-auth wrapped with ke */
1065c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1066c1d255d3SCy Schubert wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
1067c1d255d3SCy Schubert wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
1068c1d255d3SCy Schubert
1069c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1070c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
1071c1d255d3SCy Schubert goto skip_i_auth;
1072c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1073c1d255d3SCy Schubert
1074c1d255d3SCy Schubert /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
1075c1d255d3SCy Schubert * 1) */
1076c1d255d3SCy Schubert WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
1077c1d255d3SCy Schubert WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
1078c1d255d3SCy Schubert if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
1079c1d255d3SCy Schubert goto fail;
1080c1d255d3SCy Schubert
1081c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1082c1d255d3SCy Schubert if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
1083c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
1084c1d255d3SCy Schubert i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
1085c1d255d3SCy Schubert }
1086c1d255d3SCy Schubert skip_i_auth:
1087c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1088c1d255d3SCy Schubert if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
1089c1d255d3SCy Schubert i_auth, i_auth_len,
1090c1d255d3SCy Schubert 2, addr, len, wrapped_i_auth) < 0)
1091c1d255d3SCy Schubert goto fail;
1092c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
1093c1d255d3SCy Schubert wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
1094c1d255d3SCy Schubert } else {
1095c1d255d3SCy Schubert /* R-nonce wrapped with k2 */
1096c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1097c1d255d3SCy Schubert wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
1098c1d255d3SCy Schubert wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
1099c1d255d3SCy Schubert
1100c1d255d3SCy Schubert WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
1101c1d255d3SCy Schubert WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
1102c1d255d3SCy Schubert os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
1103c1d255d3SCy Schubert
1104c1d255d3SCy Schubert if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
1105c1d255d3SCy Schubert r_nonce, r_nonce_len,
1106c1d255d3SCy Schubert 2, addr, len, wrapped_r_nonce) < 0)
1107c1d255d3SCy Schubert goto fail;
1108c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
1109c1d255d3SCy Schubert wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
1110c1d255d3SCy Schubert }
1111c1d255d3SCy Schubert
1112c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1113c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
1114c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
1115c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK);
1116c1d255d3SCy Schubert }
1117c1d255d3SCy Schubert skip_wrapped_data:
1118c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1119c1d255d3SCy Schubert
1120c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG,
1121c1d255d3SCy Schubert "DPP: Authentication Confirmation frame attributes",
1122c1d255d3SCy Schubert msg);
1123c1d255d3SCy Schubert if (status == DPP_STATUS_OK)
1124c1d255d3SCy Schubert dpp_auth_success(auth);
1125c1d255d3SCy Schubert
1126c1d255d3SCy Schubert return msg;
1127c1d255d3SCy Schubert
1128c1d255d3SCy Schubert fail:
1129c1d255d3SCy Schubert wpabuf_free(msg);
1130c1d255d3SCy Schubert return NULL;
1131c1d255d3SCy Schubert }
1132c1d255d3SCy Schubert
1133c1d255d3SCy Schubert
dpp_autogen_bootstrap_key(struct dpp_authentication * auth)1134c1d255d3SCy Schubert static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
1135c1d255d3SCy Schubert {
1136c1d255d3SCy Schubert struct dpp_bootstrap_info *bi;
1137c1d255d3SCy Schubert
1138c1d255d3SCy Schubert if (auth->own_bi)
1139c1d255d3SCy Schubert return 0; /* already generated */
1140c1d255d3SCy Schubert
1141c1d255d3SCy Schubert bi = os_zalloc(sizeof(*bi));
1142c1d255d3SCy Schubert if (!bi)
1143c1d255d3SCy Schubert return -1;
1144c1d255d3SCy Schubert bi->type = DPP_BOOTSTRAP_QR_CODE;
1145c1d255d3SCy Schubert if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
1146c1d255d3SCy Schubert dpp_gen_uri(bi) < 0)
1147c1d255d3SCy Schubert goto fail;
1148c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1149c1d255d3SCy Schubert "DPP: Auto-generated own bootstrapping key info: URI %s",
1150c1d255d3SCy Schubert bi->uri);
1151c1d255d3SCy Schubert
1152c1d255d3SCy Schubert auth->tmp_own_bi = auth->own_bi = bi;
1153c1d255d3SCy Schubert
1154c1d255d3SCy Schubert return 0;
1155c1d255d3SCy Schubert fail:
1156c1d255d3SCy Schubert dpp_bootstrap_info_free(bi);
1157c1d255d3SCy Schubert return -1;
1158c1d255d3SCy Schubert }
1159c1d255d3SCy Schubert
1160c1d255d3SCy Schubert
dpp_auth_init(struct dpp_global * dpp,void * msg_ctx,struct dpp_bootstrap_info * peer_bi,struct dpp_bootstrap_info * own_bi,u8 dpp_allowed_roles,unsigned int neg_freq,struct hostapd_hw_modes * own_modes,u16 num_modes)1161c1d255d3SCy Schubert struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
1162c1d255d3SCy Schubert struct dpp_bootstrap_info *peer_bi,
1163c1d255d3SCy Schubert struct dpp_bootstrap_info *own_bi,
1164c1d255d3SCy Schubert u8 dpp_allowed_roles,
1165c1d255d3SCy Schubert unsigned int neg_freq,
1166c1d255d3SCy Schubert struct hostapd_hw_modes *own_modes,
1167c1d255d3SCy Schubert u16 num_modes)
1168c1d255d3SCy Schubert {
1169c1d255d3SCy Schubert struct dpp_authentication *auth;
1170c1d255d3SCy Schubert size_t nonce_len;
1171c1d255d3SCy Schubert size_t secret_len;
1172c1d255d3SCy Schubert struct wpabuf *pi = NULL;
1173c1d255d3SCy Schubert const u8 *r_pubkey_hash, *i_pubkey_hash;
1174c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1175c1d255d3SCy Schubert u8 test_hash[SHA256_MAC_LEN];
1176c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1177c1d255d3SCy Schubert
1178c1d255d3SCy Schubert auth = dpp_alloc_auth(dpp, msg_ctx);
1179c1d255d3SCy Schubert if (!auth)
1180c1d255d3SCy Schubert return NULL;
1181c1d255d3SCy Schubert if (peer_bi->configurator_params &&
1182c1d255d3SCy Schubert dpp_set_configurator(auth, peer_bi->configurator_params) < 0)
1183c1d255d3SCy Schubert goto fail;
1184c1d255d3SCy Schubert auth->initiator = 1;
1185c1d255d3SCy Schubert auth->waiting_auth_resp = 1;
1186c1d255d3SCy Schubert auth->allowed_roles = dpp_allowed_roles;
1187c1d255d3SCy Schubert auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
1188c1d255d3SCy Schubert auth->peer_bi = peer_bi;
1189c1d255d3SCy Schubert auth->own_bi = own_bi;
1190c1d255d3SCy Schubert auth->curve = peer_bi->curve;
1191c1d255d3SCy Schubert
1192c1d255d3SCy Schubert if (dpp_autogen_bootstrap_key(auth) < 0 ||
1193c1d255d3SCy Schubert dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0)
1194c1d255d3SCy Schubert goto fail;
1195c1d255d3SCy Schubert
1196c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1197c1d255d3SCy Schubert if (dpp_nonce_override_len > 0) {
1198c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
1199c1d255d3SCy Schubert nonce_len = dpp_nonce_override_len;
1200c1d255d3SCy Schubert os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
1201c1d255d3SCy Schubert } else {
1202c1d255d3SCy Schubert nonce_len = auth->curve->nonce_len;
1203c1d255d3SCy Schubert if (random_get_bytes(auth->i_nonce, nonce_len)) {
1204c1d255d3SCy Schubert wpa_printf(MSG_ERROR,
1205c1d255d3SCy Schubert "DPP: Failed to generate I-nonce");
1206c1d255d3SCy Schubert goto fail;
1207c1d255d3SCy Schubert }
1208c1d255d3SCy Schubert }
1209c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
1210c1d255d3SCy Schubert nonce_len = auth->curve->nonce_len;
1211c1d255d3SCy Schubert if (random_get_bytes(auth->i_nonce, nonce_len)) {
1212c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
1213c1d255d3SCy Schubert goto fail;
1214c1d255d3SCy Schubert }
1215c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1216c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
1217c1d255d3SCy Schubert
1218c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1219c1d255d3SCy Schubert if (dpp_protocol_key_override_len) {
1220c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve;
1221c1d255d3SCy Schubert
1222c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1223c1d255d3SCy Schubert "DPP: TESTING - override protocol key");
1224c1d255d3SCy Schubert auth->own_protocol_key = dpp_set_keypair(
1225c1d255d3SCy Schubert &tmp_curve, dpp_protocol_key_override,
1226c1d255d3SCy Schubert dpp_protocol_key_override_len);
1227c1d255d3SCy Schubert } else {
1228c1d255d3SCy Schubert auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1229c1d255d3SCy Schubert }
1230c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */
1231c1d255d3SCy Schubert auth->own_protocol_key = dpp_gen_keypair(auth->curve);
1232c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1233c1d255d3SCy Schubert if (!auth->own_protocol_key)
1234c1d255d3SCy Schubert goto fail;
1235c1d255d3SCy Schubert
1236*4b72b91aSCy Schubert pi = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
1237c1d255d3SCy Schubert if (!pi)
1238c1d255d3SCy Schubert goto fail;
1239c1d255d3SCy Schubert
1240c1d255d3SCy Schubert /* ECDH: M = pI * BR */
1241c1d255d3SCy Schubert if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
1242c1d255d3SCy Schubert auth->Mx, &secret_len) < 0)
1243c1d255d3SCy Schubert goto fail;
1244c1d255d3SCy Schubert auth->secret_len = secret_len;
1245c1d255d3SCy Schubert
1246c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
1247c1d255d3SCy Schubert auth->Mx, auth->secret_len);
1248c1d255d3SCy Schubert auth->Mx_len = auth->secret_len;
1249c1d255d3SCy Schubert
1250c1d255d3SCy Schubert if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
1251c1d255d3SCy Schubert auth->curve->hash_len) < 0)
1252c1d255d3SCy Schubert goto fail;
1253c1d255d3SCy Schubert
1254c1d255d3SCy Schubert r_pubkey_hash = auth->peer_bi->pubkey_hash;
1255c1d255d3SCy Schubert i_pubkey_hash = auth->own_bi->pubkey_hash;
1256c1d255d3SCy Schubert
1257c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1258c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1259c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
1260c1d255d3SCy Schubert r_pubkey_hash = NULL;
1261c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1262c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1263c1d255d3SCy Schubert "DPP: TESTING - invalid R-Bootstrap Key Hash");
1264c1d255d3SCy Schubert os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
1265c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1266c1d255d3SCy Schubert r_pubkey_hash = test_hash;
1267c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1268c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
1269c1d255d3SCy Schubert i_pubkey_hash = NULL;
1270c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
1271c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1272c1d255d3SCy Schubert "DPP: TESTING - invalid I-Bootstrap Key Hash");
1273c1d255d3SCy Schubert os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
1274c1d255d3SCy Schubert test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
1275c1d255d3SCy Schubert i_pubkey_hash = test_hash;
1276c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
1277c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
1278c1d255d3SCy Schubert wpabuf_free(pi);
1279c1d255d3SCy Schubert pi = NULL;
1280c1d255d3SCy Schubert } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
1281c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
1282c1d255d3SCy Schubert wpabuf_free(pi);
1283c1d255d3SCy Schubert pi = wpabuf_alloc(2 * auth->curve->prime_len);
1284c1d255d3SCy Schubert if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
1285c1d255d3SCy Schubert goto fail;
1286c1d255d3SCy Schubert }
1287c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1288c1d255d3SCy Schubert
1289c1d255d3SCy Schubert if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq)
1290c1d255d3SCy Schubert neg_freq = 0;
1291c1d255d3SCy Schubert auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
1292c1d255d3SCy Schubert i_pubkey_hash, neg_freq);
1293c1d255d3SCy Schubert if (!auth->req_msg)
1294c1d255d3SCy Schubert goto fail;
1295c1d255d3SCy Schubert
1296c1d255d3SCy Schubert out:
1297c1d255d3SCy Schubert wpabuf_free(pi);
1298c1d255d3SCy Schubert return auth;
1299c1d255d3SCy Schubert fail:
1300c1d255d3SCy Schubert dpp_auth_deinit(auth);
1301c1d255d3SCy Schubert auth = NULL;
1302c1d255d3SCy Schubert goto out;
1303c1d255d3SCy Schubert }
1304c1d255d3SCy Schubert static void
dpp_auth_resp_rx_status(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,const u8 * wrapped_data,u16 wrapped_data_len,enum dpp_status_error status)1305c1d255d3SCy Schubert dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
1306c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len,
1307c1d255d3SCy Schubert const u8 *wrapped_data, u16 wrapped_data_len,
1308c1d255d3SCy Schubert enum dpp_status_error status)
1309c1d255d3SCy Schubert {
1310c1d255d3SCy Schubert const u8 *addr[2];
1311c1d255d3SCy Schubert size_t len[2];
1312c1d255d3SCy Schubert u8 *unwrapped = NULL;
1313c1d255d3SCy Schubert size_t unwrapped_len = 0;
1314c1d255d3SCy Schubert const u8 *i_nonce, *r_capab;
1315c1d255d3SCy Schubert u16 i_nonce_len, r_capab_len;
1316c1d255d3SCy Schubert
1317c1d255d3SCy Schubert if (status == DPP_STATUS_NOT_COMPATIBLE) {
1318c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1319c1d255d3SCy Schubert "DPP: Responder reported incompatible roles");
1320c1d255d3SCy Schubert } else if (status == DPP_STATUS_RESPONSE_PENDING) {
1321c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1322c1d255d3SCy Schubert "DPP: Responder reported more time needed");
1323c1d255d3SCy Schubert } else {
1324c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1325c1d255d3SCy Schubert "DPP: Responder reported failure (status %d)",
1326c1d255d3SCy Schubert status);
1327c1d255d3SCy Schubert dpp_auth_fail(auth, "Responder reported failure");
1328c1d255d3SCy Schubert return;
1329c1d255d3SCy Schubert }
1330c1d255d3SCy Schubert
1331c1d255d3SCy Schubert addr[0] = hdr;
1332c1d255d3SCy Schubert len[0] = DPP_HDR_LEN;
1333c1d255d3SCy Schubert addr[1] = attr_start;
1334c1d255d3SCy Schubert len[1] = attr_len;
1335c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1336c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1337c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1338c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1339c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1340c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len);
1341c1d255d3SCy Schubert if (!unwrapped)
1342c1d255d3SCy Schubert goto fail;
1343c1d255d3SCy Schubert if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
1344c1d255d3SCy Schubert wrapped_data, wrapped_data_len,
1345c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) {
1346c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
1347c1d255d3SCy Schubert goto fail;
1348c1d255d3SCy Schubert }
1349c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1350c1d255d3SCy Schubert unwrapped, unwrapped_len);
1351c1d255d3SCy Schubert
1352c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1353c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
1354c1d255d3SCy Schubert goto fail;
1355c1d255d3SCy Schubert }
1356c1d255d3SCy Schubert
1357c1d255d3SCy Schubert i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
1358c1d255d3SCy Schubert &i_nonce_len);
1359c1d255d3SCy Schubert if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
1360c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid I-nonce");
1361c1d255d3SCy Schubert goto fail;
1362c1d255d3SCy Schubert }
1363c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
1364c1d255d3SCy Schubert if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
1365c1d255d3SCy Schubert dpp_auth_fail(auth, "I-nonce mismatch");
1366c1d255d3SCy Schubert goto fail;
1367c1d255d3SCy Schubert }
1368c1d255d3SCy Schubert
1369c1d255d3SCy Schubert r_capab = dpp_get_attr(unwrapped, unwrapped_len,
1370c1d255d3SCy Schubert DPP_ATTR_R_CAPABILITIES,
1371c1d255d3SCy Schubert &r_capab_len);
1372c1d255d3SCy Schubert if (!r_capab || r_capab_len < 1) {
1373c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid R-capabilities");
1374c1d255d3SCy Schubert goto fail;
1375c1d255d3SCy Schubert }
1376c1d255d3SCy Schubert auth->r_capab = r_capab[0];
1377c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
1378c1d255d3SCy Schubert if (status == DPP_STATUS_NOT_COMPATIBLE) {
1379c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
1380c1d255d3SCy Schubert "r-capab=0x%02x", auth->r_capab);
1381c1d255d3SCy Schubert } else if (status == DPP_STATUS_RESPONSE_PENDING) {
1382c1d255d3SCy Schubert u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
1383c1d255d3SCy Schubert
1384c1d255d3SCy Schubert if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
1385c1d255d3SCy Schubert (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
1386c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO,
1387c1d255d3SCy Schubert DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
1388c1d255d3SCy Schubert role);
1389c1d255d3SCy Schubert } else {
1390c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1391c1d255d3SCy Schubert "DPP: Continue waiting for full DPP Authentication Response");
1392c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO,
1393c1d255d3SCy Schubert DPP_EVENT_RESPONSE_PENDING "%s",
1394c1d255d3SCy Schubert auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
1395c1d255d3SCy Schubert }
1396c1d255d3SCy Schubert }
1397c1d255d3SCy Schubert fail:
1398c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1399c1d255d3SCy Schubert }
1400c1d255d3SCy Schubert
1401c1d255d3SCy Schubert
1402c1d255d3SCy Schubert struct wpabuf *
dpp_auth_resp_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)1403c1d255d3SCy Schubert dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
1404c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len)
1405c1d255d3SCy Schubert {
1406*4b72b91aSCy Schubert struct crypto_ec_key *pr;
1407c1d255d3SCy Schubert size_t secret_len;
1408c1d255d3SCy Schubert const u8 *addr[2];
1409c1d255d3SCy Schubert size_t len[2];
1410c1d255d3SCy Schubert u8 *unwrapped = NULL, *unwrapped2 = NULL;
1411c1d255d3SCy Schubert size_t unwrapped_len = 0, unwrapped2_len = 0;
1412c1d255d3SCy Schubert const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
1413c1d255d3SCy Schubert *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
1414c1d255d3SCy Schubert u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
1415c1d255d3SCy Schubert r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
1416c1d255d3SCy Schubert wrapped2_len, r_auth_len;
1417c1d255d3SCy Schubert u8 r_auth2[DPP_MAX_HASH_LEN];
1418c1d255d3SCy Schubert u8 role;
1419c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1420c1d255d3SCy Schubert const u8 *version;
1421c1d255d3SCy Schubert u16 version_len;
1422c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1423c1d255d3SCy Schubert
1424c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1425c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
1426c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1427c1d255d3SCy Schubert "DPP: TESTING - stop at Authentication Response");
1428c1d255d3SCy Schubert return NULL;
1429c1d255d3SCy Schubert }
1430c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1431c1d255d3SCy Schubert
1432c1d255d3SCy Schubert if (!auth->initiator || !auth->peer_bi || auth->reconfig) {
1433c1d255d3SCy Schubert dpp_auth_fail(auth, "Unexpected Authentication Response");
1434c1d255d3SCy Schubert return NULL;
1435c1d255d3SCy Schubert }
1436c1d255d3SCy Schubert
1437c1d255d3SCy Schubert auth->waiting_auth_resp = 0;
1438c1d255d3SCy Schubert
1439c1d255d3SCy Schubert wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
1440c1d255d3SCy Schubert &wrapped_data_len);
1441c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1442c1d255d3SCy Schubert dpp_auth_fail(auth,
1443c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute");
1444c1d255d3SCy Schubert return NULL;
1445c1d255d3SCy Schubert }
1446c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
1447c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1448c1d255d3SCy Schubert
1449c1d255d3SCy Schubert attr_len = wrapped_data - 4 - attr_start;
1450c1d255d3SCy Schubert
1451c1d255d3SCy Schubert r_bootstrap = dpp_get_attr(attr_start, attr_len,
1452c1d255d3SCy Schubert DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
1453c1d255d3SCy Schubert &r_bootstrap_len);
1454c1d255d3SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
1455c1d255d3SCy Schubert dpp_auth_fail(auth,
1456c1d255d3SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute");
1457c1d255d3SCy Schubert return NULL;
1458c1d255d3SCy Schubert }
1459c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
1460c1d255d3SCy Schubert r_bootstrap, r_bootstrap_len);
1461c1d255d3SCy Schubert if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
1462c1d255d3SCy Schubert SHA256_MAC_LEN) != 0) {
1463c1d255d3SCy Schubert dpp_auth_fail(auth,
1464c1d255d3SCy Schubert "Unexpected Responder Bootstrapping Key Hash value");
1465c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG,
1466c1d255d3SCy Schubert "DPP: Expected Responder Bootstrapping Key Hash",
1467c1d255d3SCy Schubert auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
1468c1d255d3SCy Schubert return NULL;
1469c1d255d3SCy Schubert }
1470c1d255d3SCy Schubert
1471c1d255d3SCy Schubert i_bootstrap = dpp_get_attr(attr_start, attr_len,
1472c1d255d3SCy Schubert DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
1473c1d255d3SCy Schubert &i_bootstrap_len);
1474c1d255d3SCy Schubert if (i_bootstrap) {
1475c1d255d3SCy Schubert if (i_bootstrap_len != SHA256_MAC_LEN) {
1476c1d255d3SCy Schubert dpp_auth_fail(auth,
1477c1d255d3SCy Schubert "Invalid Initiator Bootstrapping Key Hash attribute");
1478c1d255d3SCy Schubert return NULL;
1479c1d255d3SCy Schubert }
1480c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP,
1481c1d255d3SCy Schubert "DPP: Initiator Bootstrapping Key Hash",
1482c1d255d3SCy Schubert i_bootstrap, i_bootstrap_len);
1483c1d255d3SCy Schubert if (!auth->own_bi ||
1484c1d255d3SCy Schubert os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
1485c1d255d3SCy Schubert SHA256_MAC_LEN) != 0) {
1486c1d255d3SCy Schubert dpp_auth_fail(auth,
1487c1d255d3SCy Schubert "Initiator Bootstrapping Key Hash attribute did not match");
1488c1d255d3SCy Schubert return NULL;
1489c1d255d3SCy Schubert }
1490c1d255d3SCy Schubert } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
1491c1d255d3SCy Schubert /* PKEX bootstrapping mandates use of mutual authentication */
1492c1d255d3SCy Schubert dpp_auth_fail(auth,
1493c1d255d3SCy Schubert "Missing Initiator Bootstrapping Key Hash attribute");
1494c1d255d3SCy Schubert return NULL;
1495c1d255d3SCy Schubert } else if (auth->own_bi &&
1496c1d255d3SCy Schubert auth->own_bi->type == DPP_BOOTSTRAP_NFC_URI &&
1497c1d255d3SCy Schubert auth->own_bi->nfc_negotiated) {
1498c1d255d3SCy Schubert /* NFC negotiated connection handover bootstrapping mandates
1499c1d255d3SCy Schubert * use of mutual authentication */
1500c1d255d3SCy Schubert dpp_auth_fail(auth,
1501c1d255d3SCy Schubert "Missing Initiator Bootstrapping Key Hash attribute");
1502c1d255d3SCy Schubert return NULL;
1503c1d255d3SCy Schubert }
1504c1d255d3SCy Schubert
1505c1d255d3SCy Schubert auth->peer_version = 1; /* default to the first version */
1506c1d255d3SCy Schubert #ifdef CONFIG_DPP2
1507c1d255d3SCy Schubert version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
1508c1d255d3SCy Schubert &version_len);
1509c1d255d3SCy Schubert if (version && DPP_VERSION > 1) {
1510c1d255d3SCy Schubert if (version_len < 1 || version[0] == 0) {
1511c1d255d3SCy Schubert dpp_auth_fail(auth,
1512c1d255d3SCy Schubert "Invalid Protocol Version attribute");
1513c1d255d3SCy Schubert return NULL;
1514c1d255d3SCy Schubert }
1515c1d255d3SCy Schubert auth->peer_version = version[0];
1516c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
1517c1d255d3SCy Schubert auth->peer_version);
1518c1d255d3SCy Schubert }
1519c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
1520c1d255d3SCy Schubert
1521c1d255d3SCy Schubert status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
1522c1d255d3SCy Schubert &status_len);
1523c1d255d3SCy Schubert if (!status || status_len < 1) {
1524c1d255d3SCy Schubert dpp_auth_fail(auth,
1525c1d255d3SCy Schubert "Missing or invalid required DPP Status attribute");
1526c1d255d3SCy Schubert return NULL;
1527c1d255d3SCy Schubert }
1528c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
1529c1d255d3SCy Schubert auth->auth_resp_status = status[0];
1530c1d255d3SCy Schubert if (status[0] != DPP_STATUS_OK) {
1531c1d255d3SCy Schubert dpp_auth_resp_rx_status(auth, hdr, attr_start,
1532c1d255d3SCy Schubert attr_len, wrapped_data,
1533c1d255d3SCy Schubert wrapped_data_len, status[0]);
1534c1d255d3SCy Schubert return NULL;
1535c1d255d3SCy Schubert }
1536c1d255d3SCy Schubert
1537c1d255d3SCy Schubert if (!i_bootstrap && auth->own_bi) {
1538c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1539c1d255d3SCy Schubert "DPP: Responder decided not to use mutual authentication");
1540c1d255d3SCy Schubert auth->own_bi = NULL;
1541c1d255d3SCy Schubert }
1542c1d255d3SCy Schubert
1543c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
1544c1d255d3SCy Schubert auth->own_bi != NULL);
1545c1d255d3SCy Schubert
1546c1d255d3SCy Schubert r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
1547c1d255d3SCy Schubert &r_proto_len);
1548c1d255d3SCy Schubert if (!r_proto) {
1549c1d255d3SCy Schubert dpp_auth_fail(auth,
1550c1d255d3SCy Schubert "Missing required Responder Protocol Key attribute");
1551c1d255d3SCy Schubert return NULL;
1552c1d255d3SCy Schubert }
1553c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
1554c1d255d3SCy Schubert r_proto, r_proto_len);
1555c1d255d3SCy Schubert
1556c1d255d3SCy Schubert /* N = pI * PR */
1557c1d255d3SCy Schubert pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
1558c1d255d3SCy Schubert if (!pr) {
1559c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid Responder Protocol Key");
1560c1d255d3SCy Schubert return NULL;
1561c1d255d3SCy Schubert }
1562c1d255d3SCy Schubert dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
1563c1d255d3SCy Schubert
1564c1d255d3SCy Schubert if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
1565c1d255d3SCy Schubert dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
1566c1d255d3SCy Schubert goto fail;
1567c1d255d3SCy Schubert }
1568*4b72b91aSCy Schubert crypto_ec_key_deinit(auth->peer_protocol_key);
1569c1d255d3SCy Schubert auth->peer_protocol_key = pr;
1570c1d255d3SCy Schubert pr = NULL;
1571c1d255d3SCy Schubert
1572c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
1573c1d255d3SCy Schubert auth->Nx, auth->secret_len);
1574c1d255d3SCy Schubert auth->Nx_len = auth->secret_len;
1575c1d255d3SCy Schubert
1576c1d255d3SCy Schubert if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
1577c1d255d3SCy Schubert auth->curve->hash_len) < 0)
1578c1d255d3SCy Schubert goto fail;
1579c1d255d3SCy Schubert
1580c1d255d3SCy Schubert addr[0] = hdr;
1581c1d255d3SCy Schubert len[0] = DPP_HDR_LEN;
1582c1d255d3SCy Schubert addr[1] = attr_start;
1583c1d255d3SCy Schubert len[1] = attr_len;
1584c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1585c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1586c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1587c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1588c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1589c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len);
1590c1d255d3SCy Schubert if (!unwrapped)
1591c1d255d3SCy Schubert goto fail;
1592c1d255d3SCy Schubert if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
1593c1d255d3SCy Schubert wrapped_data, wrapped_data_len,
1594c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) {
1595c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
1596c1d255d3SCy Schubert goto fail;
1597c1d255d3SCy Schubert }
1598c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1599c1d255d3SCy Schubert unwrapped, unwrapped_len);
1600c1d255d3SCy Schubert
1601c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1602c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
1603c1d255d3SCy Schubert goto fail;
1604c1d255d3SCy Schubert }
1605c1d255d3SCy Schubert
1606c1d255d3SCy Schubert r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
1607c1d255d3SCy Schubert &r_nonce_len);
1608c1d255d3SCy Schubert if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
1609c1d255d3SCy Schubert dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
1610c1d255d3SCy Schubert goto fail;
1611c1d255d3SCy Schubert }
1612c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
1613c1d255d3SCy Schubert os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
1614c1d255d3SCy Schubert
1615c1d255d3SCy Schubert i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
1616c1d255d3SCy Schubert &i_nonce_len);
1617c1d255d3SCy Schubert if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
1618c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid I-nonce");
1619c1d255d3SCy Schubert goto fail;
1620c1d255d3SCy Schubert }
1621c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
1622c1d255d3SCy Schubert if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
1623c1d255d3SCy Schubert dpp_auth_fail(auth, "I-nonce mismatch");
1624c1d255d3SCy Schubert goto fail;
1625c1d255d3SCy Schubert }
1626c1d255d3SCy Schubert
1627c1d255d3SCy Schubert if (auth->own_bi) {
1628c1d255d3SCy Schubert /* Mutual authentication */
1629c1d255d3SCy Schubert if (dpp_auth_derive_l_initiator(auth) < 0)
1630c1d255d3SCy Schubert goto fail;
1631c1d255d3SCy Schubert }
1632c1d255d3SCy Schubert
1633c1d255d3SCy Schubert r_capab = dpp_get_attr(unwrapped, unwrapped_len,
1634c1d255d3SCy Schubert DPP_ATTR_R_CAPABILITIES,
1635c1d255d3SCy Schubert &r_capab_len);
1636c1d255d3SCy Schubert if (!r_capab || r_capab_len < 1) {
1637c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid R-capabilities");
1638c1d255d3SCy Schubert goto fail;
1639c1d255d3SCy Schubert }
1640c1d255d3SCy Schubert auth->r_capab = r_capab[0];
1641c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
1642c1d255d3SCy Schubert role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
1643c1d255d3SCy Schubert if ((auth->allowed_roles ==
1644c1d255d3SCy Schubert (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
1645c1d255d3SCy Schubert (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
1646c1d255d3SCy Schubert /* Peer selected its role, so move from "either role" to the
1647c1d255d3SCy Schubert * role that is compatible with peer's selection. */
1648c1d255d3SCy Schubert auth->configurator = role == DPP_CAPAB_ENROLLEE;
1649c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
1650c1d255d3SCy Schubert auth->configurator ? "Configurator" : "Enrollee");
1651c1d255d3SCy Schubert } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
1652c1d255d3SCy Schubert (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
1653c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
1654c1d255d3SCy Schubert wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
1655c1d255d3SCy Schubert "Unexpected role in R-capabilities 0x%02x",
1656c1d255d3SCy Schubert role);
1657c1d255d3SCy Schubert if (role != DPP_CAPAB_ENROLLEE &&
1658c1d255d3SCy Schubert role != DPP_CAPAB_CONFIGURATOR)
1659c1d255d3SCy Schubert goto fail;
1660c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1661c1d255d3SCy Schubert auth->remove_on_tx_status = 1;
1662c1d255d3SCy Schubert return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
1663c1d255d3SCy Schubert }
1664c1d255d3SCy Schubert
1665c1d255d3SCy Schubert wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
1666c1d255d3SCy Schubert DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
1667c1d255d3SCy Schubert if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
1668c1d255d3SCy Schubert dpp_auth_fail(auth,
1669c1d255d3SCy Schubert "Missing or invalid Secondary Wrapped Data");
1670c1d255d3SCy Schubert goto fail;
1671c1d255d3SCy Schubert }
1672c1d255d3SCy Schubert
1673c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1674c1d255d3SCy Schubert wrapped2, wrapped2_len);
1675c1d255d3SCy Schubert
1676c1d255d3SCy Schubert if (dpp_derive_bk_ke(auth) < 0)
1677c1d255d3SCy Schubert goto fail;
1678c1d255d3SCy Schubert
1679c1d255d3SCy Schubert unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
1680c1d255d3SCy Schubert unwrapped2 = os_malloc(unwrapped2_len);
1681c1d255d3SCy Schubert if (!unwrapped2)
1682c1d255d3SCy Schubert goto fail;
1683c1d255d3SCy Schubert if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
1684c1d255d3SCy Schubert wrapped2, wrapped2_len,
1685c1d255d3SCy Schubert 0, NULL, NULL, unwrapped2) < 0) {
1686c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
1687c1d255d3SCy Schubert goto fail;
1688c1d255d3SCy Schubert }
1689c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1690c1d255d3SCy Schubert unwrapped2, unwrapped2_len);
1691c1d255d3SCy Schubert
1692c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
1693c1d255d3SCy Schubert dpp_auth_fail(auth,
1694c1d255d3SCy Schubert "Invalid attribute in secondary unwrapped data");
1695c1d255d3SCy Schubert goto fail;
1696c1d255d3SCy Schubert }
1697c1d255d3SCy Schubert
1698c1d255d3SCy Schubert r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
1699c1d255d3SCy Schubert &r_auth_len);
1700c1d255d3SCy Schubert if (!r_auth || r_auth_len != auth->curve->hash_len) {
1701c1d255d3SCy Schubert dpp_auth_fail(auth,
1702c1d255d3SCy Schubert "Missing or invalid Responder Authenticating Tag");
1703c1d255d3SCy Schubert goto fail;
1704c1d255d3SCy Schubert }
1705c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
1706c1d255d3SCy Schubert r_auth, r_auth_len);
1707c1d255d3SCy Schubert /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
1708c1d255d3SCy Schubert if (dpp_gen_r_auth(auth, r_auth2) < 0)
1709c1d255d3SCy Schubert goto fail;
1710c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
1711c1d255d3SCy Schubert r_auth2, r_auth_len);
1712c1d255d3SCy Schubert if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
1713c1d255d3SCy Schubert dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
1714c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1715c1d255d3SCy Schubert bin_clear_free(unwrapped2, unwrapped2_len);
1716c1d255d3SCy Schubert auth->remove_on_tx_status = 1;
1717c1d255d3SCy Schubert return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
1718c1d255d3SCy Schubert }
1719c1d255d3SCy Schubert
1720c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1721c1d255d3SCy Schubert bin_clear_free(unwrapped2, unwrapped2_len);
1722c1d255d3SCy Schubert
1723c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1724c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
1725c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1726c1d255d3SCy Schubert "DPP: TESTING - Authentication Response in place of Confirm");
1727c1d255d3SCy Schubert if (dpp_auth_build_resp_ok(auth) < 0)
1728c1d255d3SCy Schubert return NULL;
1729c1d255d3SCy Schubert return wpabuf_dup(auth->resp_msg);
1730c1d255d3SCy Schubert }
1731c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1732c1d255d3SCy Schubert
1733c1d255d3SCy Schubert return dpp_auth_build_conf(auth, DPP_STATUS_OK);
1734c1d255d3SCy Schubert
1735c1d255d3SCy Schubert fail:
1736c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1737c1d255d3SCy Schubert bin_clear_free(unwrapped2, unwrapped2_len);
1738*4b72b91aSCy Schubert crypto_ec_key_deinit(pr);
1739c1d255d3SCy Schubert return NULL;
1740c1d255d3SCy Schubert }
1741c1d255d3SCy Schubert
1742c1d255d3SCy Schubert
dpp_auth_conf_rx_failure(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len,const u8 * wrapped_data,u16 wrapped_data_len,enum dpp_status_error status)1743c1d255d3SCy Schubert static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
1744c1d255d3SCy Schubert const u8 *hdr,
1745c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len,
1746c1d255d3SCy Schubert const u8 *wrapped_data,
1747c1d255d3SCy Schubert u16 wrapped_data_len,
1748c1d255d3SCy Schubert enum dpp_status_error status)
1749c1d255d3SCy Schubert {
1750c1d255d3SCy Schubert const u8 *addr[2];
1751c1d255d3SCy Schubert size_t len[2];
1752c1d255d3SCy Schubert u8 *unwrapped = NULL;
1753c1d255d3SCy Schubert size_t unwrapped_len = 0;
1754c1d255d3SCy Schubert const u8 *r_nonce;
1755c1d255d3SCy Schubert u16 r_nonce_len;
1756c1d255d3SCy Schubert
1757c1d255d3SCy Schubert /* Authentication Confirm failure cases are expected to include
1758c1d255d3SCy Schubert * {R-nonce}k2 in the Wrapped Data attribute. */
1759c1d255d3SCy Schubert
1760c1d255d3SCy Schubert addr[0] = hdr;
1761c1d255d3SCy Schubert len[0] = DPP_HDR_LEN;
1762c1d255d3SCy Schubert addr[1] = attr_start;
1763c1d255d3SCy Schubert len[1] = attr_len;
1764c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1765c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1766c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1767c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1768c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1769c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len);
1770c1d255d3SCy Schubert if (!unwrapped) {
1771c1d255d3SCy Schubert dpp_auth_fail(auth, "Authentication failed");
1772c1d255d3SCy Schubert goto fail;
1773c1d255d3SCy Schubert }
1774c1d255d3SCy Schubert if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
1775c1d255d3SCy Schubert wrapped_data, wrapped_data_len,
1776c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) {
1777c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
1778c1d255d3SCy Schubert goto fail;
1779c1d255d3SCy Schubert }
1780c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1781c1d255d3SCy Schubert unwrapped, unwrapped_len);
1782c1d255d3SCy Schubert
1783c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1784c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
1785c1d255d3SCy Schubert goto fail;
1786c1d255d3SCy Schubert }
1787c1d255d3SCy Schubert
1788c1d255d3SCy Schubert r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
1789c1d255d3SCy Schubert &r_nonce_len);
1790c1d255d3SCy Schubert if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
1791c1d255d3SCy Schubert dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
1792c1d255d3SCy Schubert goto fail;
1793c1d255d3SCy Schubert }
1794c1d255d3SCy Schubert if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
1795c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
1796c1d255d3SCy Schubert r_nonce, r_nonce_len);
1797c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
1798c1d255d3SCy Schubert auth->r_nonce, r_nonce_len);
1799c1d255d3SCy Schubert dpp_auth_fail(auth, "R-nonce mismatch");
1800c1d255d3SCy Schubert goto fail;
1801c1d255d3SCy Schubert }
1802c1d255d3SCy Schubert
1803c1d255d3SCy Schubert if (status == DPP_STATUS_NOT_COMPATIBLE)
1804c1d255d3SCy Schubert dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
1805c1d255d3SCy Schubert else if (status == DPP_STATUS_AUTH_FAILURE)
1806c1d255d3SCy Schubert dpp_auth_fail(auth, "Peer reported authentication failure)");
1807c1d255d3SCy Schubert
1808c1d255d3SCy Schubert fail:
1809c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1810c1d255d3SCy Schubert return -1;
1811c1d255d3SCy Schubert }
1812c1d255d3SCy Schubert
1813c1d255d3SCy Schubert
dpp_auth_conf_rx(struct dpp_authentication * auth,const u8 * hdr,const u8 * attr_start,size_t attr_len)1814c1d255d3SCy Schubert int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
1815c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len)
1816c1d255d3SCy Schubert {
1817c1d255d3SCy Schubert const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
1818c1d255d3SCy Schubert u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
1819c1d255d3SCy Schubert i_auth_len;
1820c1d255d3SCy Schubert const u8 *addr[2];
1821c1d255d3SCy Schubert size_t len[2];
1822c1d255d3SCy Schubert u8 *unwrapped = NULL;
1823c1d255d3SCy Schubert size_t unwrapped_len = 0;
1824c1d255d3SCy Schubert u8 i_auth2[DPP_MAX_HASH_LEN];
1825c1d255d3SCy Schubert
1826c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
1827c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
1828c1d255d3SCy Schubert wpa_printf(MSG_INFO,
1829c1d255d3SCy Schubert "DPP: TESTING - stop at Authentication Confirm");
1830c1d255d3SCy Schubert return -1;
1831c1d255d3SCy Schubert }
1832c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
1833c1d255d3SCy Schubert
1834c1d255d3SCy Schubert if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf ||
1835c1d255d3SCy Schubert auth->reconfig) {
1836c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
1837c1d255d3SCy Schubert "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
1838c1d255d3SCy Schubert auth->initiator, !!auth->own_bi,
1839c1d255d3SCy Schubert auth->waiting_auth_conf);
1840c1d255d3SCy Schubert dpp_auth_fail(auth, "Unexpected Authentication Confirm");
1841c1d255d3SCy Schubert return -1;
1842c1d255d3SCy Schubert }
1843c1d255d3SCy Schubert
1844c1d255d3SCy Schubert auth->waiting_auth_conf = 0;
1845c1d255d3SCy Schubert
1846c1d255d3SCy Schubert wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
1847c1d255d3SCy Schubert &wrapped_data_len);
1848c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
1849c1d255d3SCy Schubert dpp_auth_fail(auth,
1850c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute");
1851c1d255d3SCy Schubert return -1;
1852c1d255d3SCy Schubert }
1853c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
1854c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1855c1d255d3SCy Schubert
1856c1d255d3SCy Schubert attr_len = wrapped_data - 4 - attr_start;
1857c1d255d3SCy Schubert
1858c1d255d3SCy Schubert r_bootstrap = dpp_get_attr(attr_start, attr_len,
1859c1d255d3SCy Schubert DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
1860c1d255d3SCy Schubert &r_bootstrap_len);
1861c1d255d3SCy Schubert if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
1862c1d255d3SCy Schubert dpp_auth_fail(auth,
1863c1d255d3SCy Schubert "Missing or invalid required Responder Bootstrapping Key Hash attribute");
1864c1d255d3SCy Schubert return -1;
1865c1d255d3SCy Schubert }
1866c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
1867c1d255d3SCy Schubert r_bootstrap, r_bootstrap_len);
1868c1d255d3SCy Schubert if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
1869c1d255d3SCy Schubert SHA256_MAC_LEN) != 0) {
1870c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG,
1871c1d255d3SCy Schubert "DPP: Expected Responder Bootstrapping Key Hash",
1872c1d255d3SCy Schubert auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
1873c1d255d3SCy Schubert dpp_auth_fail(auth,
1874c1d255d3SCy Schubert "Responder Bootstrapping Key Hash mismatch");
1875c1d255d3SCy Schubert return -1;
1876c1d255d3SCy Schubert }
1877c1d255d3SCy Schubert
1878c1d255d3SCy Schubert i_bootstrap = dpp_get_attr(attr_start, attr_len,
1879c1d255d3SCy Schubert DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
1880c1d255d3SCy Schubert &i_bootstrap_len);
1881c1d255d3SCy Schubert if (i_bootstrap) {
1882c1d255d3SCy Schubert if (i_bootstrap_len != SHA256_MAC_LEN) {
1883c1d255d3SCy Schubert dpp_auth_fail(auth,
1884c1d255d3SCy Schubert "Invalid Initiator Bootstrapping Key Hash attribute");
1885c1d255d3SCy Schubert return -1;
1886c1d255d3SCy Schubert }
1887c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP,
1888c1d255d3SCy Schubert "DPP: Initiator Bootstrapping Key Hash",
1889c1d255d3SCy Schubert i_bootstrap, i_bootstrap_len);
1890c1d255d3SCy Schubert if (!auth->peer_bi ||
1891c1d255d3SCy Schubert os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
1892c1d255d3SCy Schubert SHA256_MAC_LEN) != 0) {
1893c1d255d3SCy Schubert dpp_auth_fail(auth,
1894c1d255d3SCy Schubert "Initiator Bootstrapping Key Hash mismatch");
1895c1d255d3SCy Schubert return -1;
1896c1d255d3SCy Schubert }
1897c1d255d3SCy Schubert } else if (auth->peer_bi) {
1898c1d255d3SCy Schubert /* Mutual authentication and peer did not include its
1899c1d255d3SCy Schubert * Bootstrapping Key Hash attribute. */
1900c1d255d3SCy Schubert dpp_auth_fail(auth,
1901c1d255d3SCy Schubert "Missing Initiator Bootstrapping Key Hash attribute");
1902c1d255d3SCy Schubert return -1;
1903c1d255d3SCy Schubert }
1904c1d255d3SCy Schubert
1905c1d255d3SCy Schubert status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
1906c1d255d3SCy Schubert &status_len);
1907c1d255d3SCy Schubert if (!status || status_len < 1) {
1908c1d255d3SCy Schubert dpp_auth_fail(auth,
1909c1d255d3SCy Schubert "Missing or invalid required DPP Status attribute");
1910c1d255d3SCy Schubert return -1;
1911c1d255d3SCy Schubert }
1912c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
1913c1d255d3SCy Schubert if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
1914c1d255d3SCy Schubert status[0] == DPP_STATUS_AUTH_FAILURE)
1915c1d255d3SCy Schubert return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
1916c1d255d3SCy Schubert attr_len, wrapped_data,
1917c1d255d3SCy Schubert wrapped_data_len, status[0]);
1918c1d255d3SCy Schubert
1919c1d255d3SCy Schubert if (status[0] != DPP_STATUS_OK) {
1920c1d255d3SCy Schubert dpp_auth_fail(auth, "Authentication failed");
1921c1d255d3SCy Schubert return -1;
1922c1d255d3SCy Schubert }
1923c1d255d3SCy Schubert
1924c1d255d3SCy Schubert addr[0] = hdr;
1925c1d255d3SCy Schubert len[0] = DPP_HDR_LEN;
1926c1d255d3SCy Schubert addr[1] = attr_start;
1927c1d255d3SCy Schubert len[1] = attr_len;
1928c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1929c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1930c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1931c1d255d3SCy Schubert wrapped_data, wrapped_data_len);
1932c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
1933c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len);
1934c1d255d3SCy Schubert if (!unwrapped)
1935c1d255d3SCy Schubert return -1;
1936c1d255d3SCy Schubert if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
1937c1d255d3SCy Schubert wrapped_data, wrapped_data_len,
1938c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) {
1939c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed");
1940c1d255d3SCy Schubert goto fail;
1941c1d255d3SCy Schubert }
1942c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
1943c1d255d3SCy Schubert unwrapped, unwrapped_len);
1944c1d255d3SCy Schubert
1945c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
1946c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
1947c1d255d3SCy Schubert goto fail;
1948c1d255d3SCy Schubert }
1949c1d255d3SCy Schubert
1950c1d255d3SCy Schubert i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
1951c1d255d3SCy Schubert &i_auth_len);
1952c1d255d3SCy Schubert if (!i_auth || i_auth_len != auth->curve->hash_len) {
1953c1d255d3SCy Schubert dpp_auth_fail(auth,
1954c1d255d3SCy Schubert "Missing or invalid Initiator Authenticating Tag");
1955c1d255d3SCy Schubert goto fail;
1956c1d255d3SCy Schubert }
1957c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
1958c1d255d3SCy Schubert i_auth, i_auth_len);
1959c1d255d3SCy Schubert /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
1960c1d255d3SCy Schubert if (dpp_gen_i_auth(auth, i_auth2) < 0)
1961c1d255d3SCy Schubert goto fail;
1962c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
1963c1d255d3SCy Schubert i_auth2, i_auth_len);
1964c1d255d3SCy Schubert if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
1965c1d255d3SCy Schubert dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
1966c1d255d3SCy Schubert goto fail;
1967c1d255d3SCy Schubert }
1968c1d255d3SCy Schubert
1969c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1970c1d255d3SCy Schubert dpp_auth_success(auth);
1971c1d255d3SCy Schubert return 0;
1972c1d255d3SCy Schubert fail:
1973c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len);
1974c1d255d3SCy Schubert return -1;
1975c1d255d3SCy Schubert }
1976