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