]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/common/dpp.c
Fix a typo in function documentation
[thirdparty/hostap.git] / src / common / dpp.c
CommitLineData
be27e185
JM
1/*
2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
2bbe6ad3 4 * Copyright (c) 2018-2020, The Linux Foundation
be27e185
JM
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10#include "utils/includes.h"
88a78bdd 11#include <fcntl.h>
461d39af 12#include <openssl/opensslv.h>
be27e185 13#include <openssl/err.h>
746c1792
JM
14#include <openssl/asn1.h>
15#include <openssl/asn1t.h>
be27e185
JM
16
17#include "utils/common.h"
18#include "utils/base64.h"
461d39af 19#include "utils/json.h"
88a78bdd
JM
20#include "utils/ip_addr.h"
21#include "utils/eloop.h"
be27e185 22#include "common/ieee802_11_common.h"
30d27b04
JM
23#include "common/ieee802_11_defs.h"
24#include "common/wpa_ctrl.h"
bd23daa8 25#include "common/gas.h"
be27e185 26#include "crypto/crypto.h"
30d27b04
JM
27#include "crypto/random.h"
28#include "crypto/aes.h"
29#include "crypto/aes_siv.h"
30#include "crypto/sha384.h"
31#include "crypto/sha512.h"
ea91ddb0 32#include "tls/asn1.h"
f97ace34 33#include "drivers/driver.h"
be27e185
JM
34#include "dpp.h"
35
36
74045744
JM
37static const char * dpp_netrole_str(enum dpp_netrole netrole);
38
60239f60
JM
39#ifdef CONFIG_TESTING_OPTIONS
40enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
2bdc47a9
JM
41u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
42u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
acc555f9
JM
43u8 dpp_pkex_ephemeral_key_override[600];
44size_t dpp_pkex_ephemeral_key_override_len = 0;
f5526975
JM
45u8 dpp_protocol_key_override[600];
46size_t dpp_protocol_key_override_len = 0;
055cd397
JM
47u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
48size_t dpp_nonce_override_len = 0;
b6b4226b
JM
49
50static int dpp_test_gen_invalid_key(struct wpabuf *msg,
51 const struct dpp_curve_params *curve);
60239f60
JM
52#endif /* CONFIG_TESTING_OPTIONS */
53
5ecdf06c
JM
54#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
55 (defined(LIBRESSL_VERSION_NUMBER) && \
56 LIBRESSL_VERSION_NUMBER < 0x20700000L)
461d39af
JM
57/* Compatibility wrappers for older versions. */
58
59static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
60{
61 sig->r = r;
62 sig->s = s;
63 return 1;
64}
65
66
67static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
68 const BIGNUM **ps)
69{
70 if (pr)
71 *pr = sig->r;
72 if (ps)
73 *ps = sig->s;
74}
75
76#endif
77
78
88a78bdd
JM
79struct dpp_connection {
80 struct dl_list list;
81 struct dpp_controller *ctrl;
82 struct dpp_relay_controller *relay;
83 struct dpp_global *global;
84 struct dpp_authentication *auth;
85 int sock;
86 u8 mac_addr[ETH_ALEN];
87 unsigned int freq;
88 u8 msg_len[4];
89 size_t msg_len_octets;
90 struct wpabuf *msg;
91 struct wpabuf *msg_out;
92 size_t msg_out_pos;
93 unsigned int read_eloop:1;
94 unsigned int write_eloop:1;
95 unsigned int on_tcp_tx_complete_gas_done:1;
96 unsigned int on_tcp_tx_complete_remove:1;
97 unsigned int on_tcp_tx_complete_auth_ok:1;
98};
99
100/* Remote Controller */
101struct dpp_relay_controller {
102 struct dl_list list;
103 struct dpp_global *global;
104 u8 pkhash[SHA256_MAC_LEN];
105 struct hostapd_ip_addr ipaddr;
106 void *cb_ctx;
107 void (*tx)(void *ctx, const u8 *addr, unsigned int freq, const u8 *msg,
108 size_t len);
109 void (*gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token,
110 int prot, struct wpabuf *buf);
111 struct dl_list conn; /* struct dpp_connection */
112};
113
114/* Local Controller */
115struct dpp_controller {
116 struct dpp_global *global;
117 u8 allowed_roles;
118 int qr_mutual;
119 int sock;
120 struct dl_list conn; /* struct dpp_connection */
121 char *configurator_params;
122};
123
87d8435c 124struct dpp_global {
2ed2b52f 125 void *msg_ctx;
87d8435c
JM
126 struct dl_list bootstrap; /* struct dpp_bootstrap_info */
127 struct dl_list configurator; /* struct dpp_configurator */
88a78bdd
JM
128#ifdef CONFIG_DPP2
129 struct dl_list controllers; /* struct dpp_relay_controller */
130 struct dpp_controller *controller;
131 struct dl_list tcp_init; /* struct dpp_connection */
132 void *cb_ctx;
133 int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
134#endif /* CONFIG_DPP2 */
87d8435c
JM
135};
136
be27e185
JM
137static const struct dpp_curve_params dpp_curves[] = {
138 /* The mandatory to support and the default NIST P-256 curve needs to
139 * be the first entry on this list. */
31f03cb0
JM
140 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
141 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
142 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
143 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
144 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
145 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
146 { NULL, 0, 0, 0, 0, NULL, 0, NULL }
500ed7f0
JM
147};
148
149
150/* Role-specific elements for PKEX */
151
152/* NIST P-256 */
153static const u8 pkex_init_x_p256[32] = {
154 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
155 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
156 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
157 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
158 };
159static const u8 pkex_init_y_p256[32] = {
160 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
161 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
162 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
163 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
164 };
165static const u8 pkex_resp_x_p256[32] = {
166 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
167 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
168 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
169 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
170};
171static const u8 pkex_resp_y_p256[32] = {
fe3f81e6
JM
172 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
173 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
174 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
175 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
500ed7f0
JM
176};
177
178/* NIST P-384 */
179static const u8 pkex_init_x_p384[48] = {
180 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
181 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
182 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
183 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
184 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
185 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
186};
187static const u8 pkex_init_y_p384[48] = {
fe3f81e6
JM
188 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
189 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
190 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
191 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
192 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
193 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
500ed7f0
JM
194};
195static const u8 pkex_resp_x_p384[48] = {
196 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
197 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
198 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
199 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
200 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
201 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
202};
203static const u8 pkex_resp_y_p384[48] = {
fe3f81e6
JM
204 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
205 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
206 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
207 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
208 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
209 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
500ed7f0
JM
210};
211
212/* NIST P-521 */
213static const u8 pkex_init_x_p521[66] = {
214 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
215 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
216 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
217 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
218 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
219 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
220 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
221 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
222 0x97, 0x76
223};
224static const u8 pkex_init_y_p521[66] = {
fe3f81e6
JM
225 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
226 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
227 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
228 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
229 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
230 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
231 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
232 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
233 0x03, 0xa8
500ed7f0
JM
234};
235static const u8 pkex_resp_x_p521[66] = {
236 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
237 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
238 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
239 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
240 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
241 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
242 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
243 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
244 0x84, 0xb4
245};
246static const u8 pkex_resp_y_p521[66] = {
fe3f81e6
JM
247 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
248 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
249 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
250 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
251 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
252 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
253 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
254 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
255 0xce, 0xe1
500ed7f0
JM
256};
257
258/* Brainpool P-256r1 */
259static const u8 pkex_init_x_bp_p256r1[32] = {
260 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
261 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
262 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
263 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
264};
265static const u8 pkex_init_y_bp_p256r1[32] = {
fe3f81e6
JM
266 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
267 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
268 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
269 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
500ed7f0
JM
270};
271static const u8 pkex_resp_x_bp_p256r1[32] = {
272 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
273 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
274 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
275 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
276};
277static const u8 pkex_resp_y_bp_p256r1[32] = {
278 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
279 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
280 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
281 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
282};
283
284/* Brainpool P-384r1 */
285static const u8 pkex_init_x_bp_p384r1[48] = {
286 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
287 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
288 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
289 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
290 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
291 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
292};
293static const u8 pkex_init_y_bp_p384r1[48] = {
294 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
295 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
296 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
297 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
298 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
299 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
300};
301static const u8 pkex_resp_x_bp_p384r1[48] = {
302 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
303 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
304 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
305 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
306 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
307 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
308};
309static const u8 pkex_resp_y_bp_p384r1[48] = {
310 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
311 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
312 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
313 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
314 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
315 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
316};
317
318/* Brainpool P-512r1 */
319static const u8 pkex_init_x_bp_p512r1[64] = {
320 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
321 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
322 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
323 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
324 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
325 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
326 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
327 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
328};
329static const u8 pkex_init_y_bp_p512r1[64] = {
fe3f81e6
JM
330 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
331 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
332 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
333 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
334 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
335 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
336 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
337 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
500ed7f0
JM
338};
339static const u8 pkex_resp_x_bp_p512r1[64] = {
340 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
341 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
342 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
343 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
344 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
345 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
346 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
347 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
348};
349static const u8 pkex_resp_y_bp_p512r1[64] = {
fe3f81e6
JM
350 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
351 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
352 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
353 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
354 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
355 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
356 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
357 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
be27e185
JM
358};
359
360
d722c50d
JM
361static void dpp_debug_print_point(const char *title, const EC_GROUP *group,
362 const EC_POINT *point)
363{
364 BIGNUM *x, *y;
365 BN_CTX *ctx;
366 char *x_str = NULL, *y_str = NULL;
367
368 if (!wpa_debug_show_keys)
369 return;
370
371 ctx = BN_CTX_new();
372 x = BN_new();
373 y = BN_new();
374 if (!ctx || !x || !y ||
375 EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
376 goto fail;
377
378 x_str = BN_bn2hex(x);
379 y_str = BN_bn2hex(y);
380 if (!x_str || !y_str)
381 goto fail;
382
383 wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
384
385fail:
386 OPENSSL_free(x_str);
387 OPENSSL_free(y_str);
388 BN_free(x);
389 BN_free(y);
390 BN_CTX_free(ctx);
391}
392
393
b9d47b48
JM
394static int dpp_hash_vector(const struct dpp_curve_params *curve,
395 size_t num_elem, const u8 *addr[], const size_t *len,
396 u8 *mac)
397{
398 if (curve->hash_len == 32)
399 return sha256_vector(num_elem, addr, len, mac);
400 if (curve->hash_len == 48)
401 return sha384_vector(num_elem, addr, len, mac);
402 if (curve->hash_len == 64)
403 return sha512_vector(num_elem, addr, len, mac);
404 return -1;
405}
406
407
408static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
409 const char *label, u8 *out, size_t outlen)
410{
411 if (hash_len == 32)
412 return hmac_sha256_kdf(secret, secret_len, NULL,
413 (const u8 *) label, os_strlen(label),
414 out, outlen);
415 if (hash_len == 48)
416 return hmac_sha384_kdf(secret, secret_len, NULL,
417 (const u8 *) label, os_strlen(label),
418 out, outlen);
419 if (hash_len == 64)
420 return hmac_sha512_kdf(secret, secret_len, NULL,
421 (const u8 *) label, os_strlen(label),
422 out, outlen);
423 return -1;
424}
425
426
427static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
428 size_t num_elem, const u8 *addr[],
429 const size_t *len, u8 *mac)
430{
431 if (hash_len == 32)
432 return hmac_sha256_vector(key, key_len, num_elem, addr, len,
433 mac);
434 if (hash_len == 48)
435 return hmac_sha384_vector(key, key_len, num_elem, addr, len,
436 mac);
437 if (hash_len == 64)
438 return hmac_sha512_vector(key, key_len, num_elem, addr, len,
439 mac);
440 return -1;
441}
442
443
444static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len,
445 const u8 *data, size_t data_len, u8 *mac)
446{
447 if (hash_len == 32)
448 return hmac_sha256(key, key_len, data, data_len, mac);
449 if (hash_len == 48)
450 return hmac_sha384(key, key_len, data, data_len, mac);
451 if (hash_len == 64)
452 return hmac_sha512(key, key_len, data, data_len, mac);
453 return -1;
454}
455
456
ea91ddb0
JM
457#ifdef CONFIG_DPP2
458
459static int dpp_pbkdf2_f(size_t hash_len,
460 const u8 *password, size_t password_len,
461 const u8 *salt, size_t salt_len,
462 unsigned int iterations, unsigned int count, u8 *digest)
463{
464 unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN];
465 unsigned int i;
466 size_t j;
467 u8 count_buf[4];
468 const u8 *addr[2];
469 size_t len[2];
470
471 addr[0] = salt;
472 len[0] = salt_len;
473 addr[1] = count_buf;
474 len[1] = 4;
475
476 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
477 * U1 = PRF(P, S || i)
478 * U2 = PRF(P, U1)
479 * Uc = PRF(P, Uc-1)
480 */
481
482 WPA_PUT_BE32(count_buf, count);
483 if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len,
484 tmp))
485 return -1;
486 os_memcpy(digest, tmp, hash_len);
487
488 for (i = 1; i < iterations; i++) {
489 if (dpp_hmac(hash_len, password, password_len, tmp, hash_len,
490 tmp2))
491 return -1;
492 os_memcpy(tmp, tmp2, hash_len);
493 for (j = 0; j < hash_len; j++)
494 digest[j] ^= tmp2[j];
495 }
496
497 return 0;
498}
499
500
501static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
502 const u8 *salt, size_t salt_len, unsigned int iterations,
503 u8 *buf, size_t buflen)
504{
505 unsigned int count = 0;
506 unsigned char *pos = buf;
507 size_t left = buflen, plen;
508 unsigned char digest[DPP_MAX_HASH_LEN];
509
510 while (left > 0) {
511 count++;
512 if (dpp_pbkdf2_f(hash_len, password, password_len,
513 salt, salt_len, iterations, count, digest))
514 return -1;
515 plen = left > hash_len ? hash_len : left;
516 os_memcpy(pos, digest, plen);
517 pos += plen;
518 left -= plen;
519 }
520
521 return 0;
522}
523
524#endif /* CONFIG_DPP2 */
525
526
fc0efa2a
JM
527static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
528{
529 int num_bytes, offset;
530
531 num_bytes = BN_num_bytes(bn);
532 if ((size_t) num_bytes > len)
533 return -1;
534 offset = len - num_bytes;
535 os_memset(pos, 0, offset);
536 BN_bn2bin(bn, pos + offset);
537 return 0;
538}
539
540
30d27b04
JM
541static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
542{
543 int len, res;
544 EC_KEY *eckey;
545 struct wpabuf *buf;
546 unsigned char *pos;
547
548 eckey = EVP_PKEY_get1_EC_KEY(pkey);
549 if (!eckey)
550 return NULL;
551 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
552 len = i2o_ECPublicKey(eckey, NULL);
553 if (len <= 0) {
554 wpa_printf(MSG_ERROR,
555 "DDP: Failed to determine public key encoding length");
556 EC_KEY_free(eckey);
557 return NULL;
558 }
559
560 buf = wpabuf_alloc(len);
561 if (!buf) {
562 EC_KEY_free(eckey);
563 return NULL;
564 }
565
566 pos = wpabuf_put(buf, len);
567 res = i2o_ECPublicKey(eckey, &pos);
568 EC_KEY_free(eckey);
569 if (res != len) {
570 wpa_printf(MSG_ERROR,
571 "DDP: Failed to encode public key (res=%d/%d)",
572 res, len);
573 wpabuf_free(buf);
574 return NULL;
575 }
576
577 if (!prefix) {
578 /* Remove 0x04 prefix to match DPP definition */
579 pos = wpabuf_mhead(buf);
580 os_memmove(pos, pos + 1, len - 1);
581 buf->used--;
582 }
583
584 return buf;
585}
586
587
588static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
589 const u8 *buf_x, const u8 *buf_y,
590 size_t len)
591{
592 EC_KEY *eckey = NULL;
593 BN_CTX *ctx;
594 EC_POINT *point = NULL;
595 BIGNUM *x = NULL, *y = NULL;
596 EVP_PKEY *pkey = NULL;
597
598 ctx = BN_CTX_new();
599 if (!ctx) {
600 wpa_printf(MSG_ERROR, "DPP: Out of memory");
601 return NULL;
602 }
603
604 point = EC_POINT_new(group);
605 x = BN_bin2bn(buf_x, len, NULL);
606 y = BN_bin2bn(buf_y, len, NULL);
607 if (!point || !x || !y) {
608 wpa_printf(MSG_ERROR, "DPP: Out of memory");
609 goto fail;
610 }
611
612 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
613 wpa_printf(MSG_ERROR,
614 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
615 ERR_error_string(ERR_get_error(), NULL));
616 goto fail;
617 }
618
619 if (!EC_POINT_is_on_curve(group, point, ctx) ||
620 EC_POINT_is_at_infinity(group, point)) {
621 wpa_printf(MSG_ERROR, "DPP: Invalid point");
622 goto fail;
623 }
d722c50d 624 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
30d27b04
JM
625
626 eckey = EC_KEY_new();
627 if (!eckey ||
628 EC_KEY_set_group(eckey, group) != 1 ||
629 EC_KEY_set_public_key(eckey, point) != 1) {
630 wpa_printf(MSG_ERROR,
631 "DPP: Failed to set EC_KEY: %s",
632 ERR_error_string(ERR_get_error(), NULL));
633 goto fail;
634 }
635 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
636
637 pkey = EVP_PKEY_new();
638 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
639 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
640 goto fail;
641 }
642
643out:
644 BN_free(x);
645 BN_free(y);
646 EC_KEY_free(eckey);
647 EC_POINT_free(point);
648 BN_CTX_free(ctx);
649 return pkey;
650fail:
651 EVP_PKEY_free(pkey);
652 pkey = NULL;
653 goto out;
654}
655
656
657static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key,
658 const u8 *buf, size_t len)
659{
660 EC_KEY *eckey;
661 const EC_GROUP *group;
662 EVP_PKEY *pkey = NULL;
663
664 if (len & 1)
665 return NULL;
666
667 eckey = EVP_PKEY_get1_EC_KEY(group_key);
668 if (!eckey) {
669 wpa_printf(MSG_ERROR,
670 "DPP: Could not get EC_KEY from group_key");
671 return NULL;
672 }
673
674 group = EC_KEY_get0_group(eckey);
675 if (group)
676 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
677 len / 2);
678 else
679 wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
680
681 EC_KEY_free(eckey);
682 return pkey;
683}
684
685
29ef1c5e
JM
686static int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer,
687 u8 *secret, size_t *secret_len)
688{
689 EVP_PKEY_CTX *ctx;
690 int ret = -1;
691
692 ERR_clear_error();
693 *secret_len = 0;
694
695 ctx = EVP_PKEY_CTX_new(own, NULL);
696 if (!ctx) {
697 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
698 ERR_error_string(ERR_get_error(), NULL));
699 return -1;
700 }
701
702 if (EVP_PKEY_derive_init(ctx) != 1) {
703 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
704 ERR_error_string(ERR_get_error(), NULL));
705 goto fail;
706 }
707
708 if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
709 wpa_printf(MSG_ERROR,
710 "DPP: EVP_PKEY_derive_set_peet failed: %s",
711 ERR_error_string(ERR_get_error(), NULL));
712 goto fail;
713 }
714
715 if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
716 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
717 ERR_error_string(ERR_get_error(), NULL));
718 goto fail;
719 }
720
721 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
722 u8 buf[200];
723 int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
724
725 /* It looks like OpenSSL can return unexpectedly large buffer
726 * need for shared secret from EVP_PKEY_derive(NULL) in some
727 * cases. For example, group 19 has shown cases where secret_len
728 * is set to 72 even though the actual length ends up being
729 * updated to 32 when EVP_PKEY_derive() is called with a buffer
730 * for the value. Work around this by trying to fetch the value
731 * and continue if it is within supported range even when the
732 * initial buffer need is claimed to be larger. */
733 wpa_printf(level,
734 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
735 (int) *secret_len);
736 if (*secret_len > 200)
737 goto fail;
738 if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
739 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
740 ERR_error_string(ERR_get_error(), NULL));
741 goto fail;
742 }
743 if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
744 wpa_printf(MSG_ERROR,
745 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
746 (int) *secret_len);
747 goto fail;
748 }
749 wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
750 buf, *secret_len);
751 os_memcpy(secret, buf, *secret_len);
752 forced_memzero(buf, sizeof(buf));
753 goto done;
754 }
755
756 if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
757 wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
758 ERR_error_string(ERR_get_error(), NULL));
759 goto fail;
760 }
761
762done:
763 ret = 0;
764
765fail:
766 EVP_PKEY_CTX_free(ctx);
767 return ret;
768}
769
770
26806abe
JM
771static void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
772{
773 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
774}
775
776
30d27b04
JM
777struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
778 size_t len)
779{
780 struct wpabuf *msg;
781
8c19ea3f 782 msg = wpabuf_alloc(8 + len);
30d27b04
JM
783 if (!msg)
784 return NULL;
785 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC);
786 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
787 wpabuf_put_be24(msg, OUI_WFA);
788 wpabuf_put_u8(msg, DPP_OUI_TYPE);
8c19ea3f 789 wpabuf_put_u8(msg, 1); /* Crypto Suite */
30d27b04
JM
790 wpabuf_put_u8(msg, type);
791 return msg;
792}
793
794
795const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
796{
797 u16 id, alen;
798 const u8 *pos = buf, *end = buf + len;
799
800 while (end - pos >= 4) {
801 id = WPA_GET_LE16(pos);
802 pos += 2;
803 alen = WPA_GET_LE16(pos);
804 pos += 2;
805 if (alen > end - pos)
806 return NULL;
807 if (id == req_id) {
808 *ret_len = alen;
809 return pos;
810 }
811 pos += alen;
812 }
813
814 return NULL;
815}
816
817
52d469de
JM
818static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
819 u16 req_id, u16 *ret_len)
820{
821 u16 id, alen;
822 const u8 *pos, *end = buf + len;
823
824 if (!prev)
825 pos = buf;
826 else
827 pos = prev + WPA_GET_LE16(prev - 2);
828 while (end - pos >= 4) {
829 id = WPA_GET_LE16(pos);
830 pos += 2;
831 alen = WPA_GET_LE16(pos);
832 pos += 2;
833 if (alen > end - pos)
834 return NULL;
835 if (id == req_id) {
836 *ret_len = alen;
837 return pos;
838 }
839 pos += alen;
840 }
841
842 return NULL;
843}
844
845
30d27b04
JM
846int dpp_check_attrs(const u8 *buf, size_t len)
847{
848 const u8 *pos, *end;
0c881807 849 int wrapped_data = 0;
30d27b04
JM
850
851 pos = buf;
852 end = buf + len;
853 while (end - pos >= 4) {
854 u16 id, alen;
855
856 id = WPA_GET_LE16(pos);
857 pos += 2;
858 alen = WPA_GET_LE16(pos);
859 pos += 2;
860 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u",
861 id, alen);
862 if (alen > end - pos) {
863 wpa_printf(MSG_DEBUG,
864 "DPP: Truncated message - not enough room for the attribute - dropped");
865 return -1;
866 }
0c881807
JM
867 if (wrapped_data) {
868 wpa_printf(MSG_DEBUG,
869 "DPP: An unexpected attribute included after the Wrapped Data attribute");
870 return -1;
871 }
872 if (id == DPP_ATTR_WRAPPED_DATA)
873 wrapped_data = 1;
30d27b04
JM
874 pos += alen;
875 }
876
877 if (end != pos) {
878 wpa_printf(MSG_DEBUG,
879 "DPP: Unexpected octets (%d) after the last attribute",
880 (int) (end - pos));
881 return -1;
882 }
883
884 return 0;
885}
886
887
be27e185
JM
888void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
889{
890 if (!info)
891 return;
892 os_free(info->uri);
893 os_free(info->info);
2bbe6ad3
JM
894 os_free(info->chan);
895 os_free(info->pk);
be27e185
JM
896 EVP_PKEY_free(info->pubkey);
897 os_free(info);
898}
899
900
484788b8
JM
901const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type)
902{
903 switch (type) {
904 case DPP_BOOTSTRAP_QR_CODE:
905 return "QRCODE";
906 case DPP_BOOTSTRAP_PKEX:
907 return "PKEX";
e780b4bf
JM
908 case DPP_BOOTSTRAP_NFC_URI:
909 return "NFC-URI";
484788b8
JM
910 }
911 return "??";
912}
913
914
be27e185
JM
915static int dpp_uri_valid_info(const char *info)
916{
917 while (*info) {
918 unsigned char val = *info++;
919
920 if (val < 0x20 || val > 0x7e || val == 0x3b)
921 return 0;
922 }
923
924 return 1;
925}
926
927
928static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri)
929{
930 bi->uri = os_strdup(uri);
931 return bi->uri ? 0 : -1;
932}
933
934
935int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
936 const char *chan_list)
937{
b1aee7a6
JM
938 const char *pos = chan_list, *pos2;
939 int opclass = -1, channel, freq;
be27e185
JM
940
941 while (pos && *pos && *pos != ';') {
b1aee7a6
JM
942 pos2 = pos;
943 while (*pos2 >= '0' && *pos2 <= '9')
944 pos2++;
945 if (*pos2 == '/') {
946 opclass = atoi(pos);
947 pos = pos2 + 1;
948 }
be27e185
JM
949 if (opclass <= 0)
950 goto fail;
be27e185
JM
951 channel = atoi(pos);
952 if (channel <= 0)
953 goto fail;
954 while (*pos >= '0' && *pos <= '9')
955 pos++;
956 freq = ieee80211_chan_to_freq(NULL, opclass, channel);
957 wpa_printf(MSG_DEBUG,
958 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
959 opclass, channel, freq);
960 if (freq < 0) {
961 wpa_printf(MSG_DEBUG,
962 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
963 opclass, channel);
964 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
965 wpa_printf(MSG_DEBUG,
966 "DPP: Too many channels in URI channel-list - ignore list");
967 bi->num_freq = 0;
968 break;
969 } else {
970 bi->freq[bi->num_freq++] = freq;
971 }
972
973 if (*pos == ';' || *pos == '\0')
974 break;
975 if (*pos != ',')
976 goto fail;
977 pos++;
978 }
979
980 return 0;
981fail:
982 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list");
983 return -1;
984}
985
986
987int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac)
988{
989 if (!mac)
990 return 0;
991
992 if (hwaddr_aton2(mac, bi->mac_addr) < 0) {
993 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac");
994 return -1;
995 }
996
997 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr));
998
999 return 0;
1000}
1001
1002
1003int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info)
1004{
1005 const char *end;
1006
1007 if (!info)
1008 return 0;
1009
1010 end = os_strchr(info, ';');
1011 if (!end)
1012 end = info + os_strlen(info);
1013 bi->info = os_malloc(end - info + 1);
1014 if (!bi->info)
1015 return -1;
1016 os_memcpy(bi->info, info, end - info);
1017 bi->info[end - info] = '\0';
1018 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info);
1019 if (!dpp_uri_valid_info(bi->info)) {
1020 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload");
1021 return -1;
1022 }
1023
1024 return 0;
1025}
1026
1027
1028static const struct dpp_curve_params *
1029dpp_get_curve_oid(const ASN1_OBJECT *poid)
1030{
1031 ASN1_OBJECT *oid;
1032 int i;
1033
1034 for (i = 0; dpp_curves[i].name; i++) {
1035 oid = OBJ_txt2obj(dpp_curves[i].name, 0);
1036 if (oid && OBJ_cmp(poid, oid) == 0)
1037 return &dpp_curves[i];
1038 }
1039 return NULL;
1040}
1041
1042
1043static const struct dpp_curve_params * dpp_get_curve_nid(int nid)
1044{
1045 int i, tmp;
1046
1047 if (!nid)
1048 return NULL;
1049 for (i = 0; dpp_curves[i].name; i++) {
1050 tmp = OBJ_txt2nid(dpp_curves[i].name);
1051 if (tmp == nid)
1052 return &dpp_curves[i];
1053 }
1054 return NULL;
1055}
1056
1057
1058static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info)
1059{
1060 const char *end;
1061 u8 *data;
1062 size_t data_len;
1063 EVP_PKEY *pkey;
1064 const unsigned char *p;
1065 int res;
1066 X509_PUBKEY *pub = NULL;
1067 ASN1_OBJECT *ppkalg;
1068 const unsigned char *pk;
1069 int ppklen;
1070 X509_ALGOR *pa;
5bcddb93
JM
1071#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1072 (defined(LIBRESSL_VERSION_NUMBER) && \
1073 LIBRESSL_VERSION_NUMBER < 0x20800000L)
be27e185 1074 ASN1_OBJECT *pa_oid;
809c6750
JM
1075#else
1076 const ASN1_OBJECT *pa_oid;
1077#endif
be27e185
JM
1078 const void *pval;
1079 int ptype;
1080 const ASN1_OBJECT *poid;
1081 char buf[100];
1082
1083 end = os_strchr(info, ';');
1084 if (!end)
1085 return -1;
1086
8e5e36a1 1087 data = base64_decode(info, end - info, &data_len);
be27e185
JM
1088 if (!data) {
1089 wpa_printf(MSG_DEBUG,
1090 "DPP: Invalid base64 encoding on URI public-key");
1091 return -1;
1092 }
1093 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key",
1094 data, data_len);
1095
1096 if (sha256_vector(1, (const u8 **) &data, &data_len,
1097 bi->pubkey_hash) < 0) {
1098 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
bae282e3 1099 os_free(data);
be27e185
JM
1100 return -1;
1101 }
30d27b04
JM
1102 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash",
1103 bi->pubkey_hash, SHA256_MAC_LEN);
be27e185
JM
1104
1105 /* DER encoded ASN.1 SubjectPublicKeyInfo
1106 *
1107 * SubjectPublicKeyInfo ::= SEQUENCE {
1108 * algorithm AlgorithmIdentifier,
1109 * subjectPublicKey BIT STRING }
1110 *
1111 * AlgorithmIdentifier ::= SEQUENCE {
1112 * algorithm OBJECT IDENTIFIER,
1113 * parameters ANY DEFINED BY algorithm OPTIONAL }
1114 *
1115 * subjectPublicKey = compressed format public key per ANSI X9.63
1116 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1117 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1118 * prime256v1 (1.2.840.10045.3.1.7)
1119 */
1120
1121 p = data;
1122 pkey = d2i_PUBKEY(NULL, &p, data_len);
1123 os_free(data);
1124
1125 if (!pkey) {
1126 wpa_printf(MSG_DEBUG,
1127 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1128 return -1;
1129 }
1130
1131 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
1132 wpa_printf(MSG_DEBUG,
1133 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1134 EVP_PKEY_free(pkey);
1135 return -1;
1136 }
1137
1138 res = X509_PUBKEY_set(&pub, pkey);
1139 if (res != 1) {
1140 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
1141 goto fail;
1142 }
1143
1144 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
1145 if (res != 1) {
1146 wpa_printf(MSG_DEBUG,
1147 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1148 goto fail;
1149 }
1150 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
1151 if (res < 0 || (size_t) res >= sizeof(buf)) {
1152 wpa_printf(MSG_DEBUG,
1153 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1154 goto fail;
1155 }
1156 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
1157 if (os_strcmp(buf, "id-ecPublicKey") != 0) {
1158 wpa_printf(MSG_DEBUG,
1159 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1160 goto fail;
1161 }
1162
1163 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
1164 if (ptype != V_ASN1_OBJECT) {
1165 wpa_printf(MSG_DEBUG,
1166 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1167 goto fail;
1168 }
1169 poid = pval;
1170 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
1171 if (res < 0 || (size_t) res >= sizeof(buf)) {
1172 wpa_printf(MSG_DEBUG,
1173 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1174 goto fail;
1175 }
1176 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
1177 bi->curve = dpp_get_curve_oid(poid);
1178 if (!bi->curve) {
1179 wpa_printf(MSG_DEBUG,
1180 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1181 buf);
1182 goto fail;
1183 }
1184
1185 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
1186
1187 X509_PUBKEY_free(pub);
1188 bi->pubkey = pkey;
1189 return 0;
1190fail:
1191 X509_PUBKEY_free(pub);
1192 EVP_PKEY_free(pkey);
1193 return -1;
1194}
1195
1196
1197static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
1198{
1199 const char *pos = uri;
1200 const char *end;
1201 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
1202 struct dpp_bootstrap_info *bi;
1203
1204 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
1205
1206 if (os_strncmp(pos, "DPP:", 4) != 0) {
1207 wpa_printf(MSG_INFO, "DPP: Not a DPP URI");
1208 return NULL;
1209 }
1210 pos += 4;
1211
1212 for (;;) {
1213 end = os_strchr(pos, ';');
1214 if (!end)
1215 break;
1216
1217 if (end == pos) {
1218 /* Handle terminating ";;" and ignore unexpected ";"
1219 * for parsing robustness. */
1220 pos++;
1221 continue;
1222 }
1223
1224 if (pos[0] == 'C' && pos[1] == ':' && !chan_list)
1225 chan_list = pos + 2;
1226 else if (pos[0] == 'M' && pos[1] == ':' && !mac)
1227 mac = pos + 2;
1228 else if (pos[0] == 'I' && pos[1] == ':' && !info)
1229 info = pos + 2;
1230 else if (pos[0] == 'K' && pos[1] == ':' && !pk)
1231 pk = pos + 2;
1232 else
1233 wpa_hexdump_ascii(MSG_DEBUG,
1234 "DPP: Ignore unrecognized URI parameter",
1235 pos, end - pos);
1236 pos = end + 1;
1237 }
1238
1239 if (!pk) {
1240 wpa_printf(MSG_INFO, "DPP: URI missing public-key");
1241 return NULL;
1242 }
1243
1244 bi = os_zalloc(sizeof(*bi));
1245 if (!bi)
1246 return NULL;
1247
1248 if (dpp_clone_uri(bi, uri) < 0 ||
1249 dpp_parse_uri_chan_list(bi, chan_list) < 0 ||
1250 dpp_parse_uri_mac(bi, mac) < 0 ||
1251 dpp_parse_uri_info(bi, info) < 0 ||
1252 dpp_parse_uri_pk(bi, pk) < 0) {
1253 dpp_bootstrap_info_free(bi);
1254 bi = NULL;
1255 }
1256
1257 return bi;
1258}
1259
1260
be27e185
JM
1261static void dpp_debug_print_key(const char *title, EVP_PKEY *key)
1262{
1263 EC_KEY *eckey;
1264 BIO *out;
1265 size_t rlen;
1266 char *txt;
1267 int res;
1268 unsigned char *der = NULL;
1269 int der_len;
d722c50d
JM
1270 const EC_GROUP *group;
1271 const EC_POINT *point;
be27e185
JM
1272
1273 out = BIO_new(BIO_s_mem());
1274 if (!out)
1275 return;
1276
1277 EVP_PKEY_print_private(out, key, 0, NULL);
1278 rlen = BIO_ctrl_pending(out);
1279 txt = os_malloc(rlen + 1);
1280 if (txt) {
1281 res = BIO_read(out, txt, rlen);
1282 if (res > 0) {
1283 txt[res] = '\0';
1284 wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
1285 }
1286 os_free(txt);
1287 }
1288 BIO_free(out);
1289
1290 eckey = EVP_PKEY_get1_EC_KEY(key);
1291 if (!eckey)
1292 return;
1293
d722c50d
JM
1294 group = EC_KEY_get0_group(eckey);
1295 point = EC_KEY_get0_public_key(eckey);
1296 if (group && point)
1297 dpp_debug_print_point(title, group, point);
1298
be27e185
JM
1299 der_len = i2d_ECPrivateKey(eckey, &der);
1300 if (der_len > 0)
1301 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
1302 OPENSSL_free(der);
1303 if (der_len <= 0) {
1304 der = NULL;
1305 der_len = i2d_EC_PUBKEY(eckey, &der);
1306 if (der_len > 0)
1307 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
1308 OPENSSL_free(der);
1309 }
1310
1311 EC_KEY_free(eckey);
1312}
1313
1314
1315static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
1316{
be27e185 1317 EVP_PKEY_CTX *kctx = NULL;
7a9ddba6 1318 EC_KEY *ec_params = NULL;
be27e185
JM
1319 EVP_PKEY *params = NULL, *key = NULL;
1320 int nid;
1321
1322 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
1323
1324 nid = OBJ_txt2nid(curve->name);
1325 if (nid == NID_undef) {
1326 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
1327 return NULL;
1328 }
c23e87d0 1329
7641d485
JM
1330 ec_params = EC_KEY_new_by_curve_name(nid);
1331 if (!ec_params) {
be27e185
JM
1332 wpa_printf(MSG_ERROR,
1333 "DPP: Failed to generate EC_KEY parameters");
1334 goto fail;
1335 }
1336 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
1337 params = EVP_PKEY_new();
1338 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
1339 wpa_printf(MSG_ERROR,
1340 "DPP: Failed to generate EVP_PKEY parameters");
1341 goto fail;
1342 }
be27e185
JM
1343
1344 kctx = EVP_PKEY_CTX_new(params, NULL);
1345 if (!kctx ||
1346 EVP_PKEY_keygen_init(kctx) != 1 ||
1347 EVP_PKEY_keygen(kctx, &key) != 1) {
1348 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
7a9ddba6 1349 key = NULL;
be27e185
JM
1350 goto fail;
1351 }
1352
1353 if (wpa_debug_show_keys)
1354 dpp_debug_print_key("Own generated key", key);
1355
7a9ddba6
JM
1356fail:
1357 EC_KEY_free(ec_params);
be27e185
JM
1358 EVP_PKEY_free(params);
1359 EVP_PKEY_CTX_free(kctx);
1360 return key;
be27e185
JM
1361}
1362
1363
1364static const struct dpp_curve_params *
1365dpp_get_curve_name(const char *name)
1366{
1367 int i;
1368
1369 for (i = 0; dpp_curves[i].name; i++) {
1370 if (os_strcmp(name, dpp_curves[i].name) == 0 ||
1371 (dpp_curves[i].jwk_crv &&
1372 os_strcmp(name, dpp_curves[i].jwk_crv) == 0))
1373 return &dpp_curves[i];
1374 }
1375 return NULL;
1376}
1377
1378
461d39af
JM
1379static const struct dpp_curve_params *
1380dpp_get_curve_jwk_crv(const char *name)
1381{
1382 int i;
1383
1384 for (i = 0; dpp_curves[i].name; i++) {
1385 if (dpp_curves[i].jwk_crv &&
1386 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)
1387 return &dpp_curves[i];
1388 }
1389 return NULL;
1390}
1391
1392
be27e185
JM
1393static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
1394 const u8 *privkey, size_t privkey_len)
1395{
1396 EVP_PKEY *pkey;
1397 EC_KEY *eckey;
1398 const EC_GROUP *group;
1399 int nid;
1400
1401 pkey = EVP_PKEY_new();
1402 if (!pkey)
1403 return NULL;
1404 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
1405 if (!eckey) {
1406 wpa_printf(MSG_INFO,
1407 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1408 ERR_error_string(ERR_get_error(), NULL));
1409 EVP_PKEY_free(pkey);
1410 return NULL;
1411 }
1412 group = EC_KEY_get0_group(eckey);
1413 if (!group) {
1414 EC_KEY_free(eckey);
1415 EVP_PKEY_free(pkey);
1416 return NULL;
1417 }
1418 nid = EC_GROUP_get_curve_name(group);
1419 *curve = dpp_get_curve_nid(nid);
1420 if (!*curve) {
1421 wpa_printf(MSG_INFO,
1422 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1423 nid);
1424 EC_KEY_free(eckey);
1425 EVP_PKEY_free(pkey);
1426 return NULL;
1427 }
1428
1429 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
1430 EC_KEY_free(eckey);
1431 EVP_PKEY_free(pkey);
1432 return NULL;
1433 }
1434 return pkey;
1435}
1436
1437
746c1792
JM
1438typedef struct {
1439 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1440 * as an OID identifying the curve */
1441 X509_ALGOR *alg;
1442 /* Compressed format public key per ANSI X9.63 */
1443 ASN1_BIT_STRING *pub_key;
1444} DPP_BOOTSTRAPPING_KEY;
1445
1446ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
1447 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
1448 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
1449} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
1450
1451IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
1452
1453
f2d27ef9 1454static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
500ed7f0
JM
1455{
1456 unsigned char *der = NULL;
1457 int der_len;
1458 EC_KEY *eckey;
746c1792
JM
1459 struct wpabuf *ret = NULL;
1460 size_t len;
1461 const EC_GROUP *group;
1462 const EC_POINT *point;
1463 BN_CTX *ctx;
1464 DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
1465 int nid;
500ed7f0 1466
746c1792 1467 ctx = BN_CTX_new();
f2d27ef9 1468 eckey = EVP_PKEY_get1_EC_KEY(key);
746c1792
JM
1469 if (!ctx || !eckey)
1470 goto fail;
1471
1472 group = EC_KEY_get0_group(eckey);
1473 point = EC_KEY_get0_public_key(eckey);
1474 if (!group || !point)
1475 goto fail;
d722c50d 1476 dpp_debug_print_point("DPP: bootstrap public key", group, point);
746c1792
JM
1477 nid = EC_GROUP_get_curve_name(group);
1478
1479 bootstrap = DPP_BOOTSTRAPPING_KEY_new();
1480 if (!bootstrap ||
1481 X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
1482 V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
1483 goto fail;
1484
1485 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1486 NULL, 0, ctx);
1487 if (len == 0)
1488 goto fail;
1489
1490 der = OPENSSL_malloc(len);
1491 if (!der)
1492 goto fail;
1493 len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
1494 der, len, ctx);
1495
1496 OPENSSL_free(bootstrap->pub_key->data);
1497 bootstrap->pub_key->data = der;
1498 der = NULL;
1499 bootstrap->pub_key->length = len;
1500 /* No unused bits */
1501 bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
1502 bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
1503
1504 der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
500ed7f0
JM
1505 if (der_len <= 0) {
1506 wpa_printf(MSG_ERROR,
1507 "DDP: Failed to build DER encoded public key");
746c1792 1508 goto fail;
500ed7f0
JM
1509 }
1510
f2d27ef9 1511 ret = wpabuf_alloc_copy(der, der_len);
746c1792
JM
1512fail:
1513 DPP_BOOTSTRAPPING_KEY_free(bootstrap);
500ed7f0 1514 OPENSSL_free(der);
746c1792
JM
1515 EC_KEY_free(eckey);
1516 BN_CTX_free(ctx);
f2d27ef9
JM
1517 return ret;
1518}
1519
1520
1521int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
1522{
1523 struct wpabuf *der;
1524 int res;
1525 const u8 *addr[1];
1526 size_t len[1];
1527
1528 der = dpp_bootstrap_key_der(bi->pubkey);
1529 if (!der)
1530 return -1;
1531 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1532 der);
1533
1534 addr[0] = wpabuf_head(der);
1535 len[0] = wpabuf_len(der);
1536 res = sha256_vector(1, addr, len, bi->pubkey_hash);
500ed7f0
JM
1537 if (res < 0)
1538 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
f2d27ef9
JM
1539 else
1540 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1541 SHA256_MAC_LEN);
1542 wpabuf_free(der);
500ed7f0
JM
1543 return res;
1544}
1545
1546
2bbe6ad3
JM
1547static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
1548 const u8 *privkey, size_t privkey_len)
be27e185 1549{
8e5e36a1 1550 char *base64 = NULL;
be27e185
JM
1551 char *pos, *end;
1552 size_t len;
f2d27ef9
JM
1553 struct wpabuf *der = NULL;
1554 const u8 *addr[1];
1555 int res;
be27e185
JM
1556
1557 if (!curve) {
1558 bi->curve = &dpp_curves[0];
1559 } else {
1560 bi->curve = dpp_get_curve_name(curve);
1561 if (!bi->curve) {
1562 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
1563 curve);
2bbe6ad3 1564 return -1;
be27e185
JM
1565 }
1566 }
1567 if (privkey)
1568 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len);
1569 else
1570 bi->pubkey = dpp_gen_keypair(bi->curve);
1571 if (!bi->pubkey)
1572 goto fail;
1573 bi->own = 1;
1574
f2d27ef9
JM
1575 der = dpp_bootstrap_key_der(bi->pubkey);
1576 if (!der)
be27e185 1577 goto fail;
f2d27ef9
JM
1578 wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
1579 der);
be27e185 1580
f2d27ef9
JM
1581 addr[0] = wpabuf_head(der);
1582 len = wpabuf_len(der);
1583 res = sha256_vector(1, addr, &len, bi->pubkey_hash);
f981ce72 1584 if (res < 0) {
be27e185 1585 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
f981ce72
JM
1586 goto fail;
1587 }
1588 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash,
1589 SHA256_MAC_LEN);
be27e185 1590
f2d27ef9
JM
1591 base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len);
1592 wpabuf_free(der);
58efbcbc 1593 der = NULL;
be27e185
JM
1594 if (!base64)
1595 goto fail;
8e5e36a1 1596 pos = base64;
be27e185
JM
1597 end = pos + len;
1598 for (;;) {
1599 pos = os_strchr(pos, '\n');
1600 if (!pos)
1601 break;
1602 os_memmove(pos, pos + 1, end - pos);
1603 }
2bbe6ad3
JM
1604 os_free(bi->pk);
1605 bi->pk = base64;
1606 return 0;
be27e185
JM
1607fail:
1608 os_free(base64);
f2d27ef9 1609 wpabuf_free(der);
2bbe6ad3 1610 return -1;
be27e185 1611}
30d27b04
JM
1612
1613
1614static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1,
1615 unsigned int hash_len)
1616{
1617 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1618 const char *info = "first intermediate key";
b9d47b48 1619 int res;
30d27b04
JM
1620
1621 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1622
1623 /* HKDF-Extract(<>, M.x) */
1624 os_memset(salt, 0, hash_len);
b9d47b48 1625 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0)
30d27b04 1626 return -1;
30d27b04
JM
1627 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1628 prk, hash_len);
1629
1630 /* HKDF-Expand(PRK, info, L) */
b9d47b48 1631 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len);
30d27b04
JM
1632 os_memset(prk, 0, hash_len);
1633 if (res < 0)
1634 return -1;
1635
1636 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1637 k1, hash_len);
1638 return 0;
1639}
1640
1641
1642static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2,
1643 unsigned int hash_len)
1644{
1645 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
1646 const char *info = "second intermediate key";
1647 int res;
1648
1649 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1650
1651 /* HKDF-Extract(<>, N.x) */
1652 os_memset(salt, 0, hash_len);
b9d47b48 1653 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk);
30d27b04
JM
1654 if (res < 0)
1655 return -1;
1656 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1657 prk, hash_len);
1658
1659 /* HKDF-Expand(PRK, info, L) */
b9d47b48 1660 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len);
30d27b04
JM
1661 os_memset(prk, 0, hash_len);
1662 if (res < 0)
1663 return -1;
1664
1665 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1666 k2, hash_len);
1667 return 0;
1668}
1669
1670
1671static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke,
1672 unsigned int hash_len)
1673{
1674 size_t nonce_len;
1675 u8 nonces[2 * DPP_MAX_NONCE_LEN];
1676 const char *info_ke = "DPP Key";
1677 u8 prk[DPP_MAX_HASH_LEN];
1678 int res;
1679 const u8 *addr[3];
1680 size_t len[3];
1681 size_t num_elem = 0;
1682
630ea133
JM
1683 if (!auth->Mx_len || !auth->Nx_len) {
1684 wpa_printf(MSG_DEBUG,
1685 "DPP: Mx/Nx not available - cannot derive ke");
1686 return -1;
1687 }
1688
30d27b04
JM
1689 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1690
1691 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1692 nonce_len = auth->curve->nonce_len;
1693 os_memcpy(nonces, auth->i_nonce, nonce_len);
1694 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len);
1695 addr[num_elem] = auth->Mx;
630ea133 1696 len[num_elem] = auth->Mx_len;
30d27b04
JM
1697 num_elem++;
1698 addr[num_elem] = auth->Nx;
630ea133 1699 len[num_elem] = auth->Nx_len;
30d27b04
JM
1700 num_elem++;
1701 if (auth->peer_bi && auth->own_bi) {
630ea133
JM
1702 if (!auth->Lx_len) {
1703 wpa_printf(MSG_DEBUG,
1704 "DPP: Lx not available - cannot derive ke");
1705 return -1;
1706 }
30d27b04
JM
1707 addr[num_elem] = auth->Lx;
1708 len[num_elem] = auth->secret_len;
1709 num_elem++;
1710 }
b9d47b48
JM
1711 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len,
1712 num_elem, addr, len, prk);
30d27b04
JM
1713 if (res < 0)
1714 return -1;
1715 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
1716 prk, hash_len);
1717
1718 /* HKDF-Expand(PRK, info, L) */
b9d47b48 1719 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len);
30d27b04
JM
1720 os_memset(prk, 0, hash_len);
1721 if (res < 0)
1722 return -1;
1723
1724 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)",
1725 ke, hash_len);
1726 return 0;
1727}
1728
1729
56f24d1d
JM
1730static void dpp_build_attr_status(struct wpabuf *msg,
1731 enum dpp_status_error status)
1732{
1733 wpa_printf(MSG_DEBUG, "DPP: Status %d", status);
1734 wpabuf_put_le16(msg, DPP_ATTR_STATUS);
1735 wpabuf_put_le16(msg, 1);
1736 wpabuf_put_u8(msg, status);
1737}
1738
1739
9efa5314
JM
1740static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf *msg,
1741 const u8 *hash)
1742{
1743 if (hash) {
1744 wpa_printf(MSG_DEBUG, "DPP: R-Bootstrap Key Hash");
1745 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH);
1746 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1747 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1748 }
1749}
1750
1751
1752static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf *msg,
1753 const u8 *hash)
1754{
1755 if (hash) {
1756 wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash");
1757 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH);
1758 wpabuf_put_le16(msg, SHA256_MAC_LEN);
1759 wpabuf_put_data(msg, hash, SHA256_MAC_LEN);
1760 }
1761}
1762
1763
606a8e8d
JM
1764static struct wpabuf * dpp_auth_build_req(struct dpp_authentication *auth,
1765 const struct wpabuf *pi,
1766 size_t nonce_len,
1767 const u8 *r_pubkey_hash,
d2709206
JM
1768 const u8 *i_pubkey_hash,
1769 unsigned int neg_freq)
30d27b04 1770{
606a8e8d 1771 struct wpabuf *msg;
30d27b04
JM
1772 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1];
1773 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE];
1774 u8 *pos;
dc4d271c
JM
1775 const u8 *addr[2];
1776 size_t len[2], siv_len, attr_len;
1777 u8 *attr_start, *attr_end;
30d27b04 1778
30d27b04 1779 /* Build DPP Authentication Request frame attributes */
606a8e8d 1780 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + (pi ? wpabuf_len(pi) : 0) +
dc4d271c 1781 4 + sizeof(wrapped_data);
d2709206
JM
1782 if (neg_freq > 0)
1783 attr_len += 4 + 2;
0b4a906d
JM
1784#ifdef CONFIG_DPP2
1785 attr_len += 5;
1786#endif /* CONFIG_DPP2 */
60239f60
JM
1787#ifdef CONFIG_TESTING_OPTIONS
1788 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ)
acdf703d 1789 attr_len += 5;
60239f60 1790#endif /* CONFIG_TESTING_OPTIONS */
dc4d271c 1791 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len);
30d27b04 1792 if (!msg)
606a8e8d 1793 return NULL;
dc4d271c
JM
1794
1795 attr_start = wpabuf_put(msg, 0);
30d27b04
JM
1796
1797 /* Responder Bootstrapping Key Hash */
9efa5314 1798 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
30d27b04
JM
1799
1800 /* Initiator Bootstrapping Key Hash */
9efa5314 1801 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
30d27b04
JM
1802
1803 /* Initiator Protocol Key */
606a8e8d
JM
1804 if (pi) {
1805 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY);
1806 wpabuf_put_le16(msg, wpabuf_len(pi));
1807 wpabuf_put_buf(msg, pi);
1808 }
30d27b04 1809
d2709206
JM
1810 /* Channel */
1811 if (neg_freq > 0) {
1812 u8 op_class, channel;
1813
1814 if (ieee80211_freq_to_channel_ext(neg_freq, 0, 0, &op_class,
1815 &channel) ==
1816 NUM_HOSTAPD_MODES) {
1817 wpa_printf(MSG_INFO,
1818 "DPP: Unsupported negotiation frequency request: %d",
1819 neg_freq);
1820 wpabuf_free(msg);
1821 return NULL;
1822 }
1823 wpabuf_put_le16(msg, DPP_ATTR_CHANNEL);
1824 wpabuf_put_le16(msg, 2);
1825 wpabuf_put_u8(msg, op_class);
1826 wpabuf_put_u8(msg, channel);
1827 }
1828
0b4a906d
JM
1829#ifdef CONFIG_DPP2
1830 /* Protocol Version */
1831 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1832 wpabuf_put_le16(msg, 1);
1833 wpabuf_put_u8(msg, 2);
1834#endif /* CONFIG_DPP2 */
1835
0e7cb8c6
JM
1836#ifdef CONFIG_TESTING_OPTIONS
1837 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ) {
1838 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
1839 goto skip_wrapped_data;
1840 }
1841#endif /* CONFIG_TESTING_OPTIONS */
1842
30d27b04
JM
1843 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1844 pos = clear;
606a8e8d 1845
0e7cb8c6
JM
1846#ifdef CONFIG_TESTING_OPTIONS
1847 if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_REQ) {
1848 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
1849 goto skip_i_nonce;
1850 }
a4446739
JM
1851 if (dpp_test == DPP_TEST_INVALID_I_NONCE_AUTH_REQ) {
1852 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-nonce");
1853 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1854 pos += 2;
1855 WPA_PUT_LE16(pos, nonce_len - 1);
1856 pos += 2;
1857 os_memcpy(pos, auth->i_nonce, nonce_len - 1);
1858 pos += nonce_len - 1;
1859 goto skip_i_nonce;
1860 }
0e7cb8c6
JM
1861#endif /* CONFIG_TESTING_OPTIONS */
1862
30d27b04
JM
1863 /* I-nonce */
1864 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
1865 pos += 2;
1866 WPA_PUT_LE16(pos, nonce_len);
1867 pos += 2;
1868 os_memcpy(pos, auth->i_nonce, nonce_len);
1869 pos += nonce_len;
606a8e8d 1870
0e7cb8c6
JM
1871#ifdef CONFIG_TESTING_OPTIONS
1872skip_i_nonce:
1873 if (dpp_test == DPP_TEST_NO_I_CAPAB_AUTH_REQ) {
1874 wpa_printf(MSG_INFO, "DPP: TESTING - no I-capab");
1875 goto skip_i_capab;
1876 }
1877#endif /* CONFIG_TESTING_OPTIONS */
1878
30d27b04
JM
1879 /* I-capabilities */
1880 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES);
1881 pos += 2;
1882 WPA_PUT_LE16(pos, 1);
1883 pos += 2;
d1f08264 1884 auth->i_capab = auth->allowed_roles;
30d27b04 1885 *pos++ = auth->i_capab;
60239f60
JM
1886#ifdef CONFIG_TESTING_OPTIONS
1887 if (dpp_test == DPP_TEST_ZERO_I_CAPAB) {
1888 wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities");
1889 pos[-1] = 0;
1890 }
0e7cb8c6 1891skip_i_capab:
60239f60 1892#endif /* CONFIG_TESTING_OPTIONS */
30d27b04 1893
dc4d271c
JM
1894 attr_end = wpabuf_put(msg, 0);
1895
1896 /* OUI, OUI type, Crypto Suite, DPP frame type */
1897 addr[0] = wpabuf_head_u8(msg) + 2;
1898 len[0] = 3 + 1 + 1 + 1;
1899 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
1900
1901 /* Attributes before Wrapped Data */
1902 addr[1] = attr_start;
1903 len[1] = attr_end - attr_start;
1904 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
1905
30d27b04
JM
1906 siv_len = pos - clear;
1907 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
1908 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len,
606a8e8d
JM
1909 2, addr, len, wrapped_data) < 0) {
1910 wpabuf_free(msg);
1911 return NULL;
1912 }
30d27b04
JM
1913 siv_len += AES_BLOCK_SIZE;
1914 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
1915 wrapped_data, siv_len);
1916
1917 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
1918 wpabuf_put_le16(msg, siv_len);
1919 wpabuf_put_data(msg, wrapped_data, siv_len);
1920
60239f60
JM
1921#ifdef CONFIG_TESTING_OPTIONS
1922 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) {
1923 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 1924 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 1925 }
0e7cb8c6 1926skip_wrapped_data:
60239f60
JM
1927#endif /* CONFIG_TESTING_OPTIONS */
1928
30d27b04
JM
1929 wpa_hexdump_buf(MSG_DEBUG,
1930 "DPP: Authentication Request frame attributes", msg);
1931
606a8e8d
JM
1932 return msg;
1933}
1934
1935
a03406db
JM
1936static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
1937 enum dpp_status_error status,
1938 const struct wpabuf *pr,
1939 size_t nonce_len,
1940 const u8 *r_pubkey_hash,
1941 const u8 *i_pubkey_hash,
1942 const u8 *r_nonce, const u8 *i_nonce,
1943 const u8 *wrapped_r_auth,
1944 size_t wrapped_r_auth_len,
1945 const u8 *siv_key)
1946{
1947 struct wpabuf *msg;
1948#define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1949 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1950 u8 clear[DPP_AUTH_RESP_CLEAR_LEN];
1951 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE];
1952 const u8 *addr[2];
1953 size_t len[2], siv_len, attr_len;
1954 u8 *attr_start, *attr_end, *pos;
1955
95b0104a
JM
1956 auth->waiting_auth_conf = 1;
1957 auth->auth_resp_tries = 0;
1958
a03406db
JM
1959 /* Build DPP Authentication Response frame attributes */
1960 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
1961 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
0b4a906d
JM
1962#ifdef CONFIG_DPP2
1963 attr_len += 5;
1964#endif /* CONFIG_DPP2 */
a03406db
JM
1965#ifdef CONFIG_TESTING_OPTIONS
1966 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP)
acdf703d 1967 attr_len += 5;
a03406db
JM
1968#endif /* CONFIG_TESTING_OPTIONS */
1969 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
1970 if (!msg)
1971 return NULL;
a03406db
JM
1972
1973 attr_start = wpabuf_put(msg, 0);
1974
1975 /* DPP Status */
56f24d1d
JM
1976 if (status != 255)
1977 dpp_build_attr_status(msg, status);
a03406db
JM
1978
1979 /* Responder Bootstrapping Key Hash */
9efa5314 1980 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
a03406db 1981
9efa5314
JM
1982 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1983 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
a03406db
JM
1984
1985 /* Responder Protocol Key */
1986 if (pr) {
1987 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY);
1988 wpabuf_put_le16(msg, wpabuf_len(pr));
1989 wpabuf_put_buf(msg, pr);
1990 }
1991
0b4a906d
JM
1992#ifdef CONFIG_DPP2
1993 /* Protocol Version */
5e98998e
JM
1994 if (auth->peer_version >= 2) {
1995 wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
1996 wpabuf_put_le16(msg, 1);
1997 wpabuf_put_u8(msg, 2);
1998 }
0b4a906d
JM
1999#endif /* CONFIG_DPP2 */
2000
a03406db
JM
2001 attr_end = wpabuf_put(msg, 0);
2002
ce9acce0
JM
2003#ifdef CONFIG_TESTING_OPTIONS
2004 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP) {
2005 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2006 goto skip_wrapped_data;
2007 }
2008#endif /* CONFIG_TESTING_OPTIONS */
2009
a03406db
JM
2010 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2011 pos = clear;
2012
2013 if (r_nonce) {
2014 /* R-nonce */
2015 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE);
2016 pos += 2;
2017 WPA_PUT_LE16(pos, nonce_len);
2018 pos += 2;
2019 os_memcpy(pos, r_nonce, nonce_len);
2020 pos += nonce_len;
2021 }
2022
2023 if (i_nonce) {
2024 /* I-nonce */
2025 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE);
2026 pos += 2;
2027 WPA_PUT_LE16(pos, nonce_len);
2028 pos += 2;
2029 os_memcpy(pos, i_nonce, nonce_len);
978bc3f2
JM
2030#ifdef CONFIG_TESTING_OPTIONS
2031 if (dpp_test == DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP) {
2032 wpa_printf(MSG_INFO, "DPP: TESTING - I-nonce mismatch");
2033 pos[nonce_len / 2] ^= 0x01;
2034 }
2035#endif /* CONFIG_TESTING_OPTIONS */
a03406db
JM
2036 pos += nonce_len;
2037 }
2038
ce9acce0
JM
2039#ifdef CONFIG_TESTING_OPTIONS
2040 if (dpp_test == DPP_TEST_NO_R_CAPAB_AUTH_RESP) {
2041 wpa_printf(MSG_INFO, "DPP: TESTING - no R-capab");
2042 goto skip_r_capab;
2043 }
2044#endif /* CONFIG_TESTING_OPTIONS */
2045
a03406db
JM
2046 /* R-capabilities */
2047 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES);
2048 pos += 2;
2049 WPA_PUT_LE16(pos, 1);
2050 pos += 2;
2051 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR :
2052 DPP_CAPAB_ENROLLEE;
2053 *pos++ = auth->r_capab;
2054#ifdef CONFIG_TESTING_OPTIONS
2055 if (dpp_test == DPP_TEST_ZERO_R_CAPAB) {
2056 wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities");
2057 pos[-1] = 0;
978bc3f2
JM
2058 } else if (dpp_test == DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP) {
2059 wpa_printf(MSG_INFO,
2060 "DPP: TESTING - incompatible R-capabilities");
d1f08264
JM
2061 if ((auth->i_capab & DPP_CAPAB_ROLE_MASK) ==
2062 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE))
2063 pos[-1] = 0;
2064 else
2065 pos[-1] = auth->configurator ? DPP_CAPAB_ENROLLEE :
2066 DPP_CAPAB_CONFIGURATOR;
a03406db 2067 }
ce9acce0 2068skip_r_capab:
a03406db
JM
2069#endif /* CONFIG_TESTING_OPTIONS */
2070
2071 if (wrapped_r_auth) {
2072 /* {R-auth}ke */
2073 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA);
2074 pos += 2;
2075 WPA_PUT_LE16(pos, wrapped_r_auth_len);
2076 pos += 2;
2077 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len);
2078 pos += wrapped_r_auth_len;
2079 }
2080
2081 /* OUI, OUI type, Crypto Suite, DPP frame type */
2082 addr[0] = wpabuf_head_u8(msg) + 2;
2083 len[0] = 3 + 1 + 1 + 1;
2084 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
2085
2086 /* Attributes before Wrapped Data */
2087 addr[1] = attr_start;
2088 len[1] = attr_end - attr_start;
2089 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
2090
2091 siv_len = pos - clear;
2092 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len);
2093 if (aes_siv_encrypt(siv_key, auth->curve->hash_len, clear, siv_len,
2094 2, addr, len, wrapped_data) < 0) {
2095 wpabuf_free(msg);
2096 return NULL;
2097 }
2098 siv_len += AES_BLOCK_SIZE;
2099 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2100 wrapped_data, siv_len);
2101
2102 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2103 wpabuf_put_le16(msg, siv_len);
2104 wpabuf_put_data(msg, wrapped_data, siv_len);
2105
2106#ifdef CONFIG_TESTING_OPTIONS
2107 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) {
2108 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 2109 dpp_build_attr_status(msg, DPP_STATUS_OK);
a03406db 2110 }
ce9acce0 2111skip_wrapped_data:
a03406db
JM
2112#endif /* CONFIG_TESTING_OPTIONS */
2113
2114 wpa_hexdump_buf(MSG_DEBUG,
2115 "DPP: Authentication Response frame attributes", msg);
2116 return msg;
2117}
2118
2119
f97ace34
JM
2120static int dpp_channel_ok_init(struct hostapd_hw_modes *own_modes,
2121 u16 num_modes, unsigned int freq)
2122{
2123 u16 m;
2124 int c, flag;
2125
2126 if (!own_modes || !num_modes)
2127 return 1;
2128
2129 for (m = 0; m < num_modes; m++) {
2130 for (c = 0; c < own_modes[m].num_channels; c++) {
2131 if ((unsigned int) own_modes[m].channels[c].freq !=
2132 freq)
2133 continue;
2134 flag = own_modes[m].channels[c].flag;
2135 if (!(flag & (HOSTAPD_CHAN_DISABLED |
2136 HOSTAPD_CHAN_NO_IR |
2137 HOSTAPD_CHAN_RADAR)))
2138 return 1;
2139 }
2140 }
2141
2142 wpa_printf(MSG_DEBUG, "DPP: Peer channel %u MHz not supported", freq);
2143 return 0;
2144}
2145
2146
2147static int freq_included(const unsigned int freqs[], unsigned int num,
2148 unsigned int freq)
2149{
2150 while (num > 0) {
2151 if (freqs[--num] == freq)
2152 return 1;
2153 }
2154 return 0;
2155}
2156
2157
2158static void freq_to_start(unsigned int freqs[], unsigned int num,
2159 unsigned int freq)
2160{
2161 unsigned int i;
2162
2163 for (i = 0; i < num; i++) {
2164 if (freqs[i] == freq)
2165 break;
2166 }
2167 if (i == 0 || i >= num)
2168 return;
2169 os_memmove(&freqs[1], &freqs[0], i * sizeof(freqs[0]));
2170 freqs[0] = freq;
2171}
2172
2173
2174static int dpp_channel_intersect(struct dpp_authentication *auth,
2175 struct hostapd_hw_modes *own_modes,
2176 u16 num_modes)
2177{
2178 struct dpp_bootstrap_info *peer_bi = auth->peer_bi;
2179 unsigned int i, freq;
2180
2181 for (i = 0; i < peer_bi->num_freq; i++) {
2182 freq = peer_bi->freq[i];
2183 if (freq_included(auth->freq, auth->num_freq, freq))
2184 continue;
2185 if (dpp_channel_ok_init(own_modes, num_modes, freq))
2186 auth->freq[auth->num_freq++] = freq;
2187 }
2188 if (!auth->num_freq) {
2189 wpa_printf(MSG_INFO,
2190 "DPP: No available channels for initiating DPP Authentication");
2191 return -1;
2192 }
2193 auth->curr_freq = auth->freq[0];
2194 return 0;
2195}
2196
2197
2198static int dpp_channel_local_list(struct dpp_authentication *auth,
2199 struct hostapd_hw_modes *own_modes,
2200 u16 num_modes)
2201{
2202 u16 m;
2203 int c, flag;
2204 unsigned int freq;
2205
2206 auth->num_freq = 0;
2207
2208 if (!own_modes || !num_modes) {
2209 auth->freq[0] = 2412;
2210 auth->freq[1] = 2437;
2211 auth->freq[2] = 2462;
2212 auth->num_freq = 3;
2213 return 0;
2214 }
2215
2216 for (m = 0; m < num_modes; m++) {
2217 for (c = 0; c < own_modes[m].num_channels; c++) {
2218 freq = own_modes[m].channels[c].freq;
2219 flag = own_modes[m].channels[c].flag;
2220 if (flag & (HOSTAPD_CHAN_DISABLED |
2221 HOSTAPD_CHAN_NO_IR |
2222 HOSTAPD_CHAN_RADAR))
2223 continue;
2224 if (freq_included(auth->freq, auth->num_freq, freq))
2225 continue;
2226 auth->freq[auth->num_freq++] = freq;
2227 if (auth->num_freq == DPP_BOOTSTRAP_MAX_FREQ) {
2228 m = num_modes;
2229 break;
2230 }
2231 }
2232 }
2233
2234 return auth->num_freq == 0 ? -1 : 0;
2235}
2236
2237
2238static int dpp_prepare_channel_list(struct dpp_authentication *auth,
2239 struct hostapd_hw_modes *own_modes,
2240 u16 num_modes)
2241{
2242 int res;
2243 char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end;
2244 unsigned int i;
2245
2246 if (auth->peer_bi->num_freq > 0)
2247 res = dpp_channel_intersect(auth, own_modes, num_modes);
2248 else
2249 res = dpp_channel_local_list(auth, own_modes, num_modes);
2250 if (res < 0)
2251 return res;
2252
2253 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2254 * likely channels first. */
2255 freq_to_start(auth->freq, auth->num_freq, 2462);
2256 freq_to_start(auth->freq, auth->num_freq, 2412);
2257 freq_to_start(auth->freq, auth->num_freq, 2437);
2258
2259 auth->freq_idx = 0;
2260 auth->curr_freq = auth->freq[0];
2261
2262 pos = freqs;
2263 end = pos + sizeof(freqs);
2264 for (i = 0; i < auth->num_freq; i++) {
2265 res = os_snprintf(pos, end - pos, " %u", auth->freq[i]);
2266 if (os_snprintf_error(end - pos, res))
2267 break;
2268 pos += res;
2269 }
2270 *pos = '\0';
2271 wpa_printf(MSG_DEBUG, "DPP: Possible frequencies for initiating:%s",
2272 freqs);
2273
2274 return 0;
2275}
2276
2277
2bbe6ad3
JM
2278static int dpp_gen_uri(struct dpp_bootstrap_info *bi)
2279{
2280 char macstr[ETH_ALEN * 2 + 10];
2281 size_t len;
2282
2283 len = 4; /* "DPP:" */
2284 if (bi->chan)
2285 len += 3 + os_strlen(bi->chan); /* C:...; */
2286 if (is_zero_ether_addr(bi->mac_addr))
2287 macstr[0] = '\0';
2288 else
2289 os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";",
2290 MAC2STR(bi->mac_addr));
2291 len += os_strlen(macstr); /* M:...; */
2292 if (bi->info)
2293 len += 3 + os_strlen(bi->info); /* I:...; */
2294 len += 4 + os_strlen(bi->pk); /* K:...;; */
2295
2296 os_free(bi->uri);
2297 bi->uri = os_malloc(len + 1);
2298 if (!bi->uri)
2299 return -1;
2300 os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2301 bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
2302 bi->chan ? ";" : "",
2303 macstr,
2304 bi->info ? "I:" : "", bi->info ? bi->info : "",
2305 bi->info ? ";" : "",
2306 bi->pk);
2307 return 0;
2308}
2309
2310
73f21929
JM
2311static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth)
2312{
2313 struct dpp_bootstrap_info *bi;
73f21929
JM
2314
2315 if (auth->own_bi)
2316 return 0; /* already generated */
2317
2318 bi = os_zalloc(sizeof(*bi));
2319 if (!bi)
2320 return -1;
2321 bi->type = DPP_BOOTSTRAP_QR_CODE;
2bbe6ad3
JM
2322 if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 ||
2323 dpp_gen_uri(bi) < 0)
73f21929 2324 goto fail;
73f21929
JM
2325 wpa_printf(MSG_DEBUG,
2326 "DPP: Auto-generated own bootstrapping key info: URI %s",
2327 bi->uri);
2328
2329 auth->tmp_own_bi = auth->own_bi = bi;
2330
73f21929
JM
2331 return 0;
2332fail:
73f21929
JM
2333 dpp_bootstrap_info_free(bi);
2334 return -1;
2335}
2336
2337
1ba4a10a
JM
2338static struct dpp_authentication * dpp_alloc_auth(void *msg_ctx)
2339{
2340 struct dpp_authentication *auth;
2341
2342 auth = os_zalloc(sizeof(*auth));
2343 if (!auth)
2344 return NULL;
2345 auth->msg_ctx = msg_ctx;
2346 auth->conf_resp_status = 255;
2347 return auth;
2348}
2349
2350
606a8e8d
JM
2351struct dpp_authentication * dpp_auth_init(void *msg_ctx,
2352 struct dpp_bootstrap_info *peer_bi,
2353 struct dpp_bootstrap_info *own_bi,
d1f08264 2354 u8 dpp_allowed_roles,
f97ace34
JM
2355 unsigned int neg_freq,
2356 struct hostapd_hw_modes *own_modes,
2357 u16 num_modes)
606a8e8d
JM
2358{
2359 struct dpp_authentication *auth;
2360 size_t nonce_len;
606a8e8d
JM
2361 size_t secret_len;
2362 struct wpabuf *pi = NULL;
606a8e8d 2363 const u8 *r_pubkey_hash, *i_pubkey_hash;
65ecce87
JM
2364#ifdef CONFIG_TESTING_OPTIONS
2365 u8 test_hash[SHA256_MAC_LEN];
2366#endif /* CONFIG_TESTING_OPTIONS */
606a8e8d 2367
1ba4a10a 2368 auth = dpp_alloc_auth(msg_ctx);
606a8e8d
JM
2369 if (!auth)
2370 return NULL;
606a8e8d 2371 auth->initiator = 1;
f97ace34 2372 auth->waiting_auth_resp = 1;
d1f08264
JM
2373 auth->allowed_roles = dpp_allowed_roles;
2374 auth->configurator = !!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR);
606a8e8d
JM
2375 auth->peer_bi = peer_bi;
2376 auth->own_bi = own_bi;
2377 auth->curve = peer_bi->curve;
2378
73f21929
JM
2379 if (dpp_autogen_bootstrap_key(auth) < 0 ||
2380 dpp_prepare_channel_list(auth, own_modes, num_modes) < 0)
f97ace34
JM
2381 goto fail;
2382
055cd397
JM
2383#ifdef CONFIG_TESTING_OPTIONS
2384 if (dpp_nonce_override_len > 0) {
2385 wpa_printf(MSG_INFO, "DPP: TESTING - override I-nonce");
2386 nonce_len = dpp_nonce_override_len;
2387 os_memcpy(auth->i_nonce, dpp_nonce_override, nonce_len);
2388 } else {
2389 nonce_len = auth->curve->nonce_len;
2390 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2391 wpa_printf(MSG_ERROR,
2392 "DPP: Failed to generate I-nonce");
2393 goto fail;
2394 }
2395 }
2396#else /* CONFIG_TESTING_OPTIONS */
606a8e8d
JM
2397 nonce_len = auth->curve->nonce_len;
2398 if (random_get_bytes(auth->i_nonce, nonce_len)) {
2399 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce");
2400 goto fail;
2401 }
055cd397 2402#endif /* CONFIG_TESTING_OPTIONS */
606a8e8d
JM
2403 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len);
2404
f5526975
JM
2405#ifdef CONFIG_TESTING_OPTIONS
2406 if (dpp_protocol_key_override_len) {
2407 const struct dpp_curve_params *tmp_curve;
2408
2409 wpa_printf(MSG_INFO,
2410 "DPP: TESTING - override protocol key");
2411 auth->own_protocol_key = dpp_set_keypair(
2412 &tmp_curve, dpp_protocol_key_override,
2413 dpp_protocol_key_override_len);
2414 } else {
2415 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
2416 }
2417#else /* CONFIG_TESTING_OPTIONS */
606a8e8d 2418 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
f5526975 2419#endif /* CONFIG_TESTING_OPTIONS */
606a8e8d
JM
2420 if (!auth->own_protocol_key)
2421 goto fail;
2422
2423 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2424 if (!pi)
2425 goto fail;
2426
2427 /* ECDH: M = pI * BR */
29ef1c5e
JM
2428 if (dpp_ecdh(auth->own_protocol_key, auth->peer_bi->pubkey,
2429 auth->Mx, &secret_len) < 0)
606a8e8d 2430 goto fail;
606a8e8d 2431 auth->secret_len = secret_len;
606a8e8d
JM
2432
2433 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
2434 auth->Mx, auth->secret_len);
630ea133 2435 auth->Mx_len = auth->secret_len;
606a8e8d
JM
2436
2437 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
2438 auth->curve->hash_len) < 0)
2439 goto fail;
2440
2441 r_pubkey_hash = auth->peer_bi->pubkey_hash;
73f21929 2442 i_pubkey_hash = auth->own_bi->pubkey_hash;
606a8e8d 2443
0e7cb8c6
JM
2444#ifdef CONFIG_TESTING_OPTIONS
2445 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2446 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
2447 r_pubkey_hash = NULL;
65ecce87
JM
2448 } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2449 wpa_printf(MSG_INFO,
2450 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2451 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
2452 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2453 r_pubkey_hash = test_hash;
0e7cb8c6
JM
2454 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2455 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
2456 i_pubkey_hash = NULL;
65ecce87
JM
2457 } else if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ) {
2458 wpa_printf(MSG_INFO,
2459 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2460 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
2461 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
2462 i_pubkey_hash = test_hash;
0e7cb8c6
JM
2463 } else if (dpp_test == DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ) {
2464 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Proto Key");
2465 wpabuf_free(pi);
2466 pi = NULL;
b6b4226b
JM
2467 } else if (dpp_test == DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ) {
2468 wpa_printf(MSG_INFO, "DPP: TESTING - invalid I-Proto Key");
2469 wpabuf_free(pi);
2470 pi = wpabuf_alloc(2 * auth->curve->prime_len);
2471 if (!pi || dpp_test_gen_invalid_key(pi, auth->curve) < 0)
2472 goto fail;
0e7cb8c6
JM
2473 }
2474#endif /* CONFIG_TESTING_OPTIONS */
2475
606a8e8d 2476 auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash,
d2709206 2477 i_pubkey_hash, neg_freq);
606a8e8d
JM
2478 if (!auth->req_msg)
2479 goto fail;
2480
2481out:
30d27b04 2482 wpabuf_free(pi);
606a8e8d
JM
2483 return auth;
2484fail:
30d27b04 2485 dpp_auth_deinit(auth);
606a8e8d
JM
2486 auth = NULL;
2487 goto out;
30d27b04
JM
2488}
2489
2490
bd23daa8
JM
2491static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth,
2492 const char *json)
461d39af
JM
2493{
2494 size_t nonce_len;
2495 size_t json_len, clear_len;
2496 struct wpabuf *clear = NULL, *msg = NULL;
2497 u8 *wrapped;
60239f60 2498 size_t attr_len;
461d39af
JM
2499
2500 wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
2501
2502 nonce_len = auth->curve->nonce_len;
2503 if (random_get_bytes(auth->e_nonce, nonce_len)) {
2504 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce");
2505 goto fail;
2506 }
2507 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len);
2508 json_len = os_strlen(json);
5a5639b0 2509 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configRequest JSON", json, json_len);
461d39af
JM
2510
2511 /* { E-nonce, configAttrib }ke */
2512 clear_len = 4 + nonce_len + 4 + json_len;
2513 clear = wpabuf_alloc(clear_len);
60239f60
JM
2514 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
2515#ifdef CONFIG_TESTING_OPTIONS
2516 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ)
acdf703d 2517 attr_len += 5;
60239f60
JM
2518#endif /* CONFIG_TESTING_OPTIONS */
2519 msg = wpabuf_alloc(attr_len);
461d39af
JM
2520 if (!clear || !msg)
2521 goto fail;
2522
f411ad1b
JM
2523#ifdef CONFIG_TESTING_OPTIONS
2524 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_REQ) {
2525 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
2526 goto skip_e_nonce;
2527 }
f0a383a9
JM
2528 if (dpp_test == DPP_TEST_INVALID_E_NONCE_CONF_REQ) {
2529 wpa_printf(MSG_INFO, "DPP: TESTING - invalid E-nonce");
2530 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2531 wpabuf_put_le16(clear, nonce_len - 1);
2532 wpabuf_put_data(clear, auth->e_nonce, nonce_len - 1);
2533 goto skip_e_nonce;
2534 }
f411ad1b
JM
2535 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_REQ) {
2536 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
2537 goto skip_wrapped_data;
2538 }
2539#endif /* CONFIG_TESTING_OPTIONS */
2540
461d39af
JM
2541 /* E-nonce */
2542 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
2543 wpabuf_put_le16(clear, nonce_len);
2544 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
2545
f411ad1b
JM
2546#ifdef CONFIG_TESTING_OPTIONS
2547skip_e_nonce:
2548 if (dpp_test == DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ) {
2549 wpa_printf(MSG_INFO, "DPP: TESTING - no configAttrib");
2550 goto skip_conf_attr_obj;
2551 }
2552#endif /* CONFIG_TESTING_OPTIONS */
2553
461d39af
JM
2554 /* configAttrib */
2555 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
2556 wpabuf_put_le16(clear, json_len);
2557 wpabuf_put_data(clear, json, json_len);
2558
f411ad1b
JM
2559#ifdef CONFIG_TESTING_OPTIONS
2560skip_conf_attr_obj:
2561#endif /* CONFIG_TESTING_OPTIONS */
2562
461d39af
JM
2563 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
2564 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2565 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
2566
2567 /* No AES-SIV AD */
2568 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
2569 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
2570 wpabuf_head(clear), wpabuf_len(clear),
2571 0, NULL, NULL, wrapped) < 0)
2572 goto fail;
2573 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
2574 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
2575
60239f60
JM
2576#ifdef CONFIG_TESTING_OPTIONS
2577 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) {
2578 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 2579 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 2580 }
f411ad1b 2581skip_wrapped_data:
60239f60
JM
2582#endif /* CONFIG_TESTING_OPTIONS */
2583
461d39af
JM
2584 wpa_hexdump_buf(MSG_DEBUG,
2585 "DPP: Configuration Request frame attributes", msg);
2586 wpabuf_free(clear);
2587 return msg;
2588
2589fail:
2590 wpabuf_free(clear);
2591 wpabuf_free(msg);
2592 return NULL;
2593}
2594
2595
bd23daa8
JM
2596static void dpp_write_adv_proto(struct wpabuf *buf)
2597{
2598 /* Advertisement Protocol IE */
2599 wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2600 wpabuf_put_u8(buf, 8); /* Length */
2601 wpabuf_put_u8(buf, 0x7f);
2602 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
2603 wpabuf_put_u8(buf, 5);
2604 wpabuf_put_be24(buf, OUI_WFA);
2605 wpabuf_put_u8(buf, DPP_OUI_TYPE);
2606 wpabuf_put_u8(buf, 0x01);
2607}
2608
2609
2610static void dpp_write_gas_query(struct wpabuf *buf, struct wpabuf *query)
2611{
2612 /* GAS Query */
2613 wpabuf_put_le16(buf, wpabuf_len(query));
2614 wpabuf_put_buf(buf, query);
2615}
2616
2617
2618struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
2619 const char *json)
2620{
2621 struct wpabuf *buf, *conf_req;
2622
2623 conf_req = dpp_build_conf_req_attr(auth, json);
2624 if (!conf_req) {
2625 wpa_printf(MSG_DEBUG,
2626 "DPP: No configuration request data available");
2627 return NULL;
2628 }
2629
2630 buf = gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req));
2631 if (!buf) {
2632 wpabuf_free(conf_req);
2633 return NULL;
2634 }
2635
2636 dpp_write_adv_proto(buf);
2637 dpp_write_gas_query(buf, conf_req);
2638 wpabuf_free(conf_req);
2639 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: GAS Config Request", buf);
2640
2641 return buf;
2642}
2643
2644
5a5639b0 2645struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
74045744
JM
2646 const char *name,
2647 enum dpp_netrole netrole,
8f8c423a 2648 const char *mud_url, int *opclasses)
5a5639b0 2649{
590bc64d 2650 size_t len, name_len;
5a5639b0
JM
2651 const char *tech = "infra";
2652 const char *dpp_name;
5a5639b0
JM
2653 struct wpabuf *buf, *json;
2654
2655#ifdef CONFIG_TESTING_OPTIONS
2656 if (dpp_test == DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ) {
2657 static const char *bogus_tech = "knfra";
2658
2659 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Config Attr");
2660 tech = bogus_tech;
2661 }
2662#endif /* CONFIG_TESTING_OPTIONS */
2663
2664 dpp_name = name ? name : "Test";
590bc64d 2665 name_len = os_strlen(dpp_name);
5a5639b0 2666
590bc64d 2667 len = 100 + name_len * 6 + 1 + int_array_len(opclasses) * 4;
5a5639b0
JM
2668 if (mud_url && mud_url[0])
2669 len += 10 + os_strlen(mud_url);
2670 json = wpabuf_alloc(len);
590bc64d 2671 if (!json)
5a5639b0 2672 return NULL;
5a5639b0 2673
590bc64d
JM
2674 json_start_object(json, NULL);
2675 if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
2676 wpabuf_free(json);
2677 return NULL;
2678 }
2679 json_value_sep(json);
2680 json_add_string(json, "wi-fi_tech", tech);
2681 json_value_sep(json);
74045744 2682 json_add_string(json, "netRole", dpp_netrole_str(netrole));
590bc64d
JM
2683 if (mud_url && mud_url[0]) {
2684 json_value_sep(json);
2685 json_add_string(json, "mudurl", mud_url);
2686 }
8f8c423a
JM
2687 if (opclasses) {
2688 int i;
2689
590bc64d
JM
2690 json_value_sep(json);
2691 json_start_array(json, "bandSupport");
8f8c423a
JM
2692 for (i = 0; opclasses[i]; i++)
2693 wpabuf_printf(json, "%s%u", i ? "," : "", opclasses[i]);
590bc64d 2694 json_end_array(json);
8f8c423a 2695 }
590bc64d 2696 json_end_object(json);
5a5639b0
JM
2697
2698 buf = dpp_build_conf_req(auth, wpabuf_head(json));
2699 wpabuf_free(json);
2700
2701 return buf;
2702}
2703
2704
30d27b04
JM
2705static void dpp_auth_success(struct dpp_authentication *auth)
2706{
2707 wpa_printf(MSG_DEBUG,
2708 "DPP: Authentication success - clear temporary keys");
2709 os_memset(auth->Mx, 0, sizeof(auth->Mx));
630ea133 2710 auth->Mx_len = 0;
30d27b04 2711 os_memset(auth->Nx, 0, sizeof(auth->Nx));
630ea133 2712 auth->Nx_len = 0;
30d27b04 2713 os_memset(auth->Lx, 0, sizeof(auth->Lx));
630ea133 2714 auth->Lx_len = 0;
30d27b04
JM
2715 os_memset(auth->k1, 0, sizeof(auth->k1));
2716 os_memset(auth->k2, 0, sizeof(auth->k2));
2717
2718 auth->auth_success = 1;
2719}
2720
2721
2722static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
2723{
2724 struct wpabuf *pix, *prx, *bix, *brx;
2725 const u8 *addr[7];
2726 size_t len[7];
2727 size_t i, num_elem = 0;
2728 size_t nonce_len;
2729 u8 zero = 0;
2730 int res = -1;
2731
2732 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2733 nonce_len = auth->curve->nonce_len;
2734
2735 if (auth->initiator) {
2736 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2737 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2738 if (auth->own_bi)
2739 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2740 else
2741 bix = NULL;
2742 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2743 } else {
2744 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2745 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2746 if (auth->peer_bi)
2747 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2748 else
2749 bix = NULL;
2750 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2751 }
2752 if (!pix || !prx || !brx)
2753 goto fail;
2754
2755 addr[num_elem] = auth->i_nonce;
2756 len[num_elem] = nonce_len;
2757 num_elem++;
2758
2759 addr[num_elem] = auth->r_nonce;
2760 len[num_elem] = nonce_len;
2761 num_elem++;
2762
2763 addr[num_elem] = wpabuf_head(pix);
2764 len[num_elem] = wpabuf_len(pix) / 2;
2765 num_elem++;
2766
2767 addr[num_elem] = wpabuf_head(prx);
2768 len[num_elem] = wpabuf_len(prx) / 2;
2769 num_elem++;
2770
2771 if (bix) {
2772 addr[num_elem] = wpabuf_head(bix);
2773 len[num_elem] = wpabuf_len(bix) / 2;
2774 num_elem++;
2775 }
2776
2777 addr[num_elem] = wpabuf_head(brx);
2778 len[num_elem] = wpabuf_len(brx) / 2;
2779 num_elem++;
2780
2781 addr[num_elem] = &zero;
2782 len[num_elem] = 1;
2783 num_elem++;
2784
2785 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components");
2786 for (i = 0; i < num_elem; i++)
2787 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
b9d47b48 2788 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth);
30d27b04
JM
2789 if (res == 0)
2790 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth,
2791 auth->curve->hash_len);
2792fail:
2793 wpabuf_free(pix);
2794 wpabuf_free(prx);
2795 wpabuf_free(bix);
2796 wpabuf_free(brx);
2797 return res;
2798}
2799
2800
2801static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
2802{
2803 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL;
2804 const u8 *addr[7];
2805 size_t len[7];
2806 size_t i, num_elem = 0;
2807 size_t nonce_len;
2808 u8 one = 1;
2809 int res = -1;
2810
2811 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2812 nonce_len = auth->curve->nonce_len;
2813
2814 if (auth->initiator) {
2815 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2816 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2817 if (auth->own_bi)
2818 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2819 else
2820 bix = NULL;
2821 if (!auth->peer_bi)
2822 goto fail;
2823 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2824 } else {
2825 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
2826 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
2827 if (auth->peer_bi)
2828 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
2829 else
2830 bix = NULL;
2831 if (!auth->own_bi)
2832 goto fail;
2833 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
2834 }
2835 if (!pix || !prx || !brx)
2836 goto fail;
2837
2838 addr[num_elem] = auth->r_nonce;
2839 len[num_elem] = nonce_len;
2840 num_elem++;
2841
2842 addr[num_elem] = auth->i_nonce;
2843 len[num_elem] = nonce_len;
2844 num_elem++;
2845
2846 addr[num_elem] = wpabuf_head(prx);
2847 len[num_elem] = wpabuf_len(prx) / 2;
2848 num_elem++;
2849
2850 addr[num_elem] = wpabuf_head(pix);
2851 len[num_elem] = wpabuf_len(pix) / 2;
2852 num_elem++;
2853
2854 addr[num_elem] = wpabuf_head(brx);
2855 len[num_elem] = wpabuf_len(brx) / 2;
2856 num_elem++;
2857
2858 if (bix) {
2859 addr[num_elem] = wpabuf_head(bix);
2860 len[num_elem] = wpabuf_len(bix) / 2;
2861 num_elem++;
2862 }
2863
2864 addr[num_elem] = &one;
2865 len[num_elem] = 1;
2866 num_elem++;
2867
2868 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components");
2869 for (i = 0; i < num_elem; i++)
2870 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]);
b9d47b48 2871 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth);
30d27b04
JM
2872 if (res == 0)
2873 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth,
2874 auth->curve->hash_len);
2875fail:
2876 wpabuf_free(pix);
2877 wpabuf_free(prx);
2878 wpabuf_free(bix);
2879 wpabuf_free(brx);
2880 return res;
2881}
2882
2883
2884static int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
2885{
2886 const EC_GROUP *group;
2887 EC_POINT *l = NULL;
2888 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL;
2889 const EC_POINT *BI_point;
2890 BN_CTX *bnctx;
2891 BIGNUM *lx, *sum, *q;
2892 const BIGNUM *bR_bn, *pR_bn;
2893 int ret = -1;
30d27b04
JM
2894
2895 /* L = ((bR + pR) modulo q) * BI */
2896
2897 bnctx = BN_CTX_new();
2898 sum = BN_new();
2899 q = BN_new();
2900 lx = BN_new();
2901 if (!bnctx || !sum || !q || !lx)
2902 goto fail;
2903 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2904 if (!BI)
2905 goto fail;
2906 BI_point = EC_KEY_get0_public_key(BI);
2907 group = EC_KEY_get0_group(BI);
2908 if (!group)
2909 goto fail;
2910
2911 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2912 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
2913 if (!bR || !pR)
2914 goto fail;
2915 bR_bn = EC_KEY_get0_private_key(bR);
2916 pR_bn = EC_KEY_get0_private_key(pR);
2917 if (!bR_bn || !pR_bn)
2918 goto fail;
2919 if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
2920 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
2921 goto fail;
2922 l = EC_POINT_new(group);
2923 if (!l ||
2924 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
2925 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2926 bnctx) != 1) {
2927 wpa_printf(MSG_ERROR,
2928 "OpenSSL: failed: %s",
2929 ERR_error_string(ERR_get_error(), NULL));
2930 goto fail;
2931 }
2932
fc0efa2a 2933 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
30d27b04 2934 goto fail;
30d27b04 2935 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
630ea133 2936 auth->Lx_len = auth->secret_len;
30d27b04
JM
2937 ret = 0;
2938fail:
2939 EC_POINT_clear_free(l);
2940 EC_KEY_free(BI);
2941 EC_KEY_free(bR);
2942 EC_KEY_free(pR);
2943 BN_clear_free(lx);
2944 BN_clear_free(sum);
2945 BN_free(q);
2946 BN_CTX_free(bnctx);
2947 return ret;
2948}
2949
2950
2951static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
2952{
2953 const EC_GROUP *group;
2954 EC_POINT *l = NULL, *sum = NULL;
2955 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL;
2956 const EC_POINT *BR_point, *PR_point;
2957 BN_CTX *bnctx;
2958 BIGNUM *lx;
2959 const BIGNUM *bI_bn;
2960 int ret = -1;
30d27b04
JM
2961
2962 /* L = bI * (BR + PR) */
2963
2964 bnctx = BN_CTX_new();
2965 lx = BN_new();
2966 if (!bnctx || !lx)
2967 goto fail;
2968 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey);
2969 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key);
2970 if (!BR || !PR)
2971 goto fail;
2972 BR_point = EC_KEY_get0_public_key(BR);
2973 PR_point = EC_KEY_get0_public_key(PR);
2974
2975 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey);
2976 if (!bI)
2977 goto fail;
2978 group = EC_KEY_get0_group(bI);
2979 bI_bn = EC_KEY_get0_private_key(bI);
2980 if (!group || !bI_bn)
2981 goto fail;
2982 sum = EC_POINT_new(group);
2983 l = EC_POINT_new(group);
2984 if (!sum || !l ||
2985 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
2986 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
2987 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
2988 bnctx) != 1) {
2989 wpa_printf(MSG_ERROR,
2990 "OpenSSL: failed: %s",
2991 ERR_error_string(ERR_get_error(), NULL));
2992 goto fail;
2993 }
2994
fc0efa2a 2995 if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
30d27b04 2996 goto fail;
30d27b04 2997 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
630ea133 2998 auth->Lx_len = auth->secret_len;
30d27b04
JM
2999 ret = 0;
3000fail:
3001 EC_POINT_clear_free(l);
5a052f92 3002 EC_POINT_clear_free(sum);
30d27b04
JM
3003 EC_KEY_free(bI);
3004 EC_KEY_free(BR);
3005 EC_KEY_free(PR);
3006 BN_clear_free(lx);
3007 BN_CTX_free(bnctx);
3008 return ret;
3009}
3010
3011
a03406db 3012static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
30d27b04
JM
3013{
3014 size_t nonce_len;
30d27b04
JM
3015 size_t secret_len;
3016 struct wpabuf *msg, *pr = NULL;
3017 u8 r_auth[4 + DPP_MAX_HASH_LEN];
ce9acce0 3018 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE], *w_r_auth;
30d27b04 3019 size_t wrapped_r_auth_len;
a03406db 3020 int ret = -1;
ce9acce0
JM
3021 const u8 *r_pubkey_hash, *i_pubkey_hash, *r_nonce, *i_nonce;
3022 enum dpp_status_error status = DPP_STATUS_OK;
65ecce87
JM
3023#ifdef CONFIG_TESTING_OPTIONS
3024 u8 test_hash[SHA256_MAC_LEN];
3025#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3026
3027 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
762fb4f0
JM
3028 if (!auth->own_bi)
3029 return -1;
30d27b04 3030
055cd397
JM
3031#ifdef CONFIG_TESTING_OPTIONS
3032 if (dpp_nonce_override_len > 0) {
3033 wpa_printf(MSG_INFO, "DPP: TESTING - override R-nonce");
3034 nonce_len = dpp_nonce_override_len;
3035 os_memcpy(auth->r_nonce, dpp_nonce_override, nonce_len);
3036 } else {
3037 nonce_len = auth->curve->nonce_len;
3038 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3039 wpa_printf(MSG_ERROR,
3040 "DPP: Failed to generate R-nonce");
3041 goto fail;
3042 }
3043 }
3044#else /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3045 nonce_len = auth->curve->nonce_len;
3046 if (random_get_bytes(auth->r_nonce, nonce_len)) {
3047 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce");
3048 goto fail;
3049 }
055cd397 3050#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3051 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
3052
6602d9e3 3053 EVP_PKEY_free(auth->own_protocol_key);
f5526975
JM
3054#ifdef CONFIG_TESTING_OPTIONS
3055 if (dpp_protocol_key_override_len) {
3056 const struct dpp_curve_params *tmp_curve;
3057
3058 wpa_printf(MSG_INFO,
3059 "DPP: TESTING - override protocol key");
3060 auth->own_protocol_key = dpp_set_keypair(
3061 &tmp_curve, dpp_protocol_key_override,
3062 dpp_protocol_key_override_len);
3063 } else {
3064 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
3065 }
3066#else /* CONFIG_TESTING_OPTIONS */
30d27b04 3067 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
f5526975 3068#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3069 if (!auth->own_protocol_key)
3070 goto fail;
3071
3072 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
3073 if (!pr)
3074 goto fail;
3075
3076 /* ECDH: N = pR * PI */
29ef1c5e
JM
3077 if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
3078 auth->Nx, &secret_len) < 0)
30d27b04 3079 goto fail;
30d27b04
JM
3080
3081 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3082 auth->Nx, auth->secret_len);
630ea133 3083 auth->Nx_len = auth->secret_len;
30d27b04
JM
3084
3085 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3086 auth->curve->hash_len) < 0)
3087 goto fail;
3088
3089 if (auth->own_bi && auth->peer_bi) {
3090 /* Mutual authentication */
3091 if (dpp_auth_derive_l_responder(auth) < 0)
3092 goto fail;
3093 }
3094
3095 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
3096 goto fail;
3097
3098 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3099 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG);
3100 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len);
978bc3f2
JM
3101 if (dpp_gen_r_auth(auth, r_auth + 4) < 0)
3102 goto fail;
3103#ifdef CONFIG_TESTING_OPTIONS
3104 if (dpp_test == DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP) {
3105 wpa_printf(MSG_INFO, "DPP: TESTING - R-auth mismatch");
3106 r_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3107 }
3108#endif /* CONFIG_TESTING_OPTIONS */
3109 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
30d27b04
JM
3110 r_auth, 4 + auth->curve->hash_len,
3111 0, NULL, NULL, wrapped_r_auth) < 0)
3112 goto fail;
3113 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE;
3114 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke",
3115 wrapped_r_auth, wrapped_r_auth_len);
ce9acce0 3116 w_r_auth = wrapped_r_auth;
30d27b04 3117
a03406db
JM
3118 r_pubkey_hash = auth->own_bi->pubkey_hash;
3119 if (auth->peer_bi)
3120 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3121 else
3122 i_pubkey_hash = NULL;
3123
ce9acce0
JM
3124 i_nonce = auth->i_nonce;
3125 r_nonce = auth->r_nonce;
3126
3127#ifdef CONFIG_TESTING_OPTIONS
3128 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3129 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3130 r_pubkey_hash = NULL;
65ecce87
JM
3131 } else if (dpp_test ==
3132 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3133 wpa_printf(MSG_INFO,
3134 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3135 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3136 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3137 r_pubkey_hash = test_hash;
ce9acce0
JM
3138 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3139 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3140 i_pubkey_hash = NULL;
65ecce87
JM
3141 } else if (dpp_test ==
3142 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3143 wpa_printf(MSG_INFO,
3144 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3145 if (i_pubkey_hash)
3146 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3147 else
3148 os_memset(test_hash, 0, SHA256_MAC_LEN);
3149 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3150 i_pubkey_hash = test_hash;
ce9acce0
JM
3151 } else if (dpp_test == DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP) {
3152 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Proto Key");
3153 wpabuf_free(pr);
3154 pr = NULL;
b6b4226b
JM
3155 } else if (dpp_test == DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP) {
3156 wpa_printf(MSG_INFO, "DPP: TESTING - invalid R-Proto Key");
3157 wpabuf_free(pr);
3158 pr = wpabuf_alloc(2 * auth->curve->prime_len);
3159 if (!pr || dpp_test_gen_invalid_key(pr, auth->curve) < 0)
3160 goto fail;
ce9acce0
JM
3161 } else if (dpp_test == DPP_TEST_NO_R_AUTH_AUTH_RESP) {
3162 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth");
3163 w_r_auth = NULL;
3164 wrapped_r_auth_len = 0;
3165 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3166 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
3167 status = 255;
3f35ec2d
JM
3168 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_RESP) {
3169 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3170 status = 254;
ce9acce0
JM
3171 } else if (dpp_test == DPP_TEST_NO_R_NONCE_AUTH_RESP) {
3172 wpa_printf(MSG_INFO, "DPP: TESTING - no R-nonce");
3173 r_nonce = NULL;
3174 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3175 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3176 i_nonce = NULL;
3177 }
3178#endif /* CONFIG_TESTING_OPTIONS */
3179
3180 msg = dpp_auth_build_resp(auth, status, pr, nonce_len,
a03406db 3181 r_pubkey_hash, i_pubkey_hash,
ce9acce0
JM
3182 r_nonce, i_nonce,
3183 w_r_auth, wrapped_r_auth_len,
a03406db 3184 auth->k2);
30d27b04
JM
3185 if (!msg)
3186 goto fail;
95b0104a 3187 wpabuf_free(auth->resp_msg);
dc4d271c 3188 auth->resp_msg = msg;
a03406db 3189 ret = 0;
30d27b04
JM
3190fail:
3191 wpabuf_free(pr);
a03406db 3192 return ret;
30d27b04
JM
3193}
3194
3195
3196static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
3197 enum dpp_status_error status)
3198{
30d27b04 3199 struct wpabuf *msg;
ce9acce0 3200 const u8 *r_pubkey_hash, *i_pubkey_hash, *i_nonce;
65ecce87
JM
3201#ifdef CONFIG_TESTING_OPTIONS
3202 u8 test_hash[SHA256_MAC_LEN];
3203#endif /* CONFIG_TESTING_OPTIONS */
30d27b04 3204
762fb4f0
JM
3205 if (!auth->own_bi)
3206 return -1;
30d27b04
JM
3207 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response");
3208
a03406db
JM
3209 r_pubkey_hash = auth->own_bi->pubkey_hash;
3210 if (auth->peer_bi)
3211 i_pubkey_hash = auth->peer_bi->pubkey_hash;
3212 else
3213 i_pubkey_hash = NULL;
3214
ce9acce0
JM
3215 i_nonce = auth->i_nonce;
3216
3217#ifdef CONFIG_TESTING_OPTIONS
3218 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3219 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3220 r_pubkey_hash = NULL;
65ecce87
JM
3221 } else if (dpp_test ==
3222 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3223 wpa_printf(MSG_INFO,
3224 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3225 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3226 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3227 r_pubkey_hash = test_hash;
ce9acce0
JM
3228 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3229 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3230 i_pubkey_hash = NULL;
65ecce87
JM
3231 } else if (dpp_test ==
3232 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP) {
3233 wpa_printf(MSG_INFO,
3234 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3235 if (i_pubkey_hash)
3236 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3237 else
3238 os_memset(test_hash, 0, SHA256_MAC_LEN);
3239 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3240 i_pubkey_hash = test_hash;
ce9acce0
JM
3241 } else if (dpp_test == DPP_TEST_NO_STATUS_AUTH_RESP) {
3242 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
89b6d8a2 3243 status = 255;
ce9acce0
JM
3244 } else if (dpp_test == DPP_TEST_NO_I_NONCE_AUTH_RESP) {
3245 wpa_printf(MSG_INFO, "DPP: TESTING - no I-nonce");
3246 i_nonce = NULL;
3247 }
3248#endif /* CONFIG_TESTING_OPTIONS */
3249
a03406db
JM
3250 msg = dpp_auth_build_resp(auth, status, NULL, auth->curve->nonce_len,
3251 r_pubkey_hash, i_pubkey_hash,
ce9acce0 3252 NULL, i_nonce, NULL, 0, auth->k1);
30d27b04 3253 if (!msg)
a03406db 3254 return -1;
95b0104a 3255 wpabuf_free(auth->resp_msg);
dc4d271c 3256 auth->resp_msg = msg;
30d27b04 3257 return 0;
30d27b04
JM
3258}
3259
3260
3261struct dpp_authentication *
3262dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
3263 struct dpp_bootstrap_info *peer_bi,
3264 struct dpp_bootstrap_info *own_bi,
dc4d271c 3265 unsigned int freq, const u8 *hdr, const u8 *attr_start,
27fefbbb 3266 size_t attr_len)
30d27b04
JM
3267{
3268 EVP_PKEY *pi = NULL;
3269 EVP_PKEY_CTX *ctx = NULL;
3270 size_t secret_len;
dc4d271c
JM
3271 const u8 *addr[2];
3272 size_t len[2];
30d27b04
JM
3273 u8 *unwrapped = NULL;
3274 size_t unwrapped_len = 0;
d2709206
JM
3275 const u8 *wrapped_data, *i_proto, *i_nonce, *i_capab, *i_bootstrap,
3276 *channel;
27fefbbb 3277 u16 wrapped_data_len, i_proto_len, i_nonce_len, i_capab_len,
d2709206 3278 i_bootstrap_len, channel_len;
30d27b04 3279 struct dpp_authentication *auth = NULL;
0b4a906d
JM
3280#ifdef CONFIG_DPP2
3281 const u8 *version;
3282 u16 version_len;
3283#endif /* CONFIG_DPP2 */
30d27b04 3284
34603767
JM
3285#ifdef CONFIG_TESTING_OPTIONS
3286 if (dpp_test == DPP_TEST_STOP_AT_AUTH_REQ) {
3287 wpa_printf(MSG_INFO,
3288 "DPP: TESTING - stop at Authentication Request");
3289 return NULL;
3290 }
3291#endif /* CONFIG_TESTING_OPTIONS */
3292
27fefbbb
JM
3293 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3294 &wrapped_data_len);
3295 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
26806abe
JM
3296 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
3297 "Missing or invalid required Wrapped Data attribute");
30d27b04 3298 return NULL;
27fefbbb
JM
3299 }
3300 wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data",
3301 wrapped_data, wrapped_data_len);
30d27b04
JM
3302 attr_len = wrapped_data - 4 - attr_start;
3303
1ba4a10a 3304 auth = dpp_alloc_auth(msg_ctx);
30d27b04
JM
3305 if (!auth)
3306 goto fail;
30d27b04
JM
3307 auth->peer_bi = peer_bi;
3308 auth->own_bi = own_bi;
3309 auth->curve = own_bi->curve;
3310 auth->curr_freq = freq;
3311
0b4a906d
JM
3312 auth->peer_version = 1; /* default to the first version */
3313#ifdef CONFIG_DPP2
3314 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3315 &version_len);
3316 if (version) {
3317 if (version_len < 1 || version[0] == 0) {
3318 dpp_auth_fail(auth,
3319 "Invalid Protocol Version attribute");
3320 goto fail;
3321 }
3322 auth->peer_version = version[0];
3323 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3324 auth->peer_version);
3325 }
3326#endif /* CONFIG_DPP2 */
3327
d2709206
JM
3328 channel = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CHANNEL,
3329 &channel_len);
3330 if (channel) {
3331 int neg_freq;
3332
3333 if (channel_len < 2) {
3334 dpp_auth_fail(auth, "Too short Channel attribute");
3335 goto fail;
3336 }
3337
3338 neg_freq = ieee80211_chan_to_freq(NULL, channel[0], channel[1]);
3339 wpa_printf(MSG_DEBUG,
3340 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3341 channel[0], channel[1], neg_freq);
3342 if (neg_freq < 0) {
3343 dpp_auth_fail(auth,
3344 "Unsupported Channel attribute value");
3345 goto fail;
3346 }
3347
3348 if (auth->curr_freq != (unsigned int) neg_freq) {
3349 wpa_printf(MSG_DEBUG,
3350 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3351 freq, neg_freq);
3352 auth->curr_freq = neg_freq;
3353 }
3354 }
3355
30d27b04
JM
3356 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY,
3357 &i_proto_len);
3358 if (!i_proto) {
26806abe
JM
3359 dpp_auth_fail(auth,
3360 "Missing required Initiator Protocol Key attribute");
30d27b04
JM
3361 goto fail;
3362 }
3363 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key",
3364 i_proto, i_proto_len);
3365
3366 /* M = bR * PI */
3367 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len);
3368 if (!pi) {
26806abe 3369 dpp_auth_fail(auth, "Invalid Initiator Protocol Key");
30d27b04
JM
3370 goto fail;
3371 }
3372 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi);
3373
29ef1c5e 3374 if (dpp_ecdh(own_bi->pubkey, pi, auth->Mx, &secret_len) < 0)
30d27b04 3375 goto fail;
30d27b04 3376 auth->secret_len = secret_len;
30d27b04
JM
3377
3378 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)",
3379 auth->Mx, auth->secret_len);
630ea133 3380 auth->Mx_len = auth->secret_len;
30d27b04
JM
3381
3382 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1,
3383 auth->curve->hash_len) < 0)
3384 goto fail;
3385
dc4d271c
JM
3386 addr[0] = hdr;
3387 len[0] = DPP_HDR_LEN;
3388 addr[1] = attr_start;
3389 len[1] = attr_len;
3390 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3391 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
3392 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3393 wrapped_data, wrapped_data_len);
3394 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3395 unwrapped = os_malloc(unwrapped_len);
3396 if (!unwrapped)
3397 goto fail;
3398 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3399 wrapped_data, wrapped_data_len,
dc4d271c 3400 2, addr, len, unwrapped) < 0) {
26806abe 3401 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3402 goto fail;
3403 }
3404 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3405 unwrapped, unwrapped_len);
3406
3407 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 3408 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
3409 goto fail;
3410 }
3411
3412 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3413 &i_nonce_len);
3414 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 3415 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
3416 goto fail;
3417 }
3418 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3419 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len);
3420
3421 i_capab = dpp_get_attr(unwrapped, unwrapped_len,
3422 DPP_ATTR_I_CAPABILITIES,
3423 &i_capab_len);
3424 if (!i_capab || i_capab_len < 1) {
26806abe 3425 dpp_auth_fail(auth, "Missing or invalid I-capabilities");
30d27b04
JM
3426 goto fail;
3427 }
3428 auth->i_capab = i_capab[0];
3429 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab);
3430
3431 bin_clear_free(unwrapped, unwrapped_len);
3432 unwrapped = NULL;
3433
3434 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) {
3435 case DPP_CAPAB_ENROLLEE:
3436 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) {
3437 wpa_printf(MSG_DEBUG,
3438 "DPP: Local policy does not allow Configurator role");
3439 goto not_compatible;
3440 }
3441 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3442 auth->configurator = 1;
3443 break;
3444 case DPP_CAPAB_CONFIGURATOR:
3445 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) {
3446 wpa_printf(MSG_DEBUG,
3447 "DPP: Local policy does not allow Enrollee role");
3448 goto not_compatible;
3449 }
3450 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3451 auth->configurator = 0;
3452 break;
d1f08264
JM
3453 case DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE:
3454 if (dpp_allowed_roles & DPP_CAPAB_ENROLLEE) {
3455 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee");
3456 auth->configurator = 0;
3457 } else if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) {
3458 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator");
3459 auth->configurator = 1;
3460 } else {
3461 wpa_printf(MSG_DEBUG,
3462 "DPP: Local policy does not allow Configurator/Enrollee role");
3463 goto not_compatible;
3464 }
3465 break;
30d27b04
JM
3466 default:
3467 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities");
3749ad0e
JM
3468 wpa_msg(auth->msg_ctx, MSG_INFO,
3469 DPP_EVENT_FAIL "Invalid role in I-capabilities 0x%02x",
3470 auth->i_capab & DPP_CAPAB_ROLE_MASK);
3471 goto fail;
30d27b04
JM
3472 }
3473
3474 auth->peer_protocol_key = pi;
3475 pi = NULL;
3476 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) {
3477 char hex[SHA256_MAC_LEN * 2 + 1];
3478
3479 wpa_printf(MSG_DEBUG,
3480 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3481 if (dpp_auth_build_resp_status(auth,
3482 DPP_STATUS_RESPONSE_PENDING) < 0)
3483 goto fail;
3484 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3485 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3486 &i_bootstrap_len);
3487 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) {
3488 auth->response_pending = 1;
3489 os_memcpy(auth->waiting_pubkey_hash,
3490 i_bootstrap, i_bootstrap_len);
3491 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap,
3492 i_bootstrap_len);
3493 } else {
3494 hex[0] = '\0';
3495 }
3496
3497 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE
3498 "%s", hex);
3499 return auth;
3500 }
a03406db 3501 if (dpp_auth_build_resp_ok(auth) < 0)
30d27b04
JM
3502 goto fail;
3503
3504 return auth;
3505
3506not_compatible:
3507 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3508 "i-capab=0x%02x", auth->i_capab);
3509 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)
3510 auth->configurator = 1;
3511 else
3512 auth->configurator = 0;
3513 auth->peer_protocol_key = pi;
3514 pi = NULL;
3515 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0)
3516 goto fail;
3517
3518 auth->remove_on_tx_status = 1;
3519 return auth;
3520fail:
3521 bin_clear_free(unwrapped, unwrapped_len);
3522 EVP_PKEY_free(pi);
3523 EVP_PKEY_CTX_free(ctx);
3524 dpp_auth_deinit(auth);
3525 return NULL;
3526}
3527
3528
3529int dpp_notify_new_qr_code(struct dpp_authentication *auth,
3530 struct dpp_bootstrap_info *peer_bi)
3531{
3532 if (!auth || !auth->response_pending ||
3533 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash,
3534 SHA256_MAC_LEN) != 0)
3535 return 0;
3536
3537 wpa_printf(MSG_DEBUG,
3538 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3539 MACSTR, MAC2STR(auth->peer_mac_addr));
3540 auth->peer_bi = peer_bi;
3541
a03406db 3542 if (dpp_auth_build_resp_ok(auth) < 0)
30d27b04
JM
3543 return -1;
3544
3545 return 1;
3546}
3547
3548
7d917ab0
JM
3549static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth,
3550 enum dpp_status_error status)
30d27b04
JM
3551{
3552 struct wpabuf *msg;
3553 u8 i_auth[4 + DPP_MAX_HASH_LEN];
3554 size_t i_auth_len;
7d917ab0
JM
3555 u8 r_nonce[4 + DPP_MAX_NONCE_LEN];
3556 size_t r_nonce_len;
dc4d271c
JM
3557 const u8 *addr[2];
3558 size_t len[2], attr_len;
30d27b04 3559 u8 *wrapped_i_auth;
7d917ab0 3560 u8 *wrapped_r_nonce;
dc4d271c 3561 u8 *attr_start, *attr_end;
65ecce87
JM
3562 const u8 *r_pubkey_hash, *i_pubkey_hash;
3563#ifdef CONFIG_TESTING_OPTIONS
3564 u8 test_hash[SHA256_MAC_LEN];
3565#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
3566
3567 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation");
3568
3569 i_auth_len = 4 + auth->curve->hash_len;
7d917ab0 3570 r_nonce_len = 4 + auth->curve->nonce_len;
30d27b04 3571 /* Build DPP Authentication Confirmation frame attributes */
dc4d271c 3572 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
7d917ab0 3573 4 + i_auth_len + r_nonce_len + AES_BLOCK_SIZE;
60239f60
JM
3574#ifdef CONFIG_TESTING_OPTIONS
3575 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF)
acdf703d 3576 attr_len += 5;
60239f60 3577#endif /* CONFIG_TESTING_OPTIONS */
dc4d271c 3578 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len);
30d27b04
JM
3579 if (!msg)
3580 goto fail;
3581
dc4d271c
JM
3582 attr_start = wpabuf_put(msg, 0);
3583
65ecce87
JM
3584 r_pubkey_hash = auth->peer_bi->pubkey_hash;
3585 if (auth->own_bi)
3586 i_pubkey_hash = auth->own_bi->pubkey_hash;
3587 else
3588 i_pubkey_hash = NULL;
3589
f9c7d770 3590#ifdef CONFIG_TESTING_OPTIONS
3f35ec2d
JM
3591 if (dpp_test == DPP_TEST_NO_STATUS_AUTH_CONF) {
3592 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
f9c7d770 3593 goto skip_status;
3f35ec2d
JM
3594 } else if (dpp_test == DPP_TEST_INVALID_STATUS_AUTH_CONF) {
3595 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
3596 status = 254;
3597 }
f9c7d770
JM
3598#endif /* CONFIG_TESTING_OPTIONS */
3599
30d27b04 3600 /* DPP Status */
56f24d1d 3601 dpp_build_attr_status(msg, status);
30d27b04 3602
f9c7d770
JM
3603#ifdef CONFIG_TESTING_OPTIONS
3604skip_status:
65ecce87
JM
3605 if (dpp_test == DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3606 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Bootstrap Key Hash");
3607 r_pubkey_hash = NULL;
3608 } else if (dpp_test ==
3609 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3610 wpa_printf(MSG_INFO,
3611 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3612 os_memcpy(test_hash, r_pubkey_hash, SHA256_MAC_LEN);
3613 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3614 r_pubkey_hash = test_hash;
3615 } else if (dpp_test == DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3616 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Bootstrap Key Hash");
3617 i_pubkey_hash = NULL;
3618 } else if (dpp_test ==
3619 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF) {
3620 wpa_printf(MSG_INFO,
3621 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3622 if (i_pubkey_hash)
3623 os_memcpy(test_hash, i_pubkey_hash, SHA256_MAC_LEN);
3624 else
3625 os_memset(test_hash, 0, SHA256_MAC_LEN);
3626 test_hash[SHA256_MAC_LEN - 1] ^= 0x01;
3627 i_pubkey_hash = test_hash;
3628 }
f9c7d770
JM
3629#endif /* CONFIG_TESTING_OPTIONS */
3630
30d27b04 3631 /* Responder Bootstrapping Key Hash */
9efa5314 3632 dpp_build_attr_r_bootstrap_key_hash(msg, r_pubkey_hash);
f9c7d770 3633
9efa5314
JM
3634 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3635 dpp_build_attr_i_bootstrap_key_hash(msg, i_pubkey_hash);
30d27b04 3636
f9c7d770 3637#ifdef CONFIG_TESTING_OPTIONS
f9c7d770
JM
3638 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF)
3639 goto skip_wrapped_data;
3640 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3641 i_auth_len = 0;
3642#endif /* CONFIG_TESTING_OPTIONS */
3643
dc4d271c
JM
3644 attr_end = wpabuf_put(msg, 0);
3645
3646 /* OUI, OUI type, Crypto Suite, DPP frame type */
3647 addr[0] = wpabuf_head_u8(msg) + 2;
3648 len[0] = 3 + 1 + 1 + 1;
3649 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3650
3651 /* Attributes before Wrapped Data */
3652 addr[1] = attr_start;
3653 len[1] = attr_end - attr_start;
3654 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
3655
7d917ab0
JM
3656 if (status == DPP_STATUS_OK) {
3657 /* I-auth wrapped with ke */
3658 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3659 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE);
3660 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE);
f9c7d770
JM
3661
3662#ifdef CONFIG_TESTING_OPTIONS
7d917ab0
JM
3663 if (dpp_test == DPP_TEST_NO_I_AUTH_AUTH_CONF)
3664 goto skip_i_auth;
f9c7d770
JM
3665#endif /* CONFIG_TESTING_OPTIONS */
3666
7d917ab0
JM
3667 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3668 * 1) */
3669 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG);
3670 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len);
3671 if (dpp_gen_i_auth(auth, i_auth + 4) < 0)
3672 goto fail;
f9c7d770
JM
3673
3674#ifdef CONFIG_TESTING_OPTIONS
7d917ab0
JM
3675 if (dpp_test == DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF) {
3676 wpa_printf(MSG_INFO, "DPP: TESTING - I-auth mismatch");
3677 i_auth[4 + auth->curve->hash_len / 2] ^= 0x01;
3678 }
f9c7d770
JM
3679skip_i_auth:
3680#endif /* CONFIG_TESTING_OPTIONS */
7d917ab0
JM
3681 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
3682 i_auth, i_auth_len,
3683 2, addr, len, wrapped_i_auth) < 0)
3684 goto fail;
3685 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke",
3686 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE);
3687 } else {
3688 /* R-nonce wrapped with k2 */
3689 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
3690 wpabuf_put_le16(msg, r_nonce_len + AES_BLOCK_SIZE);
3691 wrapped_r_nonce = wpabuf_put(msg, r_nonce_len + AES_BLOCK_SIZE);
3692
3693 WPA_PUT_LE16(r_nonce, DPP_ATTR_R_NONCE);
3694 WPA_PUT_LE16(&r_nonce[2], auth->curve->nonce_len);
3695 os_memcpy(r_nonce + 4, auth->r_nonce, auth->curve->nonce_len);
3696
3697 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len,
3698 r_nonce, r_nonce_len,
3699 2, addr, len, wrapped_r_nonce) < 0)
3700 goto fail;
3701 wpa_hexdump(MSG_DEBUG, "DPP: {R-nonce}k2",
3702 wrapped_r_nonce, r_nonce_len + AES_BLOCK_SIZE);
3703 }
30d27b04 3704
60239f60
JM
3705#ifdef CONFIG_TESTING_OPTIONS
3706 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) {
3707 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 3708 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 3709 }
f9c7d770 3710skip_wrapped_data:
60239f60
JM
3711#endif /* CONFIG_TESTING_OPTIONS */
3712
30d27b04
JM
3713 wpa_hexdump_buf(MSG_DEBUG,
3714 "DPP: Authentication Confirmation frame attributes",
3715 msg);
7d917ab0
JM
3716 if (status == DPP_STATUS_OK)
3717 dpp_auth_success(auth);
30d27b04
JM
3718
3719 return msg;
3720
3721fail:
8a37d54e 3722 wpabuf_free(msg);
30d27b04
JM
3723 return NULL;
3724}
3725
3726
3727static void
dc4d271c 3728dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr,
30d27b04
JM
3729 const u8 *attr_start, size_t attr_len,
3730 const u8 *wrapped_data, u16 wrapped_data_len,
3731 enum dpp_status_error status)
3732{
dc4d271c
JM
3733 const u8 *addr[2];
3734 size_t len[2];
30d27b04
JM
3735 u8 *unwrapped = NULL;
3736 size_t unwrapped_len = 0;
3737 const u8 *i_nonce, *r_capab;
3738 u16 i_nonce_len, r_capab_len;
3739
3740 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3741 wpa_printf(MSG_DEBUG,
3742 "DPP: Responder reported incompatible roles");
3743 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3744 wpa_printf(MSG_DEBUG,
3745 "DPP: Responder reported more time needed");
3746 } else {
3747 wpa_printf(MSG_DEBUG,
3748 "DPP: Responder reported failure (status %d)",
3749 status);
26806abe 3750 dpp_auth_fail(auth, "Responder reported failure");
30d27b04
JM
3751 return;
3752 }
3753
dc4d271c
JM
3754 addr[0] = hdr;
3755 len[0] = DPP_HDR_LEN;
3756 addr[1] = attr_start;
3757 len[1] = attr_len;
3758 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
3759 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
3760 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
3761 wrapped_data, wrapped_data_len);
3762 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
3763 unwrapped = os_malloc(unwrapped_len);
3764 if (!unwrapped)
3765 goto fail;
3766 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len,
3767 wrapped_data, wrapped_data_len,
dc4d271c 3768 2, addr, len, unwrapped) < 0) {
26806abe 3769 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
3770 goto fail;
3771 }
3772 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
3773 unwrapped, unwrapped_len);
3774
3775 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 3776 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
3777 goto fail;
3778 }
3779
3780 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
3781 &i_nonce_len);
3782 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 3783 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
3784 goto fail;
3785 }
3786 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
3787 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
26806abe 3788 dpp_auth_fail(auth, "I-nonce mismatch");
30d27b04
JM
3789 goto fail;
3790 }
3791
3792 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
3793 DPP_ATTR_R_CAPABILITIES,
3794 &r_capab_len);
3795 if (!r_capab || r_capab_len < 1) {
26806abe 3796 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
30d27b04
JM
3797 goto fail;
3798 }
3799 auth->r_capab = r_capab[0];
3800 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3801 if (status == DPP_STATUS_NOT_COMPATIBLE) {
3802 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE
3803 "r-capab=0x%02x", auth->r_capab);
3804 } else if (status == DPP_STATUS_RESPONSE_PENDING) {
3749ad0e
JM
3805 u8 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
3806
3807 if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
3808 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
3809 wpa_msg(auth->msg_ctx, MSG_INFO,
3810 DPP_EVENT_FAIL "Unexpected role in R-capabilities 0x%02x",
3811 role);
3812 } else {
3813 wpa_printf(MSG_DEBUG,
3814 "DPP: Continue waiting for full DPP Authentication Response");
73f21929
JM
3815 wpa_msg(auth->msg_ctx, MSG_INFO,
3816 DPP_EVENT_RESPONSE_PENDING "%s",
3817 auth->tmp_own_bi ? auth->tmp_own_bi->uri : "");
3749ad0e 3818 }
30d27b04
JM
3819 }
3820fail:
3821 bin_clear_free(unwrapped, unwrapped_len);
3822}
3823
3824
3825struct wpabuf *
dc4d271c
JM
3826dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
3827 const u8 *attr_start, size_t attr_len)
30d27b04
JM
3828{
3829 EVP_PKEY *pr;
30d27b04 3830 size_t secret_len;
dc4d271c
JM
3831 const u8 *addr[2];
3832 size_t len[2];
30d27b04
JM
3833 u8 *unwrapped = NULL, *unwrapped2 = NULL;
3834 size_t unwrapped_len = 0, unwrapped2_len = 0;
3835 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto,
3836 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth;
3837 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
3838 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len,
3839 wrapped2_len, r_auth_len;
3840 u8 r_auth2[DPP_MAX_HASH_LEN];
3749ad0e 3841 u8 role;
0b4a906d
JM
3842#ifdef CONFIG_DPP2
3843 const u8 *version;
3844 u16 version_len;
3845#endif /* CONFIG_DPP2 */
30d27b04 3846
34603767
JM
3847#ifdef CONFIG_TESTING_OPTIONS
3848 if (dpp_test == DPP_TEST_STOP_AT_AUTH_RESP) {
3849 wpa_printf(MSG_INFO,
3850 "DPP: TESTING - stop at Authentication Response");
3851 return NULL;
3852 }
3853#endif /* CONFIG_TESTING_OPTIONS */
3854
810bedf2 3855 if (!auth->initiator || !auth->peer_bi) {
03abb6b5
JM
3856 dpp_auth_fail(auth, "Unexpected Authentication Response");
3857 return NULL;
3858 }
3859
f97ace34
JM
3860 auth->waiting_auth_resp = 0;
3861
30d27b04
JM
3862 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
3863 &wrapped_data_len);
26806abe
JM
3864 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
3865 dpp_auth_fail(auth,
3866 "Missing or invalid required Wrapped Data attribute");
30d27b04
JM
3867 return NULL;
3868 }
3869 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
3870 wrapped_data, wrapped_data_len);
3871
30d27b04
JM
3872 attr_len = wrapped_data - 4 - attr_start;
3873
3874 r_bootstrap = dpp_get_attr(attr_start, attr_len,
3875 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
3876 &r_bootstrap_len);
3877 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
26806abe
JM
3878 dpp_auth_fail(auth,
3879 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
30d27b04
JM
3880 return NULL;
3881 }
3882 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
3883 r_bootstrap, r_bootstrap_len);
3884 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash,
3885 SHA256_MAC_LEN) != 0) {
26806abe
JM
3886 dpp_auth_fail(auth,
3887 "Unexpected Responder Bootstrapping Key Hash value");
30d27b04
JM
3888 wpa_hexdump(MSG_DEBUG,
3889 "DPP: Expected Responder Bootstrapping Key Hash",
3890 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
3891 return NULL;
3892 }
3893
3894 i_bootstrap = dpp_get_attr(attr_start, attr_len,
3895 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
3896 &i_bootstrap_len);
3897 if (i_bootstrap) {
3898 if (i_bootstrap_len != SHA256_MAC_LEN) {
26806abe
JM
3899 dpp_auth_fail(auth,
3900 "Invalid Initiator Bootstrapping Key Hash attribute");
30d27b04
JM
3901 return NULL;
3902 }
3903 wpa_hexdump(MSG_MSGDUMP,
3904 "DPP: Initiator Bootstrapping Key Hash",
3905 i_bootstrap, i_bootstrap_len);
3906 if (!auth->own_bi ||
3907 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash,
3908 SHA256_MAC_LEN) != 0) {
26806abe
JM
3909 dpp_auth_fail(auth,
3910 "Initiator Bootstrapping Key Hash attribute did not match");
30d27b04
JM
3911 return NULL;
3912 }
9b511120
JM
3913 } else if (auth->own_bi && auth->own_bi->type == DPP_BOOTSTRAP_PKEX) {
3914 /* PKEX bootstrapping mandates use of mutual authentication */
3915 dpp_auth_fail(auth,
3916 "Missing Initiator Bootstrapping Key Hash attribute");
3917 return NULL;
30d27b04
JM
3918 }
3919
0b4a906d
JM
3920 auth->peer_version = 1; /* default to the first version */
3921#ifdef CONFIG_DPP2
3922 version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION,
3923 &version_len);
3924 if (version) {
3925 if (version_len < 1 || version[0] == 0) {
3926 dpp_auth_fail(auth,
3927 "Invalid Protocol Version attribute");
3928 return NULL;
3929 }
3930 auth->peer_version = version[0];
3931 wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
3932 auth->peer_version);
3933 }
3934#endif /* CONFIG_DPP2 */
3935
30d27b04
JM
3936 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
3937 &status_len);
3938 if (!status || status_len < 1) {
26806abe
JM
3939 dpp_auth_fail(auth,
3940 "Missing or invalid required DPP Status attribute");
30d27b04
JM
3941 return NULL;
3942 }
3943 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
3944 auth->auth_resp_status = status[0];
3945 if (status[0] != DPP_STATUS_OK) {
dc4d271c 3946 dpp_auth_resp_rx_status(auth, hdr, attr_start,
30d27b04
JM
3947 attr_len, wrapped_data,
3948 wrapped_data_len, status[0]);
3949 return NULL;
3950 }
3951
9b511120
JM
3952 if (!i_bootstrap && auth->own_bi) {
3953 wpa_printf(MSG_DEBUG,
3954 "DPP: Responder decided not to use mutual authentication");
3955 auth->own_bi = NULL;
3956 }
3957
163fc3d5
JM
3958 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_DIRECTION "mutual=%d",
3959 auth->own_bi != NULL);
3960
30d27b04
JM
3961 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY,
3962 &r_proto_len);
3963 if (!r_proto) {
26806abe
JM
3964 dpp_auth_fail(auth,
3965 "Missing required Responder Protocol Key attribute");
30d27b04
JM
3966 return NULL;
3967 }
3968 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key",
3969 r_proto, r_proto_len);
3970
3971 /* N = pI * PR */
3972 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len);
3973 if (!pr) {
26806abe 3974 dpp_auth_fail(auth, "Invalid Responder Protocol Key");
30d27b04
JM
3975 return NULL;
3976 }
3977 dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
3978
29ef1c5e 3979 if (dpp_ecdh(auth->own_protocol_key, pr, auth->Nx, &secret_len) < 0) {
26806abe 3980 dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
30d27b04
JM
3981 goto fail;
3982 }
c5622b43 3983 EVP_PKEY_free(auth->peer_protocol_key);
30d27b04
JM
3984 auth->peer_protocol_key = pr;
3985 pr = NULL;
3986
3987 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
3988 auth->Nx, auth->secret_len);
630ea133 3989 auth->Nx_len = auth->secret_len;
30d27b04
JM
3990
3991 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2,
3992 auth->curve->hash_len) < 0)
3993 goto fail;
3994
dc4d271c
JM
3995 addr[0] = hdr;
3996 len[0] = DPP_HDR_LEN;
3997 addr[1] = attr_start;
3998 len[1] = attr_len;
3999 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4000 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
4001 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4002 wrapped_data, wrapped_data_len);
4003 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4004 unwrapped = os_malloc(unwrapped_len);
4005 if (!unwrapped)
4006 goto fail;
4007 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4008 wrapped_data, wrapped_data_len,
dc4d271c 4009 2, addr, len, unwrapped) < 0) {
26806abe 4010 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
4011 goto fail;
4012 }
4013 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4014 unwrapped, unwrapped_len);
4015
4016 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
26806abe 4017 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
4018 goto fail;
4019 }
4020
4021 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4022 &r_nonce_len);
4023 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
26806abe 4024 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
30d27b04
JM
4025 goto fail;
4026 }
4027 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len);
4028 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len);
4029
4030 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE,
4031 &i_nonce_len);
4032 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) {
26806abe 4033 dpp_auth_fail(auth, "Missing or invalid I-nonce");
30d27b04
JM
4034 goto fail;
4035 }
4036 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len);
4037 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) {
26806abe 4038 dpp_auth_fail(auth, "I-nonce mismatch");
30d27b04
JM
4039 goto fail;
4040 }
4041
810bedf2 4042 if (auth->own_bi) {
30d27b04
JM
4043 /* Mutual authentication */
4044 if (dpp_auth_derive_l_initiator(auth) < 0)
4045 goto fail;
4046 }
4047
30d27b04
JM
4048 r_capab = dpp_get_attr(unwrapped, unwrapped_len,
4049 DPP_ATTR_R_CAPABILITIES,
4050 &r_capab_len);
4051 if (!r_capab || r_capab_len < 1) {
26806abe 4052 dpp_auth_fail(auth, "Missing or invalid R-capabilities");
30d27b04
JM
4053 goto fail;
4054 }
4055 auth->r_capab = r_capab[0];
4056 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab);
3749ad0e 4057 role = auth->r_capab & DPP_CAPAB_ROLE_MASK;
d1f08264
JM
4058 if ((auth->allowed_roles ==
4059 (DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE)) &&
4060 (role == DPP_CAPAB_CONFIGURATOR || role == DPP_CAPAB_ENROLLEE)) {
4061 /* Peer selected its role, so move from "either role" to the
4062 * role that is compatible with peer's selection. */
4063 auth->configurator = role == DPP_CAPAB_ENROLLEE;
4064 wpa_printf(MSG_DEBUG, "DPP: Acting as %s",
4065 auth->configurator ? "Configurator" : "Enrollee");
4066 } else if ((auth->configurator && role != DPP_CAPAB_ENROLLEE) ||
4067 (!auth->configurator && role != DPP_CAPAB_CONFIGURATOR)) {
30d27b04 4068 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection");
3749ad0e
JM
4069 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
4070 "Unexpected role in R-capabilities 0x%02x",
4071 role);
7d917ab0
JM
4072 if (role != DPP_CAPAB_ENROLLEE &&
4073 role != DPP_CAPAB_CONFIGURATOR)
4074 goto fail;
4075 bin_clear_free(unwrapped, unwrapped_len);
4076 auth->remove_on_tx_status = 1;
4077 return dpp_auth_build_conf(auth, DPP_STATUS_NOT_COMPATIBLE);
30d27b04
JM
4078 }
4079
4080 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len,
4081 DPP_ATTR_WRAPPED_DATA, &wrapped2_len);
4082 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) {
26806abe
JM
4083 dpp_auth_fail(auth,
4084 "Missing or invalid Secondary Wrapped Data");
30d27b04
JM
4085 goto fail;
4086 }
4087
4088 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4089 wrapped2, wrapped2_len);
7d917ab0
JM
4090
4091 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0)
4092 goto fail;
4093
30d27b04
JM
4094 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE;
4095 unwrapped2 = os_malloc(unwrapped2_len);
4096 if (!unwrapped2)
4097 goto fail;
4098 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4099 wrapped2, wrapped2_len,
4100 0, NULL, NULL, unwrapped2) < 0) {
26806abe 4101 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
4102 goto fail;
4103 }
4104 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4105 unwrapped2, unwrapped2_len);
4106
4107 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) {
26806abe
JM
4108 dpp_auth_fail(auth,
4109 "Invalid attribute in secondary unwrapped data");
30d27b04
JM
4110 goto fail;
4111 }
4112
4113 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG,
4114 &r_auth_len);
4115 if (!r_auth || r_auth_len != auth->curve->hash_len) {
26806abe
JM
4116 dpp_auth_fail(auth,
4117 "Missing or invalid Responder Authenticating Tag");
30d27b04
JM
4118 goto fail;
4119 }
4120 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag",
4121 r_auth, r_auth_len);
4122 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4123 if (dpp_gen_r_auth(auth, r_auth2) < 0)
4124 goto fail;
4125 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag",
4126 r_auth2, r_auth_len);
4127 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) {
26806abe 4128 dpp_auth_fail(auth, "Mismatching Responder Authenticating Tag");
7d917ab0
JM
4129 bin_clear_free(unwrapped, unwrapped_len);
4130 bin_clear_free(unwrapped2, unwrapped2_len);
4131 auth->remove_on_tx_status = 1;
4132 return dpp_auth_build_conf(auth, DPP_STATUS_AUTH_FAILURE);
30d27b04
JM
4133 }
4134
4135 bin_clear_free(unwrapped, unwrapped_len);
4136 bin_clear_free(unwrapped2, unwrapped2_len);
4137
762fb4f0
JM
4138#ifdef CONFIG_TESTING_OPTIONS
4139 if (dpp_test == DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF) {
4140 wpa_printf(MSG_INFO,
4141 "DPP: TESTING - Authentication Response in place of Confirm");
4142 if (dpp_auth_build_resp_ok(auth) < 0)
4143 return NULL;
4144 return wpabuf_dup(auth->resp_msg);
4145 }
4146#endif /* CONFIG_TESTING_OPTIONS */
4147
7d917ab0 4148 return dpp_auth_build_conf(auth, DPP_STATUS_OK);
30d27b04
JM
4149
4150fail:
4151 bin_clear_free(unwrapped, unwrapped_len);
4152 bin_clear_free(unwrapped2, unwrapped2_len);
4153 EVP_PKEY_free(pr);
30d27b04
JM
4154 return NULL;
4155}
4156
4157
19ef4289
JM
4158static int dpp_auth_conf_rx_failure(struct dpp_authentication *auth,
4159 const u8 *hdr,
4160 const u8 *attr_start, size_t attr_len,
4161 const u8 *wrapped_data,
4162 u16 wrapped_data_len,
4163 enum dpp_status_error status)
4164{
4165 const u8 *addr[2];
4166 size_t len[2];
4167 u8 *unwrapped = NULL;
4168 size_t unwrapped_len = 0;
4169 const u8 *r_nonce;
4170 u16 r_nonce_len;
4171
4172 /* Authentication Confirm failure cases are expected to include
4173 * {R-nonce}k2 in the Wrapped Data attribute. */
4174
4175 addr[0] = hdr;
4176 len[0] = DPP_HDR_LEN;
4177 addr[1] = attr_start;
4178 len[1] = attr_len;
4179 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4180 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
4181 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4182 wrapped_data, wrapped_data_len);
4183 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4184 unwrapped = os_malloc(unwrapped_len);
4185 if (!unwrapped) {
4186 dpp_auth_fail(auth, "Authentication failed");
4187 goto fail;
4188 }
4189 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len,
4190 wrapped_data, wrapped_data_len,
4191 2, addr, len, unwrapped) < 0) {
4192 dpp_auth_fail(auth, "AES-SIV decryption failed");
4193 goto fail;
4194 }
4195 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4196 unwrapped, unwrapped_len);
4197
4198 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
4199 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
4200 goto fail;
4201 }
4202
4203 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE,
4204 &r_nonce_len);
4205 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) {
4206 dpp_auth_fail(auth, "DPP: Missing or invalid R-nonce");
4207 goto fail;
4208 }
4209 if (os_memcmp(r_nonce, auth->r_nonce, r_nonce_len) != 0) {
4210 wpa_hexdump(MSG_DEBUG, "DPP: Received R-nonce",
4211 r_nonce, r_nonce_len);
4212 wpa_hexdump(MSG_DEBUG, "DPP: Expected R-nonce",
4213 auth->r_nonce, r_nonce_len);
4214 dpp_auth_fail(auth, "R-nonce mismatch");
4215 goto fail;
4216 }
4217
4218 if (status == DPP_STATUS_NOT_COMPATIBLE)
4219 dpp_auth_fail(auth, "Peer reported incompatible R-capab role");
4220 else if (status == DPP_STATUS_AUTH_FAILURE)
4221 dpp_auth_fail(auth, "Peer reported authentication failure)");
4222
4223fail:
4224 bin_clear_free(unwrapped, unwrapped_len);
4225 return -1;
4226}
4227
4228
dc4d271c
JM
4229int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
4230 const u8 *attr_start, size_t attr_len)
30d27b04
JM
4231{
4232 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth;
4233 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len,
4234 i_auth_len;
dc4d271c
JM
4235 const u8 *addr[2];
4236 size_t len[2];
30d27b04
JM
4237 u8 *unwrapped = NULL;
4238 size_t unwrapped_len = 0;
4239 u8 i_auth2[DPP_MAX_HASH_LEN];
4240
34603767
JM
4241#ifdef CONFIG_TESTING_OPTIONS
4242 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
4243 wpa_printf(MSG_INFO,
4244 "DPP: TESTING - stop at Authentication Confirm");
4245 return -1;
4246 }
4247#endif /* CONFIG_TESTING_OPTIONS */
4248
18714af2
JM
4249 if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) {
4250 wpa_printf(MSG_DEBUG,
4251 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4252 auth->initiator, !!auth->own_bi,
4253 auth->waiting_auth_conf);
03abb6b5 4254 dpp_auth_fail(auth, "Unexpected Authentication Confirm");
116454f4 4255 return -1;
03abb6b5
JM
4256 }
4257
95b0104a
JM
4258 auth->waiting_auth_conf = 0;
4259
30d27b04
JM
4260 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
4261 &wrapped_data_len);
dcdaeab7
JM
4262 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
4263 dpp_auth_fail(auth,
4264 "Missing or invalid required Wrapped Data attribute");
30d27b04
JM
4265 return -1;
4266 }
4267 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
4268 wrapped_data, wrapped_data_len);
4269
30d27b04
JM
4270 attr_len = wrapped_data - 4 - attr_start;
4271
4272 r_bootstrap = dpp_get_attr(attr_start, attr_len,
4273 DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
4274 &r_bootstrap_len);
dcdaeab7
JM
4275 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
4276 dpp_auth_fail(auth,
4277 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
30d27b04
JM
4278 return -1;
4279 }
4280 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash",
4281 r_bootstrap, r_bootstrap_len);
4282 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash,
4283 SHA256_MAC_LEN) != 0) {
4284 wpa_hexdump(MSG_DEBUG,
4285 "DPP: Expected Responder Bootstrapping Key Hash",
4286 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN);
dcdaeab7
JM
4287 dpp_auth_fail(auth,
4288 "Responder Bootstrapping Key Hash mismatch");
30d27b04
JM
4289 return -1;
4290 }
4291
4292 i_bootstrap = dpp_get_attr(attr_start, attr_len,
4293 DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
4294 &i_bootstrap_len);
4295 if (i_bootstrap) {
dcdaeab7
JM
4296 if (i_bootstrap_len != SHA256_MAC_LEN) {
4297 dpp_auth_fail(auth,
4298 "Invalid Initiator Bootstrapping Key Hash attribute");
30d27b04
JM
4299 return -1;
4300 }
4301 wpa_hexdump(MSG_MSGDUMP,
4302 "DPP: Initiator Bootstrapping Key Hash",
4303 i_bootstrap, i_bootstrap_len);
4304 if (!auth->peer_bi ||
4305 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash,
4306 SHA256_MAC_LEN) != 0) {
dcdaeab7
JM
4307 dpp_auth_fail(auth,
4308 "Initiator Bootstrapping Key Hash mismatch");
30d27b04
JM
4309 return -1;
4310 }
810bedf2 4311 } else if (auth->peer_bi) {
9b511120
JM
4312 /* Mutual authentication and peer did not include its
4313 * Bootstrapping Key Hash attribute. */
4314 dpp_auth_fail(auth,
4315 "Missing Initiator Bootstrapping Key Hash attribute");
4316 return -1;
30d27b04
JM
4317 }
4318
4319 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS,
4320 &status_len);
4321 if (!status || status_len < 1) {
dcdaeab7
JM
4322 dpp_auth_fail(auth,
4323 "Missing or invalid required DPP Status attribute");
30d27b04
JM
4324 return -1;
4325 }
4326 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
19ef4289
JM
4327 if (status[0] == DPP_STATUS_NOT_COMPATIBLE ||
4328 status[0] == DPP_STATUS_AUTH_FAILURE)
4329 return dpp_auth_conf_rx_failure(auth, hdr, attr_start,
4330 attr_len, wrapped_data,
4331 wrapped_data_len, status[0]);
4332
30d27b04 4333 if (status[0] != DPP_STATUS_OK) {
dcdaeab7 4334 dpp_auth_fail(auth, "Authentication failed");
30d27b04
JM
4335 return -1;
4336 }
4337
dc4d271c
JM
4338 addr[0] = hdr;
4339 len[0] = DPP_HDR_LEN;
4340 addr[1] = attr_start;
4341 len[1] = attr_len;
4342 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
4343 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
30d27b04
JM
4344 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
4345 wrapped_data, wrapped_data_len);
4346 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
4347 unwrapped = os_malloc(unwrapped_len);
4348 if (!unwrapped)
4349 return -1;
4350 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
4351 wrapped_data, wrapped_data_len,
dc4d271c 4352 2, addr, len, unwrapped) < 0) {
dcdaeab7 4353 dpp_auth_fail(auth, "AES-SIV decryption failed");
30d27b04
JM
4354 goto fail;
4355 }
4356 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
4357 unwrapped, unwrapped_len);
4358
4359 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
dcdaeab7 4360 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
30d27b04
JM
4361 goto fail;
4362 }
4363
4364 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
4365 &i_auth_len);
4366 if (!i_auth || i_auth_len != auth->curve->hash_len) {
dcdaeab7
JM
4367 dpp_auth_fail(auth,
4368 "Missing or invalid Initiator Authenticating Tag");
30d27b04
JM
4369 goto fail;
4370 }
4371 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag",
4372 i_auth, i_auth_len);
4373 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4374 if (dpp_gen_i_auth(auth, i_auth2) < 0)
4375 goto fail;
4376 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag",
4377 i_auth2, i_auth_len);
4378 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) {
dcdaeab7 4379 dpp_auth_fail(auth, "Mismatching Initiator Authenticating Tag");
30d27b04
JM
4380 goto fail;
4381 }
4382
4383 bin_clear_free(unwrapped, unwrapped_len);
4384 dpp_auth_success(auth);
4385 return 0;
4386fail:
4387 bin_clear_free(unwrapped, unwrapped_len);
4388 return -1;
4389}
4390
4391
9305c233
JM
4392static int bin_str_eq(const char *val, size_t len, const char *cmp)
4393{
4394 return os_strlen(cmp) == len && os_memcmp(val, cmp, len) == 0;
4395}
4396
4397
4398struct dpp_configuration * dpp_configuration_alloc(const char *type)
4399{
4400 struct dpp_configuration *conf;
4401 const char *end;
4402 size_t len;
4403
4404 conf = os_zalloc(sizeof(*conf));
4405 if (!conf)
4406 goto fail;
4407
4408 end = os_strchr(type, ' ');
4409 if (end)
4410 len = end - type;
4411 else
4412 len = os_strlen(type);
4413
4414 if (bin_str_eq(type, len, "psk"))
4415 conf->akm = DPP_AKM_PSK;
4416 else if (bin_str_eq(type, len, "sae"))
4417 conf->akm = DPP_AKM_SAE;
18015fc8
JM
4418 else if (bin_str_eq(type, len, "psk-sae") ||
4419 bin_str_eq(type, len, "psk+sae"))
9305c233 4420 conf->akm = DPP_AKM_PSK_SAE;
18015fc8
JM
4421 else if (bin_str_eq(type, len, "sae-dpp") ||
4422 bin_str_eq(type, len, "dpp+sae"))
4423 conf->akm = DPP_AKM_SAE_DPP;
4424 else if (bin_str_eq(type, len, "psk-sae-dpp") ||
4425 bin_str_eq(type, len, "dpp+psk+sae"))
4426 conf->akm = DPP_AKM_PSK_SAE_DPP;
9305c233
JM
4427 else if (bin_str_eq(type, len, "dpp"))
4428 conf->akm = DPP_AKM_DPP;
4429 else
4430 goto fail;
4431
4432 return conf;
4433fail:
4434 dpp_configuration_free(conf);
4435 return NULL;
4436}
4437
4438
18015fc8 4439int dpp_akm_psk(enum dpp_akm akm)
9305c233 4440{
18015fc8
JM
4441 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4442 akm == DPP_AKM_PSK_SAE_DPP;
9305c233
JM
4443}
4444
4445
18015fc8 4446int dpp_akm_sae(enum dpp_akm akm)
9305c233 4447{
18015fc8
JM
4448 return akm == DPP_AKM_SAE || akm == DPP_AKM_PSK_SAE ||
4449 akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
4450}
4451
4452
4453int dpp_akm_legacy(enum dpp_akm akm)
4454{
4455 return akm == DPP_AKM_PSK || akm == DPP_AKM_PSK_SAE ||
4456 akm == DPP_AKM_SAE;
4457}
4458
4459
4460int dpp_akm_dpp(enum dpp_akm akm)
4461{
4462 return akm == DPP_AKM_DPP || akm == DPP_AKM_SAE_DPP ||
4463 akm == DPP_AKM_PSK_SAE_DPP;
4464}
4465
4466
4467int dpp_akm_ver2(enum dpp_akm akm)
4468{
4469 return akm == DPP_AKM_SAE_DPP || akm == DPP_AKM_PSK_SAE_DPP;
9305c233
JM
4470}
4471
4472
4473int dpp_configuration_valid(const struct dpp_configuration *conf)
4474{
4475 if (conf->ssid_len == 0)
4476 return 0;
4477 if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
4478 return 0;
4479 if (dpp_akm_sae(conf->akm) && !conf->passphrase)
4480 return 0;
4481 return 1;
4482}
4483
4484
461d39af
JM
4485void dpp_configuration_free(struct dpp_configuration *conf)
4486{
4487 if (!conf)
4488 return;
4489 str_clear_free(conf->passphrase);
20f612d9 4490 os_free(conf->group_id);
461d39af
JM
4491 bin_clear_free(conf, sizeof(*conf));
4492}
4493
4494
7eb06a33
JM
4495static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
4496 const char *cmd, int idx)
9305c233
JM
4497{
4498 const char *pos, *end;
4499 struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
4500 struct dpp_configuration *conf = NULL;
4501
4502 pos = os_strstr(cmd, " conf=sta-");
4503 if (pos) {
4504 conf_sta = dpp_configuration_alloc(pos + 10);
4505 if (!conf_sta)
4506 goto fail;
99918e06 4507 conf_sta->netrole = DPP_NETROLE_STA;
9305c233
JM
4508 conf = conf_sta;
4509 }
4510
4511 pos = os_strstr(cmd, " conf=ap-");
4512 if (pos) {
4513 conf_ap = dpp_configuration_alloc(pos + 9);
4514 if (!conf_ap)
4515 goto fail;
99918e06 4516 conf_ap->netrole = DPP_NETROLE_AP;
9305c233
JM
4517 conf = conf_ap;
4518 }
4519
e2b1e7dc
JM
4520 pos = os_strstr(cmd, " conf=configurator");
4521 if (pos)
4522 auth->provision_configurator = 1;
4523
9305c233
JM
4524 if (!conf)
4525 return 0;
4526
4527 pos = os_strstr(cmd, " ssid=");
4528 if (pos) {
4529 pos += 6;
4530 end = os_strchr(pos, ' ');
4531 conf->ssid_len = end ? (size_t) (end - pos) : os_strlen(pos);
4532 conf->ssid_len /= 2;
4533 if (conf->ssid_len > sizeof(conf->ssid) ||
4534 hexstr2bin(pos, conf->ssid, conf->ssid_len) < 0)
4535 goto fail;
4536 } else {
4537#ifdef CONFIG_TESTING_OPTIONS
4538 /* use a default SSID for legacy testing reasons */
4539 os_memcpy(conf->ssid, "test", 4);
4540 conf->ssid_len = 4;
4541#else /* CONFIG_TESTING_OPTIONS */
4542 goto fail;
4543#endif /* CONFIG_TESTING_OPTIONS */
4544 }
4545
71e2848e
JM
4546 pos = os_strstr(cmd, " ssid_charset=");
4547 if (pos) {
4548 if (conf_ap) {
4549 wpa_printf(MSG_INFO,
4550 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4551 goto fail;
4552 }
4553 conf->ssid_charset = atoi(pos + 14);
4554 }
4555
9305c233
JM
4556 pos = os_strstr(cmd, " pass=");
4557 if (pos) {
4558 size_t pass_len;
4559
4560 pos += 6;
4561 end = os_strchr(pos, ' ');
4562 pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
4563 pass_len /= 2;
4564 if (pass_len > 63 || pass_len < 8)
4565 goto fail;
4566 conf->passphrase = os_zalloc(pass_len + 1);
4567 if (!conf->passphrase ||
4568 hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
4569 goto fail;
4570 }
4571
4572 pos = os_strstr(cmd, " psk=");
4573 if (pos) {
4574 pos += 5;
4575 if (hexstr2bin(pos, conf->psk, PMK_LEN) < 0)
4576 goto fail;
4577 conf->psk_set = 1;
4578 }
4579
4580 pos = os_strstr(cmd, " group_id=");
4581 if (pos) {
4582 size_t group_id_len;
4583
4584 pos += 10;
4585 end = os_strchr(pos, ' ');
4586 group_id_len = end ? (size_t) (end - pos) : os_strlen(pos);
4587 conf->group_id = os_malloc(group_id_len + 1);
4588 if (!conf->group_id)
4589 goto fail;
4590 os_memcpy(conf->group_id, pos, group_id_len);
4591 conf->group_id[group_id_len] = '\0';
4592 }
4593
4594 pos = os_strstr(cmd, " expiry=");
4595 if (pos) {
4596 long int val;
4597
4598 pos += 8;
4599 val = strtol(pos, NULL, 0);
4600 if (val <= 0)
4601 goto fail;
4602 conf->netaccesskey_expiry = val;
4603 }
4604
4605 if (!dpp_configuration_valid(conf))
4606 goto fail;
4607
7eb06a33
JM
4608 if (idx == 0) {
4609 auth->conf_sta = conf_sta;
4610 auth->conf_ap = conf_ap;
4611 } else if (idx == 1) {
4612 auth->conf2_sta = conf_sta;
4613 auth->conf2_ap = conf_ap;
4614 } else {
4615 goto fail;
4616 }
9305c233
JM
4617 return 0;
4618
4619fail:
4620 dpp_configuration_free(conf_sta);
4621 dpp_configuration_free(conf_ap);
4622 return -1;
4623}
4624
4625
7eb06a33
JM
4626static int dpp_configuration_parse(struct dpp_authentication *auth,
4627 const char *cmd)
4628{
4629 const char *pos;
4630 char *tmp;
4631 size_t len;
4632 int res;
4633
4634 pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
4635 if (!pos)
4636 return dpp_configuration_parse_helper(auth, cmd, 0);
4637
4638 len = pos - cmd;
4639 tmp = os_malloc(len + 1);
4640 if (!tmp)
4641 goto fail;
4642 os_memcpy(tmp, cmd, len);
4643 tmp[len] = '\0';
4644 res = dpp_configuration_parse_helper(auth, cmd, 0);
4645 str_clear_free(tmp);
4646 if (res)
4647 goto fail;
4648 res = dpp_configuration_parse_helper(auth, cmd + len, 1);
4649 if (res)
4650 goto fail;
4651 return 0;
4652fail:
4653 dpp_configuration_free(auth->conf_sta);
4654 dpp_configuration_free(auth->conf2_sta);
4655 dpp_configuration_free(auth->conf_ap);
4656 dpp_configuration_free(auth->conf2_ap);
4657 return -1;
4658}
4659
4660
87d8435c
JM
4661static struct dpp_configurator *
4662dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
4663{
4664 struct dpp_configurator *conf;
4665
4666 if (!dpp)
4667 return NULL;
4668
4669 dl_list_for_each(conf, &dpp->configurator,
4670 struct dpp_configurator, list) {
4671 if (conf->id == id)
4672 return conf;
4673 }
4674 return NULL;
4675}
4676
4677
4678int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
4679 struct dpp_authentication *auth,
4680 const char *cmd)
4681{
4682 const char *pos;
de08fae6
JM
4683 char *tmp = NULL;
4684 int ret = -1;
87d8435c
JM
4685
4686 if (!cmd)
4687 return 0;
de08fae6
JM
4688 if (cmd[0] != ' ') {
4689 size_t len;
4690
4691 len = os_strlen(cmd);
4692 tmp = os_malloc(len + 2);
4693 if (!tmp)
4694 goto fail;
4695 tmp[0] = ' ';
4696 os_memcpy(tmp + 1, cmd, len + 1);
4697 cmd = tmp;
4698 }
87d8435c
JM
4699
4700 wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd);
4701
4702 pos = os_strstr(cmd, " configurator=");
4703 if (pos) {
4704 pos += 14;
4705 auth->conf = dpp_configurator_get_id(dpp, atoi(pos));
4706 if (!auth->conf) {
4707 wpa_printf(MSG_INFO,
4708 "DPP: Could not find the specified configurator");
de08fae6 4709 goto fail;
87d8435c
JM
4710 }
4711 }
4712
b10e01a7
JM
4713 pos = os_strstr(cmd, " conn_status=");
4714 if (pos) {
4715 pos += 13;
4716 auth->send_conn_status = atoi(pos);
4717 }
4718
68fea960
JM
4719 pos = os_strstr(cmd, " akm_use_selector=");
4720 if (pos) {
4721 pos += 18;
4722 auth->akm_use_selector = atoi(pos);
4723 }
4724
87d8435c
JM
4725 if (dpp_configuration_parse(auth, cmd) < 0) {
4726 wpa_msg(msg_ctx, MSG_INFO,
4727 "DPP: Failed to set configurator parameters");
de08fae6 4728 goto fail;
87d8435c 4729 }
de08fae6
JM
4730 ret = 0;
4731fail:
4732 os_free(tmp);
4733 return ret;
87d8435c
JM
4734}
4735
4736
ea91ddb0
JM
4737static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
4738{
4739 while (key) {
4740 struct dpp_asymmetric_key *next = key->next;
4741
4742 EVP_PKEY_free(key->csign);
4743 str_clear_free(key->config_template);
4744 str_clear_free(key->connector_template);
4745 os_free(key);
4746 key = next;
4747 }
4748}
4749
4750
30d27b04
JM
4751void dpp_auth_deinit(struct dpp_authentication *auth)
4752{
52d469de
JM
4753 unsigned int i;
4754
30d27b04
JM
4755 if (!auth)
4756 return;
461d39af 4757 dpp_configuration_free(auth->conf_ap);
7eb06a33 4758 dpp_configuration_free(auth->conf2_ap);
461d39af 4759 dpp_configuration_free(auth->conf_sta);
7eb06a33 4760 dpp_configuration_free(auth->conf2_sta);
30d27b04
JM
4761 EVP_PKEY_free(auth->own_protocol_key);
4762 EVP_PKEY_free(auth->peer_protocol_key);
dc4d271c
JM
4763 wpabuf_free(auth->req_msg);
4764 wpabuf_free(auth->resp_msg);
461d39af 4765 wpabuf_free(auth->conf_req);
52d469de
JM
4766 for (i = 0; i < auth->num_conf_obj; i++) {
4767 struct dpp_config_obj *conf = &auth->conf_obj[i];
4768
4769 os_free(conf->connector);
4770 wpabuf_free(conf->c_sign_key);
4771 }
ea91ddb0 4772 dpp_free_asymmetric_key(auth->conf_key_pkg);
461d39af 4773 wpabuf_free(auth->net_access_key);
73f21929 4774 dpp_bootstrap_info_free(auth->tmp_own_bi);
461d39af
JM
4775#ifdef CONFIG_TESTING_OPTIONS
4776 os_free(auth->config_obj_override);
4777 os_free(auth->discovery_override);
4778 os_free(auth->groups_override);
461d39af 4779#endif /* CONFIG_TESTING_OPTIONS */
30d27b04
JM
4780 bin_clear_free(auth, sizeof(*auth));
4781}
461d39af
JM
4782
4783
4784static struct wpabuf *
4785dpp_build_conf_start(struct dpp_authentication *auth,
4786 struct dpp_configuration *conf, size_t tailroom)
4787{
4788 struct wpabuf *buf;
461d39af
JM
4789
4790#ifdef CONFIG_TESTING_OPTIONS
4791 if (auth->discovery_override)
4792 tailroom += os_strlen(auth->discovery_override);
4793#endif /* CONFIG_TESTING_OPTIONS */
4794
4795 buf = wpabuf_alloc(200 + tailroom);
4796 if (!buf)
4797 return NULL;
590bc64d
JM
4798 json_start_object(buf, NULL);
4799 json_add_string(buf, "wi-fi_tech", "infra");
4800 json_value_sep(buf);
461d39af
JM
4801#ifdef CONFIG_TESTING_OPTIONS
4802 if (auth->discovery_override) {
4803 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'",
4804 auth->discovery_override);
590bc64d 4805 wpabuf_put_str(buf, "\"discovery\":");
461d39af 4806 wpabuf_put_str(buf, auth->discovery_override);
590bc64d 4807 json_value_sep(buf);
461d39af
JM
4808 return buf;
4809 }
4810#endif /* CONFIG_TESTING_OPTIONS */
590bc64d 4811 json_start_object(buf, "discovery");
71e2848e
JM
4812 if (((!conf->ssid_charset || auth->peer_version < 2) &&
4813 json_add_string_escape(buf, "ssid", conf->ssid,
4814 conf->ssid_len) < 0) ||
4815 ((conf->ssid_charset && auth->peer_version >= 2) &&
4816 json_add_base64url(buf, "ssid64", conf->ssid,
4817 conf->ssid_len) < 0)) {
590bc64d
JM
4818 wpabuf_free(buf);
4819 return NULL;
4820 }
71e2848e
JM
4821 if (conf->ssid_charset > 0) {
4822 json_value_sep(buf);
4823 json_add_int(buf, "ssid_charset", conf->ssid_charset);
4824 }
590bc64d
JM
4825 json_end_object(buf);
4826 json_value_sep(buf);
461d39af
JM
4827
4828 return buf;
4829}
4830
4831
461d39af
JM
4832static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
4833 const char *kid, const struct dpp_curve_params *curve)
4834{
4835 struct wpabuf *pub;
4836 const u8 *pos;
461d39af
JM
4837 int ret = -1;
4838
4839 pub = dpp_get_pubkey_point(key, 0);
4840 if (!pub)
4841 goto fail;
590bc64d
JM
4842
4843 json_start_object(buf, name);
4844 json_add_string(buf, "kty", "EC");
4845 json_value_sep(buf);
4846 json_add_string(buf, "crv", curve->jwk_crv);
4847 json_value_sep(buf);
461d39af 4848 pos = wpabuf_head(pub);
590bc64d
JM
4849 if (json_add_base64url(buf, "x", pos, curve->prime_len) < 0)
4850 goto fail;
4851 json_value_sep(buf);
461d39af 4852 pos += curve->prime_len;
590bc64d 4853 if (json_add_base64url(buf, "y", pos, curve->prime_len) < 0)
58efbcbc 4854 goto fail;
461d39af 4855 if (kid) {
590bc64d
JM
4856 json_value_sep(buf);
4857 json_add_string(buf, "kid", kid);
461d39af 4858 }
590bc64d 4859 json_end_object(buf);
461d39af 4860 ret = 0;
58efbcbc 4861fail:
461d39af 4862 wpabuf_free(pub);
461d39af 4863 return ret;
461d39af
JM
4864}
4865
4866
18015fc8
JM
4867static void dpp_build_legacy_cred_params(struct wpabuf *buf,
4868 struct dpp_configuration *conf)
4869{
4870 if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
590bc64d
JM
4871 json_add_string_escape(buf, "pass", conf->passphrase,
4872 os_strlen(conf->passphrase));
18015fc8
JM
4873 } else if (conf->psk_set) {
4874 char psk[2 * sizeof(conf->psk) + 1];
4875
4876 wpa_snprintf_hex(psk, sizeof(psk),
4877 conf->psk, sizeof(conf->psk));
590bc64d
JM
4878 json_add_string(buf, "psk_hex", psk);
4879 forced_memzero(psk, sizeof(psk));
18015fc8
JM
4880 }
4881}
4882
4883
99918e06
JM
4884static const char * dpp_netrole_str(enum dpp_netrole netrole)
4885{
4886 switch (netrole) {
4887 case DPP_NETROLE_STA:
4888 return "sta";
4889 case DPP_NETROLE_AP:
4890 return "ap";
5661ebd7
JM
4891 case DPP_NETROLE_CONFIGURATOR:
4892 return "configurator";
99918e06
JM
4893 default:
4894 return "??";
4895 }
4896}
4897
4898
461d39af 4899static struct wpabuf *
99918e06 4900dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
461d39af
JM
4901 struct dpp_configuration *conf)
4902{
4903 struct wpabuf *buf = NULL;
4904 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL;
4905 size_t tailroom;
4906 const struct dpp_curve_params *curve;
590bc64d 4907 struct wpabuf *jws_prot_hdr;
461d39af
JM
4908 size_t signed1_len, signed2_len, signed3_len;
4909 struct wpabuf *dppcon = NULL;
4910 unsigned char *signature = NULL;
4911 const unsigned char *p;
4912 size_t signature_len;
4913 EVP_MD_CTX *md_ctx = NULL;
4914 ECDSA_SIG *sig = NULL;
4915 char *dot = ".";
461d39af
JM
4916 const EVP_MD *sign_md;
4917 const BIGNUM *r, *s;
4918 size_t extra_len = 1000;
18015fc8
JM
4919 int incl_legacy;
4920 enum dpp_akm akm;
68fea960 4921 const char *akm_str;
461d39af
JM
4922
4923 if (!auth->conf) {
4924 wpa_printf(MSG_INFO,
4925 "DPP: No configurator specified - cannot generate DPP config object");
4926 goto fail;
4927 }
4928 curve = auth->conf->curve;
4929 if (curve->hash_len == SHA256_MAC_LEN) {
461d39af
JM
4930 sign_md = EVP_sha256();
4931 } else if (curve->hash_len == SHA384_MAC_LEN) {
461d39af
JM
4932 sign_md = EVP_sha384();
4933 } else if (curve->hash_len == SHA512_MAC_LEN) {
461d39af
JM
4934 sign_md = EVP_sha512();
4935 } else {
4936 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
4937 goto fail;
4938 }
4939
18015fc8
JM
4940 akm = conf->akm;
4941 if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
4942 wpa_printf(MSG_DEBUG,
4943 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4944 akm = DPP_AKM_DPP;
4945 }
4946
461d39af
JM
4947#ifdef CONFIG_TESTING_OPTIONS
4948 if (auth->groups_override)
4949 extra_len += os_strlen(auth->groups_override);
461d39af
JM
4950#endif /* CONFIG_TESTING_OPTIONS */
4951
20f612d9
PK
4952 if (conf->group_id)
4953 extra_len += os_strlen(conf->group_id);
4954
461d39af
JM
4955 /* Connector (JSON dppCon object) */
4956 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
4957 if (!dppcon)
4958 goto fail;
4959#ifdef CONFIG_TESTING_OPTIONS
a4bf0078 4960 if (auth->groups_override) {
461d39af
JM
4961 wpabuf_put_u8(dppcon, '{');
4962 if (auth->groups_override) {
4963 wpa_printf(MSG_DEBUG,
4964 "DPP: TESTING - groups override: '%s'",
4965 auth->groups_override);
4966 wpabuf_put_str(dppcon, "\"groups\":");
4967 wpabuf_put_str(dppcon, auth->groups_override);
590bc64d 4968 json_value_sep(dppcon);
461d39af 4969 }
461d39af
JM
4970 goto skip_groups;
4971 }
4972#endif /* CONFIG_TESTING_OPTIONS */
590bc64d
JM
4973 json_start_object(dppcon, NULL);
4974 json_start_array(dppcon, "groups");
4975 json_start_object(dppcon, NULL);
4976 json_add_string(dppcon, "groupId",
4977 conf->group_id ? conf->group_id : "*");
4978 json_value_sep(dppcon);
4979 json_add_string(dppcon, "netRole", dpp_netrole_str(conf->netrole));
4980 json_end_object(dppcon);
4981 json_end_array(dppcon);
4982 json_value_sep(dppcon);
461d39af
JM
4983#ifdef CONFIG_TESTING_OPTIONS
4984skip_groups:
4985#endif /* CONFIG_TESTING_OPTIONS */
4986 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
4987 auth->curve) < 0) {
4988 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
4989 goto fail;
4990 }
4991 if (conf->netaccesskey_expiry) {
4992 struct os_tm tm;
590bc64d 4993 char expiry[30];
461d39af
JM
4994
4995 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) {
4996 wpa_printf(MSG_DEBUG,
4997 "DPP: Failed to generate expiry string");
4998 goto fail;
4999 }
590bc64d
JM
5000 os_snprintf(expiry, sizeof(expiry),
5001 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5002 tm.year, tm.month, tm.day,
5003 tm.hour, tm.min, tm.sec);
5004 json_value_sep(dppcon);
5005 json_add_string(dppcon, "expiry", expiry);
5006 }
5007 json_end_object(dppcon);
461d39af
JM
5008 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s",
5009 (const char *) wpabuf_head(dppcon));
5010
590bc64d
JM
5011 jws_prot_hdr = wpabuf_alloc(100);
5012 if (!jws_prot_hdr)
5013 goto fail;
5014 json_start_object(jws_prot_hdr, NULL);
5015 json_add_string(jws_prot_hdr, "typ", "dppCon");
5016 json_value_sep(jws_prot_hdr);
5017 json_add_string(jws_prot_hdr, "kid", auth->conf->kid);
5018 json_value_sep(jws_prot_hdr);
5019 json_add_string(jws_prot_hdr, "alg", curve->jws_alg);
5020 json_end_object(jws_prot_hdr);
5021 signed1 = base64_url_encode(wpabuf_head(jws_prot_hdr),
5022 wpabuf_len(jws_prot_hdr),
b2260842 5023 &signed1_len);
590bc64d 5024 wpabuf_free(jws_prot_hdr);
b2260842
JM
5025 signed2 = base64_url_encode(wpabuf_head(dppcon), wpabuf_len(dppcon),
5026 &signed2_len);
461d39af
JM
5027 if (!signed1 || !signed2)
5028 goto fail;
5029
5030 md_ctx = EVP_MD_CTX_create();
5031 if (!md_ctx)
5032 goto fail;
5033
5034 ERR_clear_error();
5035 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL,
5036 auth->conf->csign) != 1) {
5037 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
5038 ERR_error_string(ERR_get_error(), NULL));
5039 goto fail;
5040 }
5041 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
5042 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
5043 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
5044 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
5045 ERR_error_string(ERR_get_error(), NULL));
5046 goto fail;
5047 }
5048 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
5049 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5050 ERR_error_string(ERR_get_error(), NULL));
5051 goto fail;
5052 }
5053 signature = os_malloc(signature_len);
5054 if (!signature)
5055 goto fail;
5056 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
5057 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
5058 ERR_error_string(ERR_get_error(), NULL));
5059 goto fail;
5060 }
5061 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
5062 signature, signature_len);
5063 /* Convert to raw coordinates r,s */
5064 p = signature;
5065 sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
5066 if (!sig)
5067 goto fail;
5068 ECDSA_SIG_get0(sig, &r, &s);
5069 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
5070 dpp_bn2bin_pad(s, signature + curve->prime_len,
5071 curve->prime_len) < 0)
5072 goto fail;
5073 signature_len = 2 * curve->prime_len;
5074 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
5075 signature, signature_len);
b2260842 5076 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
461d39af
JM
5077 if (!signed3)
5078 goto fail;
5079
18015fc8 5080 incl_legacy = dpp_akm_psk(akm) || dpp_akm_sae(akm);
461d39af
JM
5081 tailroom = 1000;
5082 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid);
5083 tailroom += signed1_len + signed2_len + signed3_len;
18015fc8
JM
5084 if (incl_legacy)
5085 tailroom += 1000;
461d39af
JM
5086 buf = dpp_build_conf_start(auth, conf, tailroom);
5087 if (!buf)
62293412 5088 goto fail;
461d39af 5089
68fea960
JM
5090 if (auth->akm_use_selector && dpp_akm_ver2(akm))
5091 akm_str = dpp_akm_selector_str(akm);
5092 else
5093 akm_str = dpp_akm_str(akm);
590bc64d
JM
5094 json_start_object(buf, "cred");
5095 json_add_string(buf, "akm", akm_str);
5096 json_value_sep(buf);
18015fc8
JM
5097 if (incl_legacy) {
5098 dpp_build_legacy_cred_params(buf, conf);
590bc64d 5099 json_value_sep(buf);
18015fc8
JM
5100 }
5101 wpabuf_put_str(buf, "\"signedConnector\":\"");
461d39af
JM
5102 wpabuf_put_str(buf, signed1);
5103 wpabuf_put_u8(buf, '.');
5104 wpabuf_put_str(buf, signed2);
5105 wpabuf_put_u8(buf, '.');
5106 wpabuf_put_str(buf, signed3);
590bc64d
JM
5107 wpabuf_put_str(buf, "\"");
5108 json_value_sep(buf);
461d39af
JM
5109 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid,
5110 curve) < 0) {
5111 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK");
5112 goto fail;
5113 }
461d39af 5114
590bc64d
JM
5115 json_end_object(buf);
5116 json_end_object(buf);
461d39af
JM
5117
5118 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
5119 wpabuf_head(buf), wpabuf_len(buf));
5120
5121out:
5122 EVP_MD_CTX_destroy(md_ctx);
5123 ECDSA_SIG_free(sig);
5124 os_free(signed1);
5125 os_free(signed2);
5126 os_free(signed3);
5127 os_free(signature);
5128 wpabuf_free(dppcon);
5129 return buf;
5130fail:
5131 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object");
5132 wpabuf_free(buf);
5133 buf = NULL;
5134 goto out;
5135}
5136
5137
5138static struct wpabuf *
99918e06 5139dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
461d39af
JM
5140 struct dpp_configuration *conf)
5141{
5142 struct wpabuf *buf;
68fea960 5143 const char *akm_str;
461d39af
JM
5144
5145 buf = dpp_build_conf_start(auth, conf, 1000);
5146 if (!buf)
5147 return NULL;
5148
68fea960
JM
5149 if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
5150 akm_str = dpp_akm_selector_str(conf->akm);
5151 else
5152 akm_str = dpp_akm_str(conf->akm);
590bc64d
JM
5153 json_start_object(buf, "cred");
5154 json_add_string(buf, "akm", akm_str);
5155 json_value_sep(buf);
18015fc8 5156 dpp_build_legacy_cred_params(buf, conf);
590bc64d
JM
5157 json_end_object(buf);
5158 json_end_object(buf);
461d39af
JM
5159
5160 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)",
5161 wpabuf_head(buf), wpabuf_len(buf));
5162
5163 return buf;
5164}
5165
5166
5167static struct wpabuf *
74045744
JM
5168dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
5169 int idx)
461d39af 5170{
74045744 5171 struct dpp_configuration *conf = NULL;
461d39af
JM
5172
5173#ifdef CONFIG_TESTING_OPTIONS
5174 if (auth->config_obj_override) {
7eb06a33
JM
5175 if (idx != 0)
5176 return NULL;
461d39af
JM
5177 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
5178 return wpabuf_alloc_copy(auth->config_obj_override,
5179 os_strlen(auth->config_obj_override));
5180 }
5181#endif /* CONFIG_TESTING_OPTIONS */
5182
74045744
JM
5183 if (idx == 0) {
5184 if (netrole == DPP_NETROLE_STA)
5185 conf = auth->conf_sta;
5186 else if (netrole == DPP_NETROLE_AP)
5187 conf = auth->conf_ap;
5188 } else if (idx == 1) {
5189 if (netrole == DPP_NETROLE_STA)
5190 conf = auth->conf2_sta;
5191 else if (netrole == DPP_NETROLE_AP)
5192 conf = auth->conf2_ap;
5193 }
461d39af 5194 if (!conf) {
9c08bfbd 5195 if (idx == 0)
7eb06a33
JM
5196 wpa_printf(MSG_DEBUG,
5197 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
74045744 5198 dpp_netrole_str(netrole));
461d39af
JM
5199 return NULL;
5200 }
5201
18015fc8 5202 if (dpp_akm_dpp(conf->akm))
99918e06
JM
5203 return dpp_build_conf_obj_dpp(auth, conf);
5204 return dpp_build_conf_obj_legacy(auth, conf);
461d39af
JM
5205}
5206
5207
c025c2eb
JM
5208#ifdef CONFIG_DPP2
5209
5210static struct wpabuf * dpp_build_conf_params(void)
5211{
5212 struct wpabuf *buf;
5213 size_t len;
5214 /* TODO: proper template values */
5215 const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5216 const char *connector_template = NULL;
5217
5218 len = 100 + os_strlen(conf_template);
5219 if (connector_template)
5220 len += os_strlen(connector_template);
5221 buf = wpabuf_alloc(len);
5222 if (!buf)
5223 return NULL;
5224
5225 /*
5226 * DPPConfigurationParameters ::= SEQUENCE {
5227 * configurationTemplate UTF8String,
5228 * connectorTemplate UTF8String OPTIONAL}
5229 */
5230
5231 asn1_put_utf8string(buf, conf_template);
5232 if (connector_template)
7aa47fe5 5233 asn1_put_utf8string(buf, connector_template);
c025c2eb
JM
5234 return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5235}
5236
5237
5238static struct wpabuf * dpp_build_attribute(void)
5239{
5240 struct wpabuf *conf_params, *attr;
5241
5242 /*
5243 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5244 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5245 *
5246 * Attribute ::= SEQUENCE {
5247 * type OBJECT IDENTIFIER,
5248 * values SET SIZE(1..MAX) OF Type
5249 */
5250 conf_params = dpp_build_conf_params();
5251 conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
5252 ASN1_TAG_SET);
5253 if (!conf_params)
5254 return NULL;
5255
5256 attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
5257 if (!attr) {
5258 wpabuf_clear_free(conf_params);
5259 return NULL;
5260 }
5261
5262 asn1_put_oid(attr, &asn1_dpp_config_params_oid);
5263 wpabuf_put_buf(attr, conf_params);
5264 wpabuf_clear_free(conf_params);
5265
5266 return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5267}
5268
5269
5270static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
5271{
5272 const struct asn1_oid *oid;
5273 struct wpabuf *params, *res;
5274
5275 switch (curve->ike_group) {
5276 case 19:
5277 oid = &asn1_prime256v1_oid;
5278 break;
5279 case 20:
5280 oid = &asn1_secp384r1_oid;
5281 break;
5282 case 21:
5283 oid = &asn1_secp521r1_oid;
5284 break;
5285 case 28:
5286 oid = &asn1_brainpoolP256r1_oid;
5287 break;
5288 case 29:
5289 oid = &asn1_brainpoolP384r1_oid;
5290 break;
5291 case 30:
5292 oid = &asn1_brainpoolP512r1_oid;
5293 break;
5294 default:
5295 return NULL;
5296 }
5297
5298 params = wpabuf_alloc(20);
5299 if (!params)
5300 return NULL;
5301 asn1_put_oid(params, oid); /* namedCurve */
5302
5303 res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
5304 wpabuf_free(params);
5305 return res;
5306}
5307
5308
5309static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
5310{
5311 struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
5312 EC_KEY *eckey;
5313 unsigned char *der = NULL;
5314 int der_len;
5315
5316 eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
5317 if (!eckey)
5318 return NULL;
5319
5320 EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
5321 der_len = i2d_ECPrivateKey(eckey, &der);
5322 if (der_len > 0)
5323 priv_key = wpabuf_alloc_copy(der, der_len);
5324 OPENSSL_free(der);
5325
5326 alg = dpp_build_key_alg(auth->conf->curve);
5327
5328 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5329 attr = dpp_build_attribute();
5330 attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
5331 if (!priv_key || !attr || !alg)
5332 goto fail;
5333
5334 /*
5335 * OneAsymmetricKey ::= SEQUENCE {
5336 * version Version,
5337 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5338 * privateKey PrivateKey,
5339 * attributes [0] Attributes OPTIONAL,
5340 * ...,
5341 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5342 * ...
5343 * }
5344 */
5345
5346 key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
5347 wpabuf_len(attr));
5348 if (!key)
5349 goto fail;
5350
5351 asn1_put_integer(key, 1); /* version = v2(1) */
5352
5353 /* PrivateKeyAlgorithmIdentifier */
5354 wpabuf_put_buf(key, alg);
5355
5356 /* PrivateKey ::= OCTET STRING */
5357 asn1_put_octet_string(key, priv_key);
5358
5359 /* [0] Attributes OPTIONAL */
5360 asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
5361 wpabuf_put_buf(key, attr);
5362
5363fail:
5364 wpabuf_clear_free(attr);
5365 wpabuf_clear_free(priv_key);
5366 wpabuf_free(alg);
5367
5368 /*
5369 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5370 *
5371 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5372 *
5373 * OneAsymmetricKey ::= SEQUENCE
5374 */
5375 return asn1_encaps(asn1_encaps(key,
5376 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
5377 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
c025c2eb
JM
5378}
5379
5380
5381static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
5382 size_t hash_len)
5383{
5384 struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
5385 const struct asn1_oid *oid;
5386
5387 /*
5388 * PBKDF2-params ::= SEQUENCE {
5389 * salt CHOICE {
5390 * specified OCTET STRING,
5391 * otherSource AlgorithmIdentifier}
5392 * iterationCount INTEGER (1..MAX),
5393 * keyLength INTEGER (1..MAX),
5394 * prf AlgorithmIdentifier}
5395 *
5396 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5397 * on Configurator signing key length, prf is
5398 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5399 */
5400
5401 if (hash_len == 32)
5402 oid = &asn1_pbkdf2_hmac_sha256_oid;
5403 else if (hash_len == 48)
5404 oid = &asn1_pbkdf2_hmac_sha384_oid;
5405 else if (hash_len == 64)
5406 oid = &asn1_pbkdf2_hmac_sha512_oid;
5407 else
5408 goto fail;
5409 prf = asn1_build_alg_id(oid, NULL);
5410 if (!prf)
5411 goto fail;
5412 params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
5413 if (!params)
5414 goto fail;
5415 asn1_put_octet_string(params, salt); /* salt.specified */
5416 asn1_put_integer(params, 1000); /* iterationCount */
5417 asn1_put_integer(params, hash_len); /* keyLength */
5418 wpabuf_put_buf(params, prf);
5419 params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5420 if (!params)
5421 goto fail;
5422 buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
5423fail:
5424 wpabuf_free(params);
5425 wpabuf_free(prf);
5426 return buf;
5427}
5428
5429
5430static struct wpabuf *
5431dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5432 const struct wpabuf *cont_enc_key)
5433{
5434 struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
5435 *key_enc_alg = NULL, *salt;
5436 u8 kek[DPP_MAX_HASH_LEN];
5437 const u8 *key;
5438 size_t key_len;
5439
5440 salt = wpabuf_alloc(64);
5441 if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
5442 goto fail;
5443 wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
5444
5445 /* TODO: For initial testing, use ke as the key. Replace this with a
5446 * new key once that has been defined. */
5447 key = auth->ke;
5448 key_len = auth->curve->hash_len;
5449 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
5450
5451 if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
5452 kek, hash_len)) {
5453 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
5454 goto fail;
5455 }
5456 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
5457 kek, hash_len);
5458
5459 enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
5460 if (!enc_key ||
5461 aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
5462 wpabuf_len(cont_enc_key), 0, NULL, NULL,
5463 wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
5464 goto fail;
5465 wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
5466
5467 /*
5468 * PasswordRecipientInfo ::= SEQUENCE {
5469 * version CMSVersion,
5470 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5471 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5472 * encryptedKey EncryptedKey}
5473 *
5474 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5475 * parameters contains PBKDF2-params SEQUENCE.
5476 */
5477
5478 key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
5479 key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
5480 if (!key_der_alg || !key_enc_alg)
5481 goto fail;
5482 pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
5483 wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
5484 if (!pwri)
5485 goto fail;
5486
5487 /* version = 0 */
5488 asn1_put_integer(pwri, 0);
5489
5490 /* [0] KeyDerivationAlgorithmIdentifier */
5491 asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
5492 wpabuf_len(key_der_alg));
5493 wpabuf_put_buf(pwri, key_der_alg);
5494
5495 /* KeyEncryptionAlgorithmIdentifier */
5496 wpabuf_put_buf(pwri, key_enc_alg);
5497
5498 /* EncryptedKey ::= OCTET STRING */
5499 asn1_put_octet_string(pwri, enc_key);
5500
5501fail:
5502 wpabuf_clear_free(key_der_alg);
5503 wpabuf_free(key_enc_alg);
5504 wpabuf_free(enc_key);
5505 wpabuf_free(salt);
5506 forced_memzero(kek, sizeof(kek));
5507 return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5508}
5509
5510
5511static struct wpabuf *
5512dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
5513 const struct wpabuf *cont_enc_key)
5514{
5515 struct wpabuf *pwri;
5516
5517 /*
5518 * RecipientInfo ::= CHOICE {
5519 * ktri KeyTransRecipientInfo,
5520 * kari [1] KeyAgreeRecipientInfo,
5521 * kekri [2] KEKRecipientInfo,
5522 * pwri [3] PasswordRecipientInfo,
5523 * ori [4] OtherRecipientInfo}
5524 *
5525 * Shall always use the pwri CHOICE.
5526 */
5527
5528 pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
5529 return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
5530}
5531
5532
5533static struct wpabuf *
5534dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
5535 const struct wpabuf *cont_enc_key)
5536{
5537 struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
5538 *enc_alg;
5539 const struct asn1_oid *oid;
5540 size_t enc_cont_len;
5541
5542 /*
5543 * EncryptedContentInfo ::= SEQUENCE {
5544 * contentType ContentType,
5545 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5546 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5547 */
5548
5549 if (hash_len == 32)
5550 oid = &asn1_aes_siv_cmac_aead_256_oid;
5551 else if (hash_len == 48)
5552 oid = &asn1_aes_siv_cmac_aead_384_oid;
5553 else if (hash_len == 64)
5554 oid = &asn1_aes_siv_cmac_aead_512_oid;
5555 else
5556 return NULL;
5557
5558 key_pkg = dpp_build_key_pkg(auth);
5559 enc_alg = asn1_build_alg_id(oid, NULL);
5560 if (!key_pkg || !enc_alg)
5561 goto fail;
5562
5563 wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
5564 key_pkg);
5565
5566 enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
5567 enc_cont = wpabuf_alloc(enc_cont_len);
5568 if (!enc_cont ||
5569 aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
5570 wpabuf_head(key_pkg), wpabuf_len(key_pkg),
5571 0, NULL, NULL,
5572 wpabuf_put(enc_cont, enc_cont_len)) < 0)
5573 goto fail;
5574
5575 enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
5576 wpabuf_len(enc_cont));
5577 if (!enc_cont_info)
5578 goto fail;
5579
5580 /* ContentType ::= OBJECT IDENTIFIER */
5581 asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
5582
5583 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5584 wpabuf_put_buf(enc_cont_info, enc_alg);
5585
5586 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5587 * EncryptedContent ::= OCTET STRING */
c248ebaf 5588 asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
c025c2eb
JM
5589 wpabuf_len(enc_cont));
5590 wpabuf_put_buf(enc_cont_info, enc_cont);
5591
5592fail:
5593 wpabuf_clear_free(key_pkg);
5594 wpabuf_free(enc_cont);
5595 wpabuf_free(enc_alg);
5596 return enc_cont_info;
5597}
5598
5599
5600static struct wpabuf * dpp_gen_random(size_t len)
5601{
5602 struct wpabuf *key;
5603
5604 key = wpabuf_alloc(len);
5605 if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
5606 wpabuf_free(key);
5607 key = NULL;
5608 }
5609 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
5610 return key;
5611}
5612
5613
5614static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
5615{
5616 struct wpabuf *env = NULL;
5617 struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
5618 struct wpabuf *cont_enc_key = NULL;
5619 size_t hash_len;
5620
5621 if (!auth->conf) {
5622 wpa_printf(MSG_DEBUG,
5623 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5624 return NULL;
5625 }
5626
e2b1e7dc
JM
5627 if (!auth->provision_configurator) {
5628 wpa_printf(MSG_DEBUG,
5629 "DPP: Configurator provisioning not allowed");
5630 return NULL;
5631 }
5632
c025c2eb
JM
5633 wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
5634
5635 hash_len = auth->conf->curve->hash_len;
5636 cont_enc_key = dpp_gen_random(hash_len);
5637 if (!cont_enc_key)
5638 goto fail;
5639 recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
5640 enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
5641 if (!recipient_info || !enc_cont_info)
5642 goto fail;
5643
5644 env = wpabuf_alloc(wpabuf_len(recipient_info) +
5645 wpabuf_len(enc_cont_info) +
5646 100);
5647 if (!env)
5648 goto fail;
5649
5650 /*
5651 * DPPEnvelopedData ::= EnvelopedData
5652 *
5653 * EnvelopedData ::= SEQUENCE {
5654 * version CMSVersion,
5655 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5656 * recipientInfos RecipientInfos,
5657 * encryptedContentInfo EncryptedContentInfo,
5658 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5659 *
5660 * For DPP, version is 3, both originatorInfo and
5661 * unprotectedAttrs are omitted, and recipientInfos contains a single
5662 * RecipientInfo.
5663 */
5664
5665 /* EnvelopedData.version = 3 */
5666 asn1_put_integer(env, 3);
5667
5668 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5669 asn1_put_set(env, recipient_info);
5670
5671 /* EncryptedContentInfo ::= SEQUENCE */
5672 asn1_put_sequence(env, enc_cont_info);
5673
5674 env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
5675 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
5676out:
5677 wpabuf_clear_free(cont_enc_key);
5678 wpabuf_clear_free(recipient_info);
5679 wpabuf_free(enc_cont_info);
5680 return env;
5681fail:
5682 wpabuf_free(env);
5683 env = NULL;
5684 goto out;
5685}
5686
5687#endif /* CONFIG_DPP2 */
5688
5689
461d39af
JM
5690static struct wpabuf *
5691dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
74045744 5692 u16 e_nonce_len, enum dpp_netrole netrole)
461d39af 5693{
c025c2eb 5694 struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
60239f60 5695 size_t clear_len, attr_len;
461d39af
JM
5696 struct wpabuf *clear = NULL, *msg = NULL;
5697 u8 *wrapped;
5698 const u8 *addr[1];
5699 size_t len[1];
5700 enum dpp_status_error status;
5701
c025c2eb
JM
5702 if (netrole == DPP_NETROLE_CONFIGURATOR) {
5703#ifdef CONFIG_DPP2
5704 env_data = dpp_build_enveloped_data(auth);
5705#endif /* CONFIG_DPP2 */
5706 } else {
5707 conf = dpp_build_conf_obj(auth, netrole, 0);
5708 if (conf) {
5709 wpa_hexdump_ascii(MSG_DEBUG,
5710 "DPP: configurationObject JSON",
5711 wpabuf_head(conf), wpabuf_len(conf));
5712 conf2 = dpp_build_conf_obj(auth, netrole, 1);
5713 }
461d39af 5714 }
c025c2eb
JM
5715 status = (conf || env_data) ? DPP_STATUS_OK :
5716 DPP_STATUS_CONFIGURE_FAILURE;
22f90b32 5717 auth->conf_resp_status = status;
461d39af 5718
b10e01a7 5719 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
461d39af
JM
5720 clear_len = 4 + e_nonce_len;
5721 if (conf)
5722 clear_len += 4 + wpabuf_len(conf);
7eb06a33
JM
5723 if (conf2)
5724 clear_len += 4 + wpabuf_len(conf2);
c025c2eb
JM
5725 if (env_data)
5726 clear_len += 4 + wpabuf_len(env_data);
74045744
JM
5727 if (auth->peer_version >= 2 && auth->send_conn_status &&
5728 netrole == DPP_NETROLE_STA)
b10e01a7 5729 clear_len += 4;
461d39af 5730 clear = wpabuf_alloc(clear_len);
60239f60
JM
5731 attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
5732#ifdef CONFIG_TESTING_OPTIONS
5733 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP)
acdf703d 5734 attr_len += 5;
60239f60
JM
5735#endif /* CONFIG_TESTING_OPTIONS */
5736 msg = wpabuf_alloc(attr_len);
461d39af
JM
5737 if (!clear || !msg)
5738 goto fail;
5739
f411ad1b
JM
5740#ifdef CONFIG_TESTING_OPTIONS
5741 if (dpp_test == DPP_TEST_NO_E_NONCE_CONF_RESP) {
5742 wpa_printf(MSG_INFO, "DPP: TESTING - no E-nonce");
5743 goto skip_e_nonce;
5744 }
af7f10fc
JM
5745 if (dpp_test == DPP_TEST_E_NONCE_MISMATCH_CONF_RESP) {
5746 wpa_printf(MSG_INFO, "DPP: TESTING - E-nonce mismatch");
5747 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5748 wpabuf_put_le16(clear, e_nonce_len);
5749 wpabuf_put_data(clear, e_nonce, e_nonce_len - 1);
5750 wpabuf_put_u8(clear, e_nonce[e_nonce_len - 1] ^ 0x01);
5751 goto skip_e_nonce;
5752 }
f411ad1b
JM
5753 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_CONF_RESP) {
5754 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
5755 goto skip_wrapped_data;
5756 }
5757#endif /* CONFIG_TESTING_OPTIONS */
5758
461d39af
JM
5759 /* E-nonce */
5760 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
5761 wpabuf_put_le16(clear, e_nonce_len);
5762 wpabuf_put_data(clear, e_nonce, e_nonce_len);
5763
f411ad1b
JM
5764#ifdef CONFIG_TESTING_OPTIONS
5765skip_e_nonce:
5766 if (dpp_test == DPP_TEST_NO_CONFIG_OBJ_CONF_RESP) {
5767 wpa_printf(MSG_INFO, "DPP: TESTING - Config Object");
5768 goto skip_config_obj;
5769 }
5770#endif /* CONFIG_TESTING_OPTIONS */
5771
461d39af
JM
5772 if (conf) {
5773 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5774 wpabuf_put_le16(clear, wpabuf_len(conf));
5775 wpabuf_put_buf(clear, conf);
461d39af 5776 }
7eb06a33
JM
5777 if (auth->peer_version >= 2 && conf2) {
5778 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
5779 wpabuf_put_le16(clear, wpabuf_len(conf2));
5780 wpabuf_put_buf(clear, conf2);
5781 } else if (conf2) {
5782 wpa_printf(MSG_DEBUG,
5783 "DPP: Second Config Object available, but peer does not support more than one");
5784 }
c025c2eb
JM
5785 if (env_data) {
5786 wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA);
5787 wpabuf_put_le16(clear, wpabuf_len(env_data));
5788 wpabuf_put_buf(clear, env_data);
5789 }
461d39af 5790
74045744
JM
5791 if (auth->peer_version >= 2 && auth->send_conn_status &&
5792 netrole == DPP_NETROLE_STA) {
b10e01a7
JM
5793 wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
5794 wpabuf_put_le16(clear, DPP_ATTR_SEND_CONN_STATUS);
5795 wpabuf_put_le16(clear, 0);
5796 }
5797
f411ad1b
JM
5798#ifdef CONFIG_TESTING_OPTIONS
5799skip_config_obj:
5800 if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
5801 wpa_printf(MSG_INFO, "DPP: TESTING - Status");
5802 goto skip_status;
5803 }
af7f10fc
JM
5804 if (dpp_test == DPP_TEST_INVALID_STATUS_CONF_RESP) {
5805 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
5806 status = 255;
5807 }
f411ad1b
JM
5808#endif /* CONFIG_TESTING_OPTIONS */
5809
461d39af 5810 /* DPP Status */
56f24d1d 5811 dpp_build_attr_status(msg, status);
461d39af 5812
f411ad1b
JM
5813#ifdef CONFIG_TESTING_OPTIONS
5814skip_status:
5815#endif /* CONFIG_TESTING_OPTIONS */
5816
461d39af
JM
5817 addr[0] = wpabuf_head(msg);
5818 len[0] = wpabuf_len(msg);
5819 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
5820
5821 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
5822 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5823 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
5824
5825 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
5826 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
5827 wpabuf_head(clear), wpabuf_len(clear),
5828 1, addr, len, wrapped) < 0)
5829 goto fail;
5830 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5831 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
461d39af 5832
60239f60
JM
5833#ifdef CONFIG_TESTING_OPTIONS
5834 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) {
5835 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 5836 dpp_build_attr_status(msg, DPP_STATUS_OK);
60239f60 5837 }
f411ad1b 5838skip_wrapped_data:
60239f60
JM
5839#endif /* CONFIG_TESTING_OPTIONS */
5840
461d39af
JM
5841 wpa_hexdump_buf(MSG_DEBUG,
5842 "DPP: Configuration Response attributes", msg);
f411ad1b 5843out:
c025c2eb
JM
5844 wpabuf_clear_free(conf);
5845 wpabuf_clear_free(conf2);
5846 wpabuf_clear_free(env_data);
5847 wpabuf_clear_free(clear);
f411ad1b
JM
5848
5849 return msg;
5850fail:
461d39af 5851 wpabuf_free(msg);
f411ad1b
JM
5852 msg = NULL;
5853 goto out;
461d39af
JM
5854}
5855
5856
5857struct wpabuf *
5858dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
5859 size_t attr_len)
5860{
5861 const u8 *wrapped_data, *e_nonce, *config_attr;
5862 u16 wrapped_data_len, e_nonce_len, config_attr_len;
5863 u8 *unwrapped = NULL;
5864 size_t unwrapped_len = 0;
5865 struct wpabuf *resp = NULL;
5866 struct json_token *root = NULL, *token;
74045744 5867 enum dpp_netrole netrole;
461d39af 5868
34603767
JM
5869#ifdef CONFIG_TESTING_OPTIONS
5870 if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
5871 wpa_printf(MSG_INFO,
5872 "DPP: TESTING - stop at Config Request");
5873 return NULL;
5874 }
5875#endif /* CONFIG_TESTING_OPTIONS */
5876
461d39af 5877 if (dpp_check_attrs(attr_start, attr_len) < 0) {
8c99e626 5878 dpp_auth_fail(auth, "Invalid attribute in config request");
461d39af
JM
5879 return NULL;
5880 }
5881
5882 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
5883 &wrapped_data_len);
5884 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
5885 dpp_auth_fail(auth,
5886 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
5887 return NULL;
5888 }
5889
5890 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
5891 wrapped_data, wrapped_data_len);
5892 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
5893 unwrapped = os_malloc(unwrapped_len);
5894 if (!unwrapped)
5895 return NULL;
5896 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
5897 wrapped_data, wrapped_data_len,
5898 0, NULL, NULL, unwrapped) < 0) {
8c99e626 5899 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
5900 goto fail;
5901 }
5902 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
5903 unwrapped, unwrapped_len);
5904
5905 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 5906 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
5907 goto fail;
5908 }
5909
5910 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
5911 DPP_ATTR_ENROLLEE_NONCE,
5912 &e_nonce_len);
5913 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
5914 dpp_auth_fail(auth,
5915 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
5916 goto fail;
5917 }
5918 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
22f90b32 5919 os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
461d39af
JM
5920
5921 config_attr = dpp_get_attr(unwrapped, unwrapped_len,
5922 DPP_ATTR_CONFIG_ATTR_OBJ,
5923 &config_attr_len);
5924 if (!config_attr) {
8c99e626
JM
5925 dpp_auth_fail(auth,
5926 "Missing or invalid Config Attributes attribute");
461d39af
JM
5927 goto fail;
5928 }
5929 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes",
5930 config_attr, config_attr_len);
5931
5932 root = json_parse((const char *) config_attr, config_attr_len);
5933 if (!root) {
8c99e626 5934 dpp_auth_fail(auth, "Could not parse Config Attributes");
461d39af
JM
5935 goto fail;
5936 }
5937
5938 token = json_get_member(root, "name");
5939 if (!token || token->type != JSON_STRING) {
8c99e626 5940 dpp_auth_fail(auth, "No Config Attributes - name");
461d39af
JM
5941 goto fail;
5942 }
5943 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string);
5944
5945 token = json_get_member(root, "wi-fi_tech");
5946 if (!token || token->type != JSON_STRING) {
8c99e626 5947 dpp_auth_fail(auth, "No Config Attributes - wi-fi_tech");
461d39af
JM
5948 goto fail;
5949 }
5950 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string);
5951 if (os_strcmp(token->string, "infra") != 0) {
5952 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'",
5953 token->string);
8c99e626 5954 dpp_auth_fail(auth, "Unsupported wi-fi_tech");
461d39af
JM
5955 goto fail;
5956 }
5957
5958 token = json_get_member(root, "netRole");
5959 if (!token || token->type != JSON_STRING) {
8c99e626 5960 dpp_auth_fail(auth, "No Config Attributes - netRole");
461d39af
JM
5961 goto fail;
5962 }
5963 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string);
5964 if (os_strcmp(token->string, "sta") == 0) {
74045744 5965 netrole = DPP_NETROLE_STA;
461d39af 5966 } else if (os_strcmp(token->string, "ap") == 0) {
74045744 5967 netrole = DPP_NETROLE_AP;
5661ebd7
JM
5968 } else if (os_strcmp(token->string, "configurator") == 0) {
5969 netrole = DPP_NETROLE_CONFIGURATOR;
461d39af
JM
5970 } else {
5971 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'",
5972 token->string);
8c99e626 5973 dpp_auth_fail(auth, "Unsupported netRole");
461d39af
JM
5974 goto fail;
5975 }
5976
5a5639b0
JM
5977 token = json_get_member(root, "mudurl");
5978 if (token && token->type == JSON_STRING)
5979 wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string);
5980
f32aa244
JM
5981 token = json_get_member(root, "bandSupport");
5982 if (token && token->type == JSON_ARRAY) {
5983 wpa_printf(MSG_DEBUG, "DPP: bandSupport");
5984 token = token->child;
5985 while (token) {
5986 if (token->type != JSON_NUMBER)
5987 wpa_printf(MSG_DEBUG,
5988 "DPP: Invalid bandSupport array member type");
5989 else
5990 wpa_printf(MSG_DEBUG,
5991 "DPP: Supported global operating class: %d",
5992 token->number);
5993 token = token->sibling;
5994 }
5995 }
5996
74045744 5997 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole);
461d39af
JM
5998
5999fail:
6000 json_free(root);
6001 os_free(unwrapped);
6002 return resp;
6003}
6004
6005
6006static struct wpabuf *
6095b479
JM
6007dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
6008 const u8 *prot_hdr, u16 prot_hdr_len,
461d39af
JM
6009 const EVP_MD **ret_md)
6010{
6011 struct json_token *root, *token;
6012 struct wpabuf *kid = NULL;
6013
6014 root = json_parse((const char *) prot_hdr, prot_hdr_len);
6015 if (!root) {
6016 wpa_printf(MSG_DEBUG,
6017 "DPP: JSON parsing failed for JWS Protected Header");
6018 goto fail;
6019 }
6020
6021 if (root->type != JSON_OBJECT) {
6022 wpa_printf(MSG_DEBUG,
6023 "DPP: JWS Protected Header root is not an object");
6024 goto fail;
6025 }
6026
6027 token = json_get_member(root, "typ");
6028 if (!token || token->type != JSON_STRING) {
6029 wpa_printf(MSG_DEBUG, "DPP: No typ string value found");
6030 goto fail;
6031 }
6032 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s",
6033 token->string);
6034 if (os_strcmp(token->string, "dppCon") != 0) {
6035 wpa_printf(MSG_DEBUG,
6036 "DPP: Unsupported JWS Protected Header typ=%s",
6037 token->string);
6038 goto fail;
6039 }
6040
6041 token = json_get_member(root, "alg");
6042 if (!token || token->type != JSON_STRING) {
6043 wpa_printf(MSG_DEBUG, "DPP: No alg string value found");
6044 goto fail;
6045 }
6046 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s",
6047 token->string);
6095b479
JM
6048 if (os_strcmp(token->string, curve->jws_alg) != 0) {
6049 wpa_printf(MSG_DEBUG,
6050 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6051 token->string, curve->jws_alg);
6052 goto fail;
6053 }
31f03cb0
JM
6054 if (os_strcmp(token->string, "ES256") == 0 ||
6055 os_strcmp(token->string, "BS256") == 0)
461d39af 6056 *ret_md = EVP_sha256();
31f03cb0
JM
6057 else if (os_strcmp(token->string, "ES384") == 0 ||
6058 os_strcmp(token->string, "BS384") == 0)
461d39af 6059 *ret_md = EVP_sha384();
31f03cb0
JM
6060 else if (os_strcmp(token->string, "ES512") == 0 ||
6061 os_strcmp(token->string, "BS512") == 0)
461d39af
JM
6062 *ret_md = EVP_sha512();
6063 else
6064 *ret_md = NULL;
6065 if (!*ret_md) {
6066 wpa_printf(MSG_DEBUG,
6067 "DPP: Unsupported JWS Protected Header alg=%s",
6068 token->string);
6069 goto fail;
6070 }
6071
6072 kid = json_get_member_base64url(root, "kid");
6073 if (!kid) {
6074 wpa_printf(MSG_DEBUG, "DPP: No kid string value found");
6075 goto fail;
6076 }
6077 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)",
6078 kid);
6079
6080fail:
6081 json_free(root);
6082 return kid;
6083}
6084
6085
52d469de 6086static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
461d39af
JM
6087 struct json_token *cred)
6088{
6089 struct json_token *pass, *psk_hex;
461d39af
JM
6090
6091 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential");
6092
6093 pass = json_get_member(cred, "pass");
6094 psk_hex = json_get_member(cred, "psk_hex");
6095
6096 if (pass && pass->type == JSON_STRING) {
8528994e
JM
6097 size_t len = os_strlen(pass->string);
6098
461d39af 6099 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
8528994e
JM
6100 pass->string, len);
6101 if (len < 8 || len > 63)
6102 return -1;
52d469de
JM
6103 os_strlcpy(conf->passphrase, pass->string,
6104 sizeof(conf->passphrase));
461d39af 6105 } else if (psk_hex && psk_hex->type == JSON_STRING) {
52d469de 6106 if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
5dd745b7
JM
6107 wpa_printf(MSG_DEBUG,
6108 "DPP: Unexpected psk_hex with akm=sae");
6109 return -1;
6110 }
8528994e 6111 if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
52d469de 6112 hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
461d39af
JM
6113 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
6114 return -1;
6115 }
8528994e 6116 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
52d469de
JM
6117 conf->psk, PMK_LEN);
6118 conf->psk_set = 1;
461d39af
JM
6119 } else {
6120 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
6121 return -1;
6122 }
6123
52d469de 6124 if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
5dd745b7
JM
6125 wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
6126 return -1;
6127 }
6128
461d39af
JM
6129 return 0;
6130}
6131
6132
6133static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
6134 const struct dpp_curve_params **key_curve)
6135{
6136 struct json_token *token;
6137 const struct dpp_curve_params *curve;
6138 struct wpabuf *x = NULL, *y = NULL;
6139 EC_GROUP *group;
6140 EVP_PKEY *pkey = NULL;
6141
6142 token = json_get_member(jwk, "kty");
6143 if (!token || token->type != JSON_STRING) {
6144 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK");
6145 goto fail;
6146 }
6147 if (os_strcmp(token->string, "EC") != 0) {
06e62e11 6148 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s'",
461d39af
JM
6149 token->string);
6150 goto fail;
6151 }
6152
6153 token = json_get_member(jwk, "crv");
6154 if (!token || token->type != JSON_STRING) {
6155 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK");
6156 goto fail;
6157 }
6158 curve = dpp_get_curve_jwk_crv(token->string);
6159 if (!curve) {
6160 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'",
6161 token->string);
6162 goto fail;
6163 }
6164
6165 x = json_get_member_base64url(jwk, "x");
6166 if (!x) {
6167 wpa_printf(MSG_DEBUG, "DPP: No x in JWK");
6168 goto fail;
6169 }
f1f4fa79 6170 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x);
461d39af
JM
6171 if (wpabuf_len(x) != curve->prime_len) {
6172 wpa_printf(MSG_DEBUG,
f1f4fa79 6173 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
461d39af
JM
6174 (unsigned int) wpabuf_len(x),
6175 (unsigned int) curve->prime_len, curve->name);
6176 goto fail;
6177 }
6178
6179 y = json_get_member_base64url(jwk, "y");
6180 if (!y) {
6181 wpa_printf(MSG_DEBUG, "DPP: No y in JWK");
6182 goto fail;
6183 }
f1f4fa79 6184 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y);
461d39af
JM
6185 if (wpabuf_len(y) != curve->prime_len) {
6186 wpa_printf(MSG_DEBUG,
f1f4fa79 6187 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
461d39af
JM
6188 (unsigned int) wpabuf_len(y),
6189 (unsigned int) curve->prime_len, curve->name);
6190 goto fail;
6191 }
6192
6193 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
6194 if (!group) {
6195 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
6196 goto fail;
6197 }
6198
6199 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
6200 wpabuf_len(x));
57ec74ea 6201 EC_GROUP_free(group);
461d39af
JM
6202 *key_curve = curve;
6203
6204fail:
6205 wpabuf_free(x);
6206 wpabuf_free(y);
6207
6208 return pkey;
6209}
6210
6211
6212int dpp_key_expired(const char *timestamp, os_time_t *expiry)
6213{
6214 struct os_time now;
6215 unsigned int year, month, day, hour, min, sec;
6216 os_time_t utime;
6217 const char *pos;
6218
6219 /* ISO 8601 date and time:
6220 * <date>T<time>
6221 * YYYY-MM-DDTHH:MM:SSZ
6222 * YYYY-MM-DDTHH:MM:SS+03:00
6223 */
6224 if (os_strlen(timestamp) < 19) {
6225 wpa_printf(MSG_DEBUG,
6226 "DPP: Too short timestamp - assume expired key");
6227 return 1;
6228 }
6229 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u",
6230 &year, &month, &day, &hour, &min, &sec) != 6) {
6231 wpa_printf(MSG_DEBUG,
6232 "DPP: Failed to parse expiration day - assume expired key");
6233 return 1;
6234 }
6235
6236 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) {
6237 wpa_printf(MSG_DEBUG,
6238 "DPP: Invalid date/time information - assume expired key");
6239 return 1;
6240 }
6241
6242 pos = timestamp + 19;
6243 if (*pos == 'Z' || *pos == '\0') {
6244 /* In UTC - no need to adjust */
6245 } else if (*pos == '-' || *pos == '+') {
6246 int items;
6247
6248 /* Adjust local time to UTC */
6249 items = sscanf(pos + 1, "%02u:%02u", &hour, &min);
6250 if (items < 1) {
6251 wpa_printf(MSG_DEBUG,
6252 "DPP: Invalid time zone designator (%s) - assume expired key",
6253 pos);
6254 return 1;
6255 }
6256 if (*pos == '-')
6257 utime += 3600 * hour;
6258 if (*pos == '+')
6259 utime -= 3600 * hour;
6260 if (items > 1) {
6261 if (*pos == '-')
6262 utime += 60 * min;
6263 if (*pos == '+')
6264 utime -= 60 * min;
6265 }
6266 } else {
6267 wpa_printf(MSG_DEBUG,
6268 "DPP: Invalid time zone designator (%s) - assume expired key",
6269 pos);
6270 return 1;
6271 }
6272 if (expiry)
6273 *expiry = utime;
6274
6275 if (os_get_time(&now) < 0) {
6276 wpa_printf(MSG_DEBUG,
6277 "DPP: Cannot get current time - assume expired key");
6278 return 1;
6279 }
6280
6281 if (now.sec > utime) {
6282 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)",
6283 utime, now.sec);
6284 return 1;
6285 }
6286
6287 return 0;
6288}
6289
6290
6291static int dpp_parse_connector(struct dpp_authentication *auth,
52d469de 6292 struct dpp_config_obj *conf,
461d39af
JM
6293 const unsigned char *payload,
6294 u16 payload_len)
6295{
a4bf0078 6296 struct json_token *root, *groups, *netkey, *token;
461d39af
JM
6297 int ret = -1;
6298 EVP_PKEY *key = NULL;
6299 const struct dpp_curve_params *curve;
6300 unsigned int rules = 0;
6301
6302 root = json_parse((const char *) payload, payload_len);
6303 if (!root) {
6304 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
6305 goto fail;
6306 }
6307
6308 groups = json_get_member(root, "groups");
6309 if (!groups || groups->type != JSON_ARRAY) {
6310 wpa_printf(MSG_DEBUG, "DPP: No groups array found");
6311 goto skip_groups;
6312 }
6313 for (token = groups->child; token; token = token->sibling) {
6314 struct json_token *id, *role;
6315
6316 id = json_get_member(token, "groupId");
6317 if (!id || id->type != JSON_STRING) {
6318 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string");
6319 goto fail;
6320 }
6321
6322 role = json_get_member(token, "netRole");
6323 if (!role || role->type != JSON_STRING) {
6324 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string");
6325 goto fail;
6326 }
6327 wpa_printf(MSG_DEBUG,
6328 "DPP: connector group: groupId='%s' netRole='%s'",
6329 id->string, role->string);
6330 rules++;
6331 }
6332skip_groups:
6333
461d39af
JM
6334 if (!rules) {
6335 wpa_printf(MSG_DEBUG,
a4bf0078 6336 "DPP: Connector includes no groups");
461d39af
JM
6337 goto fail;
6338 }
6339
6340 token = json_get_member(root, "expiry");
6341 if (!token || token->type != JSON_STRING) {
6342 wpa_printf(MSG_DEBUG,
6343 "DPP: No expiry string found - connector does not expire");
6344 } else {
6345 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
6346 if (dpp_key_expired(token->string,
6347 &auth->net_access_key_expiry)) {
6348 wpa_printf(MSG_DEBUG,
6349 "DPP: Connector (netAccessKey) has expired");
6350 goto fail;
6351 }
6352 }
6353
6354 netkey = json_get_member(root, "netAccessKey");
6355 if (!netkey || netkey->type != JSON_OBJECT) {
6356 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
6357 goto fail;
6358 }
6359
6360 key = dpp_parse_jwk(netkey, &curve);
6361 if (!key)
6362 goto fail;
6363 dpp_debug_print_key("DPP: Received netAccessKey", key);
6364
6365 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
6366 wpa_printf(MSG_DEBUG,
6367 "DPP: netAccessKey in connector does not match own protocol key");
6368#ifdef CONFIG_TESTING_OPTIONS
6369 if (auth->ignore_netaccesskey_mismatch) {
6370 wpa_printf(MSG_DEBUG,
6371 "DPP: TESTING - skip netAccessKey mismatch");
6372 } else {
6373 goto fail;
6374 }
6375#else /* CONFIG_TESTING_OPTIONS */
6376 goto fail;
6377#endif /* CONFIG_TESTING_OPTIONS */
6378 }
6379
6380 ret = 0;
6381fail:
6382 EVP_PKEY_free(key);
6383 json_free(root);
6384 return ret;
6385}
6386
6387
6388static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
6389{
6390 struct wpabuf *uncomp;
6391 int res;
6392 u8 hash[SHA256_MAC_LEN];
6393 const u8 *addr[1];
6394 size_t len[1];
6395
6396 if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
6397 return -1;
6398 uncomp = dpp_get_pubkey_point(pub, 1);
6399 if (!uncomp)
6400 return -1;
6401 addr[0] = wpabuf_head(uncomp);
6402 len[0] = wpabuf_len(uncomp);
6403 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key",
6404 addr[0], len[0]);
6405 res = sha256_vector(1, addr, len, hash);
6406 wpabuf_free(uncomp);
6407 if (res < 0)
6408 return -1;
6409 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) {
6410 wpa_printf(MSG_DEBUG,
6411 "DPP: Received hash value does not match calculated public key hash value");
6412 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash",
6413 hash, SHA256_MAC_LEN);
6414 return -1;
6415 }
6416 return 0;
6417}
6418
6419
52d469de 6420static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
461d39af
JM
6421{
6422 unsigned char *der = NULL;
6423 int der_len;
6424
6425 der_len = i2d_PUBKEY(csign, &der);
6426 if (der_len <= 0)
6427 return;
52d469de
JM
6428 wpabuf_free(conf->c_sign_key);
6429 conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
461d39af
JM
6430 OPENSSL_free(der);
6431}
6432
6433
52d469de
JM
6434static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
6435 struct dpp_config_obj *conf)
461d39af
JM
6436{
6437 unsigned char *der = NULL;
6438 int der_len;
6439 EC_KEY *eckey;
6440
6441 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key);
6442 if (!eckey)
6443 return;
6444
6445 der_len = i2d_ECPrivateKey(eckey, &der);
6446 if (der_len <= 0) {
6447 EC_KEY_free(eckey);
6448 return;
6449 }
6450 wpabuf_free(auth->net_access_key);
6451 auth->net_access_key = wpabuf_alloc_copy(der, der_len);
6452 OPENSSL_free(der);
6453 EC_KEY_free(eckey);
6454}
6455
6456
6457struct dpp_signed_connector_info {
6458 unsigned char *payload;
6459 size_t payload_len;
6460};
6461
e85b6601 6462static enum dpp_status_error
461d39af
JM
6463dpp_process_signed_connector(struct dpp_signed_connector_info *info,
6464 EVP_PKEY *csign_pub, const char *connector)
6465{
e85b6601 6466 enum dpp_status_error ret = 255;
461d39af
JM
6467 const char *pos, *end, *signed_start, *signed_end;
6468 struct wpabuf *kid = NULL;
6469 unsigned char *prot_hdr = NULL, *signature = NULL;
6470 size_t prot_hdr_len = 0, signature_len = 0;
6471 const EVP_MD *sign_md = NULL;
6472 unsigned char *der = NULL;
6473 int der_len;
6474 int res;
6475 EVP_MD_CTX *md_ctx = NULL;
6476 ECDSA_SIG *sig = NULL;
6477 BIGNUM *r = NULL, *s = NULL;
6095b479
JM
6478 const struct dpp_curve_params *curve;
6479 EC_KEY *eckey;
6480 const EC_GROUP *group;
6481 int nid;
461d39af 6482
6095b479
JM
6483 eckey = EVP_PKEY_get1_EC_KEY(csign_pub);
6484 if (!eckey)
6485 goto fail;
6486 group = EC_KEY_get0_group(eckey);
6487 if (!group)
6488 goto fail;
6489 nid = EC_GROUP_get_curve_name(group);
6490 curve = dpp_get_curve_nid(nid);
6491 if (!curve)
6492 goto fail;
6493 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
461d39af
JM
6494 os_memset(info, 0, sizeof(*info));
6495
6496 signed_start = pos = connector;
6497 end = os_strchr(pos, '.');
6498 if (!end) {
6499 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector");
e85b6601 6500 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6501 goto fail;
6502 }
b2260842 6503 prot_hdr = base64_url_decode(pos, end - pos, &prot_hdr_len);
461d39af
JM
6504 if (!prot_hdr) {
6505 wpa_printf(MSG_DEBUG,
6506 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
e85b6601 6507 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6508 goto fail;
6509 }
6510 wpa_hexdump_ascii(MSG_DEBUG,
6511 "DPP: signedConnector - JWS Protected Header",
6512 prot_hdr, prot_hdr_len);
6095b479 6513 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
e85b6601
JM
6514 if (!kid) {
6515 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af 6516 goto fail;
e85b6601 6517 }
461d39af
JM
6518 if (wpabuf_len(kid) != SHA256_MAC_LEN) {
6519 wpa_printf(MSG_DEBUG,
6520 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6521 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN);
e85b6601 6522 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6523 goto fail;
6524 }
6525
6526 pos = end + 1;
6527 end = os_strchr(pos, '.');
6528 if (!end) {
6529 wpa_printf(MSG_DEBUG,
6530 "DPP: Missing dot(2) in signedConnector");
e85b6601 6531 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6532 goto fail;
6533 }
6534 signed_end = end - 1;
b2260842 6535 info->payload = base64_url_decode(pos, end - pos, &info->payload_len);
461d39af
JM
6536 if (!info->payload) {
6537 wpa_printf(MSG_DEBUG,
6538 "DPP: Failed to base64url decode signedConnector JWS Payload");
e85b6601 6539 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6540 goto fail;
6541 }
6542 wpa_hexdump_ascii(MSG_DEBUG,
6543 "DPP: signedConnector - JWS Payload",
6544 info->payload, info->payload_len);
6545 pos = end + 1;
b2260842 6546 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
461d39af
JM
6547 if (!signature) {
6548 wpa_printf(MSG_DEBUG,
6549 "DPP: Failed to base64url decode signedConnector signature");
e85b6601 6550 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6551 goto fail;
6552 }
6553 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature",
6554 signature, signature_len);
6555
e85b6601
JM
6556 if (dpp_check_pubkey_match(csign_pub, kid) < 0) {
6557 ret = DPP_STATUS_NO_MATCH;
461d39af 6558 goto fail;
e85b6601 6559 }
461d39af
JM
6560
6561 if (signature_len & 0x01) {
6562 wpa_printf(MSG_DEBUG,
6563 "DPP: Unexpected signedConnector signature length (%d)",
6564 (int) signature_len);
e85b6601 6565 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6566 goto fail;
6567 }
6568
6569 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6570 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6571 r = BN_bin2bn(signature, signature_len / 2, NULL);
6572 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
6573 sig = ECDSA_SIG_new();
6574 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
6575 goto fail;
6576 r = NULL;
6577 s = NULL;
6578
6579 der_len = i2d_ECDSA_SIG(sig, &der);
6580 if (der_len <= 0) {
6581 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
6582 goto fail;
6583 }
6584 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
6585 md_ctx = EVP_MD_CTX_create();
6586 if (!md_ctx)
6587 goto fail;
6588
6589 ERR_clear_error();
6590 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
6591 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
6592 ERR_error_string(ERR_get_error(), NULL));
6593 goto fail;
6594 }
6595 if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
6596 signed_end - signed_start + 1) != 1) {
6597 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
6598 ERR_error_string(ERR_get_error(), NULL));
6599 goto fail;
6600 }
6601 res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
6602 if (res != 1) {
6603 wpa_printf(MSG_DEBUG,
6604 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6605 res, ERR_error_string(ERR_get_error(), NULL));
e85b6601 6606 ret = DPP_STATUS_INVALID_CONNECTOR;
461d39af
JM
6607 goto fail;
6608 }
6609
e85b6601 6610 ret = DPP_STATUS_OK;
461d39af 6611fail:
6095b479 6612 EC_KEY_free(eckey);
461d39af
JM
6613 EVP_MD_CTX_destroy(md_ctx);
6614 os_free(prot_hdr);
6615 wpabuf_free(kid);
6616 os_free(signature);
6617 ECDSA_SIG_free(sig);
6618 BN_free(r);
6619 BN_free(s);
6620 OPENSSL_free(der);
6621 return ret;
6622}
6623
6624
6625static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
52d469de 6626 struct dpp_config_obj *conf,
461d39af
JM
6627 struct json_token *cred)
6628{
6629 struct dpp_signed_connector_info info;
6630 struct json_token *token, *csign;
6631 int ret = -1;
6632 EVP_PKEY *csign_pub = NULL;
6633 const struct dpp_curve_params *key_curve = NULL;
6634 const char *signed_connector;
6635
6636 os_memset(&info, 0, sizeof(info));
6637
52d469de 6638 if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
18015fc8
JM
6639 wpa_printf(MSG_DEBUG,
6640 "DPP: Legacy credential included in Connector credential");
52d469de 6641 if (dpp_parse_cred_legacy(conf, cred) < 0)
18015fc8
JM
6642 return -1;
6643 }
6644
461d39af
JM
6645 wpa_printf(MSG_DEBUG, "DPP: Connector credential");
6646
6647 csign = json_get_member(cred, "csign");
6648 if (!csign || csign->type != JSON_OBJECT) {
6649 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON");
6650 goto fail;
6651 }
6652
6653 csign_pub = dpp_parse_jwk(csign, &key_curve);
6654 if (!csign_pub) {
6655 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK");
6656 goto fail;
6657 }
6658 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub);
6659
461d39af
JM
6660 token = json_get_member(cred, "signedConnector");
6661 if (!token || token->type != JSON_STRING) {
6662 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found");
6663 goto fail;
6664 }
6665 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector",
6666 token->string, os_strlen(token->string));
6667 signed_connector = token->string;
6668
6669 if (os_strchr(signed_connector, '"') ||
6670 os_strchr(signed_connector, '\n')) {
6671 wpa_printf(MSG_DEBUG,
6672 "DPP: Unexpected character in signedConnector");
6673 goto fail;
6674 }
6675
6676 if (dpp_process_signed_connector(&info, csign_pub,
e85b6601 6677 signed_connector) != DPP_STATUS_OK)
461d39af
JM
6678 goto fail;
6679
52d469de
JM
6680 if (dpp_parse_connector(auth, conf,
6681 info.payload, info.payload_len) < 0) {
461d39af
JM
6682 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
6683 goto fail;
6684 }
6685
52d469de
JM
6686 os_free(conf->connector);
6687 conf->connector = os_strdup(signed_connector);
461d39af 6688
52d469de
JM
6689 dpp_copy_csign(conf, csign_pub);
6690 dpp_copy_netaccesskey(auth, conf);
461d39af
JM
6691
6692 ret = 0;
6693fail:
6694 EVP_PKEY_free(csign_pub);
6695 os_free(info.payload);
6696 return ret;
6697}
6698
6699
5dd745b7
JM
6700const char * dpp_akm_str(enum dpp_akm akm)
6701{
6702 switch (akm) {
6703 case DPP_AKM_DPP:
6704 return "dpp";
6705 case DPP_AKM_PSK:
6706 return "psk";
6707 case DPP_AKM_SAE:
6708 return "sae";
6709 case DPP_AKM_PSK_SAE:
6710 return "psk+sae";
18015fc8
JM
6711 case DPP_AKM_SAE_DPP:
6712 return "dpp+sae";
6713 case DPP_AKM_PSK_SAE_DPP:
6714 return "dpp+psk+sae";
5dd745b7
JM
6715 default:
6716 return "??";
6717 }
6718}
6719
6720
68fea960
JM
6721const char * dpp_akm_selector_str(enum dpp_akm akm)
6722{
6723 switch (akm) {
6724 case DPP_AKM_DPP:
6725 return "506F9A02";
6726 case DPP_AKM_PSK:
6727 return "000FAC02+000FAC06";
6728 case DPP_AKM_SAE:
6729 return "000FAC08";
6730 case DPP_AKM_PSK_SAE:
6731 return "000FAC02+000FAC06+000FAC08";
6732 case DPP_AKM_SAE_DPP:
6733 return "506F9A02+000FAC08";
6734 case DPP_AKM_PSK_SAE_DPP:
6735 return "506F9A02+000FAC08+000FAC02+000FAC06";
6736 default:
6737 return "??";
6738 }
6739}
6740
6741
5dd745b7
JM
6742static enum dpp_akm dpp_akm_from_str(const char *akm)
6743{
b719a156
JM
6744 const char *pos;
6745 int dpp = 0, psk = 0, sae = 0;
6746
5dd745b7
JM
6747 if (os_strcmp(akm, "psk") == 0)
6748 return DPP_AKM_PSK;
6749 if (os_strcmp(akm, "sae") == 0)
6750 return DPP_AKM_SAE;
6751 if (os_strcmp(akm, "psk+sae") == 0)
6752 return DPP_AKM_PSK_SAE;
6753 if (os_strcmp(akm, "dpp") == 0)
6754 return DPP_AKM_DPP;
18015fc8
JM
6755 if (os_strcmp(akm, "dpp+sae") == 0)
6756 return DPP_AKM_SAE_DPP;
6757 if (os_strcmp(akm, "dpp+psk+sae") == 0)
6758 return DPP_AKM_PSK_SAE_DPP;
b719a156
JM
6759
6760 pos = akm;
6761 while (*pos) {
6762 if (os_strlen(pos) < 8)
6763 break;
6764 if (os_strncasecmp(pos, "506F9A02", 8) == 0)
6765 dpp = 1;
6766 else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
6767 psk = 1;
6768 else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
6769 psk = 1;
6770 else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
6771 sae = 1;
6772 pos += 8;
6773 if (*pos != '+')
6774 break;
6775 pos++;
6776 }
6777
6778 if (dpp && psk && sae)
6779 return DPP_AKM_PSK_SAE_DPP;
6780 if (dpp && sae)
6781 return DPP_AKM_SAE_DPP;
6782 if (dpp)
6783 return DPP_AKM_DPP;
6784 if (psk && sae)
6785 return DPP_AKM_PSK_SAE;
6786 if (sae)
6787 return DPP_AKM_SAE;
6788 if (psk)
6789 return DPP_AKM_PSK;
6790
5dd745b7
JM
6791 return DPP_AKM_UNKNOWN;
6792}
6793
6794
461d39af
JM
6795static int dpp_parse_conf_obj(struct dpp_authentication *auth,
6796 const u8 *conf_obj, u16 conf_obj_len)
6797{
6798 int ret = -1;
6799 struct json_token *root, *token, *discovery, *cred;
52d469de 6800 struct dpp_config_obj *conf;
57a63b13 6801 struct wpabuf *ssid64 = NULL;
461d39af
JM
6802
6803 root = json_parse((const char *) conf_obj, conf_obj_len);
6804 if (!root)
6805 return -1;
6806 if (root->type != JSON_OBJECT) {
8c99e626 6807 dpp_auth_fail(auth, "JSON root is not an object");
461d39af
JM
6808 goto fail;
6809 }
6810
6811 token = json_get_member(root, "wi-fi_tech");
6812 if (!token || token->type != JSON_STRING) {
8c99e626 6813 dpp_auth_fail(auth, "No wi-fi_tech string value found");
461d39af
JM
6814 goto fail;
6815 }
6816 if (os_strcmp(token->string, "infra") != 0) {
6817 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'",
6818 token->string);
8c99e626 6819 dpp_auth_fail(auth, "Unsupported wi-fi_tech value");
461d39af
JM
6820 goto fail;
6821 }
6822
6823 discovery = json_get_member(root, "discovery");
6824 if (!discovery || discovery->type != JSON_OBJECT) {
8c99e626 6825 dpp_auth_fail(auth, "No discovery object in JSON");
461d39af
JM
6826 goto fail;
6827 }
6828
57a63b13
JM
6829 ssid64 = json_get_member_base64url(discovery, "ssid64");
6830 if (ssid64) {
6831 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid64",
6832 wpabuf_head(ssid64), wpabuf_len(ssid64));
6833 if (wpabuf_len(ssid64) > SSID_MAX_LEN) {
6834 dpp_auth_fail(auth, "Too long discovery::ssid64 value");
6835 goto fail;
6836 }
6837 } else {
6838 token = json_get_member(discovery, "ssid");
6839 if (!token || token->type != JSON_STRING) {
6840 dpp_auth_fail(auth,
6841 "No discovery::ssid string value found");
6842 goto fail;
6843 }
6844 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid",
6845 token->string, os_strlen(token->string));
6846 if (os_strlen(token->string) > SSID_MAX_LEN) {
6847 dpp_auth_fail(auth,
6848 "Too long discovery::ssid string value");
6849 goto fail;
6850 }
461d39af 6851 }
52d469de
JM
6852
6853 if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
6854 wpa_printf(MSG_DEBUG,
6855 "DPP: No room for this many Config Objects - ignore this one");
57a63b13
JM
6856 ret = 0;
6857 goto fail;
52d469de
JM
6858 }
6859 conf = &auth->conf_obj[auth->num_conf_obj++];
6860
57a63b13
JM
6861 if (ssid64) {
6862 conf->ssid_len = wpabuf_len(ssid64);
6863 os_memcpy(conf->ssid, wpabuf_head(ssid64), conf->ssid_len);
6864 } else {
6865 conf->ssid_len = os_strlen(token->string);
6866 os_memcpy(conf->ssid, token->string, conf->ssid_len);
6867 }
6868
6869 token = json_get_member(discovery, "ssid_charset");
6870 if (token && token->type == JSON_NUMBER) {
6871 conf->ssid_charset = token->number;
6872 wpa_printf(MSG_DEBUG, "DPP: ssid_charset=%d",
6873 conf->ssid_charset);
6874 }
461d39af
JM
6875
6876 cred = json_get_member(root, "cred");
6877 if (!cred || cred->type != JSON_OBJECT) {
8c99e626 6878 dpp_auth_fail(auth, "No cred object in JSON");
461d39af
JM
6879 goto fail;
6880 }
6881
6882 token = json_get_member(cred, "akm");
6883 if (!token || token->type != JSON_STRING) {
8c99e626 6884 dpp_auth_fail(auth, "No cred::akm string value found");
461d39af
JM
6885 goto fail;
6886 }
52d469de 6887 conf->akm = dpp_akm_from_str(token->string);
5dd745b7 6888
52d469de
JM
6889 if (dpp_akm_legacy(conf->akm)) {
6890 if (dpp_parse_cred_legacy(conf, cred) < 0)
461d39af 6891 goto fail;
52d469de
JM
6892 } else if (dpp_akm_dpp(conf->akm)) {
6893 if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
461d39af
JM
6894 goto fail;
6895 } else {
6896 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
6897 token->string);
8c99e626 6898 dpp_auth_fail(auth, "Unsupported akm");
461d39af
JM
6899 goto fail;
6900 }
6901
6902 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully");
6903 ret = 0;
6904fail:
57a63b13 6905 wpabuf_free(ssid64);
461d39af
JM
6906 json_free(root);
6907 return ret;
6908}
6909
6910
ea91ddb0
JM
6911#ifdef CONFIG_DPP2
6912
6913struct dpp_enveloped_data {
6914 const u8 *enc_cont;
6915 size_t enc_cont_len;
6916 const u8 *enc_key;
6917 size_t enc_key_len;
6918 const u8 *salt;
6919 size_t pbkdf2_key_len;
6920 size_t prf_hash_len;
6921};
6922
6923
6924static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
6925 struct dpp_enveloped_data *data)
6926{
6927 struct asn1_hdr hdr;
6928 const u8 *end = pos + len;
6929 const u8 *next, *e_end;
6930 struct asn1_oid oid;
6931 int val;
6932 const u8 *params;
6933 size_t params_len;
6934
6935 wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
6936
6937 /*
6938 * RecipientInfo ::= CHOICE {
6939 * ktri KeyTransRecipientInfo,
6940 * kari [1] KeyAgreeRecipientInfo,
6941 * kekri [2] KEKRecipientInfo,
6942 * pwri [3] PasswordRecipientInfo,
6943 * ori [4] OtherRecipientInfo}
6944 *
6945 * Shall always use the pwri CHOICE.
6946 */
6947
6948 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
6949 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
6950 wpa_printf(MSG_DEBUG,
6951 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
6952 hdr.class, hdr.tag);
6953 return -1;
6954 }
6955 wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
6956 hdr.payload, hdr.length);
6957 pos = hdr.payload;
6958 end = pos + hdr.length;
6959
6960 /*
6961 * PasswordRecipientInfo ::= SEQUENCE {
6962 * version CMSVersion,
6963 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
6964 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
6965 * encryptedKey EncryptedKey}
6966 *
6967 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
6968 * parameters contains PBKDF2-params SEQUENCE.
6969 */
6970
6971 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
6972 return -1;
6973 pos = hdr.payload;
6974
6975 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
6976 return -1;
6977 if (val != 0) {
6978 wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
6979 return -1;
6980 }
6981
6982 wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
6983 pos, end - pos);
6984
6985 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
6986 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
6987 wpa_printf(MSG_DEBUG,
6988 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
6989 hdr.class, hdr.tag);
6990 return -1;
6991 }
6992 pos = hdr.payload;
6993 e_end = pos + hdr.length;
6994
6995 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
6996 if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
6997 &next) < 0)
6998 return -1;
6999 if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
7000 char buf[80];
7001
7002 asn1_oid_to_str(&oid, buf, sizeof(buf));
7003 wpa_printf(MSG_DEBUG,
7004 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7005 buf);
7006 return -1;
7007 }
7008
7009 /*
7010 * PBKDF2-params ::= SEQUENCE {
7011 * salt CHOICE {
7012 * specified OCTET STRING,
7013 * otherSource AlgorithmIdentifier}
7014 * iterationCount INTEGER (1..MAX),
7015 * keyLength INTEGER (1..MAX),
7016 * prf AlgorithmIdentifier}
7017 *
7018 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7019 * on Configurator signing key length, prf is
7020 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7021 */
7022 if (!params ||
7023 asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
7024 return -1;
7025 pos = hdr.payload;
7026
7027 if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
7028 hdr.class != ASN1_CLASS_UNIVERSAL ||
7029 hdr.tag != ASN1_TAG_OCTETSTRING) {
7030 wpa_printf(MSG_DEBUG,
7031 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7032 hdr.class, hdr.tag);
7033 return -1;
7034 }
7035 wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
7036 hdr.payload, hdr.length);
7037 if (hdr.length != 64) {
7038 wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
7039 hdr.length);
7040 return -1;
7041 }
7042 data->salt = hdr.payload;
7043 pos = hdr.payload + hdr.length;
7044
7045 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7046 return -1;
7047 if (val != 1000) {
7048 wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
7049 return -1;
7050 }
7051
7052 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
7053 return -1;
7054 if (val != 32 && val != 48 && val != 64) {
7055 wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
7056 return -1;
7057 }
7058 data->pbkdf2_key_len = val;
7059
7060 if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
7061 asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
7062 wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
7063 return -1;
7064 }
7065 if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
7066 data->prf_hash_len = 32;
7067 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
7068 data->prf_hash_len = 48;
7069 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
7070 data->prf_hash_len = 64;
7071 } else {
7072 char buf[80];
7073
7074 asn1_oid_to_str(&oid, buf, sizeof(buf));
7075 wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
7076 buf);
7077 return -1;
7078 }
7079
7080 pos = next;
7081
7082 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7083 *
7084 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7085 *
7086 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7087 * id-alg-AES-SIV-CMAC-aed-512. */
7088 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7089 return -1;
7090 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7091 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7092 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7093 char buf[80];
7094
7095 asn1_oid_to_str(&oid, buf, sizeof(buf));
7096 wpa_printf(MSG_DEBUG,
7097 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7098 buf);
7099 return -1;
7100 }
7101
7102 /*
7103 * encryptedKey EncryptedKey
7104 *
7105 * EncryptedKey ::= OCTET STRING
7106 */
7107 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7108 hdr.class != ASN1_CLASS_UNIVERSAL ||
7109 hdr.tag != ASN1_TAG_OCTETSTRING) {
7110 wpa_printf(MSG_DEBUG,
7111 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7112 hdr.class, hdr.tag);
7113 return -1;
7114 }
7115 wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
7116 hdr.payload, hdr.length);
7117 data->enc_key = hdr.payload;
7118 data->enc_key_len = hdr.length;
7119
7120 return 0;
7121}
7122
7123
7124static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
7125 struct dpp_enveloped_data *data)
7126{
7127 struct asn1_hdr hdr;
7128 struct asn1_oid oid;
7129
7130 /*
7131 * EncryptedContentInfo ::= SEQUENCE {
7132 * contentType ContentType,
7133 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7134 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7135 */
7136 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7137 return -1;
7138 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
7139 hdr.payload, hdr.length);
7140 if (pos < end) {
7141 wpa_hexdump(MSG_DEBUG,
7142 "DPP: Unexpected extra data after EncryptedContentInfo",
7143 pos, end - pos);
7144 return -1;
7145 }
7146
7147 end = pos;
7148 pos = hdr.payload;
7149
7150 /* ContentType ::= OBJECT IDENTIFIER */
7151 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
7152 wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
7153 return -1;
7154 }
7155 if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
7156 char buf[80];
7157
7158 asn1_oid_to_str(&oid, buf, sizeof(buf));
7159 wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
7160 return -1;
7161 }
7162
7163 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7164 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
7165 return -1;
7166 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
7167 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
7168 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
7169 char buf[80];
7170
7171 asn1_oid_to_str(&oid, buf, sizeof(buf));
7172 wpa_printf(MSG_DEBUG,
7173 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7174 buf);
7175 return -1;
7176 }
7177 /* ignore optional parameters */
7178
7179 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7180 * EncryptedContent ::= OCTET STRING */
7181 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7182 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7183 wpa_printf(MSG_DEBUG,
7184 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7185 hdr.class, hdr.tag);
7186 return -1;
7187 }
7188 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
7189 hdr.payload, hdr.length);
7190 data->enc_cont = hdr.payload;
7191 data->enc_cont_len = hdr.length;
7192 return 0;
7193}
7194
7195
7196static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
7197 struct dpp_enveloped_data *data)
7198{
7199 struct asn1_hdr hdr;
7200 const u8 *pos, *end;
7201 int val;
7202
7203 os_memset(data, 0, sizeof(*data));
7204
7205 /*
7206 * DPPEnvelopedData ::= EnvelopedData
7207 *
7208 * EnvelopedData ::= SEQUENCE {
7209 * version CMSVersion,
7210 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7211 * recipientInfos RecipientInfos,
7212 * encryptedContentInfo EncryptedContentInfo,
7213 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7214 *
7215 * CMSVersion ::= INTEGER
7216 *
7217 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7218 *
7219 * For DPP, version is 3, both originatorInfo and
7220 * unprotectedAttrs are omitted, and recipientInfos contains a single
7221 * RecipientInfo.
7222 */
7223 if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
7224 return -1;
7225 pos = hdr.payload;
7226 if (end < env_data + env_data_len) {
7227 wpa_hexdump(MSG_DEBUG,
7228 "DPP: Unexpected extra data after DPPEnvelopedData",
7229 end, env_data + env_data_len - end);
7230 return -1;
7231 }
7232
7233 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7234 return -1;
7235 if (val != 3) {
7236 wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
7237 return -1;
7238 }
7239
7240 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7241 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7242 wpa_printf(MSG_DEBUG,
7243 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7244 hdr.class, hdr.tag);
7245 return -1;
7246 }
7247
7248 if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
7249 return -1;
7250 return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
7251 data);
7252}
7253
7254
7255static struct dpp_asymmetric_key *
7256dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
7257{
7258 struct asn1_hdr hdr;
7259 const u8 *pos = buf, *end = buf + len, *next;
7260 int val;
7261 const u8 *params;
7262 size_t params_len;
7263 struct asn1_oid oid;
7264 char txt[80];
7265 struct dpp_asymmetric_key *key;
7266 EC_KEY *eckey;
7267
7268 wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
7269
7270 key = os_zalloc(sizeof(*key));
7271 if (!key)
7272 return NULL;
7273
7274 /*
7275 * OneAsymmetricKey ::= SEQUENCE {
7276 * version Version,
7277 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7278 * privateKey PrivateKey,
7279 * attributes [0] Attributes OPTIONAL,
7280 * ...,
7281 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7282 * ...
7283 * }
7284 */
7285 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
7286 goto fail;
7287 pos = hdr.payload;
7288
7289 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7290 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
7291 goto fail;
7292 if (val != 1) {
7293 wpa_printf(MSG_DEBUG,
7294 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7295 val);
7296 goto fail;
7297 }
7298
7299 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7300 if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
7301 &pos) < 0)
7302 goto fail;
7303 if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
7304 asn1_oid_to_str(&oid, txt, sizeof(txt));
7305 wpa_printf(MSG_DEBUG,
7306 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7307 txt);
7308 goto fail;
7309 }
7310 wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
7311 params, params_len);
7312 /*
7313 * ECParameters ::= CHOICE {
7314 * namedCurve OBJECT IDENTIFIER
7315 * -- implicitCurve NULL
7316 * -- specifiedCurve SpecifiedECDomain}
7317 */
7318 if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
7319 wpa_printf(MSG_DEBUG,
7320 "DPP: Could not parse ECParameters.namedCurve");
7321 goto fail;
7322 }
7323 asn1_oid_to_str(&oid, txt, sizeof(txt));
7324 wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
7325 /* Assume the curve is identified within ECPrivateKey, so that this
7326 * separate indication is not really needed. */
7327
7328 /*
7329 * PrivateKey ::= OCTET STRING
7330 * (Contains DER encoding of ECPrivateKey)
7331 */
7332 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7333 hdr.class != ASN1_CLASS_UNIVERSAL ||
7334 hdr.tag != ASN1_TAG_OCTETSTRING) {
7335 wpa_printf(MSG_DEBUG,
7336 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7337 hdr.class, hdr.tag);
7338 goto fail;
7339 }
7340 wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
7341 hdr.payload, hdr.length);
7342 pos = hdr.payload + hdr.length;
7343 eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
7344 if (!eckey) {
7345 wpa_printf(MSG_INFO,
7346 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7347 ERR_error_string(ERR_get_error(), NULL));
7348 goto fail;
7349 }
7350 key->csign = EVP_PKEY_new();
7351 if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
7352 EC_KEY_free(eckey);
7353 goto fail;
7354 }
7355 if (wpa_debug_show_keys)
7356 dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
7357
7358 /*
7359 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7360 *
7361 * Exactly one instance of type Attribute in OneAsymmetricKey.
7362 */
7363 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7364 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
7365 wpa_printf(MSG_DEBUG,
7366 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7367 hdr.class, hdr.tag);
7368 goto fail;
7369 }
7370 wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
7371 hdr.payload, hdr.length);
7372 if (hdr.payload + hdr.length < end) {
7373 wpa_hexdump_key(MSG_MSGDUMP,
7374 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7375 hdr.payload + hdr.length,
7376 end - (hdr.payload + hdr.length));
7377 }
7378 pos = hdr.payload;
7379 end = hdr.payload + hdr.length;
7380
7381 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7382 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7383 wpa_printf(MSG_DEBUG,
7384 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7385 hdr.class, hdr.tag);
7386 goto fail;
7387 }
7388 if (hdr.payload + hdr.length < end) {
7389 wpa_hexdump_key(MSG_MSGDUMP,
7390 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7391 hdr.payload + hdr.length,
7392 end - (hdr.payload + hdr.length));
7393 }
7394 pos = hdr.payload;
7395 end = hdr.payload + hdr.length;
7396
7397 /*
7398 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7399 * aa-DPPConfigurationParameters,
7400 * ... -- For local profiles
7401 * }
7402 *
7403 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7404 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7405 *
7406 * Attribute ::= SEQUENCE {
7407 * type OBJECT IDENTIFIER,
7408 * values SET SIZE(1..MAX) OF Type
7409 *
7410 * Exactly one instance of ATTRIBUTE in attrValues.
7411 */
7412 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7413 goto fail;
7414 if (pos < end) {
7415 wpa_hexdump_key(MSG_MSGDUMP,
7416 "DPP: Ignore additional data at the end of ATTRIBUTE",
7417 pos, end - pos);
7418 }
7419 end = pos;
7420 pos = hdr.payload;
7421
7422 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
7423 goto fail;
7424 if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
7425 asn1_oid_to_str(&oid, txt, sizeof(txt));
7426 wpa_printf(MSG_DEBUG,
7427 "DPP: Unexpected Attribute identifier %s", txt);
7428 goto fail;
7429 }
7430
7431 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7432 hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
7433 wpa_printf(MSG_DEBUG,
7434 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7435 hdr.class, hdr.tag);
7436 goto fail;
7437 }
7438 pos = hdr.payload;
7439 end = hdr.payload + hdr.length;
7440
7441 /*
7442 * DPPConfigurationParameters ::= SEQUENCE {
7443 * configurationTemplate UTF8String,
7444 * connectorTemplate UTF8String OPTIONAL}
7445 */
7446
7447 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
7448 pos, end - pos);
7449 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
7450 goto fail;
7451 if (pos < end) {
7452 wpa_hexdump_key(MSG_MSGDUMP,
7453 "DPP: Ignore additional data after DPPConfigurationParameters",
7454 pos, end - pos);
7455 }
7456 end = pos;
7457 pos = hdr.payload;
7458
7459 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7460 hdr.class != ASN1_CLASS_UNIVERSAL ||
7461 hdr.tag != ASN1_TAG_UTF8STRING) {
7462 wpa_printf(MSG_DEBUG,
7463 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7464 hdr.class, hdr.tag);
7465 goto fail;
7466 }
7467 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
7468 hdr.payload, hdr.length);
7469 key->config_template = os_zalloc(hdr.length + 1);
7470 if (!key->config_template)
7471 goto fail;
7472 os_memcpy(key->config_template, hdr.payload, hdr.length);
7473
7474 pos = hdr.payload + hdr.length;
7475
7476 if (pos < end) {
7477 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
7478 hdr.class != ASN1_CLASS_UNIVERSAL ||
7479 hdr.tag != ASN1_TAG_UTF8STRING) {
7480 wpa_printf(MSG_DEBUG,
7481 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7482 hdr.class, hdr.tag);
7483 goto fail;
7484 }
7485 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
7486 hdr.payload, hdr.length);
7487 key->connector_template = os_zalloc(hdr.length + 1);
7488 if (!key->connector_template)
7489 goto fail;
7490 os_memcpy(key->connector_template, hdr.payload, hdr.length);
7491 }
7492
7493 return key;
7494fail:
7495 wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
7496 dpp_free_asymmetric_key(key);
7497 return NULL;
7498}
7499
7500
7501static struct dpp_asymmetric_key *
7502dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
7503{
7504 struct asn1_hdr hdr;
7505 const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
7506 struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
7507
7508 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
7509 key_pkg, key_pkg_len);
7510
7511 /*
7512 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7513 *
7514 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7515 */
7516 while (pos < end) {
7517 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
7518 !(key = dpp_parse_one_asymmetric_key(hdr.payload,
7519 hdr.length))) {
7520 dpp_free_asymmetric_key(first);
7521 return NULL;
7522 }
7523 if (!last) {
7524 first = last = key;
7525 } else {
7526 last->next = key;
7527 last = key;
7528 }
7529 }
7530
7531 return first;
7532}
7533
7534
7535static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
7536 const u8 *env_data, size_t env_data_len)
7537{
7538 const u8 *key;
7539 size_t key_len;
7540 u8 kek[DPP_MAX_HASH_LEN];
7541 u8 cont_encr_key[DPP_MAX_HASH_LEN];
7542 size_t cont_encr_key_len;
7543 int res;
7544 u8 *key_pkg;
7545 size_t key_pkg_len;
7546 struct dpp_enveloped_data data;
7547 struct dpp_asymmetric_key *keys;
7548
7549 wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
7550
7551 if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
7552 return -1;
7553
7554 /* TODO: For initial testing, use ke as the key. Replace this with a
7555 * new key once that has been defined. */
7556 key = auth->ke;
7557 key_len = auth->curve->hash_len;
7558 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
7559
7560 if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
7561 kek, data.pbkdf2_key_len)) {
7562 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
7563 return -1;
7564 }
7565 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
7566 kek, data.pbkdf2_key_len);
7567
7568 if (data.enc_key_len < AES_BLOCK_SIZE ||
7569 data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
7570 wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
7571 return -1;
7572 }
7573 res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
7574 data.enc_key, data.enc_key_len,
7575 0, NULL, NULL, cont_encr_key);
7576 forced_memzero(kek, data.pbkdf2_key_len);
7577 if (res < 0) {
7578 wpa_printf(MSG_DEBUG,
7579 "DPP: AES-SIV decryption of encryptedKey failed");
7580 return -1;
7581 }
7582 cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
7583 wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
7584 cont_encr_key, cont_encr_key_len);
7585
7586 if (data.enc_cont_len < AES_BLOCK_SIZE)
7587 return -1;
7588 key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
7589 key_pkg = os_malloc(key_pkg_len);
7590 if (!key_pkg)
7591 return -1;
7592 res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
7593 data.enc_cont, data.enc_cont_len,
7594 0, NULL, NULL, key_pkg);
7595 forced_memzero(cont_encr_key, cont_encr_key_len);
7596 if (res < 0) {
7597 bin_clear_free(key_pkg, key_pkg_len);
7598 wpa_printf(MSG_DEBUG,
7599 "DPP: AES-SIV decryption of encryptedContent failed");
7600 return -1;
7601 }
7602
7603 keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
7604 bin_clear_free(key_pkg, key_pkg_len);
7605 dpp_free_asymmetric_key(auth->conf_key_pkg);
7606 auth->conf_key_pkg = keys;
7607
7608 return keys != NULL;;
7609}
7610
7611#endif /* CONFIG_DPP2 */
7612
7613
461d39af
JM
7614int dpp_conf_resp_rx(struct dpp_authentication *auth,
7615 const struct wpabuf *resp)
7616{
7617 const u8 *wrapped_data, *e_nonce, *status, *conf_obj;
7618 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len;
ea91ddb0
JM
7619 const u8 *env_data;
7620 u16 env_data_len;
461d39af
JM
7621 const u8 *addr[1];
7622 size_t len[1];
7623 u8 *unwrapped = NULL;
7624 size_t unwrapped_len = 0;
7625 int ret = -1;
7626
22f90b32
JM
7627 auth->conf_resp_status = 255;
7628
461d39af 7629 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
8c99e626 7630 dpp_auth_fail(auth, "Invalid attribute in config response");
461d39af
JM
7631 return -1;
7632 }
7633
7634 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7635 DPP_ATTR_WRAPPED_DATA,
7636 &wrapped_data_len);
7637 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
8c99e626
JM
7638 dpp_auth_fail(auth,
7639 "Missing or invalid required Wrapped Data attribute");
461d39af
JM
7640 return -1;
7641 }
7642
7643 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7644 wrapped_data, wrapped_data_len);
7645 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7646 unwrapped = os_malloc(unwrapped_len);
7647 if (!unwrapped)
7648 return -1;
7649
7650 addr[0] = wpabuf_head(resp);
7651 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp);
7652 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]);
7653
7654 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7655 wrapped_data, wrapped_data_len,
7656 1, addr, len, unwrapped) < 0) {
8c99e626 7657 dpp_auth_fail(auth, "AES-SIV decryption failed");
461d39af
JM
7658 goto fail;
7659 }
7660 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7661 unwrapped, unwrapped_len);
7662
7663 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
8c99e626 7664 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
461d39af
JM
7665 goto fail;
7666 }
7667
7668 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7669 DPP_ATTR_ENROLLEE_NONCE,
7670 &e_nonce_len);
7671 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
8c99e626
JM
7672 dpp_auth_fail(auth,
7673 "Missing or invalid Enrollee Nonce attribute");
461d39af
JM
7674 goto fail;
7675 }
7676 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7677 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
8c99e626 7678 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
461d39af
JM
7679 goto fail;
7680 }
7681
7682 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp),
7683 DPP_ATTR_STATUS, &status_len);
7684 if (!status || status_len < 1) {
8c99e626
JM
7685 dpp_auth_fail(auth,
7686 "Missing or invalid required DPP Status attribute");
461d39af
JM
7687 goto fail;
7688 }
22f90b32 7689 auth->conf_resp_status = status[0];
461d39af
JM
7690 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7691 if (status[0] != DPP_STATUS_OK) {
8c99e626 7692 dpp_auth_fail(auth, "Configurator rejected configuration");
461d39af
JM
7693 goto fail;
7694 }
7695
ea91ddb0
JM
7696 env_data = dpp_get_attr(unwrapped, unwrapped_len,
7697 DPP_ATTR_ENVELOPED_DATA, &env_data_len);
7698#ifdef CONFIG_DPP2
7699 if (env_data &&
7700 dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0)
7701 goto fail;
7702#endif /* CONFIG_DPP2 */
7703
52d469de
JM
7704 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
7705 &conf_obj_len);
ea91ddb0 7706 if (!conf_obj && !env_data) {
8c99e626
JM
7707 dpp_auth_fail(auth,
7708 "Missing required Configuration Object attribute");
461d39af
JM
7709 goto fail;
7710 }
52d469de
JM
7711 while (conf_obj) {
7712 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
7713 conf_obj, conf_obj_len);
7714 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
7715 goto fail;
7716 conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
7717 DPP_ATTR_CONFIG_OBJ,
7718 &conf_obj_len);
7719 }
461d39af 7720
16ef233b
JM
7721#ifdef CONFIG_DPP2
7722 status = dpp_get_attr(unwrapped, unwrapped_len,
7723 DPP_ATTR_SEND_CONN_STATUS, &status_len);
7724 if (status) {
7725 wpa_printf(MSG_DEBUG,
7726 "DPP: Configurator requested connection status result");
7727 auth->conn_status_requested = 1;
7728 }
7729#endif /* CONFIG_DPP2 */
7730
461d39af
JM
7731 ret = 0;
7732
7733fail:
7734 os_free(unwrapped);
7735 return ret;
7736}
7737
7738
22f90b32 7739#ifdef CONFIG_DPP2
cc839952 7740
22f90b32
JM
7741enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
7742 const u8 *hdr,
7743 const u8 *attr_start, size_t attr_len)
7744{
7745 const u8 *wrapped_data, *status, *e_nonce;
7746 u16 wrapped_data_len, status_len, e_nonce_len;
7747 const u8 *addr[2];
7748 size_t len[2];
7749 u8 *unwrapped = NULL;
7750 size_t unwrapped_len = 0;
7751 enum dpp_status_error ret = 256;
7752
7753 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7754 &wrapped_data_len);
7755 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7756 dpp_auth_fail(auth,
7757 "Missing or invalid required Wrapped Data attribute");
7758 goto fail;
7759 }
7760 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7761 wrapped_data, wrapped_data_len);
7762
7763 attr_len = wrapped_data - 4 - attr_start;
7764
7765 addr[0] = hdr;
7766 len[0] = DPP_HDR_LEN;
7767 addr[1] = attr_start;
7768 len[1] = attr_len;
7769 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7770 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7771 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7772 wrapped_data, wrapped_data_len);
7773 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7774 unwrapped = os_malloc(unwrapped_len);
7775 if (!unwrapped)
7776 goto fail;
7777 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7778 wrapped_data, wrapped_data_len,
7779 2, addr, len, unwrapped) < 0) {
7780 dpp_auth_fail(auth, "AES-SIV decryption failed");
7781 goto fail;
7782 }
7783 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7784 unwrapped, unwrapped_len);
7785
7786 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7787 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
7788 goto fail;
7789 }
7790
7791 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7792 DPP_ATTR_ENROLLEE_NONCE,
7793 &e_nonce_len);
7794 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
7795 dpp_auth_fail(auth,
7796 "Missing or invalid Enrollee Nonce attribute");
7797 goto fail;
7798 }
7799 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7800 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
7801 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
7802 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
7803 auth->e_nonce, e_nonce_len);
7804 goto fail;
7805 }
7806
7807 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
7808 &status_len);
7809 if (!status || status_len < 1) {
7810 dpp_auth_fail(auth,
7811 "Missing or invalid required DPP Status attribute");
7812 goto fail;
7813 }
7814 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
7815 ret = status[0];
7816
7817fail:
7818 bin_clear_free(unwrapped, unwrapped_len);
7819 return ret;
7820}
22f90b32
JM
7821
7822
7823struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
7824 enum dpp_status_error status)
7825{
7826 struct wpabuf *msg, *clear;
7827 size_t nonce_len, clear_len, attr_len;
7828 const u8 *addr[2];
7829 size_t len[2];
7830 u8 *wrapped;
7831
7832 nonce_len = auth->curve->nonce_len;
7833 clear_len = 5 + 4 + nonce_len;
7834 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
7835 clear = wpabuf_alloc(clear_len);
7836 msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
7837 if (!clear || !msg)
3a6736fe 7838 goto fail;
22f90b32
JM
7839
7840 /* DPP Status */
7841 dpp_build_attr_status(clear, status);
7842
7843 /* E-nonce */
7844 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
7845 wpabuf_put_le16(clear, nonce_len);
7846 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
7847
7848 /* OUI, OUI type, Crypto Suite, DPP frame type */
7849 addr[0] = wpabuf_head_u8(msg) + 2;
7850 len[0] = 3 + 1 + 1 + 1;
7851 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7852
7853 /* Attributes before Wrapped Data (none) */
7854 addr[1] = wpabuf_put(msg, 0);
7855 len[1] = 0;
7856 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7857
7858 /* Wrapped Data */
7859 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
7860 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7861 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
7862
7863 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
7864 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
7865 wpabuf_head(clear), wpabuf_len(clear),
7866 2, addr, len, wrapped) < 0)
7867 goto fail;
7868
7869 wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
7870 wpabuf_free(clear);
7871 return msg;
7872fail:
7873 wpabuf_free(clear);
7874 wpabuf_free(msg);
7875 return NULL;
7876}
7877
b10e01a7
JM
7878
7879static int valid_channel_list(const char *val)
7880{
7881 while (*val) {
7882 if (!((*val >= '0' && *val <= '9') ||
7883 *val == '/' || *val == ','))
7884 return 0;
7885 val++;
7886 }
7887
7888 return 1;
7889}
7890
7891
7892enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
7893 const u8 *hdr,
7894 const u8 *attr_start,
7895 size_t attr_len,
7896 u8 *ssid, size_t *ssid_len,
7897 char **channel_list)
7898{
7899 const u8 *wrapped_data, *status, *e_nonce;
7900 u16 wrapped_data_len, status_len, e_nonce_len;
7901 const u8 *addr[2];
7902 size_t len[2];
7903 u8 *unwrapped = NULL;
7904 size_t unwrapped_len = 0;
7905 enum dpp_status_error ret = 256;
7906 struct json_token *root = NULL, *token;
c54227c2 7907 struct wpabuf *ssid64;
b10e01a7
JM
7908
7909 *ssid_len = 0;
7910 *channel_list = NULL;
7911
7912 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
7913 &wrapped_data_len);
7914 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
7915 dpp_auth_fail(auth,
7916 "Missing or invalid required Wrapped Data attribute");
7917 goto fail;
7918 }
7919 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
7920 wrapped_data, wrapped_data_len);
7921
7922 attr_len = wrapped_data - 4 - attr_start;
7923
7924 addr[0] = hdr;
7925 len[0] = DPP_HDR_LEN;
7926 addr[1] = attr_start;
7927 len[1] = attr_len;
7928 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
7929 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
7930 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
7931 wrapped_data, wrapped_data_len);
7932 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
7933 unwrapped = os_malloc(unwrapped_len);
7934 if (!unwrapped)
7935 goto fail;
7936 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
7937 wrapped_data, wrapped_data_len,
7938 2, addr, len, unwrapped) < 0) {
7939 dpp_auth_fail(auth, "AES-SIV decryption failed");
7940 goto fail;
7941 }
7942 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
7943 unwrapped, unwrapped_len);
7944
7945 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
7946 dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
7947 goto fail;
7948 }
7949
7950 e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
7951 DPP_ATTR_ENROLLEE_NONCE,
7952 &e_nonce_len);
7953 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
7954 dpp_auth_fail(auth,
7955 "Missing or invalid Enrollee Nonce attribute");
7956 goto fail;
7957 }
7958 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
7959 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
7960 dpp_auth_fail(auth, "Enrollee Nonce mismatch");
7961 wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
7962 auth->e_nonce, e_nonce_len);
7963 goto fail;
7964 }
7965
7966 status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONN_STATUS,
7967 &status_len);
7968 if (!status) {
7969 dpp_auth_fail(auth,
7970 "Missing required DPP Connection Status attribute");
7971 goto fail;
7972 }
7973 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
7974 status, status_len);
7975
7976 root = json_parse((const char *) status, status_len);
7977 if (!root) {
7978 dpp_auth_fail(auth, "Could not parse connStatus");
7979 goto fail;
7980 }
7981
c54227c2
JM
7982 ssid64 = json_get_member_base64url(root, "ssid64");
7983 if (ssid64 && wpabuf_len(ssid64) <= SSID_MAX_LEN) {
7984 *ssid_len = wpabuf_len(ssid64);
7985 os_memcpy(ssid, wpabuf_head(ssid64), *ssid_len);
b10e01a7 7986 }
c54227c2 7987 wpabuf_free(ssid64);
b10e01a7
JM
7988
7989 token = json_get_member(root, "channelList");
7990 if (token && token->type == JSON_STRING &&
7991 valid_channel_list(token->string))
7992 *channel_list = os_strdup(token->string);
7993
7994 token = json_get_member(root, "result");
7995 if (!token || token->type != JSON_NUMBER) {
7996 dpp_auth_fail(auth, "No connStatus - result");
7997 goto fail;
7998 }
7999 wpa_printf(MSG_DEBUG, "DPP: result %d", token->number);
8000 ret = token->number;
8001
8002fail:
8003 json_free(root);
8004 bin_clear_free(unwrapped, unwrapped_len);
8005 return ret;
8006}
8007
16ef233b
JM
8008
8009struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
8010 enum dpp_status_error result,
8011 const u8 *ssid, size_t ssid_len,
8012 const char *channel_list)
8013{
c54227c2 8014 struct wpabuf *msg = NULL, *clear = NULL, *json;
16ef233b
JM
8015 size_t nonce_len, clear_len, attr_len;
8016 const u8 *addr[2];
8017 size_t len[2];
8018 u8 *wrapped;
8019
8020 json = wpabuf_alloc(1000);
8021 if (!json)
8022 return NULL;
590bc64d
JM
8023 json_start_object(json, NULL);
8024 json_add_int(json, "result", result);
16ef233b 8025 if (ssid) {
590bc64d
JM
8026 json_value_sep(json);
8027 if (json_add_base64url(json, "ssid64", ssid, ssid_len) < 0)
c54227c2 8028 goto fail;
590bc64d
JM
8029 }
8030 if (channel_list) {
8031 json_value_sep(json);
8032 json_add_string(json, "channelList", channel_list);
8033 }
8034 json_end_object(json);
16ef233b
JM
8035 wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus JSON",
8036 wpabuf_head(json), wpabuf_len(json));
8037
8038 nonce_len = auth->curve->nonce_len;
8039 clear_len = 5 + 4 + nonce_len + 4 + wpabuf_len(json);
8040 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
8041 clear = wpabuf_alloc(clear_len);
8042 msg = dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT, attr_len);
8043 if (!clear || !msg)
8044 goto fail;
8045
8046 /* E-nonce */
8047 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
8048 wpabuf_put_le16(clear, nonce_len);
8049 wpabuf_put_data(clear, auth->e_nonce, nonce_len);
8050
8051 /* DPP Connection Status */
8052 wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS);
8053 wpabuf_put_le16(clear, wpabuf_len(json));
8054 wpabuf_put_buf(clear, json);
8055
8056 /* OUI, OUI type, Crypto Suite, DPP frame type */
8057 addr[0] = wpabuf_head_u8(msg) + 2;
8058 len[0] = 3 + 1 + 1 + 1;
8059 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
8060
8061 /* Attributes before Wrapped Data (none) */
8062 addr[1] = wpabuf_put(msg, 0);
8063 len[1] = 0;
8064 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
8065
8066 /* Wrapped Data */
8067 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
8068 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8069 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
8070
8071 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
8072 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
8073 wpabuf_head(clear), wpabuf_len(clear),
8074 2, addr, len, wrapped) < 0)
8075 goto fail;
8076
8077 wpa_hexdump_buf(MSG_DEBUG, "DPP: Connection Status Result attributes",
8078 msg);
8079 wpabuf_free(json);
8080 wpabuf_free(clear);
8081 return msg;
8082fail:
8083 wpabuf_free(json);
8084 wpabuf_free(clear);
8085 wpabuf_free(msg);
8086 return NULL;
8087}
8088
cc839952
JM
8089#endif /* CONFIG_DPP2 */
8090
22f90b32 8091
461d39af
JM
8092void dpp_configurator_free(struct dpp_configurator *conf)
8093{
8094 if (!conf)
8095 return;
8096 EVP_PKEY_free(conf->csign);
8097 os_free(conf->kid);
8098 os_free(conf);
8099}
8100
8101
8179ae3a
PK
8102int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
8103 size_t buflen)
8104{
8105 EC_KEY *eckey;
8106 int key_len, ret = -1;
8107 unsigned char *key = NULL;
8108
8109 if (!conf->csign)
8110 return -1;
8111
8112 eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
8113 if (!eckey)
8114 return -1;
8115
8116 key_len = i2d_ECPrivateKey(eckey, &key);
8117 if (key_len > 0)
8118 ret = wpa_snprintf_hex(buf, buflen, key, key_len);
8119
8120 EC_KEY_free(eckey);
8121 OPENSSL_free(key);
8122 return ret;
8123}
8124
8125
7d9e3200 8126static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
461d39af 8127{
461d39af
JM
8128 struct wpabuf *csign_pub = NULL;
8129 u8 kid_hash[SHA256_MAC_LEN];
8130 const u8 *addr[1];
8131 size_t len[1];
7d9e3200
JM
8132 int res;
8133
8134 csign_pub = dpp_get_pubkey_point(conf->csign, 1);
8135 if (!csign_pub) {
8136 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
8137 return -1;
8138 }
8139
8140 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8141 addr[0] = wpabuf_head(csign_pub);
8142 len[0] = wpabuf_len(csign_pub);
8143 res = sha256_vector(1, addr, len, kid_hash);
8144 wpabuf_free(csign_pub);
8145 if (res < 0) {
8146 wpa_printf(MSG_DEBUG,
8147 "DPP: Failed to derive kid for C-sign-key");
8148 return -1;
8149 }
8150
8151 conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL);
8152 return conf->kid ? 0 : -1;
8153}
8154
8155
8156struct dpp_configurator *
8157dpp_keygen_configurator(const char *curve, const u8 *privkey,
8158 size_t privkey_len)
8159{
8160 struct dpp_configurator *conf;
461d39af
JM
8161
8162 conf = os_zalloc(sizeof(*conf));
8163 if (!conf)
8164 return NULL;
8165
8166 if (!curve) {
8167 conf->curve = &dpp_curves[0];
8168 } else {
8169 conf->curve = dpp_get_curve_name(curve);
8170 if (!conf->curve) {
8171 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8172 curve);
820ea0ba 8173 os_free(conf);
461d39af
JM
8174 return NULL;
8175 }
8176 }
8177 if (privkey)
8178 conf->csign = dpp_set_keypair(&conf->curve, privkey,
8179 privkey_len);
8180 else
8181 conf->csign = dpp_gen_keypair(conf->curve);
8182 if (!conf->csign)
8183 goto fail;
8184 conf->own = 1;
8185
7d9e3200 8186 if (dpp_configurator_gen_kid(conf) < 0)
461d39af 8187 goto fail;
461d39af
JM
8188 return conf;
8189fail:
8190 dpp_configurator_free(conf);
7d9e3200 8191 return NULL;
461d39af 8192}
650a70a7
JM
8193
8194
f522bb23 8195int dpp_configurator_own_config(struct dpp_authentication *auth,
a2588be8 8196 const char *curve, int ap)
f522bb23
JM
8197{
8198 struct wpabuf *conf_obj;
8199 int ret = -1;
8200
8201 if (!auth->conf) {
8202 wpa_printf(MSG_DEBUG, "DPP: No configurator specified");
8203 return -1;
8204 }
8205
8206 if (!curve) {
8207 auth->curve = &dpp_curves[0];
8208 } else {
8209 auth->curve = dpp_get_curve_name(curve);
8210 if (!auth->curve) {
8211 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s",
8212 curve);
8213 return -1;
8214 }
8215 }
8216 wpa_printf(MSG_DEBUG,
8217 "DPP: Building own configuration/connector with curve %s",
8218 auth->curve->name);
8219
8220 auth->own_protocol_key = dpp_gen_keypair(auth->curve);
8221 if (!auth->own_protocol_key)
8222 return -1;
52d469de 8223 dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
f522bb23 8224 auth->peer_protocol_key = auth->own_protocol_key;
52d469de 8225 dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
f522bb23 8226
7eb06a33 8227 conf_obj = dpp_build_conf_obj(auth, ap, 0);
78d338d1
AW
8228 if (!conf_obj) {
8229 wpabuf_free(auth->conf_obj[0].c_sign_key);
8230 auth->conf_obj[0].c_sign_key = NULL;
f522bb23 8231 goto fail;
78d338d1 8232 }
f522bb23
JM
8233 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
8234 wpabuf_len(conf_obj));
8235fail:
8236 wpabuf_free(conf_obj);
8237 auth->peer_protocol_key = NULL;
8238 return ret;
8239}
8240
8241
650a70a7
JM
8242static int dpp_compatible_netrole(const char *role1, const char *role2)
8243{
8244 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) ||
8245 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0);
8246}
8247
8248
8249static int dpp_connector_compatible_group(struct json_token *root,
8250 const char *group_id,
8251 const char *net_role)
8252{
8253 struct json_token *groups, *token;
8254
8255 groups = json_get_member(root, "groups");
8256 if (!groups || groups->type != JSON_ARRAY)
8257 return 0;
8258
8259 for (token = groups->child; token; token = token->sibling) {
8260 struct json_token *id, *role;
8261
8262 id = json_get_member(token, "groupId");
8263 if (!id || id->type != JSON_STRING)
8264 continue;
8265
8266 role = json_get_member(token, "netRole");
8267 if (!role || role->type != JSON_STRING)
8268 continue;
8269
8270 if (os_strcmp(id->string, "*") != 0 &&
8271 os_strcmp(group_id, "*") != 0 &&
8272 os_strcmp(id->string, group_id) != 0)
8273 continue;
8274
8275 if (dpp_compatible_netrole(role->string, net_role))
8276 return 1;
8277 }
8278
8279 return 0;
8280}
8281
8282
8283static int dpp_connector_match_groups(struct json_token *own_root,
8284 struct json_token *peer_root)
8285{
8286 struct json_token *groups, *token;
8287
8288 groups = json_get_member(peer_root, "groups");
8289 if (!groups || groups->type != JSON_ARRAY) {
8290 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found");
8291 return 0;
8292 }
8293
8294 for (token = groups->child; token; token = token->sibling) {
8295 struct json_token *id, *role;
8296
8297 id = json_get_member(token, "groupId");
8298 if (!id || id->type != JSON_STRING) {
8299 wpa_printf(MSG_DEBUG,
8300 "DPP: Missing peer groupId string");
8301 continue;
8302 }
8303
8304 role = json_get_member(token, "netRole");
8305 if (!role || role->type != JSON_STRING) {
8306 wpa_printf(MSG_DEBUG,
8307 "DPP: Missing peer groups::netRole string");
8308 continue;
8309 }
8310 wpa_printf(MSG_DEBUG,
8311 "DPP: peer connector group: groupId='%s' netRole='%s'",
8312 id->string, role->string);
8313 if (dpp_connector_compatible_group(own_root, id->string,
8314 role->string)) {
8315 wpa_printf(MSG_DEBUG,
8316 "DPP: Compatible group/netRole in own connector");
8317 return 1;
8318 }
8319 }
8320
8321 return 0;
8322}
8323
8324
650a70a7
JM
8325static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk,
8326 unsigned int hash_len)
8327{
8328 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
8329 const char *info = "DPP PMK";
b9d47b48 8330 int res;
650a70a7
JM
8331
8332 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8333
8334 /* HKDF-Extract(<>, N.x) */
8335 os_memset(salt, 0, hash_len);
b9d47b48 8336 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0)
650a70a7 8337 return -1;
650a70a7
JM
8338 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8339 prk, hash_len);
8340
8341 /* HKDF-Expand(PRK, info, L) */
b9d47b48 8342 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len);
650a70a7
JM
8343 os_memset(prk, 0, hash_len);
8344 if (res < 0)
8345 return -1;
8346
8347 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8348 pmk, hash_len);
8349 return 0;
8350}
8351
8352
8353static int dpp_derive_pmkid(const struct dpp_curve_params *curve,
8354 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
8355{
8356 struct wpabuf *nkx, *pkx;
8357 int ret = -1, res;
8358 const u8 *addr[2];
8359 size_t len[2];
c2d4f2eb 8360 u8 hash[SHA256_MAC_LEN];
650a70a7
JM
8361
8362 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8363 nkx = dpp_get_pubkey_point(own_key, 0);
8364 pkx = dpp_get_pubkey_point(peer_key, 0);
8365 if (!nkx || !pkx)
8366 goto fail;
8367 addr[0] = wpabuf_head(nkx);
8368 len[0] = wpabuf_len(nkx) / 2;
8369 addr[1] = wpabuf_head(pkx);
8370 len[1] = wpabuf_len(pkx) / 2;
8371 if (len[0] != len[1])
8372 goto fail;
8373 if (os_memcmp(addr[0], addr[1], len[0]) > 0) {
8374 addr[0] = wpabuf_head(pkx);
8375 addr[1] = wpabuf_head(nkx);
8376 }
650a70a7
JM
8377 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]);
8378 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]);
c2d4f2eb 8379 res = sha256_vector(2, addr, len, hash);
650a70a7
JM
8380 if (res < 0)
8381 goto fail;
c2d4f2eb 8382 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN);
650a70a7
JM
8383 os_memcpy(pmkid, hash, PMKID_LEN);
8384 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN);
8385 ret = 0;
8386fail:
8387 wpabuf_free(nkx);
8388 wpabuf_free(pkx);
8389 return ret;
8390}
8391
8392
e85b6601
JM
8393enum dpp_status_error
8394dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
8395 const u8 *net_access_key, size_t net_access_key_len,
8396 const u8 *csign_key, size_t csign_key_len,
8397 const u8 *peer_connector, size_t peer_connector_len,
8398 os_time_t *expiry)
650a70a7
JM
8399{
8400 struct json_token *root = NULL, *netkey, *token;
8401 struct json_token *own_root = NULL;
e85b6601 8402 enum dpp_status_error ret = 255, res;
650a70a7
JM
8403 EVP_PKEY *own_key = NULL, *peer_key = NULL;
8404 struct wpabuf *own_key_pub = NULL;
650a70a7
JM
8405 const struct dpp_curve_params *curve, *own_curve;
8406 struct dpp_signed_connector_info info;
8407 const unsigned char *p;
8408 EVP_PKEY *csign = NULL;
8409 char *signed_connector = NULL;
8410 const char *pos, *end;
8411 unsigned char *own_conn = NULL;
8412 size_t own_conn_len;
650a70a7
JM
8413 size_t Nx_len;
8414 u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
650a70a7
JM
8415
8416 os_memset(intro, 0, sizeof(*intro));
8417 os_memset(&info, 0, sizeof(info));
787615b3
JM
8418 if (expiry)
8419 *expiry = 0;
650a70a7
JM
8420
8421 p = csign_key;
8422 csign = d2i_PUBKEY(NULL, &p, csign_key_len);
8423 if (!csign) {
8424 wpa_printf(MSG_ERROR,
8425 "DPP: Failed to parse local C-sign-key information");
8426 goto fail;
8427 }
8428
8429 own_key = dpp_set_keypair(&own_curve, net_access_key,
8430 net_access_key_len);
8431 if (!own_key) {
8432 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
8433 goto fail;
8434 }
650a70a7
JM
8435
8436 pos = os_strchr(own_connector, '.');
43fbb8db
JM
8437 if (!pos) {
8438 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)");
650a70a7 8439 goto fail;
43fbb8db 8440 }
650a70a7
JM
8441 pos++;
8442 end = os_strchr(pos, '.');
43fbb8db
JM
8443 if (!end) {
8444 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)");
650a70a7 8445 goto fail;
43fbb8db 8446 }
b2260842 8447 own_conn = base64_url_decode(pos, end - pos, &own_conn_len);
650a70a7
JM
8448 if (!own_conn) {
8449 wpa_printf(MSG_DEBUG,
8450 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8451 goto fail;
8452 }
8453
8454 own_root = json_parse((const char *) own_conn, own_conn_len);
8455 if (!own_root) {
8456 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector");
8457 goto fail;
8458 }
8459
8460 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector",
8461 peer_connector, peer_connector_len);
8462 signed_connector = os_malloc(peer_connector_len + 1);
8463 if (!signed_connector)
8464 goto fail;
8465 os_memcpy(signed_connector, peer_connector, peer_connector_len);
8466 signed_connector[peer_connector_len] = '\0';
8467
e85b6601
JM
8468 res = dpp_process_signed_connector(&info, csign, signed_connector);
8469 if (res != DPP_STATUS_OK) {
8470 ret = res;
650a70a7 8471 goto fail;
e85b6601 8472 }
650a70a7
JM
8473
8474 root = json_parse((const char *) info.payload, info.payload_len);
8475 if (!root) {
8476 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed");
e85b6601 8477 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
8478 goto fail;
8479 }
8480
a4bf0078 8481 if (!dpp_connector_match_groups(own_root, root)) {
650a70a7 8482 wpa_printf(MSG_DEBUG,
a4bf0078 8483 "DPP: Peer connector does not include compatible group netrole with own connector");
e85b6601 8484 ret = DPP_STATUS_NO_MATCH;
650a70a7
JM
8485 goto fail;
8486 }
8487
8488 token = json_get_member(root, "expiry");
8489 if (!token || token->type != JSON_STRING) {
8490 wpa_printf(MSG_DEBUG,
8491 "DPP: No expiry string found - connector does not expire");
8492 } else {
8493 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string);
787615b3 8494 if (dpp_key_expired(token->string, expiry)) {
650a70a7
JM
8495 wpa_printf(MSG_DEBUG,
8496 "DPP: Connector (netAccessKey) has expired");
e85b6601 8497 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
8498 goto fail;
8499 }
8500 }
8501
8502 netkey = json_get_member(root, "netAccessKey");
8503 if (!netkey || netkey->type != JSON_OBJECT) {
8504 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found");
e85b6601 8505 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
8506 goto fail;
8507 }
8508
8509 peer_key = dpp_parse_jwk(netkey, &curve);
e85b6601
JM
8510 if (!peer_key) {
8511 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7 8512 goto fail;
e85b6601 8513 }
650a70a7
JM
8514 dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
8515
8516 if (own_curve != curve) {
8517 wpa_printf(MSG_DEBUG,
8518 "DPP: Mismatching netAccessKey curves (%s != %s)",
8519 own_curve->name, curve->name);
e85b6601 8520 ret = DPP_STATUS_INVALID_CONNECTOR;
650a70a7
JM
8521 goto fail;
8522 }
8523
8524 /* ECDH: N = nk * PK */
29ef1c5e 8525 if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
650a70a7 8526 goto fail;
650a70a7
JM
8527
8528 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
8529 Nx, Nx_len);
8530
8531 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8532 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) {
8533 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK");
8534 goto fail;
8535 }
8536 intro->pmk_len = curve->hash_len;
8537
8538 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8539 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
8540 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
8541 goto fail;
8542 }
8543
e85b6601 8544 ret = DPP_STATUS_OK;
650a70a7 8545fail:
e85b6601 8546 if (ret != DPP_STATUS_OK)
650a70a7
JM
8547 os_memset(intro, 0, sizeof(*intro));
8548 os_memset(Nx, 0, sizeof(Nx));
650a70a7
JM
8549 os_free(own_conn);
8550 os_free(signed_connector);
8551 os_free(info.payload);
8552 EVP_PKEY_free(own_key);
8553 wpabuf_free(own_key_pub);
650a70a7
JM
8554 EVP_PKEY_free(peer_key);
8555 EVP_PKEY_free(csign);
8556 json_free(root);
8557 json_free(own_root);
8558 return ret;
8559}
500ed7f0
JM
8560
8561
8562static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
8563 int init)
8564{
8565 EC_GROUP *group;
8566 size_t len = curve->prime_len;
8567 const u8 *x, *y;
57ec74ea 8568 EVP_PKEY *res;
500ed7f0
JM
8569
8570 switch (curve->ike_group) {
8571 case 19:
8572 x = init ? pkex_init_x_p256 : pkex_resp_x_p256;
8573 y = init ? pkex_init_y_p256 : pkex_resp_y_p256;
8574 break;
8575 case 20:
8576 x = init ? pkex_init_x_p384 : pkex_resp_x_p384;
8577 y = init ? pkex_init_y_p384 : pkex_resp_y_p384;
8578 break;
8579 case 21:
8580 x = init ? pkex_init_x_p521 : pkex_resp_x_p521;
8581 y = init ? pkex_init_y_p521 : pkex_resp_y_p521;
8582 break;
8583 case 28:
8584 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1;
8585 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1;
8586 break;
8587 case 29:
8588 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1;
8589 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1;
8590 break;
8591 case 30:
8592 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1;
8593 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1;
8594 break;
8595 default:
8596 return NULL;
8597 }
8598
8599 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8600 if (!group)
8601 return NULL;
57ec74ea
JM
8602 res = dpp_set_pubkey_point_group(group, x, y, len);
8603 EC_GROUP_free(group);
8604 return res;
500ed7f0
JM
8605}
8606
8607
8608static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
8609 const u8 *mac_init, const char *code,
8610 const char *identifier, BN_CTX *bnctx,
1cdfe8d2 8611 EC_GROUP **ret_group)
500ed7f0
JM
8612{
8613 u8 hash[DPP_MAX_HASH_LEN];
8614 const u8 *addr[3];
8615 size_t len[3];
8616 unsigned int num_elem = 0;
8617 EC_POINT *Qi = NULL;
8618 EVP_PKEY *Pi = NULL;
8619 EC_KEY *Pi_ec = NULL;
8620 const EC_POINT *Pi_point;
8621 BIGNUM *hash_bn = NULL;
8622 const EC_GROUP *group = NULL;
8623 EC_GROUP *group2 = NULL;
8624
8625 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8626
8627 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
8628 addr[num_elem] = mac_init;
8629 len[num_elem] = ETH_ALEN;
8630 num_elem++;
8631 if (identifier) {
8632 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8633 identifier);
8634 addr[num_elem] = (const u8 *) identifier;
8635 len[num_elem] = os_strlen(identifier);
8636 num_elem++;
8637 }
8638 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8639 addr[num_elem] = (const u8 *) code;
8640 len[num_elem] = os_strlen(code);
8641 num_elem++;
8642 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8643 goto fail;
8644 wpa_hexdump_key(MSG_DEBUG,
8645 "DPP: H(MAC-Initiator | [identifier |] code)",
8646 hash, curve->hash_len);
8647 Pi = dpp_pkex_get_role_elem(curve, 1);
8648 if (!Pi)
8649 goto fail;
8650 dpp_debug_print_key("DPP: Pi", Pi);
8651 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi);
8652 if (!Pi_ec)
8653 goto fail;
8654 Pi_point = EC_KEY_get0_public_key(Pi_ec);
8655
8656 group = EC_KEY_get0_group(Pi_ec);
8657 if (!group)
8658 goto fail;
8659 group2 = EC_GROUP_dup(group);
8660 if (!group2)
8661 goto fail;
8662 Qi = EC_POINT_new(group2);
8663 if (!Qi) {
8664 EC_GROUP_free(group2);
8665 goto fail;
8666 }
8667 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8668 if (!hash_bn ||
8669 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
8670 goto fail;
65731717 8671 if (EC_POINT_is_at_infinity(group, Qi)) {
578c9ea1 8672 wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
65731717
JM
8673 goto fail;
8674 }
d722c50d 8675 dpp_debug_print_point("DPP: Qi", group, Qi);
500ed7f0
JM
8676out:
8677 EC_KEY_free(Pi_ec);
8678 EVP_PKEY_free(Pi);
8679 BN_clear_free(hash_bn);
1cdfe8d2 8680 if (ret_group && Qi)
500ed7f0 8681 *ret_group = group2;
1cdfe8d2
JM
8682 else
8683 EC_GROUP_free(group2);
500ed7f0
JM
8684 return Qi;
8685fail:
8686 EC_POINT_free(Qi);
8687 Qi = NULL;
8688 goto out;
8689}
8690
8691
8692static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
8693 const u8 *mac_resp, const char *code,
8694 const char *identifier, BN_CTX *bnctx,
1cdfe8d2 8695 EC_GROUP **ret_group)
500ed7f0
JM
8696{
8697 u8 hash[DPP_MAX_HASH_LEN];
8698 const u8 *addr[3];
8699 size_t len[3];
8700 unsigned int num_elem = 0;
8701 EC_POINT *Qr = NULL;
8702 EVP_PKEY *Pr = NULL;
8703 EC_KEY *Pr_ec = NULL;
8704 const EC_POINT *Pr_point;
8705 BIGNUM *hash_bn = NULL;
8706 const EC_GROUP *group = NULL;
8707 EC_GROUP *group2 = NULL;
8708
8709 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8710
8711 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
8712 addr[num_elem] = mac_resp;
8713 len[num_elem] = ETH_ALEN;
8714 num_elem++;
8715 if (identifier) {
8716 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
8717 identifier);
8718 addr[num_elem] = (const u8 *) identifier;
8719 len[num_elem] = os_strlen(identifier);
8720 num_elem++;
8721 }
8722 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code));
8723 addr[num_elem] = (const u8 *) code;
8724 len[num_elem] = os_strlen(code);
8725 num_elem++;
8726 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
8727 goto fail;
8728 wpa_hexdump_key(MSG_DEBUG,
8729 "DPP: H(MAC-Responder | [identifier |] code)",
8730 hash, curve->hash_len);
8731 Pr = dpp_pkex_get_role_elem(curve, 0);
8732 if (!Pr)
8733 goto fail;
8734 dpp_debug_print_key("DPP: Pr", Pr);
8735 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr);
8736 if (!Pr_ec)
8737 goto fail;
8738 Pr_point = EC_KEY_get0_public_key(Pr_ec);
8739
8740 group = EC_KEY_get0_group(Pr_ec);
8741 if (!group)
8742 goto fail;
8743 group2 = EC_GROUP_dup(group);
8744 if (!group2)
8745 goto fail;
8746 Qr = EC_POINT_new(group2);
8747 if (!Qr) {
8748 EC_GROUP_free(group2);
8749 goto fail;
8750 }
8751 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
8752 if (!hash_bn ||
8753 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
8754 goto fail;
5f5fff43
JM
8755 if (EC_POINT_is_at_infinity(group, Qr)) {
8756 wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
8757 goto fail;
8758 }
d722c50d 8759 dpp_debug_print_point("DPP: Qr", group, Qr);
500ed7f0
JM
8760out:
8761 EC_KEY_free(Pr_ec);
8762 EVP_PKEY_free(Pr);
8763 BN_clear_free(hash_bn);
1cdfe8d2 8764 if (ret_group && Qr)
500ed7f0 8765 *ret_group = group2;
1cdfe8d2
JM
8766 else
8767 EC_GROUP_free(group2);
500ed7f0
JM
8768 return Qr;
8769fail:
8770 EC_POINT_free(Qr);
8771 Qr = NULL;
8772 goto out;
8773}
8774
8775
1cfcbd32
JM
8776#ifdef CONFIG_TESTING_OPTIONS
8777static int dpp_test_gen_invalid_key(struct wpabuf *msg,
8778 const struct dpp_curve_params *curve)
8779{
8780 BN_CTX *ctx;
8781 BIGNUM *x, *y;
1cfcbd32
JM
8782 int ret = -1;
8783 EC_GROUP *group;
8784 EC_POINT *point;
8785
8786 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
8787 if (!group)
4109555e 8788 return -1;
1cfcbd32
JM
8789
8790 ctx = BN_CTX_new();
8791 point = EC_POINT_new(group);
8792 x = BN_new();
8793 y = BN_new();
8794 if (!ctx || !point || !x || !y)
8795 goto fail;
8796
8797 if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
8798 goto fail;
8799
8800 /* Generate a random y coordinate that results in a point that is not
8801 * on the curve. */
8802 for (;;) {
8803 if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
8804 goto fail;
8805
8806 if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
94619905 8807 ctx) != 1) {
2b92c4f3 8808#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
2439714f
JM
8809 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8810 * return an error from EC_POINT_set_affine_coordinates_GFp()
8811 * when the point is not on the curve. */
94619905 8812 break;
2b92c4f3 8813#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
1cfcbd32 8814 goto fail;
2b92c4f3 8815#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
94619905 8816 }
1cfcbd32
JM
8817
8818 if (!EC_POINT_is_on_curve(group, point, ctx))
8819 break;
8820 }
8821
fc0efa2a
JM
8822 if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
8823 curve->prime_len) < 0 ||
8824 dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
8825 curve->prime_len) < 0)
1cfcbd32 8826 goto fail;
1cfcbd32
JM
8827
8828 ret = 0;
8829fail:
94619905
JM
8830 if (ret < 0)
8831 wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
1cfcbd32
JM
8832 BN_free(x);
8833 BN_free(y);
8834 EC_POINT_free(point);
8835 BN_CTX_free(ctx);
57ec74ea 8836 EC_GROUP_free(group);
1cfcbd32
JM
8837
8838 return ret;
8839}
8840#endif /* CONFIG_TESTING_OPTIONS */
8841
8842
500ed7f0
JM
8843static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
8844{
8845 EC_KEY *X_ec = NULL;
8846 const EC_POINT *X_point;
8847 BN_CTX *bnctx = NULL;
1cdfe8d2 8848 EC_GROUP *group = NULL;
500ed7f0
JM
8849 EC_POINT *Qi = NULL, *M = NULL;
8850 struct wpabuf *M_buf = NULL;
8851 BIGNUM *Mx = NULL, *My = NULL;
8852 struct wpabuf *msg = NULL;
8853 size_t attr_len;
8854 const struct dpp_curve_params *curve = pkex->own_bi->curve;
500ed7f0
JM
8855
8856 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
8857
8858 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8859 bnctx = BN_CTX_new();
8860 if (!bnctx)
8861 goto fail;
8862 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
8863 pkex->identifier, bnctx, &group);
8864 if (!Qi)
8865 goto fail;
8866
8867 /* Generate a random ephemeral keypair x/X */
acc555f9
JM
8868#ifdef CONFIG_TESTING_OPTIONS
8869 if (dpp_pkex_ephemeral_key_override_len) {
8870 const struct dpp_curve_params *tmp_curve;
8871
8872 wpa_printf(MSG_INFO,
8873 "DPP: TESTING - override ephemeral key x/X");
8874 pkex->x = dpp_set_keypair(&tmp_curve,
8875 dpp_pkex_ephemeral_key_override,
8876 dpp_pkex_ephemeral_key_override_len);
8877 } else {
8878 pkex->x = dpp_gen_keypair(curve);
8879 }
8880#else /* CONFIG_TESTING_OPTIONS */
500ed7f0 8881 pkex->x = dpp_gen_keypair(curve);
acc555f9 8882#endif /* CONFIG_TESTING_OPTIONS */
500ed7f0
JM
8883 if (!pkex->x)
8884 goto fail;
8885
8886 /* M = X + Qi */
8887 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x);
8888 if (!X_ec)
8889 goto fail;
8890 X_point = EC_KEY_get0_public_key(X_ec);
8891 if (!X_point)
8892 goto fail;
d722c50d 8893 dpp_debug_print_point("DPP: X", group, X_point);
500ed7f0
JM
8894 M = EC_POINT_new(group);
8895 Mx = BN_new();
8896 My = BN_new();
8897 if (!M || !Mx || !My ||
8898 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
8899 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
8900 goto fail;
d722c50d 8901 dpp_debug_print_point("DPP: M", group, M);
500ed7f0
JM
8902
8903 /* Initiator -> Responder: group, [identifier,] M */
8904 attr_len = 4 + 2;
8905 if (pkex->identifier)
8906 attr_len += 4 + os_strlen(pkex->identifier);
8907 attr_len += 4 + 2 * curve->prime_len;
8908 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
8909 if (!msg)
8910 goto fail;
8911
61f9f27f
JM
8912#ifdef CONFIG_TESTING_OPTIONS
8913 if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
8914 wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
8915 goto skip_finite_cyclic_group;
8916 }
8917#endif /* CONFIG_TESTING_OPTIONS */
8918
500ed7f0
JM
8919 /* Finite Cyclic Group attribute */
8920 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
8921 wpabuf_put_le16(msg, 2);
8922 wpabuf_put_le16(msg, curve->ike_group);
8923
61f9f27f
JM
8924#ifdef CONFIG_TESTING_OPTIONS
8925skip_finite_cyclic_group:
8926#endif /* CONFIG_TESTING_OPTIONS */
8927
500ed7f0
JM
8928 /* Code Identifier attribute */
8929 if (pkex->identifier) {
8930 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
8931 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
8932 wpabuf_put_str(msg, pkex->identifier);
8933 }
8934
61f9f27f
JM
8935#ifdef CONFIG_TESTING_OPTIONS
8936 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
8937 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
8938 goto out;
8939 }
8940#endif /* CONFIG_TESTING_OPTIONS */
8941
500ed7f0
JM
8942 /* M in Encrypted Key attribute */
8943 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
8944 wpabuf_put_le16(msg, 2 * curve->prime_len);
8945
1cfcbd32
JM
8946#ifdef CONFIG_TESTING_OPTIONS
8947 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) {
8948 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
8949 if (dpp_test_gen_invalid_key(msg, curve) < 0)
8950 goto fail;
8951 goto out;
8952 }
8953#endif /* CONFIG_TESTING_OPTIONS */
8954
fc0efa2a
JM
8955 if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
8956 curve->prime_len) < 0 ||
8957 dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
8958 dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
8959 curve->prime_len) < 0)
500ed7f0 8960 goto fail;
500ed7f0
JM
8961
8962out:
8963 wpabuf_free(M_buf);
8964 EC_KEY_free(X_ec);
8965 EC_POINT_free(M);
8966 EC_POINT_free(Qi);
8967 BN_clear_free(Mx);
8968 BN_clear_free(My);
8969 BN_CTX_free(bnctx);
1cdfe8d2 8970 EC_GROUP_free(group);
500ed7f0
JM
8971 return msg;
8972fail:
8973 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
8974 wpabuf_free(msg);
8975 msg = NULL;
8976 goto out;
8977}
8978
8979
219d4c9f
JM
8980static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
8981{
8982 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt);
8983}
8984
8985
8986struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
500ed7f0
JM
8987 const u8 *own_mac,
8988 const char *identifier,
8989 const char *code)
8990{
8991 struct dpp_pkex *pkex;
8992
2bdc47a9
JM
8993#ifdef CONFIG_TESTING_OPTIONS
8994 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
8995 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
8996 MAC2STR(dpp_pkex_own_mac_override));
8997 own_mac = dpp_pkex_own_mac_override;
8998 }
8999#endif /* CONFIG_TESTING_OPTIONS */
9000
500ed7f0
JM
9001 pkex = os_zalloc(sizeof(*pkex));
9002 if (!pkex)
9003 return NULL;
219d4c9f 9004 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
9005 pkex->initiator = 1;
9006 pkex->own_bi = bi;
9007 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9008 if (identifier) {
9009 pkex->identifier = os_strdup(identifier);
9010 if (!pkex->identifier)
9011 goto fail;
9012 }
9013 pkex->code = os_strdup(code);
9014 if (!pkex->code)
9015 goto fail;
9016 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
9017 if (!pkex->exchange_req)
9018 goto fail;
9019 return pkex;
9020fail:
9021 dpp_pkex_free(pkex);
9022 return NULL;
9023}
9024
9025
e0247e79
JM
9026static struct wpabuf *
9027dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
9028 enum dpp_status_error status,
9029 const BIGNUM *Nx, const BIGNUM *Ny)
a5c3b41b
JM
9030{
9031 struct wpabuf *msg = NULL;
9032 size_t attr_len;
a5c3b41b
JM
9033 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9034
9035 /* Initiator -> Responder: DPP Status, [identifier,] N */
9036 attr_len = 4 + 1;
e0247e79
JM
9037 if (pkex->identifier)
9038 attr_len += 4 + os_strlen(pkex->identifier);
a5c3b41b
JM
9039 attr_len += 4 + 2 * curve->prime_len;
9040 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len);
9041 if (!msg)
9042 goto fail;
9043
61f9f27f
JM
9044#ifdef CONFIG_TESTING_OPTIONS
9045 if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) {
9046 wpa_printf(MSG_INFO, "DPP: TESTING - no Status");
9047 goto skip_status;
9048 }
f31ef96d
JM
9049
9050 if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) {
9051 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status");
9052 status = 255;
9053 }
61f9f27f
JM
9054#endif /* CONFIG_TESTING_OPTIONS */
9055
a5c3b41b 9056 /* DPP Status */
56f24d1d 9057 dpp_build_attr_status(msg, status);
a5c3b41b 9058
61f9f27f
JM
9059#ifdef CONFIG_TESTING_OPTIONS
9060skip_status:
9061#endif /* CONFIG_TESTING_OPTIONS */
9062
a5c3b41b
JM
9063 /* Code Identifier attribute */
9064 if (pkex->identifier) {
9065 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
9066 wpabuf_put_le16(msg, os_strlen(pkex->identifier));
9067 wpabuf_put_str(msg, pkex->identifier);
9068 }
9069
e0247e79
JM
9070 if (status != DPP_STATUS_OK)
9071 goto skip_encrypted_key;
9072
61f9f27f
JM
9073#ifdef CONFIG_TESTING_OPTIONS
9074 if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9075 wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key");
9076 goto skip_encrypted_key;
9077 }
9078#endif /* CONFIG_TESTING_OPTIONS */
9079
a5c3b41b
JM
9080 /* N in Encrypted Key attribute */
9081 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY);
9082 wpabuf_put_le16(msg, 2 * curve->prime_len);
9083
1cfcbd32
JM
9084#ifdef CONFIG_TESTING_OPTIONS
9085 if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) {
9086 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key");
9087 if (dpp_test_gen_invalid_key(msg, curve) < 0)
9088 goto fail;
9089 goto skip_encrypted_key;
9090 }
9091#endif /* CONFIG_TESTING_OPTIONS */
9092
fc0efa2a
JM
9093 if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
9094 curve->prime_len) < 0 ||
9095 dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
9096 dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
9097 curve->prime_len) < 0)
a5c3b41b 9098 goto fail;
a5c3b41b 9099
61f9f27f 9100skip_encrypted_key:
e0247e79
JM
9101 if (status == DPP_STATUS_BAD_GROUP) {
9102 /* Finite Cyclic Group attribute */
9103 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP);
9104 wpabuf_put_le16(msg, 2);
9105 wpabuf_put_le16(msg, curve->ike_group);
9106 }
9107
a5c3b41b
JM
9108 return msg;
9109fail:
9110 wpabuf_free(msg);
9111 return NULL;
9112}
9113
9114
d05c82c4
JM
9115static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
9116 const u8 *Mx, size_t Mx_len,
9117 const u8 *Nx, size_t Nx_len,
9118 const char *code,
9119 const u8 *Kx, size_t Kx_len,
9120 u8 *z, unsigned int hash_len)
9121{
9122 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN];
9123 int res;
9124 u8 *info, *pos;
9125 size_t info_len;
9126
9127 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9128 */
9129
9130 /* HKDF-Extract(<>, IKM=K.x) */
9131 os_memset(salt, 0, hash_len);
9132 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0)
9133 return -1;
9134 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
9135 prk, hash_len);
9136 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
9137 info = os_malloc(info_len);
9138 if (!info)
9139 return -1;
9140 pos = info;
9141 os_memcpy(pos, mac_init, ETH_ALEN);
9142 pos += ETH_ALEN;
9143 os_memcpy(pos, mac_resp, ETH_ALEN);
9144 pos += ETH_ALEN;
9145 os_memcpy(pos, Mx, Mx_len);
9146 pos += Mx_len;
9147 os_memcpy(pos, Nx, Nx_len);
9148 pos += Nx_len;
9149 os_memcpy(pos, code, os_strlen(code));
9150
9151 /* HKDF-Expand(PRK, info, L) */
9152 if (hash_len == 32)
9153 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len,
9154 z, hash_len);
9155 else if (hash_len == 48)
9156 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len,
9157 z, hash_len);
9158 else if (hash_len == 64)
9159 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len,
9160 z, hash_len);
9161 else
9162 res = -1;
9163 os_free(info);
9164 os_memset(prk, 0, hash_len);
9165 if (res < 0)
9166 return -1;
9167
9168 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)",
9169 z, hash_len);
9170 return 0;
9171}
9172
9173
4a450ba2
JM
9174static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len,
9175 const char *identifier)
9176{
9177 if (!attr_id && identifier) {
9178 wpa_printf(MSG_DEBUG,
9179 "DPP: No PKEX code identifier received, but expected one");
9180 return 0;
9181 }
9182
9183 if (attr_id && !identifier) {
9184 wpa_printf(MSG_DEBUG,
9185 "DPP: PKEX code identifier received, but not expecting one");
9186 return 0;
9187 }
9188
9189 if (attr_id && identifier &&
9190 (os_strlen(identifier) != attr_id_len ||
9191 os_memcmp(identifier, attr_id, attr_id_len) != 0)) {
9192 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch");
9193 return 0;
9194 }
9195
9196 return 1;
9197}
9198
9199
219d4c9f
JM
9200struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
9201 struct dpp_bootstrap_info *bi,
500ed7f0
JM
9202 const u8 *own_mac,
9203 const u8 *peer_mac,
9204 const char *identifier,
9205 const char *code,
9206 const u8 *buf, size_t len)
9207{
9208 const u8 *attr_group, *attr_id, *attr_key;
9209 u16 attr_group_len, attr_id_len, attr_key_len;
9210 const struct dpp_curve_params *curve = bi->curve;
9211 u16 ike_group;
9212 struct dpp_pkex *pkex = NULL;
9213 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
9214 BN_CTX *bnctx = NULL;
1cdfe8d2 9215 EC_GROUP *group = NULL;
500ed7f0
JM
9216 BIGNUM *Mx = NULL, *My = NULL;
9217 EC_KEY *Y_ec = NULL, *X_ec = NULL;;
9218 const EC_POINT *Y_point;
9219 BIGNUM *Nx = NULL, *Ny = NULL;
d05c82c4
JM
9220 u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
9221 size_t Kx_len;
9222 int res;
500ed7f0 9223
29ab69e4
JM
9224 if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
9225 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9226 "PKEX counter t limit reached - ignore message");
9227 return NULL;
9228 }
9229
2bdc47a9
JM
9230#ifdef CONFIG_TESTING_OPTIONS
9231 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9232 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9233 MAC2STR(dpp_pkex_peer_mac_override));
9234 peer_mac = dpp_pkex_peer_mac_override;
9235 }
9236 if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) {
9237 wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR,
9238 MAC2STR(dpp_pkex_own_mac_override));
9239 own_mac = dpp_pkex_own_mac_override;
9240 }
9241#endif /* CONFIG_TESTING_OPTIONS */
9242
4a450ba2 9243 attr_id_len = 0;
500ed7f0
JM
9244 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
9245 &attr_id_len);
4a450ba2 9246 if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier))
500ed7f0 9247 return NULL;
500ed7f0
JM
9248
9249 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP,
9250 &attr_group_len);
9251 if (!attr_group || attr_group_len != 2) {
d7e7b712
JM
9252 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9253 "Missing or invalid Finite Cyclic Group attribute");
500ed7f0
JM
9254 return NULL;
9255 }
9256 ike_group = WPA_GET_LE16(attr_group);
9257 if (ike_group != curve->ike_group) {
d7e7b712
JM
9258 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9259 "Mismatching PKEX curve: peer=%u own=%u",
9260 ike_group, curve->ike_group);
e0247e79
JM
9261 pkex = os_zalloc(sizeof(*pkex));
9262 if (!pkex)
9263 goto fail;
9264 pkex->own_bi = bi;
9265 pkex->failed = 1;
9266 pkex->exchange_resp = dpp_pkex_build_exchange_resp(
9267 pkex, DPP_STATUS_BAD_GROUP, NULL, NULL);
9268 if (!pkex->exchange_resp)
9269 goto fail;
9270 return pkex;
500ed7f0
JM
9271 }
9272
9273 /* M in Encrypted Key attribute */
9274 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY,
9275 &attr_key_len);
9276 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 ||
9277 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) {
d7e7b712
JM
9278 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9279 "Missing Encrypted Key attribute");
500ed7f0
JM
9280 return NULL;
9281 }
9282
9283 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9284 bnctx = BN_CTX_new();
9285 if (!bnctx)
9286 goto fail;
9287 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
9288 &group);
9289 if (!Qi)
9290 goto fail;
9291
9292 /* X' = M - Qi */
9293 X = EC_POINT_new(group);
9294 M = EC_POINT_new(group);
9295 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9296 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9297 if (!X || !M || !Mx || !My ||
9298 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
9299 EC_POINT_is_at_infinity(group, M) ||
9300 !EC_POINT_is_on_curve(group, M, bnctx) ||
9301 EC_POINT_invert(group, Qi, bnctx) != 1 ||
9302 EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
9303 EC_POINT_is_at_infinity(group, X) ||
d7e7b712
JM
9304 !EC_POINT_is_on_curve(group, X, bnctx)) {
9305 wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9306 "Invalid Encrypted Key value");
29ab69e4 9307 bi->pkex_t++;
500ed7f0 9308 goto fail;
d7e7b712 9309 }
d722c50d
JM
9310 dpp_debug_print_point("DPP: M", group, M);
9311 dpp_debug_print_point("DPP: X'", group, X);
500ed7f0
JM
9312
9313 pkex = os_zalloc(sizeof(*pkex));
9314 if (!pkex)
9315 goto fail;
29ab69e4 9316 pkex->t = bi->pkex_t;
219d4c9f 9317 pkex->msg_ctx = msg_ctx;
500ed7f0
JM
9318 pkex->own_bi = bi;
9319 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
9320 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9321 if (identifier) {
9322 pkex->identifier = os_strdup(identifier);
9323 if (!pkex->identifier)
9324 goto fail;
9325 }
9326 pkex->code = os_strdup(code);
9327 if (!pkex->code)
9328 goto fail;
9329
9330 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
9331
9332 X_ec = EC_KEY_new();
9333 if (!X_ec ||
9334 EC_KEY_set_group(X_ec, group) != 1 ||
9335 EC_KEY_set_public_key(X_ec, X) != 1)
9336 goto fail;
9337 pkex->x = EVP_PKEY_new();
9338 if (!pkex->x ||
9339 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
9340 goto fail;
9341
9342 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9343 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
9344 if (!Qr)
9345 goto fail;
9346
9347 /* Generate a random ephemeral keypair y/Y */
acc555f9
JM
9348#ifdef CONFIG_TESTING_OPTIONS
9349 if (dpp_pkex_ephemeral_key_override_len) {
9350 const struct dpp_curve_params *tmp_curve;
9351
9352 wpa_printf(MSG_INFO,
9353 "DPP: TESTING - override ephemeral key y/Y");
9354 pkex->y = dpp_set_keypair(&tmp_curve,
9355 dpp_pkex_ephemeral_key_override,
9356 dpp_pkex_ephemeral_key_override_len);
9357 } else {
9358 pkex->y = dpp_gen_keypair(curve);
9359 }
9360#else /* CONFIG_TESTING_OPTIONS */
500ed7f0 9361 pkex->y = dpp_gen_keypair(curve);
acc555f9 9362#endif /* CONFIG_TESTING_OPTIONS */
500ed7f0
JM
9363 if (!pkex->y)
9364 goto fail;
9365
9366 /* N = Y + Qr */
9367 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y);
9368 if (!Y_ec)
9369 goto fail;
9370 Y_point = EC_KEY_get0_public_key(Y_ec);
9371 if (!Y_point)
9372 goto fail;
d722c50d 9373 dpp_debug_print_point("DPP: Y", group, Y_point);
500ed7f0
JM
9374 N = EC_POINT_new(group);
9375 Nx = BN_new();
9376 Ny = BN_new();
9377 if (!N || !Nx || !Ny ||
9378 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
9379 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
9380 goto fail;
d722c50d 9381 dpp_debug_print_point("DPP: N", group, N);
500ed7f0 9382
e0247e79 9383 pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
a5c3b41b
JM
9384 Nx, Ny);
9385 if (!pkex->exchange_resp)
500ed7f0
JM
9386 goto fail;
9387
d05c82c4 9388 /* K = y * X' */
29ef1c5e 9389 if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0)
d05c82c4 9390 goto fail;
d05c82c4
JM
9391
9392 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9393 Kx, Kx_len);
9394
9395 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9396 */
9397 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
9398 pkex->Mx, curve->prime_len,
9399 pkex->Nx, curve->prime_len, pkex->code,
9400 Kx, Kx_len, pkex->z, curve->hash_len);
9401 os_memset(Kx, 0, Kx_len);
9402 if (res < 0)
9403 goto fail;
9404
500ed7f0
JM
9405 pkex->exchange_done = 1;
9406
9407out:
500ed7f0
JM
9408 BN_CTX_free(bnctx);
9409 EC_POINT_free(Qi);
9410 EC_POINT_free(Qr);
9411 BN_free(Mx);
9412 BN_free(My);
9413 BN_free(Nx);
9414 BN_free(Ny);
9415 EC_POINT_free(M);
9416 EC_POINT_free(N);
9417 EC_POINT_free(X);
9418 EC_KEY_free(X_ec);
9419 EC_KEY_free(Y_ec);
1cdfe8d2 9420 EC_GROUP_free(group);
500ed7f0
JM
9421 return pkex;
9422fail:
60b9dd86 9423 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
500ed7f0
JM
9424 dpp_pkex_free(pkex);
9425 pkex = NULL;
9426 goto out;
9427}
9428
9429
b0626c2a
JM
9430static struct wpabuf *
9431dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex,
9432 const struct wpabuf *A_pub, const u8 *u)
9433{
9434 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9435 struct wpabuf *msg = NULL;
9436 size_t clear_len, attr_len;
9437 struct wpabuf *clear = NULL;
9438 u8 *wrapped;
9439 u8 octet;
9440 const u8 *addr[2];
9441 size_t len[2];
9442
9443 /* {A, u, [bootstrapping info]}z */
9444 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9445 clear = wpabuf_alloc(clear_len);
9446 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9447#ifdef CONFIG_TESTING_OPTIONS
9448 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ)
acdf703d 9449 attr_len += 5;
b0626c2a
JM
9450#endif /* CONFIG_TESTING_OPTIONS */
9451 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len);
9452 if (!clear || !msg)
9453 goto fail;
9454
61f9f27f
JM
9455#ifdef CONFIG_TESTING_OPTIONS
9456 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9457 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9458 goto skip_bootstrap_key;
9459 }
89d0bf67
JM
9460 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) {
9461 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9462 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9463 wpabuf_put_le16(clear, 2 * curve->prime_len);
9464 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9465 goto fail;
9466 goto skip_bootstrap_key;
9467 }
61f9f27f
JM
9468#endif /* CONFIG_TESTING_OPTIONS */
9469
b0626c2a
JM
9470 /* A in Bootstrap Key attribute */
9471 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9472 wpabuf_put_le16(clear, wpabuf_len(A_pub));
9473 wpabuf_put_buf(clear, A_pub);
9474
61f9f27f
JM
9475#ifdef CONFIG_TESTING_OPTIONS
9476skip_bootstrap_key:
9477 if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) {
9478 wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag");
9479 goto skip_i_auth_tag;
9480 }
7e0ebe21
JM
9481 if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) {
9482 wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch");
9483 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9484 wpabuf_put_le16(clear, curve->hash_len);
9485 wpabuf_put_data(clear, u, curve->hash_len - 1);
9486 wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01);
9487 goto skip_i_auth_tag;
9488 }
61f9f27f
JM
9489#endif /* CONFIG_TESTING_OPTIONS */
9490
b0626c2a
JM
9491 /* u in I-Auth tag attribute */
9492 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
9493 wpabuf_put_le16(clear, curve->hash_len);
9494 wpabuf_put_data(clear, u, curve->hash_len);
9495
61f9f27f
JM
9496#ifdef CONFIG_TESTING_OPTIONS
9497skip_i_auth_tag:
9498 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) {
9499 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9500 goto skip_wrapped_data;
9501 }
9502#endif /* CONFIG_TESTING_OPTIONS */
9503
b0626c2a
JM
9504 addr[0] = wpabuf_head_u8(msg) + 2;
9505 len[0] = DPP_HDR_LEN;
9506 octet = 0;
9507 addr[1] = &octet;
9508 len[1] = sizeof(octet);
9509 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9510 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9511
9512 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9513 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9514 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9515
9516 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9517 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9518 wpabuf_head(clear), wpabuf_len(clear),
9519 2, addr, len, wrapped) < 0)
9520 goto fail;
9521 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9522 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9523
9524#ifdef CONFIG_TESTING_OPTIONS
9525 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) {
9526 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 9527 dpp_build_attr_status(msg, DPP_STATUS_OK);
b0626c2a 9528 }
61f9f27f 9529skip_wrapped_data:
b0626c2a
JM
9530#endif /* CONFIG_TESTING_OPTIONS */
9531
9532out:
9533 wpabuf_free(clear);
9534 return msg;
9535
9536fail:
9537 wpabuf_free(msg);
9538 msg = NULL;
9539 goto out;
9540}
9541
9542
500ed7f0 9543struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
af4103e5 9544 const u8 *peer_mac,
500ed7f0
JM
9545 const u8 *buf, size_t buflen)
9546{
e0247e79
JM
9547 const u8 *attr_status, *attr_id, *attr_key, *attr_group;
9548 u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
1cdfe8d2 9549 EC_GROUP *group = NULL;
500ed7f0 9550 BN_CTX *bnctx = NULL;
500ed7f0
JM
9551 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9552 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9553 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
9554 BIGNUM *Nx = NULL, *Ny = NULL;
500ed7f0 9555 EC_KEY *Y_ec = NULL;
0e6709a4
JM
9556 size_t Jx_len, Kx_len;
9557 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
9558 const u8 *addr[4];
9559 size_t len[4];
9560 u8 u[DPP_MAX_HASH_LEN];
6254045a 9561 int res;
500ed7f0 9562
03abb6b5 9563 if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
9564 return NULL;
9565
2bdc47a9 9566#ifdef CONFIG_TESTING_OPTIONS
34603767
JM
9567 if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) {
9568 wpa_printf(MSG_INFO,
9569 "DPP: TESTING - stop at PKEX Exchange Response");
9570 pkex->failed = 1;
9571 return NULL;
9572 }
9573
2bdc47a9
JM
9574 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
9575 wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
9576 MAC2STR(dpp_pkex_peer_mac_override));
9577 peer_mac = dpp_pkex_peer_mac_override;
9578 }
9579#endif /* CONFIG_TESTING_OPTIONS */
9580
af4103e5
JM
9581 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
9582
500ed7f0
JM
9583 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
9584 &attr_status_len);
9585 if (!attr_status || attr_status_len != 1) {
d7e7b712 9586 dpp_pkex_fail(pkex, "No DPP Status attribute");
500ed7f0
JM
9587 return NULL;
9588 }
9589 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]);
e0247e79
JM
9590
9591 if (attr_status[0] == DPP_STATUS_BAD_GROUP) {
9592 attr_group = dpp_get_attr(buf, buflen,
9593 DPP_ATTR_FINITE_CYCLIC_GROUP,
9594 &attr_group_len);
9595 if (attr_group && attr_group_len == 2) {
9596 wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
9597 "Peer indicated mismatching PKEX group - proposed %u",
9598 WPA_GET_LE16(attr_group));
9599 return NULL;
9600 }
9601 }
9602
500ed7f0 9603 if (attr_status[0] != DPP_STATUS_OK) {
d7e7b712 9604 dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)");
500ed7f0
JM
9605 return NULL;
9606 }
9607
4a450ba2 9608 attr_id_len = 0;
500ed7f0
JM
9609 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER,
9610 &attr_id_len);
4a450ba2
JM
9611 if (!dpp_pkex_identifier_match(attr_id, attr_id_len,
9612 pkex->identifier)) {
d7e7b712 9613 dpp_pkex_fail(pkex, "PKEX code identifier mismatch");
500ed7f0
JM
9614 return NULL;
9615 }
9616
9617 /* N in Encrypted Key attribute */
9618 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY,
9619 &attr_key_len);
9620 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) {
d7e7b712 9621 dpp_pkex_fail(pkex, "Missing Encrypted Key attribute");
500ed7f0
JM
9622 return NULL;
9623 }
9624
9625 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9626 bnctx = BN_CTX_new();
9627 if (!bnctx)
9628 goto fail;
9629 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
9630 pkex->identifier, bnctx, &group);
9631 if (!Qr)
9632 goto fail;
9633
9634 /* Y' = N - Qr */
9635 Y = EC_POINT_new(group);
9636 N = EC_POINT_new(group);
9637 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
9638 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
9639 if (!Y || !N || !Nx || !Ny ||
9640 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
9641 EC_POINT_is_at_infinity(group, N) ||
9642 !EC_POINT_is_on_curve(group, N, bnctx) ||
9643 EC_POINT_invert(group, Qr, bnctx) != 1 ||
9644 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
9645 EC_POINT_is_at_infinity(group, Y) ||
d7e7b712
JM
9646 !EC_POINT_is_on_curve(group, Y, bnctx)) {
9647 dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
29ab69e4 9648 pkex->t++;
500ed7f0 9649 goto fail;
d7e7b712 9650 }
d722c50d
JM
9651 dpp_debug_print_point("DPP: N", group, N);
9652 dpp_debug_print_point("DPP: Y'", group, Y);
500ed7f0
JM
9653
9654 pkex->exchange_done = 1;
9655
9656 /* ECDH: J = a * Y’ */
9657 Y_ec = EC_KEY_new();
9658 if (!Y_ec ||
9659 EC_KEY_set_group(Y_ec, group) != 1 ||
9660 EC_KEY_set_public_key(Y_ec, Y) != 1)
9661 goto fail;
9662 pkex->y = EVP_PKEY_new();
9663 if (!pkex->y ||
9664 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
9665 goto fail;
29ef1c5e 9666 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
500ed7f0 9667 goto fail;
500ed7f0
JM
9668
9669 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
9670 Jx, Jx_len);
9671
9672 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9673 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
9674 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
9675 X_pub = dpp_get_pubkey_point(pkex->x, 0);
9676 if (!A_pub || !Y_pub || !X_pub)
9677 goto fail;
9678 addr[0] = pkex->own_mac;
9679 len[0] = ETH_ALEN;
9680 addr[1] = wpabuf_head(A_pub);
9681 len[1] = wpabuf_len(A_pub) / 2;
9682 addr[2] = wpabuf_head(Y_pub);
9683 len[2] = wpabuf_len(Y_pub) / 2;
9684 addr[3] = wpabuf_head(X_pub);
9685 len[3] = wpabuf_len(X_pub) / 2;
9686 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
9687 goto fail;
9688 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
9689
0e6709a4 9690 /* K = x * Y’ */
29ef1c5e 9691 if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0)
500ed7f0 9692 goto fail;
500ed7f0 9693
0e6709a4
JM
9694 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
9695 Kx, Kx_len);
500ed7f0 9696
0e6709a4 9697 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
500ed7f0 9698 */
6254045a
JM
9699 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
9700 pkex->Mx, curve->prime_len,
9701 attr_key /* N.x */, attr_key_len / 2,
9702 pkex->code, Kx, Kx_len,
9703 pkex->z, curve->hash_len);
9704 os_memset(Kx, 0, Kx_len);
9705 if (res < 0)
500ed7f0
JM
9706 goto fail;
9707
b0626c2a
JM
9708 msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u);
9709 if (!msg)
500ed7f0 9710 goto fail;
60239f60 9711
500ed7f0 9712out:
500ed7f0
JM
9713 wpabuf_free(A_pub);
9714 wpabuf_free(X_pub);
9715 wpabuf_free(Y_pub);
9716 EC_POINT_free(Qr);
9717 EC_POINT_free(Y);
9718 EC_POINT_free(N);
9719 BN_free(Nx);
9720 BN_free(Ny);
9721 EC_KEY_free(Y_ec);
500ed7f0 9722 BN_CTX_free(bnctx);
1cdfe8d2 9723 EC_GROUP_free(group);
500ed7f0
JM
9724 return msg;
9725fail:
60b9dd86 9726 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
500ed7f0
JM
9727 goto out;
9728}
9729
9730
b3e4cc5c
JM
9731static struct wpabuf *
9732dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex,
9733 const struct wpabuf *B_pub, const u8 *v)
9734{
9735 const struct dpp_curve_params *curve = pkex->own_bi->curve;
9736 struct wpabuf *msg = NULL;
9737 const u8 *addr[2];
9738 size_t len[2];
9739 u8 octet;
9740 u8 *wrapped;
9741 struct wpabuf *clear = NULL;
9742 size_t clear_len, attr_len;
9743
9744 /* {B, v [bootstrapping info]}z */
9745 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len;
9746 clear = wpabuf_alloc(clear_len);
9747 attr_len = 4 + clear_len + AES_BLOCK_SIZE;
9748#ifdef CONFIG_TESTING_OPTIONS
9749 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP)
acdf703d 9750 attr_len += 5;
b3e4cc5c
JM
9751#endif /* CONFIG_TESTING_OPTIONS */
9752 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len);
9753 if (!clear || !msg)
9754 goto fail;
9755
61f9f27f
JM
9756#ifdef CONFIG_TESTING_OPTIONS
9757 if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9758 wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key");
9759 goto skip_bootstrap_key;
9760 }
89d0bf67
JM
9761 if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) {
9762 wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key");
9763 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9764 wpabuf_put_le16(clear, 2 * curve->prime_len);
9765 if (dpp_test_gen_invalid_key(clear, curve) < 0)
9766 goto fail;
9767 goto skip_bootstrap_key;
9768 }
61f9f27f
JM
9769#endif /* CONFIG_TESTING_OPTIONS */
9770
9771 /* B in Bootstrap Key attribute */
b3e4cc5c
JM
9772 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY);
9773 wpabuf_put_le16(clear, wpabuf_len(B_pub));
9774 wpabuf_put_buf(clear, B_pub);
9775
61f9f27f
JM
9776#ifdef CONFIG_TESTING_OPTIONS
9777skip_bootstrap_key:
9778 if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) {
9779 wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag");
9780 goto skip_r_auth_tag;
9781 }
7e0ebe21
JM
9782 if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) {
9783 wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch");
9784 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
9785 wpabuf_put_le16(clear, curve->hash_len);
9786 wpabuf_put_data(clear, v, curve->hash_len - 1);
9787 wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01);
9788 goto skip_r_auth_tag;
9789 }
61f9f27f
JM
9790#endif /* CONFIG_TESTING_OPTIONS */
9791
b3e4cc5c
JM
9792 /* v in R-Auth tag attribute */
9793 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG);
9794 wpabuf_put_le16(clear, curve->hash_len);
9795 wpabuf_put_data(clear, v, curve->hash_len);
9796
61f9f27f
JM
9797#ifdef CONFIG_TESTING_OPTIONS
9798skip_r_auth_tag:
9799 if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) {
9800 wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data");
9801 goto skip_wrapped_data;
9802 }
9803#endif /* CONFIG_TESTING_OPTIONS */
9804
b3e4cc5c
JM
9805 addr[0] = wpabuf_head_u8(msg) + 2;
9806 len[0] = DPP_HDR_LEN;
9807 octet = 1;
9808 addr[1] = &octet;
9809 len[1] = sizeof(octet);
9810 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9811 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
9812
9813 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
9814 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9815 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
9816
9817 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
9818 if (aes_siv_encrypt(pkex->z, curve->hash_len,
9819 wpabuf_head(clear), wpabuf_len(clear),
9820 2, addr, len, wrapped) < 0)
9821 goto fail;
9822 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9823 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE);
9824
9825#ifdef CONFIG_TESTING_OPTIONS
9826 if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) {
9827 wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data");
acdf703d 9828 dpp_build_attr_status(msg, DPP_STATUS_OK);
b3e4cc5c 9829 }
61f9f27f 9830skip_wrapped_data:
b3e4cc5c
JM
9831#endif /* CONFIG_TESTING_OPTIONS */
9832
9833out:
9834 wpabuf_free(clear);
9835 return msg;
9836
9837fail:
9838 wpabuf_free(msg);
9839 msg = NULL;
9840 goto out;
9841}
9842
9843
500ed7f0 9844struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
4be5bc98 9845 const u8 *hdr,
500ed7f0
JM
9846 const u8 *buf, size_t buflen)
9847{
9848 const struct dpp_curve_params *curve = pkex->own_bi->curve;
d05c82c4
JM
9849 size_t Jx_len, Lx_len;
9850 u8 Jx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
9851 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
9852 const u8 *wrapped_data, *b_key, *peer_u;
9853 u16 wrapped_data_len, b_key_len, peer_u_len = 0;
9854 const u8 *addr[4];
9855 size_t len[4];
9856 u8 octet;
9857 u8 *unwrapped = NULL;
9858 size_t unwrapped_len = 0;
9859 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
9860 struct wpabuf *B_pub = NULL;
9861 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
500ed7f0 9862
34603767
JM
9863#ifdef CONFIG_TESTING_OPTIONS
9864 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) {
9865 wpa_printf(MSG_INFO,
9866 "DPP: TESTING - stop at PKEX CR Request");
9867 pkex->failed = 1;
9868 return NULL;
9869 }
9870#endif /* CONFIG_TESTING_OPTIONS */
9871
29ab69e4 9872 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 9873 pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator)
e0247e79
JM
9874 goto fail;
9875
500ed7f0
JM
9876 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
9877 &wrapped_data_len);
9878 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
9879 dpp_pkex_fail(pkex,
9880 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
9881 goto fail;
9882 }
9883
9884 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
9885 wrapped_data, wrapped_data_len);
9886 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
9887 unwrapped = os_malloc(unwrapped_len);
9888 if (!unwrapped)
9889 goto fail;
9890
4be5bc98
JM
9891 addr[0] = hdr;
9892 len[0] = DPP_HDR_LEN;
500ed7f0 9893 octet = 0;
4be5bc98
JM
9894 addr[1] = &octet;
9895 len[1] = sizeof(octet);
9896 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
9897 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
9898
9899 if (aes_siv_decrypt(pkex->z, curve->hash_len,
9900 wrapped_data, wrapped_data_len,
4be5bc98 9901 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
9902 dpp_pkex_fail(pkex,
9903 "AES-SIV decryption failed - possible PKEX code mismatch");
039b8e73 9904 pkex->failed = 1;
29ab69e4 9905 pkex->t++;
500ed7f0
JM
9906 goto fail;
9907 }
9908 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
9909 unwrapped, unwrapped_len);
9910
9911 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 9912 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
9913 goto fail;
9914 }
9915
9916 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
9917 &b_key_len);
9918 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 9919 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
9920 goto fail;
9921 }
9922 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
9923 b_key_len);
d7e7b712
JM
9924 if (!pkex->peer_bootstrap_key) {
9925 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 9926 goto fail;
d7e7b712 9927 }
500ed7f0
JM
9928 dpp_debug_print_key("DPP: Peer bootstrap public key",
9929 pkex->peer_bootstrap_key);
9930
9931 /* ECDH: J' = y * A' */
29ef1c5e 9932 if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0)
500ed7f0 9933 goto fail;
500ed7f0
JM
9934
9935 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
9936 Jx, Jx_len);
9937
9938 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9939 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
9940 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
9941 X_pub = dpp_get_pubkey_point(pkex->x, 0);
9942 if (!A_pub || !Y_pub || !X_pub)
9943 goto fail;
9944 addr[0] = pkex->peer_mac;
9945 len[0] = ETH_ALEN;
9946 addr[1] = wpabuf_head(A_pub);
9947 len[1] = wpabuf_len(A_pub) / 2;
9948 addr[2] = wpabuf_head(Y_pub);
9949 len[2] = wpabuf_len(Y_pub) / 2;
9950 addr[3] = wpabuf_head(X_pub);
9951 len[3] = wpabuf_len(X_pub) / 2;
9952 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
9953 goto fail;
9954
9955 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
9956 &peer_u_len);
9957 if (!peer_u || peer_u_len != curve->hash_len ||
9958 os_memcmp(peer_u, u, curve->hash_len) != 0) {
d7e7b712 9959 dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found");
500ed7f0
JM
9960 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
9961 u, curve->hash_len);
9962 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
29ab69e4 9963 pkex->t++;
500ed7f0
JM
9964 goto fail;
9965 }
9966 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
9967
9968 /* ECDH: L = b * X' */
29ef1c5e 9969 if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0)
500ed7f0 9970 goto fail;
500ed7f0
JM
9971
9972 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
9973 Lx, Lx_len);
9974
9975 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
9976 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
9977 if (!B_pub)
9978 goto fail;
9979 addr[0] = pkex->own_mac;
9980 len[0] = ETH_ALEN;
9981 addr[1] = wpabuf_head(B_pub);
9982 len[1] = wpabuf_len(B_pub) / 2;
9983 addr[2] = wpabuf_head(X_pub);
9984 len[2] = wpabuf_len(X_pub) / 2;
9985 addr[3] = wpabuf_head(Y_pub);
9986 len[3] = wpabuf_len(Y_pub) / 2;
9987 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
9988 goto fail;
9989 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
9990
b3e4cc5c
JM
9991 msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v);
9992 if (!msg)
500ed7f0 9993 goto fail;
60239f60 9994
500ed7f0 9995out:
500ed7f0
JM
9996 os_free(unwrapped);
9997 wpabuf_free(A_pub);
9998 wpabuf_free(B_pub);
9999 wpabuf_free(X_pub);
10000 wpabuf_free(Y_pub);
500ed7f0
JM
10001 return msg;
10002fail:
b3e4cc5c
JM
10003 wpa_printf(MSG_DEBUG,
10004 "DPP: PKEX Commit-Reveal Request processing failed");
500ed7f0
JM
10005 goto out;
10006}
10007
10008
4be5bc98 10009int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
500ed7f0
JM
10010 const u8 *buf, size_t buflen)
10011{
10012 const struct dpp_curve_params *curve = pkex->own_bi->curve;
10013 const u8 *wrapped_data, *b_key, *peer_v;
10014 u16 wrapped_data_len, b_key_len, peer_v_len = 0;
10015 const u8 *addr[4];
10016 size_t len[4];
10017 u8 octet;
10018 u8 *unwrapped = NULL;
10019 size_t unwrapped_len = 0;
10020 int ret = -1;
10021 u8 v[DPP_MAX_HASH_LEN];
10022 size_t Lx_len;
10023 u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
500ed7f0
JM
10024 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
10025
34603767
JM
10026#ifdef CONFIG_TESTING_OPTIONS
10027 if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) {
10028 wpa_printf(MSG_INFO,
10029 "DPP: TESTING - stop at PKEX CR Response");
10030 pkex->failed = 1;
10031 goto fail;
10032 }
10033#endif /* CONFIG_TESTING_OPTIONS */
10034
29ab69e4 10035 if (!pkex->exchange_done || pkex->failed ||
03abb6b5 10036 pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator)
e0247e79
JM
10037 goto fail;
10038
500ed7f0
JM
10039 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
10040 &wrapped_data_len);
10041 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
d7e7b712
JM
10042 dpp_pkex_fail(pkex,
10043 "Missing or invalid required Wrapped Data attribute");
500ed7f0
JM
10044 goto fail;
10045 }
10046
10047 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
10048 wrapped_data, wrapped_data_len);
10049 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
10050 unwrapped = os_malloc(unwrapped_len);
10051 if (!unwrapped)
10052 goto fail;
10053
4be5bc98
JM
10054 addr[0] = hdr;
10055 len[0] = DPP_HDR_LEN;
500ed7f0 10056 octet = 1;
4be5bc98
JM
10057 addr[1] = &octet;
10058 len[1] = sizeof(octet);
10059 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
10060 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
500ed7f0
JM
10061
10062 if (aes_siv_decrypt(pkex->z, curve->hash_len,
10063 wrapped_data, wrapped_data_len,
4be5bc98 10064 2, addr, len, unwrapped) < 0) {
219d4c9f
JM
10065 dpp_pkex_fail(pkex,
10066 "AES-SIV decryption failed - possible PKEX code mismatch");
29ab69e4 10067 pkex->t++;
500ed7f0
JM
10068 goto fail;
10069 }
10070 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
10071 unwrapped, unwrapped_len);
10072
10073 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
d7e7b712 10074 dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data");
500ed7f0
JM
10075 goto fail;
10076 }
10077
10078 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY,
10079 &b_key_len);
10080 if (!b_key || b_key_len != 2 * curve->prime_len) {
d7e7b712 10081 dpp_pkex_fail(pkex, "No valid peer bootstrapping key found");
500ed7f0
JM
10082 goto fail;
10083 }
10084 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key,
10085 b_key_len);
d7e7b712
JM
10086 if (!pkex->peer_bootstrap_key) {
10087 dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid");
500ed7f0 10088 goto fail;
d7e7b712 10089 }
500ed7f0
JM
10090 dpp_debug_print_key("DPP: Peer bootstrap public key",
10091 pkex->peer_bootstrap_key);
10092
10093 /* ECDH: L' = x * B' */
29ef1c5e 10094 if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0)
500ed7f0 10095 goto fail;
500ed7f0
JM
10096
10097 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
10098 Lx, Lx_len);
10099
10100 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10101 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
10102 X_pub = dpp_get_pubkey_point(pkex->x, 0);
10103 Y_pub = dpp_get_pubkey_point(pkex->y, 0);
10104 if (!B_pub || !X_pub || !Y_pub)
10105 goto fail;
10106 addr[0] = pkex->peer_mac;
10107 len[0] = ETH_ALEN;
10108 addr[1] = wpabuf_head(B_pub);
10109 len[1] = wpabuf_len(B_pub) / 2;
10110 addr[2] = wpabuf_head(X_pub);
10111 len[2] = wpabuf_len(X_pub) / 2;
10112 addr[3] = wpabuf_head(Y_pub);
10113 len[3] = wpabuf_len(Y_pub) / 2;
10114 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
10115 goto fail;
10116
10117 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
10118 &peer_v_len);
10119 if (!peer_v || peer_v_len != curve->hash_len ||
10120 os_memcmp(peer_v, v, curve->hash_len) != 0) {
d7e7b712 10121 dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found");
500ed7f0
JM
10122 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
10123 v, curve->hash_len);
10124 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
29ab69e4 10125 pkex->t++;
500ed7f0
JM
10126 goto fail;
10127 }
10128 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
10129
10130 ret = 0;
10131out:
10132 wpabuf_free(B_pub);
10133 wpabuf_free(X_pub);
10134 wpabuf_free(Y_pub);
500ed7f0
JM
10135 os_free(unwrapped);
10136 return ret;
10137fail:
10138 goto out;
10139}
10140
10141
10142void dpp_pkex_free(struct dpp_pkex *pkex)
10143{
10144 if (!pkex)
10145 return;
10146
10147 os_free(pkex->identifier);
10148 os_free(pkex->code);
10149 EVP_PKEY_free(pkex->x);
10150 EVP_PKEY_free(pkex->y);
10151 EVP_PKEY_free(pkex->peer_bootstrap_key);
10152 wpabuf_free(pkex->exchange_req);
10153 wpabuf_free(pkex->exchange_resp);
10154 os_free(pkex);
10155}
4b8de0c9
JM
10156
10157
10158#ifdef CONFIG_TESTING_OPTIONS
10159char * dpp_corrupt_connector_signature(const char *connector)
10160{
10161 char *tmp, *pos, *signed3 = NULL;
10162 unsigned char *signature = NULL;
10163 size_t signature_len = 0, signed3_len;
10164
10165 tmp = os_zalloc(os_strlen(connector) + 5);
10166 if (!tmp)
10167 goto fail;
10168 os_memcpy(tmp, connector, os_strlen(connector));
10169
10170 pos = os_strchr(tmp, '.');
10171 if (!pos)
10172 goto fail;
10173
10174 pos = os_strchr(pos + 1, '.');
10175 if (!pos)
10176 goto fail;
10177 pos++;
10178
10179 wpa_printf(MSG_DEBUG, "DPP: Original base64url encoded signature: %s",
10180 pos);
b2260842 10181 signature = base64_url_decode(pos, os_strlen(pos), &signature_len);
4b8de0c9
JM
10182 if (!signature || signature_len == 0)
10183 goto fail;
10184 wpa_hexdump(MSG_DEBUG, "DPP: Original Connector signature",
10185 signature, signature_len);
10186 signature[signature_len - 1] ^= 0x01;
10187 wpa_hexdump(MSG_DEBUG, "DPP: Corrupted Connector signature",
10188 signature, signature_len);
b2260842 10189 signed3 = base64_url_encode(signature, signature_len, &signed3_len);
4b8de0c9
JM
10190 if (!signed3)
10191 goto fail;
10192 os_memcpy(pos, signed3, signed3_len);
10193 pos[signed3_len] = '\0';
10194 wpa_printf(MSG_DEBUG, "DPP: Corrupted base64url encoded signature: %s",
10195 pos);
10196
10197out:
10198 os_free(signature);
10199 os_free(signed3);
10200 return tmp;
10201fail:
10202 os_free(tmp);
10203 tmp = NULL;
10204 goto out;
10205}
10206#endif /* CONFIG_TESTING_OPTIONS */
10ec6a5f
JM
10207
10208
10209#ifdef CONFIG_DPP2
10210
10211struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
10212 size_t net_access_key_len)
10213{
10214 struct wpabuf *pub = NULL;
10215 EVP_PKEY *own_key;
10216 struct dpp_pfs *pfs;
10217
10218 pfs = os_zalloc(sizeof(*pfs));
10219 if (!pfs)
10220 return NULL;
10221
10222 own_key = dpp_set_keypair(&pfs->curve, net_access_key,
10223 net_access_key_len);
10224 if (!own_key) {
10225 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
10226 goto fail;
10227 }
10228 EVP_PKEY_free(own_key);
10229
10230 pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
10231 if (!pfs->ecdh)
10232 goto fail;
10233
10234 pub = crypto_ecdh_get_pubkey(pfs->ecdh, 0);
10235 pub = wpabuf_zeropad(pub, pfs->curve->prime_len);
10236 if (!pub)
10237 goto fail;
10238
10239 pfs->ie = wpabuf_alloc(5 + wpabuf_len(pub));
10240 if (!pfs->ie)
10241 goto fail;
10242 wpabuf_put_u8(pfs->ie, WLAN_EID_EXTENSION);
10243 wpabuf_put_u8(pfs->ie, 1 + 2 + wpabuf_len(pub));
10244 wpabuf_put_u8(pfs->ie, WLAN_EID_EXT_OWE_DH_PARAM);
10245 wpabuf_put_le16(pfs->ie, pfs->curve->ike_group);
10246 wpabuf_put_buf(pfs->ie, pub);
10247 wpabuf_free(pub);
10248 wpa_hexdump_buf(MSG_DEBUG, "DPP: Diffie-Hellman Parameter element",
10249 pfs->ie);
10250
10251 return pfs;
10252fail:
10253 wpabuf_free(pub);
10254 dpp_pfs_free(pfs);
10255 return NULL;
10256}
10257
10258
10259int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len)
10260{
10261 if (peer_ie_len < 2)
10262 return -1;
10263 if (WPA_GET_LE16(peer_ie) != pfs->curve->ike_group) {
10264 wpa_printf(MSG_DEBUG, "DPP: Peer used different group for PFS");
10265 return -1;
10266 }
10267
10268 pfs->secret = crypto_ecdh_set_peerkey(pfs->ecdh, 0, peer_ie + 2,
10269 peer_ie_len - 2);
10270 pfs->secret = wpabuf_zeropad(pfs->secret, pfs->curve->prime_len);
10271 if (!pfs->secret) {
10272 wpa_printf(MSG_DEBUG, "DPP: Invalid peer DH public key");
10273 return -1;
10274 }
10275 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: DH shared secret", pfs->secret);
10276 return 0;
10277}
10278
10279
10280void dpp_pfs_free(struct dpp_pfs *pfs)
10281{
10282 if (!pfs)
10283 return;
10284 crypto_ecdh_deinit(pfs->ecdh);
10285 wpabuf_free(pfs->ie);
10286 wpabuf_clear_free(pfs->secret);
10287 os_free(pfs);
10288}
10289
10290#endif /* CONFIG_DPP2 */
87d8435c
JM
10291
10292
10293static unsigned int dpp_next_id(struct dpp_global *dpp)
10294{
10295 struct dpp_bootstrap_info *bi;
10296 unsigned int max_id = 0;
10297
10298 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10299 if (bi->id > max_id)
10300 max_id = bi->id;
10301 }
10302 return max_id + 1;
10303}
10304
10305
10306static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
10307{
10308 struct dpp_bootstrap_info *bi, *tmp;
10309 int found = 0;
10310
10311 if (!dpp)
10312 return -1;
10313
10314 dl_list_for_each_safe(bi, tmp, &dpp->bootstrap,
10315 struct dpp_bootstrap_info, list) {
10316 if (id && bi->id != id)
10317 continue;
10318 found = 1;
10319 dl_list_del(&bi->list);
10320 dpp_bootstrap_info_free(bi);
10321 }
10322
10323 if (id == 0)
10324 return 0; /* flush succeeds regardless of entries found */
10325 return found ? 0 : -1;
10326}
10327
10328
10329struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
10330 const char *uri)
10331{
10332 struct dpp_bootstrap_info *bi;
10333
10334 if (!dpp)
10335 return NULL;
10336
e780b4bf
JM
10337 bi = dpp_parse_uri(uri);
10338 if (!bi)
10339 return NULL;
10340
10341 bi->type = DPP_BOOTSTRAP_QR_CODE;
10342 bi->id = dpp_next_id(dpp);
10343 dl_list_add(&dpp->bootstrap, &bi->list);
10344 return bi;
10345}
10346
10347
10348struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
10349 const char *uri)
10350{
10351 struct dpp_bootstrap_info *bi;
10352
10353 if (!dpp)
10354 return NULL;
10355
10356 bi = dpp_parse_uri(uri);
87d8435c
JM
10357 if (!bi)
10358 return NULL;
10359
e780b4bf 10360 bi->type = DPP_BOOTSTRAP_NFC_URI;
87d8435c
JM
10361 bi->id = dpp_next_id(dpp);
10362 dl_list_add(&dpp->bootstrap, &bi->list);
10363 return bi;
10364}
10365
10366
10367int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
10368{
2bbe6ad3 10369 char *mac = NULL, *info = NULL, *curve = NULL;
87d8435c
JM
10370 char *key = NULL;
10371 u8 *privkey = NULL;
10372 size_t privkey_len = 0;
87d8435c
JM
10373 int ret = -1;
10374 struct dpp_bootstrap_info *bi;
10375
10376 if (!dpp)
10377 return -1;
10378
10379 bi = os_zalloc(sizeof(*bi));
10380 if (!bi)
10381 goto fail;
10382
10383 if (os_strstr(cmd, "type=qrcode"))
10384 bi->type = DPP_BOOTSTRAP_QR_CODE;
10385 else if (os_strstr(cmd, "type=pkex"))
10386 bi->type = DPP_BOOTSTRAP_PKEX;
e780b4bf
JM
10387 else if (os_strstr(cmd, "type=nfc-uri"))
10388 bi->type = DPP_BOOTSTRAP_NFC_URI;
87d8435c
JM
10389 else
10390 goto fail;
10391
2bbe6ad3 10392 bi->chan = get_param(cmd, " chan=");
87d8435c
JM
10393 mac = get_param(cmd, " mac=");
10394 info = get_param(cmd, " info=");
10395 curve = get_param(cmd, " curve=");
10396 key = get_param(cmd, " key=");
10397
10398 if (key) {
10399 privkey_len = os_strlen(key) / 2;
10400 privkey = os_malloc(privkey_len);
10401 if (!privkey ||
10402 hexstr2bin(key, privkey, privkey_len) < 0)
10403 goto fail;
10404 }
10405
2bbe6ad3
JM
10406 if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 ||
10407 dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
10408 dpp_parse_uri_mac(bi, mac) < 0 ||
10409 dpp_parse_uri_info(bi, info) < 0 ||
10410 dpp_gen_uri(bi) < 0)
87d8435c
JM
10411 goto fail;
10412
87d8435c
JM
10413 bi->id = dpp_next_id(dpp);
10414 dl_list_add(&dpp->bootstrap, &bi->list);
10415 ret = bi->id;
10416 bi = NULL;
10417fail:
10418 os_free(curve);
87d8435c
JM
10419 os_free(mac);
10420 os_free(info);
10421 str_clear_free(key);
10422 bin_clear_free(privkey, privkey_len);
10423 dpp_bootstrap_info_free(bi);
10424 return ret;
10425}
10426
10427
10428struct dpp_bootstrap_info *
10429dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id)
10430{
10431 struct dpp_bootstrap_info *bi;
10432
10433 if (!dpp)
10434 return NULL;
10435
10436 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10437 if (bi->id == id)
10438 return bi;
10439 }
10440 return NULL;
10441}
10442
10443
10444int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id)
10445{
10446 unsigned int id_val;
10447
10448 if (os_strcmp(id, "*") == 0) {
10449 id_val = 0;
10450 } else {
10451 id_val = atoi(id);
10452 if (id_val == 0)
10453 return -1;
10454 }
10455
10456 return dpp_bootstrap_del(dpp, id_val);
10457}
10458
10459
10460struct dpp_bootstrap_info *
10461dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
10462 unsigned int freq)
10463{
10464 struct dpp_bootstrap_info *bi;
10465
10466 bi = os_zalloc(sizeof(*bi));
10467 if (!bi)
10468 return NULL;
10469 bi->id = dpp_next_id(dpp);
10470 bi->type = DPP_BOOTSTRAP_PKEX;
10471 os_memcpy(bi->mac_addr, peer, ETH_ALEN);
10472 bi->num_freq = 1;
10473 bi->freq[0] = freq;
10474 bi->curve = pkex->own_bi->curve;
10475 bi->pubkey = pkex->peer_bootstrap_key;
10476 pkex->peer_bootstrap_key = NULL;
10477 if (dpp_bootstrap_key_hash(bi) < 0) {
10478 dpp_bootstrap_info_free(bi);
10479 return NULL;
10480 }
10481 dpp_pkex_free(pkex);
10482 dl_list_add(&dpp->bootstrap, &bi->list);
10483 return bi;
10484}
10485
10486
10487const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id)
10488{
10489 struct dpp_bootstrap_info *bi;
10490
10491 bi = dpp_bootstrap_get_id(dpp, id);
10492 if (!bi)
10493 return NULL;
10494 return bi->uri;
10495}
10496
10497
10498int dpp_bootstrap_info(struct dpp_global *dpp, int id,
10499 char *reply, int reply_size)
10500{
10501 struct dpp_bootstrap_info *bi;
9ffec2e8 10502 char pkhash[2 * SHA256_MAC_LEN + 1];
87d8435c
JM
10503
10504 bi = dpp_bootstrap_get_id(dpp, id);
10505 if (!bi)
10506 return -1;
9ffec2e8
JM
10507 wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
10508 SHA256_MAC_LEN);
87d8435c
JM
10509 return os_snprintf(reply, reply_size, "type=%s\n"
10510 "mac_addr=" MACSTR "\n"
10511 "info=%s\n"
10512 "num_freq=%u\n"
566972fd 10513 "use_freq=%u\n"
9ffec2e8
JM
10514 "curve=%s\n"
10515 "pkhash=%s\n",
87d8435c
JM
10516 dpp_bootstrap_type_txt(bi->type),
10517 MAC2STR(bi->mac_addr),
10518 bi->info ? bi->info : "",
10519 bi->num_freq,
566972fd 10520 bi->num_freq == 1 ? bi->freq[0] : 0,
9ffec2e8
JM
10521 bi->curve->name,
10522 pkhash);
87d8435c
JM
10523}
10524
10525
10526void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
10527 const u8 *r_bootstrap,
10528 struct dpp_bootstrap_info **own_bi,
10529 struct dpp_bootstrap_info **peer_bi)
10530{
10531 struct dpp_bootstrap_info *bi;
10532
10533 *own_bi = NULL;
10534 *peer_bi = NULL;
10535 if (!dpp)
10536 return;
10537
10538 dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) {
10539 if (!*own_bi && bi->own &&
10540 os_memcmp(bi->pubkey_hash, r_bootstrap,
10541 SHA256_MAC_LEN) == 0) {
10542 wpa_printf(MSG_DEBUG,
10543 "DPP: Found matching own bootstrapping information");
10544 *own_bi = bi;
10545 }
10546
10547 if (!*peer_bi && !bi->own &&
10548 os_memcmp(bi->pubkey_hash, i_bootstrap,
10549 SHA256_MAC_LEN) == 0) {
10550 wpa_printf(MSG_DEBUG,
10551 "DPP: Found matching peer bootstrapping information");
10552 *peer_bi = bi;
10553 }
10554
10555 if (*own_bi && *peer_bi)
10556 break;
10557 }
10558
10559}
10560
10561
5e287724
JM
10562static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi,
10563 struct dpp_bootstrap_info *peer_bi)
10564{
10565 unsigned int i, freq = 0;
10566 enum hostapd_hw_mode mode;
10567 u8 op_class, channel;
10568 char chan[20];
10569
10570 if (peer_bi->num_freq == 0)
10571 return 0; /* no channel preference/constraint */
10572
10573 for (i = 0; i < peer_bi->num_freq; i++) {
10574 if (own_bi->num_freq == 0 ||
10575 freq_included(own_bi->freq, own_bi->num_freq,
10576 peer_bi->freq[i])) {
10577 freq = peer_bi->freq[i];
10578 break;
10579 }
10580 }
10581 if (!freq) {
10582 wpa_printf(MSG_DEBUG, "DPP: No common channel found");
10583 return -1;
10584 }
10585
10586 mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel);
10587 if (mode == NUM_HOSTAPD_MODES) {
10588 wpa_printf(MSG_DEBUG,
10589 "DPP: Could not determine operating class or channel number for %u MHz",
10590 freq);
10591 }
10592
10593 wpa_printf(MSG_DEBUG,
10594 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10595 freq, op_class, channel);
10596 os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel);
10597 os_free(own_bi->chan);
10598 own_bi->chan = os_strdup(chan);
10599 own_bi->freq[0] = freq;
10600 own_bi->num_freq = 1;
10601 os_free(peer_bi->chan);
10602 peer_bi->chan = os_strdup(chan);
10603 peer_bi->freq[0] = freq;
10604 peer_bi->num_freq = 1;
10605
10606 return dpp_gen_uri(own_bi);
10607}
10608
10609
10610static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
10611 struct dpp_bootstrap_info *peer_bi)
10612{
10613 if (peer_bi->curve == own_bi->curve)
10614 return 0;
10615
10616 wpa_printf(MSG_DEBUG,
10617 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10618
10619 EVP_PKEY_free(own_bi->pubkey);
10620 own_bi->pubkey = NULL;
10621
10622 if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
10623 dpp_gen_uri(own_bi) < 0)
10624 goto fail;
10625
10626 return 0;
10627fail:
10628 dl_list_del(&own_bi->list);
10629 dpp_bootstrap_info_free(own_bi);
10630 return -1;
10631}
10632
10633
10634int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi,
10635 struct dpp_bootstrap_info *peer_bi)
10636{
10637 if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 ||
10638 dpp_nfc_update_bi_key(own_bi, peer_bi) < 0)
10639 return -1;
10640 return 0;
10641}
10642
10643
87d8435c
JM
10644static unsigned int dpp_next_configurator_id(struct dpp_global *dpp)
10645{
10646 struct dpp_configurator *conf;
10647 unsigned int max_id = 0;
10648
10649 dl_list_for_each(conf, &dpp->configurator, struct dpp_configurator,
10650 list) {
10651 if (conf->id > max_id)
10652 max_id = conf->id;
10653 }
10654 return max_id + 1;
10655}
10656
10657
10658int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
10659{
10660 char *curve = NULL;
10661 char *key = NULL;
10662 u8 *privkey = NULL;
10663 size_t privkey_len = 0;
10664 int ret = -1;
10665 struct dpp_configurator *conf = NULL;
10666
10667 curve = get_param(cmd, " curve=");
10668 key = get_param(cmd, " key=");
10669
10670 if (key) {
10671 privkey_len = os_strlen(key) / 2;
10672 privkey = os_malloc(privkey_len);
10673 if (!privkey ||
10674 hexstr2bin(key, privkey, privkey_len) < 0)
10675 goto fail;
10676 }
10677
10678 conf = dpp_keygen_configurator(curve, privkey, privkey_len);
10679 if (!conf)
10680 goto fail;
10681
10682 conf->id = dpp_next_configurator_id(dpp);
10683 dl_list_add(&dpp->configurator, &conf->list);
10684 ret = conf->id;
10685 conf = NULL;
10686fail:
10687 os_free(curve);
10688 str_clear_free(key);
10689 bin_clear_free(privkey, privkey_len);
10690 dpp_configurator_free(conf);
10691 return ret;
10692}
10693
10694
10695static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
10696{
10697 struct dpp_configurator *conf, *tmp;
10698 int found = 0;
10699
10700 if (!dpp)
10701 return -1;
10702
10703 dl_list_for_each_safe(conf, tmp, &dpp->configurator,
10704 struct dpp_configurator, list) {
10705 if (id && conf->id != id)
10706 continue;
10707 found = 1;
10708 dl_list_del(&conf->list);
10709 dpp_configurator_free(conf);
10710 }
10711
10712 if (id == 0)
10713 return 0; /* flush succeeds regardless of entries found */
10714 return found ? 0 : -1;
10715}
10716
10717
10718int dpp_configurator_remove(struct dpp_global *dpp, const char *id)
10719{
10720 unsigned int id_val;
10721
10722 if (os_strcmp(id, "*") == 0) {
10723 id_val = 0;
10724 } else {
10725 id_val = atoi(id);
10726 if (id_val == 0)
10727 return -1;
10728 }
10729
10730 return dpp_configurator_del(dpp, id_val);
10731}
10732
10733
10734int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
10735 char *buf, size_t buflen)
10736{
10737 struct dpp_configurator *conf;
10738
10739 conf = dpp_configurator_get_id(dpp, id);
10740 if (!conf)
10741 return -1;
10742
10743 return dpp_configurator_get_key(conf, buf, buflen);
10744}
10745
10746
88a78bdd
JM
10747#ifdef CONFIG_DPP2
10748
7d9e3200
JM
10749int dpp_configurator_from_backup(struct dpp_global *dpp,
10750 struct dpp_asymmetric_key *key)
10751{
10752 struct dpp_configurator *conf;
10753 const EC_KEY *eckey;
10754 const EC_GROUP *group;
10755 int nid;
10756 const struct dpp_curve_params *curve;
10757
10758 if (!key->csign)
10759 return -1;
10760 eckey = EVP_PKEY_get0_EC_KEY(key->csign);
10761 if (!eckey)
10762 return -1;
10763 group = EC_KEY_get0_group(eckey);
10764 if (!group)
10765 return -1;
10766 nid = EC_GROUP_get_curve_name(group);
10767 curve = dpp_get_curve_nid(nid);
10768 if (!curve) {
10769 wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
10770 return -1;
10771 }
10772
10773 conf = os_zalloc(sizeof(*conf));
10774 if (!conf)
10775 return -1;
10776 conf->curve = curve;
10777 conf->csign = key->csign;
10778 key->csign = NULL;
10779 conf->own = 1;
10780 if (dpp_configurator_gen_kid(conf) < 0) {
10781 dpp_configurator_free(conf);
10782 return -1;
10783 }
10784
10785 conf->id = dpp_next_configurator_id(dpp);
10786 dl_list_add(&dpp->configurator, &conf->list);
10787 return conf->id;
10788}
10789
10790
b10e01a7
JM
10791static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
10792 void *timeout_ctx);
10793
10794
88a78bdd
JM
10795static void dpp_connection_free(struct dpp_connection *conn)
10796{
10797 if (conn->sock >= 0) {
10798 wpa_printf(MSG_DEBUG, "DPP: Close Controller socket %d",
10799 conn->sock);
10800 eloop_unregister_sock(conn->sock, EVENT_TYPE_READ);
10801 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
10802 close(conn->sock);
10803 }
b10e01a7
JM
10804 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout,
10805 conn, NULL);
88a78bdd
JM
10806 wpabuf_free(conn->msg);
10807 wpabuf_free(conn->msg_out);
10808 dpp_auth_deinit(conn->auth);
10809 os_free(conn);
10810}
10811
10812
10813static void dpp_connection_remove(struct dpp_connection *conn)
10814{
10815 dl_list_del(&conn->list);
10816 dpp_connection_free(conn);
10817}
10818
10819
10820static void dpp_tcp_init_flush(struct dpp_global *dpp)
10821{
10822 struct dpp_connection *conn, *tmp;
10823
10824 dl_list_for_each_safe(conn, tmp, &dpp->tcp_init, struct dpp_connection,
10825 list)
10826 dpp_connection_remove(conn);
10827}
10828
10829
10830static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl)
10831{
10832 struct dpp_connection *conn, *tmp;
10833
10834 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
10835 list)
10836 dpp_connection_remove(conn);
10837 os_free(ctrl);
10838}
10839
10840
10841static void dpp_relay_flush_controllers(struct dpp_global *dpp)
10842{
10843 struct dpp_relay_controller *ctrl, *tmp;
10844
10845 if (!dpp)
10846 return;
10847
10848 dl_list_for_each_safe(ctrl, tmp, &dpp->controllers,
10849 struct dpp_relay_controller, list) {
10850 dl_list_del(&ctrl->list);
10851 dpp_relay_controller_free(ctrl);
10852 }
10853}
10854
10855#endif /* CONFIG_DPP2 */
10856
10857
2ed2b52f 10858struct dpp_global * dpp_global_init(struct dpp_global_config *config)
87d8435c
JM
10859{
10860 struct dpp_global *dpp;
10861
10862 dpp = os_zalloc(sizeof(*dpp));
10863 if (!dpp)
10864 return NULL;
2ed2b52f 10865 dpp->msg_ctx = config->msg_ctx;
88a78bdd
JM
10866#ifdef CONFIG_DPP2
10867 dpp->cb_ctx = config->cb_ctx;
10868 dpp->process_conf_obj = config->process_conf_obj;
10869#endif /* CONFIG_DPP2 */
87d8435c
JM
10870
10871 dl_list_init(&dpp->bootstrap);
10872 dl_list_init(&dpp->configurator);
88a78bdd
JM
10873#ifdef CONFIG_DPP2
10874 dl_list_init(&dpp->controllers);
10875 dl_list_init(&dpp->tcp_init);
10876#endif /* CONFIG_DPP2 */
87d8435c
JM
10877
10878 return dpp;
10879}
10880
10881
10882void dpp_global_clear(struct dpp_global *dpp)
10883{
10884 if (!dpp)
10885 return;
10886
10887 dpp_bootstrap_del(dpp, 0);
10888 dpp_configurator_del(dpp, 0);
88a78bdd
JM
10889#ifdef CONFIG_DPP2
10890 dpp_tcp_init_flush(dpp);
10891 dpp_relay_flush_controllers(dpp);
10892 dpp_controller_stop(dpp);
10893#endif /* CONFIG_DPP2 */
87d8435c
JM
10894}
10895
10896
10897void dpp_global_deinit(struct dpp_global *dpp)
10898{
10899 dpp_global_clear(dpp);
10900 os_free(dpp);
10901}
88a78bdd
JM
10902
10903
10904#ifdef CONFIG_DPP2
10905
10906static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx);
10907static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx);
10908static void dpp_controller_auth_success(struct dpp_connection *conn,
10909 int initiator);
10910
10911
10912int dpp_relay_add_controller(struct dpp_global *dpp,
10913 struct dpp_relay_config *config)
10914{
10915 struct dpp_relay_controller *ctrl;
10916
10917 if (!dpp)
10918 return -1;
10919
10920 ctrl = os_zalloc(sizeof(*ctrl));
10921 if (!ctrl)
10922 return -1;
10923 dl_list_init(&ctrl->conn);
10924 ctrl->global = dpp;
10925 os_memcpy(&ctrl->ipaddr, config->ipaddr, sizeof(*config->ipaddr));
10926 os_memcpy(ctrl->pkhash, config->pkhash, SHA256_MAC_LEN);
10927 ctrl->cb_ctx = config->cb_ctx;
10928 ctrl->tx = config->tx;
10929 ctrl->gas_resp_tx = config->gas_resp_tx;
10930 dl_list_add(&dpp->controllers, &ctrl->list);
10931 return 0;
10932}
10933
10934
10935static struct dpp_relay_controller *
10936dpp_relay_controller_get(struct dpp_global *dpp, const u8 *pkhash)
10937{
10938 struct dpp_relay_controller *ctrl;
10939
10940 if (!dpp)
10941 return NULL;
10942
10943 dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller,
10944 list) {
10945 if (os_memcmp(pkhash, ctrl->pkhash, SHA256_MAC_LEN) == 0)
10946 return ctrl;
10947 }
10948
10949 return NULL;
10950}
10951
10952
10953static void dpp_controller_gas_done(struct dpp_connection *conn)
10954{
10955 struct dpp_authentication *auth = conn->auth;
10956
10957 if (auth->peer_version >= 2 &&
10958 auth->conf_resp_status == DPP_STATUS_OK) {
10959 wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
10960 auth->waiting_conf_result = 1;
10961 return;
10962 }
10963
10964 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
10965 dpp_connection_remove(conn);
10966}
10967
10968
10969static int dpp_tcp_send(struct dpp_connection *conn)
10970{
10971 int res;
10972
10973 if (!conn->msg_out) {
10974 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
10975 conn->write_eloop = 0;
10976 return -1;
10977 }
10978 res = send(conn->sock,
10979 wpabuf_head_u8(conn->msg_out) + conn->msg_out_pos,
10980 wpabuf_len(conn->msg_out) - conn->msg_out_pos, 0);
10981 if (res < 0) {
10982 wpa_printf(MSG_DEBUG, "DPP: Failed to send buffer: %s",
10983 strerror(errno));
10984 dpp_connection_remove(conn);
10985 return -1;
10986 }
10987
10988 conn->msg_out_pos += res;
10989 if (wpabuf_len(conn->msg_out) > conn->msg_out_pos) {
10990 wpa_printf(MSG_DEBUG,
10991 "DPP: %u/%u bytes of message sent to Controller",
10992 (unsigned int) conn->msg_out_pos,
10993 (unsigned int) wpabuf_len(conn->msg_out));
10994 if (!conn->write_eloop &&
10995 eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
10996 dpp_conn_tx_ready, conn, NULL) == 0)
10997 conn->write_eloop = 1;
10998 return 1;
10999 }
11000
11001 wpa_printf(MSG_DEBUG, "DPP: Full message sent over TCP");
11002 wpabuf_free(conn->msg_out);
11003 conn->msg_out = NULL;
11004 conn->msg_out_pos = 0;
11005 eloop_unregister_sock(conn->sock, EVENT_TYPE_WRITE);
11006 conn->write_eloop = 0;
11007 if (!conn->read_eloop &&
11008 eloop_register_sock(conn->sock, EVENT_TYPE_READ,
11009 dpp_controller_rx, conn, NULL) == 0)
11010 conn->read_eloop = 1;
11011 if (conn->on_tcp_tx_complete_remove) {
11012 dpp_connection_remove(conn);
11013 } else if (conn->ctrl && conn->on_tcp_tx_complete_gas_done &&
11014 conn->auth) {
11015 dpp_controller_gas_done(conn);
11016 } else if (conn->on_tcp_tx_complete_auth_ok) {
11017 conn->on_tcp_tx_complete_auth_ok = 0;
11018 dpp_controller_auth_success(conn, 1);
11019 }
11020
11021 return 0;
11022}
11023
11024
11025static void dpp_controller_start_gas_client(struct dpp_connection *conn)
11026{
11027 struct dpp_authentication *auth = conn->auth;
11028 struct wpabuf *buf;
88a78bdd
JM
11029 int netrole_ap = 0; /* TODO: make this configurable */
11030
8f8c423a 11031 buf = dpp_build_conf_req_helper(auth, "Test", netrole_ap, NULL, NULL);
88a78bdd
JM
11032 if (!buf) {
11033 wpa_printf(MSG_DEBUG,
11034 "DPP: No configuration request data available");
11035 return;
11036 }
11037
11038 wpabuf_free(conn->msg_out);
11039 conn->msg_out_pos = 0;
11040 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1);
11041 if (!conn->msg_out) {
11042 wpabuf_free(buf);
11043 return;
11044 }
11045 wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1);
fc03ea2c 11046 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1,
88a78bdd
JM
11047 wpabuf_len(buf) - 1);
11048 wpabuf_free(buf);
11049
11050 if (dpp_tcp_send(conn) == 1) {
11051 if (!conn->write_eloop) {
11052 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11053 dpp_conn_tx_ready,
11054 conn, NULL) < 0)
11055 return;
11056 conn->write_eloop = 1;
11057 }
11058 }
11059}
11060
11061
11062static void dpp_controller_auth_success(struct dpp_connection *conn,
11063 int initiator)
11064{
11065 struct dpp_authentication *auth = conn->auth;
11066
11067 if (!auth)
11068 return;
11069
11070 wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
11071 wpa_msg(conn->global->msg_ctx, MSG_INFO,
11072 DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
11073#ifdef CONFIG_TESTING_OPTIONS
11074 if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
11075 wpa_printf(MSG_INFO,
11076 "DPP: TESTING - stop at Authentication Confirm");
11077 if (auth->configurator) {
11078 /* Prevent GAS response */
11079 auth->auth_success = 0;
11080 }
11081 return;
11082 }
11083#endif /* CONFIG_TESTING_OPTIONS */
11084
11085 if (!auth->configurator)
11086 dpp_controller_start_gas_client(conn);
11087}
11088
11089
11090static void dpp_conn_tx_ready(int sock, void *eloop_ctx, void *sock_ctx)
11091{
11092 struct dpp_connection *conn = eloop_ctx;
11093
11094 wpa_printf(MSG_DEBUG, "DPP: TCP socket %d ready for TX", sock);
11095 dpp_tcp_send(conn);
11096}
11097
11098
11099static int dpp_ipaddr_to_sockaddr(struct sockaddr *addr, socklen_t *addrlen,
11100 const struct hostapd_ip_addr *ipaddr,
11101 int port)
11102{
11103 struct sockaddr_in *dst;
11104#ifdef CONFIG_IPV6
11105 struct sockaddr_in6 *dst6;
11106#endif /* CONFIG_IPV6 */
11107
11108 switch (ipaddr->af) {
11109 case AF_INET:
11110 dst = (struct sockaddr_in *) addr;
11111 os_memset(dst, 0, sizeof(*dst));
11112 dst->sin_family = AF_INET;
11113 dst->sin_addr.s_addr = ipaddr->u.v4.s_addr;
11114 dst->sin_port = htons(port);
11115 *addrlen = sizeof(*dst);
11116 break;
11117#ifdef CONFIG_IPV6
11118 case AF_INET6:
11119 dst6 = (struct sockaddr_in6 *) addr;
11120 os_memset(dst6, 0, sizeof(*dst6));
11121 dst6->sin6_family = AF_INET6;
11122 os_memcpy(&dst6->sin6_addr, &ipaddr->u.v6,
11123 sizeof(struct in6_addr));
11124 dst6->sin6_port = htons(port);
11125 *addrlen = sizeof(*dst6);
11126 break;
11127#endif /* CONFIG_IPV6 */
11128 default:
11129 return -1;
11130 }
11131
11132 return 0;
11133}
11134
11135
11136static struct dpp_connection *
11137dpp_relay_new_conn(struct dpp_relay_controller *ctrl, const u8 *src,
11138 unsigned int freq)
11139{
11140 struct dpp_connection *conn;
11141 struct sockaddr_storage addr;
11142 socklen_t addrlen;
11143 char txt[100];
11144
11145 if (dl_list_len(&ctrl->conn) >= 15) {
11146 wpa_printf(MSG_DEBUG,
11147 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11148 return NULL;
11149 }
11150
11151 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &addr, &addrlen,
11152 &ctrl->ipaddr, DPP_TCP_PORT) < 0)
11153 return NULL;
11154
11155 conn = os_zalloc(sizeof(*conn));
11156 if (!conn)
11157 return NULL;
11158
11159 conn->global = ctrl->global;
11160 conn->relay = ctrl;
11161 os_memcpy(conn->mac_addr, src, ETH_ALEN);
11162 conn->freq = freq;
11163
11164 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
11165 if (conn->sock < 0)
11166 goto fail;
11167 wpa_printf(MSG_DEBUG, "DPP: TCP relay socket %d connection to %s",
11168 conn->sock, hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt)));
11169
11170 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
11171 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
11172 strerror(errno));
11173 goto fail;
11174 }
11175
11176 if (connect(conn->sock, (struct sockaddr *) &addr, addrlen) < 0) {
11177 if (errno != EINPROGRESS) {
11178 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
11179 strerror(errno));
11180 goto fail;
11181 }
11182
11183 /*
11184 * Continue connecting in the background; eloop will call us
11185 * once the connection is ready (or failed).
11186 */
11187 }
11188
11189 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11190 dpp_conn_tx_ready, conn, NULL) < 0)
11191 goto fail;
11192 conn->write_eloop = 1;
11193
11194 /* TODO: eloop timeout to clear a connection if it does not complete
11195 * properly */
11196
11197 dl_list_add(&ctrl->conn, &conn->list);
11198 return conn;
11199fail:
11200 dpp_connection_free(conn);
11201 return NULL;
11202}
11203
11204
11205static struct wpabuf * dpp_tcp_encaps(const u8 *hdr, const u8 *buf, size_t len)
11206{
11207 struct wpabuf *msg;
11208
11209 msg = wpabuf_alloc(4 + 1 + DPP_HDR_LEN + len);
11210 if (!msg)
11211 return NULL;
11212 wpabuf_put_be32(msg, 1 + DPP_HDR_LEN + len);
11213 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC);
11214 wpabuf_put_data(msg, hdr, DPP_HDR_LEN);
11215 wpabuf_put_data(msg, buf, len);
11216 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11217 return msg;
11218}
11219
11220
11221static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr,
11222 const u8 *buf, size_t len)
11223{
11224 u8 type = hdr[DPP_HDR_LEN - 1];
11225
11226 wpa_printf(MSG_DEBUG,
11227 "DPP: Continue already established Relay/Controller connection for this session");
11228 wpabuf_free(conn->msg_out);
11229 conn->msg_out_pos = 0;
11230 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11231 if (!conn->msg_out) {
11232 dpp_connection_remove(conn);
11233 return -1;
11234 }
11235
11236 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11237 * TX status */
11238 if (type == DPP_PA_CONFIGURATION_RESULT)
11239 conn->on_tcp_tx_complete_remove = 1;
11240 dpp_tcp_send(conn);
11241 return 0;
11242}
11243
11244
11245int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr,
11246 const u8 *buf, size_t len, unsigned int freq,
11247 const u8 *i_bootstrap, const u8 *r_bootstrap)
11248{
11249 struct dpp_relay_controller *ctrl;
11250 struct dpp_connection *conn;
11251 u8 type = hdr[DPP_HDR_LEN - 1];
11252
11253 /* Check if there is an already started session for this peer and if so,
11254 * continue that session (send this over TCP) and return 0.
11255 */
11256 if (type != DPP_PA_PEER_DISCOVERY_REQ &&
11257 type != DPP_PA_PEER_DISCOVERY_RESP) {
11258 dl_list_for_each(ctrl, &dpp->controllers,
11259 struct dpp_relay_controller, list) {
11260 dl_list_for_each(conn, &ctrl->conn,
11261 struct dpp_connection, list) {
11262 if (os_memcmp(src, conn->mac_addr,
11263 ETH_ALEN) == 0)
11264 return dpp_relay_tx(conn, hdr, buf, len);
11265 }
11266 }
11267 }
11268
11269 if (!r_bootstrap)
11270 return -1;
11271
11272 ctrl = dpp_relay_controller_get(dpp, r_bootstrap);
11273 if (!ctrl)
11274 return -1;
11275
11276 wpa_printf(MSG_DEBUG,
11277 "DPP: Authentication Request for a configured Controller");
11278 conn = dpp_relay_new_conn(ctrl, src, freq);
11279 if (!conn)
11280 return -1;
11281
11282 conn->msg_out = dpp_tcp_encaps(hdr, buf, len);
11283 if (!conn->msg_out) {
11284 dpp_connection_remove(conn);
11285 return -1;
11286 }
11287 /* Message will be sent in dpp_conn_tx_ready() */
11288
11289 return 0;
11290}
11291
11292
11293int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
11294 size_t data_len)
11295{
11296 struct dpp_relay_controller *ctrl;
11297 struct dpp_connection *conn, *found = NULL;
11298 struct wpabuf *msg;
11299
11300 /* Check if there is a successfully completed authentication for this
11301 * and if so, continue that session (send this over TCP) and return 0.
11302 */
11303 dl_list_for_each(ctrl, &dpp->controllers,
11304 struct dpp_relay_controller, list) {
11305 if (found)
11306 break;
11307 dl_list_for_each(conn, &ctrl->conn,
11308 struct dpp_connection, list) {
11309 if (os_memcmp(src, conn->mac_addr,
11310 ETH_ALEN) == 0) {
11311 found = conn;
11312 break;
11313 }
11314 }
11315 }
11316
11317 if (!found)
11318 return -1;
11319
11320 msg = wpabuf_alloc(4 + 1 + data_len);
11321 if (!msg)
11322 return -1;
11323 wpabuf_put_be32(msg, 1 + data_len);
11324 wpabuf_put_u8(msg, WLAN_PA_GAS_INITIAL_REQ);
11325 wpabuf_put_data(msg, data, data_len);
11326 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", msg);
11327
11328 wpabuf_free(conn->msg_out);
11329 conn->msg_out_pos = 0;
11330 conn->msg_out = msg;
11331 dpp_tcp_send(conn);
11332 return 0;
11333}
11334
11335
11336static void dpp_controller_free(struct dpp_controller *ctrl)
11337{
11338 struct dpp_connection *conn, *tmp;
11339
11340 if (!ctrl)
11341 return;
11342
11343 dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection,
11344 list)
11345 dpp_connection_remove(conn);
11346
11347 if (ctrl->sock >= 0) {
11348 close(ctrl->sock);
11349 eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ);
11350 }
11351 os_free(ctrl->configurator_params);
11352 os_free(ctrl);
11353}
11354
11355
11356static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
11357 const u8 *hdr, const u8 *buf, size_t len)
11358{
11359 const u8 *r_bootstrap, *i_bootstrap;
11360 u16 r_bootstrap_len, i_bootstrap_len;
11361 struct dpp_bootstrap_info *own_bi = NULL, *peer_bi = NULL;
11362
b93a0ce7
JM
11363 if (!conn->ctrl)
11364 return 0;
11365
88a78bdd
JM
11366 wpa_printf(MSG_DEBUG, "DPP: Authentication Request");
11367
11368 r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
11369 &r_bootstrap_len);
11370 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
11371 wpa_printf(MSG_INFO,
11372 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11373 return -1;
11374 }
11375 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash",
11376 r_bootstrap, r_bootstrap_len);
11377
11378 i_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
11379 &i_bootstrap_len);
11380 if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
11381 wpa_printf(MSG_INFO,
11382 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11383 return -1;
11384 }
11385 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash",
11386 i_bootstrap, i_bootstrap_len);
11387
11388 /* Try to find own and peer bootstrapping key matches based on the
11389 * received hash values */
11390 dpp_bootstrap_find_pair(conn->ctrl->global, i_bootstrap, r_bootstrap,
11391 &own_bi, &peer_bi);
11392 if (!own_bi) {
11393 wpa_printf(MSG_INFO,
11394 "No matching own bootstrapping key found - ignore message");
11395 return -1;
11396 }
11397
11398 if (conn->auth) {
11399 wpa_printf(MSG_INFO,
11400 "Already in DPP authentication exchange - ignore new one");
11401 return 0;
11402 }
11403
11404 conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx,
11405 conn->ctrl->allowed_roles,
11406 conn->ctrl->qr_mutual,
11407 peer_bi, own_bi, -1, hdr, buf, len);
11408 if (!conn->auth) {
11409 wpa_printf(MSG_DEBUG, "DPP: No response generated");
11410 return -1;
11411 }
11412
b93a0ce7 11413 if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx,
88a78bdd
JM
11414 conn->auth,
11415 conn->ctrl->configurator_params) < 0) {
11416 dpp_connection_remove(conn);
11417 return -1;
11418 }
11419
11420 wpabuf_free(conn->msg_out);
11421 conn->msg_out_pos = 0;
11422 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1);
11423 if (!conn->msg_out)
11424 return -1;
11425 wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1);
fc03ea2c 11426 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1,
88a78bdd
JM
11427 wpabuf_len(conn->auth->resp_msg) - 1);
11428
11429 if (dpp_tcp_send(conn) == 1) {
11430 if (!conn->write_eloop) {
11431 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11432 dpp_conn_tx_ready,
11433 conn, NULL) < 0)
11434 return -1;
11435 conn->write_eloop = 1;
11436 }
11437 }
11438
11439 return 0;
11440}
11441
11442
11443static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
11444 const u8 *hdr, const u8 *buf, size_t len)
11445{
11446 struct dpp_authentication *auth = conn->auth;
11447 struct wpabuf *msg;
11448
11449 if (!auth)
11450 return -1;
11451
11452 wpa_printf(MSG_DEBUG, "DPP: Authentication Response");
11453
11454 msg = dpp_auth_resp_rx(auth, hdr, buf, len);
11455 if (!msg) {
11456 if (auth->auth_resp_status == DPP_STATUS_RESPONSE_PENDING) {
11457 wpa_printf(MSG_DEBUG,
11458 "DPP: Start wait for full response");
11459 return -1;
11460 }
11461 wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
11462 dpp_connection_remove(conn);
11463 return -1;
11464 }
11465
11466 wpabuf_free(conn->msg_out);
11467 conn->msg_out_pos = 0;
11468 conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
11469 if (!conn->msg_out) {
11470 wpabuf_free(msg);
11471 return -1;
11472 }
11473 wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1);
fc03ea2c 11474 wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1,
88a78bdd
JM
11475 wpabuf_len(msg) - 1);
11476 wpabuf_free(msg);
11477
11478 conn->on_tcp_tx_complete_auth_ok = 1;
11479 if (dpp_tcp_send(conn) == 1) {
11480 if (!conn->write_eloop) {
11481 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
11482 dpp_conn_tx_ready,
11483 conn, NULL) < 0)
11484 return -1;
11485 conn->write_eloop = 1;
11486 }
11487 }
11488
11489 return 0;
11490}
11491
11492
11493static int dpp_controller_rx_auth_conf(struct dpp_connection *conn,
11494 const u8 *hdr, const u8 *buf, size_t len)
11495{
11496 struct dpp_authentication *auth = conn->auth;
11497
11498 wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation");
11499
11500 if (!auth) {
11501 wpa_printf(MSG_DEBUG,
11502 "DPP: No DPP Authentication in progress - drop");
11503 return -1;
11504 }
11505
11506 if (dpp_auth_conf_rx(auth, hdr, buf, len) < 0) {
11507 wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
11508 return -1;
11509 }
11510
11511 dpp_controller_auth_success(conn, 0);
11512 return 0;
11513}
11514
11515
b10e01a7
JM
11516static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx,
11517 void *timeout_ctx)
11518{
11519 struct dpp_connection *conn = eloop_ctx;
11520
11521 if (!conn->auth->waiting_conf_result)
11522 return;
11523
11524 wpa_printf(MSG_DEBUG,
11525 "DPP: Timeout while waiting for Connection Status Result");
11526 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11527 DPP_EVENT_CONN_STATUS_RESULT "timeout");
11528 dpp_connection_remove(conn);
11529}
11530
11531
88a78bdd
JM
11532static int dpp_controller_rx_conf_result(struct dpp_connection *conn,
11533 const u8 *hdr, const u8 *buf,
11534 size_t len)
11535{
11536 struct dpp_authentication *auth = conn->auth;
11537 enum dpp_status_error status;
11538
11539 if (!conn->ctrl)
11540 return 0;
11541
11542 wpa_printf(MSG_DEBUG, "DPP: Configuration Result");
11543
11544 if (!auth || !auth->waiting_conf_result) {
11545 wpa_printf(MSG_DEBUG,
11546 "DPP: No DPP Configuration waiting for result - drop");
11547 return -1;
11548 }
11549
11550 status = dpp_conf_result_rx(auth, hdr, buf, len);
b10e01a7
JM
11551 if (status == DPP_STATUS_OK && auth->send_conn_status) {
11552 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11553 DPP_EVENT_CONF_SENT "wait_conn_status=1");
11554 wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result");
11555 eloop_cancel_timeout(
11556 dpp_controller_conn_status_result_wait_timeout,
11557 conn, NULL);
11558 eloop_register_timeout(
11559 16, 0, dpp_controller_conn_status_result_wait_timeout,
11560 conn, NULL);
11561 return 0;
11562 }
88a78bdd
JM
11563 if (status == DPP_STATUS_OK)
11564 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11565 DPP_EVENT_CONF_SENT);
11566 else
11567 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11568 DPP_EVENT_CONF_FAILED);
11569 return -1; /* to remove the completed connection */
11570}
11571
11572
b10e01a7
JM
11573static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn,
11574 const u8 *hdr, const u8 *buf,
11575 size_t len)
11576{
11577 struct dpp_authentication *auth = conn->auth;
11578 enum dpp_status_error status;
11579 u8 ssid[SSID_MAX_LEN];
11580 size_t ssid_len = 0;
11581 char *channel_list = NULL;
11582
11583 if (!conn->ctrl)
11584 return 0;
11585
11586 wpa_printf(MSG_DEBUG, "DPP: Connection Status Result");
11587
11588 if (!auth || !auth->waiting_conn_status_result) {
11589 wpa_printf(MSG_DEBUG,
11590 "DPP: No DPP Configuration waiting for connection status result - drop");
11591 return -1;
11592 }
11593
11594 status = dpp_conn_status_result_rx(auth, hdr, buf, len,
11595 ssid, &ssid_len, &channel_list);
11596 wpa_msg(conn->ctrl->global->msg_ctx, MSG_INFO,
11597 DPP_EVENT_CONN_STATUS_RESULT
11598 "result=%d ssid=%s channel_list=%s",
11599 status, wpa_ssid_txt(ssid, ssid_len),
11600 channel_list ? channel_list : "N/A");
11601 os_free(channel_list);
11602 return -1; /* to remove the completed connection */
11603}
11604
11605
88a78bdd
JM
11606static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg,
11607 size_t len)
11608{
11609 const u8 *pos, *end;
11610 u8 type;
11611
11612 wpa_printf(MSG_DEBUG, "DPP: Received DPP Action frame over TCP");
11613 pos = msg;
11614 end = msg + len;
11615
11616 if (end - pos < DPP_HDR_LEN ||
11617 WPA_GET_BE24(pos) != OUI_WFA ||
11618 pos[3] != DPP_OUI_TYPE) {
11619 wpa_printf(MSG_DEBUG, "DPP: Unrecognized header");
11620 return -1;
11621 }
11622
11623 if (pos[4] != 1) {
11624 wpa_printf(MSG_DEBUG, "DPP: Unsupported Crypto Suite %u",
11625 pos[4]);
11626 return -1;
11627 }
11628 type = pos[5];
11629 wpa_printf(MSG_DEBUG, "DPP: Received message type %u", type);
11630 pos += DPP_HDR_LEN;
11631
11632 wpa_hexdump(MSG_MSGDUMP, "DPP: Received message attributes",
11633 pos, end - pos);
11634 if (dpp_check_attrs(pos, end - pos) < 0)
11635 return -1;
11636
11637 if (conn->relay) {
11638 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11639 conn->relay->tx(conn->relay->cb_ctx, conn->mac_addr,
11640 conn->freq, msg, len);
11641 return 0;
11642 }
11643
11644 switch (type) {
11645 case DPP_PA_AUTHENTICATION_REQ:
11646 return dpp_controller_rx_auth_req(conn, msg, pos, end - pos);
11647 case DPP_PA_AUTHENTICATION_RESP:
11648 return dpp_controller_rx_auth_resp(conn, msg, pos, end - pos);
11649 case DPP_PA_AUTHENTICATION_CONF:
11650 return dpp_controller_rx_auth_conf(conn, msg, pos, end - pos);
11651 case DPP_PA_CONFIGURATION_RESULT:
11652 return dpp_controller_rx_conf_result(conn, msg, pos, end - pos);
b10e01a7
JM
11653 case DPP_PA_CONNECTION_STATUS_RESULT:
11654 return dpp_controller_rx_conn_status_result(conn, msg, pos,
11655 end - pos);
88a78bdd
JM
11656 default:
11657 /* TODO: missing messages types */
11658 wpa_printf(MSG_DEBUG,
11659 "DPP: Unsupported frame subtype %d", type);
11660 return -1;
11661 }
11662}
11663
11664
11665static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg,
11666 size_t len)
11667{
11668 const u8 *pos, *end, *next;
11669 u8 dialog_token;
11670 const u8 *adv_proto;
11671 u16 slen;
11672 struct wpabuf *resp, *buf;
11673 struct dpp_authentication *auth = conn->auth;
11674
11675 if (len < 1 + 2)
11676 return -1;
11677
11678 wpa_printf(MSG_DEBUG,
11679 "DPP: Received DPP Configuration Request over TCP");
11680
11681 if (!conn->ctrl || !auth || !auth->auth_success) {
11682 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11683 return -1;
11684 }
11685
11686 pos = msg;
11687 end = msg + len;
11688
11689 dialog_token = *pos++;
11690 adv_proto = pos++;
11691 slen = *pos++;
11692 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11693 slen > end - pos || slen < 2)
11694 return -1;
11695
11696 next = pos + slen;
11697 pos++; /* skip QueryRespLenLimit and PAME-BI */
11698
11699 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11700 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11701 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11702 return -1;
11703
11704 pos = next;
11705 /* Query Request */
11706 if (end - pos < 2)
11707 return -1;
11708 slen = WPA_GET_LE16(pos);
11709 pos += 2;
11710 if (slen > end - pos)
11711 return -1;
11712
11713 resp = dpp_conf_req_rx(auth, pos, slen);
11714 if (!resp)
11715 return -1;
11716
11717 buf = wpabuf_alloc(4 + 18 + wpabuf_len(resp));
11718 if (!buf) {
11719 wpabuf_free(resp);
11720 return -1;
11721 }
11722
11723 wpabuf_put_be32(buf, 18 + wpabuf_len(resp));
11724
11725 wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
11726 wpabuf_put_u8(buf, dialog_token);
11727 wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
11728 wpabuf_put_le16(buf, 0); /* GAS Comeback Delay */
11729
11730 dpp_write_adv_proto(buf);
11731 dpp_write_gas_query(buf, resp);
11732 wpabuf_free(resp);
11733
11734 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11735 * the Relay */
11736 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", buf);
11737 wpabuf_free(conn->msg_out);
11738 conn->msg_out_pos = 0;
11739 conn->msg_out = buf;
11740 conn->on_tcp_tx_complete_gas_done = 1;
11741 dpp_tcp_send(conn);
11742 return 0;
11743}
11744
11745
11746static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
11747{
11748 struct dpp_authentication *auth = conn->auth;
11749 int res;
11750 struct wpabuf *msg, *encaps;
11751 enum dpp_status_error status;
11752
11753 wpa_printf(MSG_DEBUG,
11754 "DPP: Configuration Response for local stack from TCP");
11755
11756 res = dpp_conf_resp_rx(auth, resp);
11757 wpabuf_free(resp);
11758 if (res < 0) {
11759 wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
11760 return -1;
11761 }
11762
11763 if (conn->global->process_conf_obj)
11764 res = conn->global->process_conf_obj(conn->global->cb_ctx,
11765 auth);
11766 else
11767 res = 0;
11768
11769 if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK)
11770 return -1;
11771
cc839952 11772#ifdef CONFIG_DPP2
88a78bdd
JM
11773 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
11774 status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK;
11775 msg = dpp_build_conf_result(auth, status);
11776 if (!msg)
11777 return -1;
11778
11779 encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1);
11780 if (!encaps) {
11781 wpabuf_free(msg);
11782 return -1;
11783 }
11784 wpabuf_put_be32(encaps, wpabuf_len(msg) - 1);
fc03ea2c 11785 wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1);
88a78bdd
JM
11786 wpabuf_free(msg);
11787 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps);
11788
11789 wpabuf_free(conn->msg_out);
11790 conn->msg_out_pos = 0;
11791 conn->msg_out = encaps;
11792 conn->on_tcp_tx_complete_remove = 1;
11793 dpp_tcp_send(conn);
11794
11795 /* This exchange will be terminated in the TX status handler */
11796
11797 return 0;
cc839952
JM
11798#else /* CONFIG_DPP2 */
11799 return -1;
11800#endif /* CONFIG_DPP2 */
88a78bdd
JM
11801}
11802
11803
11804static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
11805 size_t len)
11806{
11807 struct wpabuf *buf;
11808 u8 dialog_token;
11809 const u8 *pos, *end, *next, *adv_proto;
11810 u16 status, slen;
11811
11812 if (len < 5 + 2)
11813 return -1;
11814
11815 wpa_printf(MSG_DEBUG,
11816 "DPP: Received DPP Configuration Response over TCP");
11817
11818 pos = msg;
11819 end = msg + len;
11820
11821 dialog_token = *pos++;
11822 status = WPA_GET_LE16(pos);
11823 if (status != WLAN_STATUS_SUCCESS) {
11824 wpa_printf(MSG_DEBUG, "DPP: Unexpected Status Code %u", status);
11825 return -1;
11826 }
11827 pos += 2;
11828 pos += 2; /* ignore GAS Comeback Delay */
11829
11830 adv_proto = pos++;
11831 slen = *pos++;
11832 if (*adv_proto != WLAN_EID_ADV_PROTO ||
11833 slen > end - pos || slen < 2)
11834 return -1;
11835
11836 next = pos + slen;
11837 pos++; /* skip QueryRespLenLimit and PAME-BI */
11838
11839 if (slen != 8 || *pos != WLAN_EID_VENDOR_SPECIFIC ||
11840 pos[1] != 5 || WPA_GET_BE24(&pos[2]) != OUI_WFA ||
11841 pos[5] != DPP_OUI_TYPE || pos[6] != 0x01)
11842 return -1;
11843
11844 pos = next;
11845 /* Query Response */
11846 if (end - pos < 2)
11847 return -1;
11848 slen = WPA_GET_LE16(pos);
11849 pos += 2;
11850 if (slen > end - pos)
11851 return -1;
11852
11853 buf = wpabuf_alloc(slen);
11854 if (!buf)
11855 return -1;
11856 wpabuf_put_data(buf, pos, slen);
11857
11858 if (!conn->relay && !conn->ctrl)
11859 return dpp_tcp_rx_gas_resp(conn, buf);
11860
11861 if (!conn->relay) {
11862 wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
11863 wpabuf_free(buf);
11864 return -1;
11865 }
11866 wpa_printf(MSG_DEBUG, "DPP: Relay - send over WLAN");
11867 conn->relay->gas_resp_tx(conn->relay->cb_ctx, conn->mac_addr,
11868 dialog_token, 0, buf);
11869
11870 return 0;
11871}
11872
11873
11874static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx)
11875{
11876 struct dpp_connection *conn = eloop_ctx;
11877 int res;
11878 const u8 *pos;
11879
11880 wpa_printf(MSG_DEBUG, "DPP: TCP data available for reading (sock %d)",
11881 sd);
11882
11883 if (conn->msg_len_octets < 4) {
11884 u32 msglen;
11885
11886 res = recv(sd, &conn->msg_len[conn->msg_len_octets],
11887 4 - conn->msg_len_octets, 0);
11888 if (res < 0) {
11889 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s",
11890 strerror(errno));
11891 dpp_connection_remove(conn);
11892 return;
11893 }
11894 if (res == 0) {
11895 wpa_printf(MSG_DEBUG,
11896 "DPP: No more data available over TCP");
11897 dpp_connection_remove(conn);
11898 return;
11899 }
11900 wpa_printf(MSG_DEBUG,
11901 "DPP: Received %d/%d octet(s) of message length field",
11902 res, (int) (4 - conn->msg_len_octets));
11903 conn->msg_len_octets += res;
11904
11905 if (conn->msg_len_octets < 4) {
11906 wpa_printf(MSG_DEBUG,
11907 "DPP: Need %d more octets of message length field",
11908 (int) (4 - conn->msg_len_octets));
11909 return;
11910 }
11911
11912 msglen = WPA_GET_BE32(conn->msg_len);
11913 wpa_printf(MSG_DEBUG, "DPP: Message length: %u", msglen);
11914 if (msglen > 65535) {
11915 wpa_printf(MSG_INFO, "DPP: Unexpectedly long message");
11916 dpp_connection_remove(conn);
11917 return;
11918 }
11919
11920 wpabuf_free(conn->msg);
11921 conn->msg = wpabuf_alloc(msglen);
11922 }
11923
11924 if (!conn->msg) {
11925 wpa_printf(MSG_DEBUG,
11926 "DPP: No buffer available for receiving the message");
11927 dpp_connection_remove(conn);
11928 return;
11929 }
11930
11931 wpa_printf(MSG_DEBUG, "DPP: Need %u more octets of message payload",
11932 (unsigned int) wpabuf_tailroom(conn->msg));
11933
11934 res = recv(sd, wpabuf_put(conn->msg, 0), wpabuf_tailroom(conn->msg), 0);
11935 if (res < 0) {
11936 wpa_printf(MSG_DEBUG, "DPP: recv failed: %s", strerror(errno));
11937 dpp_connection_remove(conn);
11938 return;
11939 }
11940 if (res == 0) {
11941 wpa_printf(MSG_DEBUG, "DPP: No more data available over TCP");
11942 dpp_connection_remove(conn);
11943 return;
11944 }
11945 wpa_printf(MSG_DEBUG, "DPP: Received %d octets", res);
11946 wpabuf_put(conn->msg, res);
11947
11948 if (wpabuf_tailroom(conn->msg) > 0) {
11949 wpa_printf(MSG_DEBUG,
11950 "DPP: Need %u more octets of message payload",
11951 (unsigned int) wpabuf_tailroom(conn->msg));
11952 return;
11953 }
11954
11955 conn->msg_len_octets = 0;
11956 wpa_hexdump_buf(MSG_DEBUG, "DPP: Received TCP message", conn->msg);
11957 if (wpabuf_len(conn->msg) < 1) {
11958 dpp_connection_remove(conn);
11959 return;
11960 }
11961
11962 pos = wpabuf_head(conn->msg);
11963 switch (*pos) {
11964 case WLAN_PA_VENDOR_SPECIFIC:
11965 if (dpp_controller_rx_action(conn, pos + 1,
11966 wpabuf_len(conn->msg) - 1) < 0)
11967 dpp_connection_remove(conn);
11968 break;
11969 case WLAN_PA_GAS_INITIAL_REQ:
11970 if (dpp_controller_rx_gas_req(conn, pos + 1,
11971 wpabuf_len(conn->msg) - 1) < 0)
11972 dpp_connection_remove(conn);
11973 break;
11974 case WLAN_PA_GAS_INITIAL_RESP:
11975 if (dpp_rx_gas_resp(conn, pos + 1,
11976 wpabuf_len(conn->msg) - 1) < 0)
11977 dpp_connection_remove(conn);
11978 break;
11979 default:
11980 wpa_printf(MSG_DEBUG, "DPP: Ignore unsupported message type %u",
11981 *pos);
11982 break;
11983 }
11984}
11985
11986
11987static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx)
11988{
11989 struct dpp_controller *ctrl = eloop_ctx;
11990 struct sockaddr_in addr;
11991 socklen_t addr_len = sizeof(addr);
11992 int fd;
11993 struct dpp_connection *conn;
11994
11995 wpa_printf(MSG_DEBUG, "DPP: New TCP connection");
11996
11997 fd = accept(ctrl->sock, (struct sockaddr *) &addr, &addr_len);
11998 if (fd < 0) {
11999 wpa_printf(MSG_DEBUG,
12000 "DPP: Failed to accept new connection: %s",
12001 strerror(errno));
12002 return;
12003 }
12004 wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d",
12005 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
12006
12007 conn = os_zalloc(sizeof(*conn));
12008 if (!conn)
12009 goto fail;
12010
12011 conn->global = ctrl->global;
12012 conn->ctrl = ctrl;
12013 conn->sock = fd;
12014
12015 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12016 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12017 strerror(errno));
12018 goto fail;
12019 }
12020
12021 if (eloop_register_sock(conn->sock, EVENT_TYPE_READ,
12022 dpp_controller_rx, conn, NULL) < 0)
12023 goto fail;
12024 conn->read_eloop = 1;
12025
12026 /* TODO: eloop timeout to expire connections that do not complete in
12027 * reasonable time */
12028 dl_list_add(&ctrl->conn, &conn->list);
12029 return;
12030
12031fail:
12032 close(fd);
12033 os_free(conn);
12034}
12035
12036
12037int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth,
12038 const struct hostapd_ip_addr *addr, int port)
12039{
12040 struct dpp_connection *conn;
12041 struct sockaddr_storage saddr;
12042 socklen_t addrlen;
12043 const u8 *hdr, *pos, *end;
12044 char txt[100];
12045
12046 wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d",
12047 hostapd_ip_txt(addr, txt, sizeof(txt)), port);
12048 if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen,
12049 addr, port) < 0) {
12050 dpp_auth_deinit(auth);
12051 return -1;
12052 }
12053
12054 conn = os_zalloc(sizeof(*conn));
12055 if (!conn) {
12056 dpp_auth_deinit(auth);
12057 return -1;
12058 }
12059
12060 conn->global = dpp;
12061 conn->auth = auth;
12062 conn->sock = socket(AF_INET, SOCK_STREAM, 0);
12063 if (conn->sock < 0)
12064 goto fail;
12065
12066 if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) {
12067 wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s",
12068 strerror(errno));
12069 goto fail;
12070 }
12071
12072 if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) {
12073 if (errno != EINPROGRESS) {
12074 wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s",
12075 strerror(errno));
12076 goto fail;
12077 }
12078
12079 /*
12080 * Continue connecting in the background; eloop will call us
12081 * once the connection is ready (or failed).
12082 */
12083 }
12084
12085 if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE,
12086 dpp_conn_tx_ready, conn, NULL) < 0)
12087 goto fail;
12088 conn->write_eloop = 1;
12089
12090 hdr = wpabuf_head(auth->req_msg);
12091 end = hdr + wpabuf_len(auth->req_msg);
12092 hdr += 2; /* skip Category and Actiom */
12093 pos = hdr + DPP_HDR_LEN;
12094 conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos);
12095 if (!conn->msg_out)
12096 goto fail;
12097 /* Message will be sent in dpp_conn_tx_ready() */
12098
12099 /* TODO: eloop timeout to clear a connection if it does not complete
12100 * properly */
12101 dl_list_add(&dpp->tcp_init, &conn->list);
12102 return 0;
12103fail:
12104 dpp_connection_free(conn);
12105 return -1;
12106}
12107
12108
12109int dpp_controller_start(struct dpp_global *dpp,
12110 struct dpp_controller_config *config)
12111{
12112 struct dpp_controller *ctrl;
12113 int on = 1;
12114 struct sockaddr_in sin;
12115 int port;
12116
12117 if (!dpp || dpp->controller)
12118 return -1;
12119
12120 ctrl = os_zalloc(sizeof(*ctrl));
12121 if (!ctrl)
12122 return -1;
12123 ctrl->global = dpp;
12124 if (config->configurator_params)
12125 ctrl->configurator_params =
12126 os_strdup(config->configurator_params);
12127 dl_list_init(&ctrl->conn);
12128 /* TODO: configure these somehow */
12129 ctrl->allowed_roles = DPP_CAPAB_ENROLLEE | DPP_CAPAB_CONFIGURATOR;
12130 ctrl->qr_mutual = 0;
12131
12132 ctrl->sock = socket(AF_INET, SOCK_STREAM, 0);
12133 if (ctrl->sock < 0)
12134 goto fail;
12135
12136 if (setsockopt(ctrl->sock, SOL_SOCKET, SO_REUSEADDR,
12137 &on, sizeof(on)) < 0) {
12138 wpa_printf(MSG_DEBUG,
12139 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12140 strerror(errno));
12141 /* try to continue anyway */
12142 }
12143
12144 if (fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0) {
12145 wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s",
12146 strerror(errno));
12147 goto fail;
12148 }
12149
12150 /* TODO: IPv6 */
12151 os_memset(&sin, 0, sizeof(sin));
12152 sin.sin_family = AF_INET;
12153 sin.sin_addr.s_addr = INADDR_ANY;
12154 port = config->tcp_port ? config->tcp_port : DPP_TCP_PORT;
12155 sin.sin_port = htons(port);
12156 if (bind(ctrl->sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
12157 wpa_printf(MSG_INFO,
12158 "DPP: Failed to bind Controller TCP port: %s",
12159 strerror(errno));
12160 goto fail;
12161 }
12162 if (listen(ctrl->sock, 10 /* max backlog */) < 0 ||
12163 fcntl(ctrl->sock, F_SETFL, O_NONBLOCK) < 0 ||
12164 eloop_register_sock(ctrl->sock, EVENT_TYPE_READ,
12165 dpp_controller_tcp_cb, ctrl, NULL))
12166 goto fail;
12167
12168 dpp->controller = ctrl;
12169 wpa_printf(MSG_DEBUG, "DPP: Controller started on TCP port %d", port);
12170 return 0;
12171fail:
12172 dpp_controller_free(ctrl);
12173 return -1;
12174}
12175
12176
12177void dpp_controller_stop(struct dpp_global *dpp)
12178{
12179 if (dpp) {
12180 dpp_controller_free(dpp->controller);
12181 dpp->controller = NULL;
12182 }
12183}
12184
12185#endif /* CONFIG_DPP2 */