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