2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2020, The Linux Foundation
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
10 #include "utils/includes.h"
12 #include <openssl/opensslv.h>
13 #include <openssl/err.h>
14 #include <openssl/asn1.h>
15 #include <openssl/asn1t.h>
17 #include "utils/common.h"
18 #include "utils/base64.h"
19 #include "utils/json.h"
20 #include "utils/ip_addr.h"
21 #include "utils/eloop.h"
22 #include "common/ieee802_11_common.h"
23 #include "common/ieee802_11_defs.h"
24 #include "common/wpa_ctrl.h"
25 #include "common/gas.h"
26 #include "crypto/crypto.h"
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"
33 #include "drivers/driver.h"
37 static const char * dpp_netrole_str(enum dpp_netrole netrole
);
39 #ifdef CONFIG_TESTING_OPTIONS
40 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
41 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
42 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
43 u8 dpp_pkex_ephemeral_key_override
[600];
44 size_t dpp_pkex_ephemeral_key_override_len
= 0;
45 u8 dpp_protocol_key_override
[600];
46 size_t dpp_protocol_key_override_len
= 0;
47 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
48 size_t dpp_nonce_override_len
= 0;
50 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
51 const struct dpp_curve_params
*curve
);
52 #endif /* CONFIG_TESTING_OPTIONS */
54 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
55 (defined(LIBRESSL_VERSION_NUMBER) && \
56 LIBRESSL_VERSION_NUMBER < 0x20700000L)
57 /* Compatibility wrappers for older versions. */
59 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
67 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
77 static EC_KEY
* EVP_PKEY_get0_EC_KEY(EVP_PKEY
*pkey
)
79 if (pkey
->type
!= EVP_PKEY_EC
)
87 struct dpp_connection
{
89 struct dpp_controller
*ctrl
;
90 struct dpp_relay_controller
*relay
;
91 struct dpp_global
*global
;
92 struct dpp_authentication
*auth
;
94 u8 mac_addr
[ETH_ALEN
];
97 size_t msg_len_octets
;
99 struct wpabuf
*msg_out
;
101 unsigned int read_eloop
:1;
102 unsigned int write_eloop
:1;
103 unsigned int on_tcp_tx_complete_gas_done
:1;
104 unsigned int on_tcp_tx_complete_remove
:1;
105 unsigned int on_tcp_tx_complete_auth_ok
:1;
108 /* Remote Controller */
109 struct dpp_relay_controller
{
111 struct dpp_global
*global
;
112 u8 pkhash
[SHA256_MAC_LEN
];
113 struct hostapd_ip_addr ipaddr
;
115 void (*tx
)(void *ctx
, const u8
*addr
, unsigned int freq
, const u8
*msg
,
117 void (*gas_resp_tx
)(void *ctx
, const u8
*addr
, u8 dialog_token
,
118 int prot
, struct wpabuf
*buf
);
119 struct dl_list conn
; /* struct dpp_connection */
122 /* Local Controller */
123 struct dpp_controller
{
124 struct dpp_global
*global
;
128 struct dl_list conn
; /* struct dpp_connection */
129 char *configurator_params
;
134 struct dl_list bootstrap
; /* struct dpp_bootstrap_info */
135 struct dl_list configurator
; /* struct dpp_configurator */
137 struct dl_list controllers
; /* struct dpp_relay_controller */
138 struct dpp_controller
*controller
;
139 struct dl_list tcp_init
; /* struct dpp_connection */
141 int (*process_conf_obj
)(void *ctx
, struct dpp_authentication
*auth
);
142 void (*remove_bi
)(void *ctx
, struct dpp_bootstrap_info
*bi
);
143 #endif /* CONFIG_DPP2 */
146 static const struct dpp_curve_params dpp_curves
[] = {
147 /* The mandatory to support and the default NIST P-256 curve needs to
148 * be the first entry on this list. */
149 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
150 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
151 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
152 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
153 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
154 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
155 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
159 /* Role-specific elements for PKEX */
162 static const u8 pkex_init_x_p256
[32] = {
163 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
164 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
165 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
166 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
168 static const u8 pkex_init_y_p256
[32] = {
169 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
170 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
171 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
172 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
174 static const u8 pkex_resp_x_p256
[32] = {
175 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
176 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
177 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
178 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
180 static const u8 pkex_resp_y_p256
[32] = {
181 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
182 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
183 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
184 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
188 static const u8 pkex_init_x_p384
[48] = {
189 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
190 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
191 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
192 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
193 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
194 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
196 static const u8 pkex_init_y_p384
[48] = {
197 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
198 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
199 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
200 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
201 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
202 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
204 static const u8 pkex_resp_x_p384
[48] = {
205 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
206 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
207 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
208 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
209 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
210 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
212 static const u8 pkex_resp_y_p384
[48] = {
213 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
214 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
215 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
216 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
217 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
218 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
222 static const u8 pkex_init_x_p521
[66] = {
223 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
224 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
225 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
226 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
227 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
228 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
229 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
230 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
233 static const u8 pkex_init_y_p521
[66] = {
234 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
235 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
236 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
237 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
238 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
239 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
240 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
241 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
244 static const u8 pkex_resp_x_p521
[66] = {
245 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
246 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
247 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
248 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
249 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
250 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
251 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
252 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
255 static const u8 pkex_resp_y_p521
[66] = {
256 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
257 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
258 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
259 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
260 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
261 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
262 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
263 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
267 /* Brainpool P-256r1 */
268 static const u8 pkex_init_x_bp_p256r1
[32] = {
269 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
270 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
271 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
272 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
274 static const u8 pkex_init_y_bp_p256r1
[32] = {
275 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
276 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
277 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
278 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
280 static const u8 pkex_resp_x_bp_p256r1
[32] = {
281 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
282 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
283 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
284 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
286 static const u8 pkex_resp_y_bp_p256r1
[32] = {
287 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
288 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
289 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
290 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
293 /* Brainpool P-384r1 */
294 static const u8 pkex_init_x_bp_p384r1
[48] = {
295 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
296 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
297 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
298 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
299 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
300 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
302 static const u8 pkex_init_y_bp_p384r1
[48] = {
303 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
304 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
305 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
306 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
307 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
308 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
310 static const u8 pkex_resp_x_bp_p384r1
[48] = {
311 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
312 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
313 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
314 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
315 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
316 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
318 static const u8 pkex_resp_y_bp_p384r1
[48] = {
319 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
320 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
321 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
322 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
323 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
324 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
327 /* Brainpool P-512r1 */
328 static const u8 pkex_init_x_bp_p512r1
[64] = {
329 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
330 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
331 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
332 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
333 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
334 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
335 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
336 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
338 static const u8 pkex_init_y_bp_p512r1
[64] = {
339 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
340 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
341 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
342 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
343 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
344 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
345 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
346 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
348 static const u8 pkex_resp_x_bp_p512r1
[64] = {
349 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
350 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
351 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
352 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
353 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
354 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
355 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
356 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
358 static const u8 pkex_resp_y_bp_p512r1
[64] = {
359 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
360 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
361 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
362 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
363 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
364 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
365 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
366 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
370 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
371 const EC_POINT
*point
)
375 char *x_str
= NULL
, *y_str
= NULL
;
377 if (!wpa_debug_show_keys
)
383 if (!ctx
|| !x
|| !y
||
384 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
387 x_str
= BN_bn2hex(x
);
388 y_str
= BN_bn2hex(y
);
389 if (!x_str
|| !y_str
)
392 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
403 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
404 size_t num_elem
, const u8
*addr
[], const size_t *len
,
407 if (curve
->hash_len
== 32)
408 return sha256_vector(num_elem
, addr
, len
, mac
);
409 if (curve
->hash_len
== 48)
410 return sha384_vector(num_elem
, addr
, len
, mac
);
411 if (curve
->hash_len
== 64)
412 return sha512_vector(num_elem
, addr
, len
, mac
);
417 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
418 const char *label
, u8
*out
, size_t outlen
)
421 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
422 (const u8
*) label
, os_strlen(label
),
425 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
426 (const u8
*) label
, os_strlen(label
),
429 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
430 (const u8
*) label
, os_strlen(label
),
436 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
437 size_t num_elem
, const u8
*addr
[],
438 const size_t *len
, u8
*mac
)
441 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
444 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
447 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
453 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
454 const u8
*data
, size_t data_len
, u8
*mac
)
457 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
459 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
461 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
468 static int dpp_pbkdf2_f(size_t hash_len
,
469 const u8
*password
, size_t password_len
,
470 const u8
*salt
, size_t salt_len
,
471 unsigned int iterations
, unsigned int count
, u8
*digest
)
473 unsigned char tmp
[DPP_MAX_HASH_LEN
], tmp2
[DPP_MAX_HASH_LEN
];
485 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
486 * U1 = PRF(P, S || i)
491 WPA_PUT_BE32(count_buf
, count
);
492 if (dpp_hmac_vector(hash_len
, password
, password_len
, 2, addr
, len
,
495 os_memcpy(digest
, tmp
, hash_len
);
497 for (i
= 1; i
< iterations
; i
++) {
498 if (dpp_hmac(hash_len
, password
, password_len
, tmp
, hash_len
,
501 os_memcpy(tmp
, tmp2
, hash_len
);
502 for (j
= 0; j
< hash_len
; j
++)
503 digest
[j
] ^= tmp2
[j
];
510 static int dpp_pbkdf2(size_t hash_len
, const u8
*password
, size_t password_len
,
511 const u8
*salt
, size_t salt_len
, unsigned int iterations
,
512 u8
*buf
, size_t buflen
)
514 unsigned int count
= 0;
515 unsigned char *pos
= buf
;
516 size_t left
= buflen
, plen
;
517 unsigned char digest
[DPP_MAX_HASH_LEN
];
521 if (dpp_pbkdf2_f(hash_len
, password
, password_len
,
522 salt
, salt_len
, iterations
, count
, digest
))
524 plen
= left
> hash_len
? hash_len
: left
;
525 os_memcpy(pos
, digest
, plen
);
533 #endif /* CONFIG_DPP2 */
536 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
538 int num_bytes
, offset
;
540 num_bytes
= BN_num_bytes(bn
);
541 if ((size_t) num_bytes
> len
)
543 offset
= len
- num_bytes
;
544 os_memset(pos
, 0, offset
);
545 BN_bn2bin(bn
, pos
+ offset
);
550 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
557 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
560 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
561 len
= i2o_ECPublicKey(eckey
, NULL
);
563 wpa_printf(MSG_ERROR
,
564 "DDP: Failed to determine public key encoding length");
569 buf
= wpabuf_alloc(len
);
575 pos
= wpabuf_put(buf
, len
);
576 res
= i2o_ECPublicKey(eckey
, &pos
);
579 wpa_printf(MSG_ERROR
,
580 "DDP: Failed to encode public key (res=%d/%d)",
587 /* Remove 0x04 prefix to match DPP definition */
588 pos
= wpabuf_mhead(buf
);
589 os_memmove(pos
, pos
+ 1, len
- 1);
597 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
598 const u8
*buf_x
, const u8
*buf_y
,
601 EC_KEY
*eckey
= NULL
;
603 EC_POINT
*point
= NULL
;
604 BIGNUM
*x
= NULL
, *y
= NULL
;
605 EVP_PKEY
*pkey
= NULL
;
609 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
613 point
= EC_POINT_new(group
);
614 x
= BN_bin2bn(buf_x
, len
, NULL
);
615 y
= BN_bin2bn(buf_y
, len
, NULL
);
616 if (!point
|| !x
|| !y
) {
617 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
621 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
622 wpa_printf(MSG_ERROR
,
623 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
624 ERR_error_string(ERR_get_error(), NULL
));
628 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
629 EC_POINT_is_at_infinity(group
, point
)) {
630 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
633 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
635 eckey
= EC_KEY_new();
637 EC_KEY_set_group(eckey
, group
) != 1 ||
638 EC_KEY_set_public_key(eckey
, point
) != 1) {
639 wpa_printf(MSG_ERROR
,
640 "DPP: Failed to set EC_KEY: %s",
641 ERR_error_string(ERR_get_error(), NULL
));
644 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
646 pkey
= EVP_PKEY_new();
647 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
648 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
656 EC_POINT_free(point
);
666 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
667 const u8
*buf
, size_t len
)
670 const EC_GROUP
*group
;
671 EVP_PKEY
*pkey
= NULL
;
676 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
678 wpa_printf(MSG_ERROR
,
679 "DPP: Could not get EC_KEY from group_key");
683 group
= EC_KEY_get0_group(eckey
);
685 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
688 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
695 static int dpp_ecdh(EVP_PKEY
*own
, EVP_PKEY
*peer
,
696 u8
*secret
, size_t *secret_len
)
704 ctx
= EVP_PKEY_CTX_new(own
, NULL
);
706 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_CTX_new failed: %s",
707 ERR_error_string(ERR_get_error(), NULL
));
711 if (EVP_PKEY_derive_init(ctx
) != 1) {
712 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive_init failed: %s",
713 ERR_error_string(ERR_get_error(), NULL
));
717 if (EVP_PKEY_derive_set_peer(ctx
, peer
) != 1) {
718 wpa_printf(MSG_ERROR
,
719 "DPP: EVP_PKEY_derive_set_peet failed: %s",
720 ERR_error_string(ERR_get_error(), NULL
));
724 if (EVP_PKEY_derive(ctx
, NULL
, secret_len
) != 1) {
725 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive(NULL) failed: %s",
726 ERR_error_string(ERR_get_error(), NULL
));
730 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
732 int level
= *secret_len
> 200 ? MSG_ERROR
: MSG_DEBUG
;
734 /* It looks like OpenSSL can return unexpectedly large buffer
735 * need for shared secret from EVP_PKEY_derive(NULL) in some
736 * cases. For example, group 19 has shown cases where secret_len
737 * is set to 72 even though the actual length ends up being
738 * updated to 32 when EVP_PKEY_derive() is called with a buffer
739 * for the value. Work around this by trying to fetch the value
740 * and continue if it is within supported range even when the
741 * initial buffer need is claimed to be larger. */
743 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
745 if (*secret_len
> 200)
747 if (EVP_PKEY_derive(ctx
, buf
, secret_len
) != 1) {
748 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
749 ERR_error_string(ERR_get_error(), NULL
));
752 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
753 wpa_printf(MSG_ERROR
,
754 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
758 wpa_hexdump_key(MSG_DEBUG
, "DPP: Unexpected secret_len change",
760 os_memcpy(secret
, buf
, *secret_len
);
761 forced_memzero(buf
, sizeof(buf
));
765 if (EVP_PKEY_derive(ctx
, secret
, secret_len
) != 1) {
766 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
767 ERR_error_string(ERR_get_error(), NULL
));
775 EVP_PKEY_CTX_free(ctx
);
780 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
782 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
786 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
791 msg
= wpabuf_alloc(8 + len
);
794 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
795 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
796 wpabuf_put_be24(msg
, OUI_WFA
);
797 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
798 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
799 wpabuf_put_u8(msg
, type
);
804 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
807 const u8
*pos
= buf
, *end
= buf
+ len
;
809 while (end
- pos
>= 4) {
810 id
= WPA_GET_LE16(pos
);
812 alen
= WPA_GET_LE16(pos
);
814 if (alen
> end
- pos
)
827 static const u8
* dpp_get_attr_next(const u8
*prev
, const u8
*buf
, size_t len
,
828 u16 req_id
, u16
*ret_len
)
831 const u8
*pos
, *end
= buf
+ len
;
836 pos
= prev
+ WPA_GET_LE16(prev
- 2);
837 while (end
- pos
>= 4) {
838 id
= WPA_GET_LE16(pos
);
840 alen
= WPA_GET_LE16(pos
);
842 if (alen
> end
- pos
)
855 int dpp_check_attrs(const u8
*buf
, size_t len
)
858 int wrapped_data
= 0;
862 while (end
- pos
>= 4) {
865 id
= WPA_GET_LE16(pos
);
867 alen
= WPA_GET_LE16(pos
);
869 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
871 if (alen
> end
- pos
) {
872 wpa_printf(MSG_DEBUG
,
873 "DPP: Truncated message - not enough room for the attribute - dropped");
877 wpa_printf(MSG_DEBUG
,
878 "DPP: An unexpected attribute included after the Wrapped Data attribute");
881 if (id
== DPP_ATTR_WRAPPED_DATA
)
887 wpa_printf(MSG_DEBUG
,
888 "DPP: Unexpected octets (%d) after the last attribute",
897 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
905 EVP_PKEY_free(info
->pubkey
);
906 str_clear_free(info
->configurator_params
);
911 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
914 case DPP_BOOTSTRAP_QR_CODE
:
916 case DPP_BOOTSTRAP_PKEX
:
918 case DPP_BOOTSTRAP_NFC_URI
:
925 static int dpp_uri_valid_info(const char *info
)
928 unsigned char val
= *info
++;
930 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
938 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
940 bi
->uri
= os_strdup(uri
);
941 return bi
->uri
? 0 : -1;
945 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
946 const char *chan_list
)
948 const char *pos
= chan_list
, *pos2
;
949 int opclass
= -1, channel
, freq
;
951 while (pos
&& *pos
&& *pos
!= ';') {
953 while (*pos2
>= '0' && *pos2
<= '9')
964 while (*pos
>= '0' && *pos
<= '9')
966 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
967 wpa_printf(MSG_DEBUG
,
968 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
969 opclass
, channel
, freq
);
971 wpa_printf(MSG_DEBUG
,
972 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
974 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
975 wpa_printf(MSG_DEBUG
,
976 "DPP: Too many channels in URI channel-list - ignore list");
980 bi
->freq
[bi
->num_freq
++] = freq
;
983 if (*pos
== ';' || *pos
== '\0')
992 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
997 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
1002 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
1003 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
1007 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
1013 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
1020 end
= os_strchr(info
, ';');
1022 end
= info
+ os_strlen(info
);
1023 bi
->info
= os_malloc(end
- info
+ 1);
1026 os_memcpy(bi
->info
, info
, end
- info
);
1027 bi
->info
[end
- info
] = '\0';
1028 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
1029 if (!dpp_uri_valid_info(bi
->info
)) {
1030 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
1038 static const struct dpp_curve_params
*
1039 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
1044 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1045 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
1046 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
1047 return &dpp_curves
[i
];
1053 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
1059 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1060 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
1062 return &dpp_curves
[i
];
1068 static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info
*bi
,
1069 const u8
*data
, size_t data_len
)
1076 if (sha256_vector(1, addr
, len
, bi
->pubkey_hash
) < 0)
1078 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
1079 bi
->pubkey_hash
, SHA256_MAC_LEN
);
1081 addr
[0] = (const u8
*) "chirp";
1085 if (sha256_vector(2, addr
, len
, bi
->pubkey_hash_chirp
) < 0)
1087 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash (chirp)",
1088 bi
->pubkey_hash_chirp
, SHA256_MAC_LEN
);
1094 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
1100 const unsigned char *p
;
1102 X509_PUBKEY
*pub
= NULL
;
1103 ASN1_OBJECT
*ppkalg
;
1104 const unsigned char *pk
;
1107 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1108 (defined(LIBRESSL_VERSION_NUMBER) && \
1109 LIBRESSL_VERSION_NUMBER < 0x20800000L)
1110 ASN1_OBJECT
*pa_oid
;
1112 const ASN1_OBJECT
*pa_oid
;
1116 const ASN1_OBJECT
*poid
;
1119 end
= os_strchr(info
, ';');
1123 data
= base64_decode(info
, end
- info
, &data_len
);
1125 wpa_printf(MSG_DEBUG
,
1126 "DPP: Invalid base64 encoding on URI public-key");
1129 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
1132 if (dpp_bi_pubkey_hash(bi
, data
, data_len
) < 0) {
1133 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1138 /* DER encoded ASN.1 SubjectPublicKeyInfo
1140 * SubjectPublicKeyInfo ::= SEQUENCE {
1141 * algorithm AlgorithmIdentifier,
1142 * subjectPublicKey BIT STRING }
1144 * AlgorithmIdentifier ::= SEQUENCE {
1145 * algorithm OBJECT IDENTIFIER,
1146 * parameters ANY DEFINED BY algorithm OPTIONAL }
1148 * subjectPublicKey = compressed format public key per ANSI X9.63
1149 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1150 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1151 * prime256v1 (1.2.840.10045.3.1.7)
1155 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
1159 wpa_printf(MSG_DEBUG
,
1160 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1164 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
1165 wpa_printf(MSG_DEBUG
,
1166 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1167 EVP_PKEY_free(pkey
);
1171 res
= X509_PUBKEY_set(&pub
, pkey
);
1173 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
1177 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
1179 wpa_printf(MSG_DEBUG
,
1180 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1183 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
1184 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1185 wpa_printf(MSG_DEBUG
,
1186 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1189 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
1190 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
1191 wpa_printf(MSG_DEBUG
,
1192 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1196 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
1197 if (ptype
!= V_ASN1_OBJECT
) {
1198 wpa_printf(MSG_DEBUG
,
1199 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1203 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
1204 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1205 wpa_printf(MSG_DEBUG
,
1206 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1209 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
1210 bi
->curve
= dpp_get_curve_oid(poid
);
1212 wpa_printf(MSG_DEBUG
,
1213 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1218 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
1220 X509_PUBKEY_free(pub
);
1224 X509_PUBKEY_free(pub
);
1225 EVP_PKEY_free(pkey
);
1230 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1232 const char *pos
= uri
;
1234 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1235 struct dpp_bootstrap_info
*bi
;
1237 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1239 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1240 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1246 end
= os_strchr(pos
, ';');
1251 /* Handle terminating ";;" and ignore unexpected ";"
1252 * for parsing robustness. */
1257 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1258 chan_list
= pos
+ 2;
1259 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1261 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1263 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1266 wpa_hexdump_ascii(MSG_DEBUG
,
1267 "DPP: Ignore unrecognized URI parameter",
1273 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1277 bi
= os_zalloc(sizeof(*bi
));
1281 if (dpp_clone_uri(bi
, uri
) < 0 ||
1282 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1283 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1284 dpp_parse_uri_info(bi
, info
) < 0 ||
1285 dpp_parse_uri_pk(bi
, pk
) < 0) {
1286 dpp_bootstrap_info_free(bi
);
1294 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1301 unsigned char *der
= NULL
;
1303 const EC_GROUP
*group
;
1304 const EC_POINT
*point
;
1306 out
= BIO_new(BIO_s_mem());
1310 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1311 rlen
= BIO_ctrl_pending(out
);
1312 txt
= os_malloc(rlen
+ 1);
1314 res
= BIO_read(out
, txt
, rlen
);
1317 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1323 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1327 group
= EC_KEY_get0_group(eckey
);
1328 point
= EC_KEY_get0_public_key(eckey
);
1330 dpp_debug_print_point(title
, group
, point
);
1332 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1334 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1338 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1340 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1348 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1350 EVP_PKEY_CTX
*kctx
= NULL
;
1351 EC_KEY
*ec_params
= NULL
;
1352 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1355 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1357 nid
= OBJ_txt2nid(curve
->name
);
1358 if (nid
== NID_undef
) {
1359 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1363 ec_params
= EC_KEY_new_by_curve_name(nid
);
1365 wpa_printf(MSG_ERROR
,
1366 "DPP: Failed to generate EC_KEY parameters");
1369 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1370 params
= EVP_PKEY_new();
1371 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1372 wpa_printf(MSG_ERROR
,
1373 "DPP: Failed to generate EVP_PKEY parameters");
1377 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1379 EVP_PKEY_keygen_init(kctx
) != 1 ||
1380 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1381 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1386 if (wpa_debug_show_keys
)
1387 dpp_debug_print_key("Own generated key", key
);
1390 EC_KEY_free(ec_params
);
1391 EVP_PKEY_free(params
);
1392 EVP_PKEY_CTX_free(kctx
);
1397 static const struct dpp_curve_params
*
1398 dpp_get_curve_name(const char *name
)
1402 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1403 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1404 (dpp_curves
[i
].jwk_crv
&&
1405 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1406 return &dpp_curves
[i
];
1412 static const struct dpp_curve_params
*
1413 dpp_get_curve_jwk_crv(const char *name
)
1417 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1418 if (dpp_curves
[i
].jwk_crv
&&
1419 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1420 return &dpp_curves
[i
];
1426 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1427 const u8
*privkey
, size_t privkey_len
)
1431 const EC_GROUP
*group
;
1434 pkey
= EVP_PKEY_new();
1437 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1439 wpa_printf(MSG_INFO
,
1440 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1441 ERR_error_string(ERR_get_error(), NULL
));
1442 EVP_PKEY_free(pkey
);
1445 group
= EC_KEY_get0_group(eckey
);
1448 EVP_PKEY_free(pkey
);
1451 nid
= EC_GROUP_get_curve_name(group
);
1452 *curve
= dpp_get_curve_nid(nid
);
1454 wpa_printf(MSG_INFO
,
1455 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1458 EVP_PKEY_free(pkey
);
1462 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1464 EVP_PKEY_free(pkey
);
1472 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1473 * as an OID identifying the curve */
1475 /* Compressed format public key per ANSI X9.63 */
1476 ASN1_BIT_STRING
*pub_key
;
1477 } DPP_BOOTSTRAPPING_KEY
;
1479 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1480 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1481 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1482 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1484 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1487 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1489 unsigned char *der
= NULL
;
1492 struct wpabuf
*ret
= NULL
;
1494 const EC_GROUP
*group
;
1495 const EC_POINT
*point
;
1497 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1501 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1505 group
= EC_KEY_get0_group(eckey
);
1506 point
= EC_KEY_get0_public_key(eckey
);
1507 if (!group
|| !point
)
1509 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1510 nid
= EC_GROUP_get_curve_name(group
);
1512 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1514 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1515 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1518 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1523 der
= OPENSSL_malloc(len
);
1526 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1529 OPENSSL_free(bootstrap
->pub_key
->data
);
1530 bootstrap
->pub_key
->data
= der
;
1532 bootstrap
->pub_key
->length
= len
;
1533 /* No unused bits */
1534 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1535 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1537 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1539 wpa_printf(MSG_ERROR
,
1540 "DDP: Failed to build DER encoded public key");
1544 ret
= wpabuf_alloc_copy(der
, der_len
);
1546 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1554 static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1559 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1562 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1564 res
= dpp_bi_pubkey_hash(bi
, wpabuf_head(der
), wpabuf_len(der
));
1566 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1572 static int dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1573 const u8
*privkey
, size_t privkey_len
)
1575 char *base64
= NULL
;
1578 struct wpabuf
*der
= NULL
;
1581 bi
->curve
= &dpp_curves
[0];
1583 bi
->curve
= dpp_get_curve_name(curve
);
1585 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1591 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1593 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1598 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1601 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1604 if (dpp_bi_pubkey_hash(bi
, wpabuf_head(der
), wpabuf_len(der
)) < 0) {
1605 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1609 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1617 pos
= os_strchr(pos
, '\n');
1620 os_memmove(pos
, pos
+ 1, end
- pos
);
1632 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1633 unsigned int hash_len
)
1635 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1636 const char *info
= "first intermediate key";
1639 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1641 /* HKDF-Extract(<>, M.x) */
1642 os_memset(salt
, 0, hash_len
);
1643 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1645 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1648 /* HKDF-Expand(PRK, info, L) */
1649 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1650 os_memset(prk
, 0, hash_len
);
1654 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1660 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1661 unsigned int hash_len
)
1663 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1664 const char *info
= "second intermediate key";
1667 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1669 /* HKDF-Extract(<>, N.x) */
1670 os_memset(salt
, 0, hash_len
);
1671 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1674 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1677 /* HKDF-Expand(PRK, info, L) */
1678 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1679 os_memset(prk
, 0, hash_len
);
1683 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1689 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1690 unsigned int hash_len
)
1693 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1694 const char *info_ke
= "DPP Key";
1695 u8 prk
[DPP_MAX_HASH_LEN
];
1699 size_t num_elem
= 0;
1701 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1702 wpa_printf(MSG_DEBUG
,
1703 "DPP: Mx/Nx not available - cannot derive ke");
1707 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1709 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1710 nonce_len
= auth
->curve
->nonce_len
;
1711 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1712 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1713 addr
[num_elem
] = auth
->Mx
;
1714 len
[num_elem
] = auth
->Mx_len
;
1716 addr
[num_elem
] = auth
->Nx
;
1717 len
[num_elem
] = auth
->Nx_len
;
1719 if (auth
->peer_bi
&& auth
->own_bi
) {
1720 if (!auth
->Lx_len
) {
1721 wpa_printf(MSG_DEBUG
,
1722 "DPP: Lx not available - cannot derive ke");
1725 addr
[num_elem
] = auth
->Lx
;
1726 len
[num_elem
] = auth
->secret_len
;
1729 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1730 num_elem
, addr
, len
, prk
);
1733 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1736 /* HKDF-Expand(PRK, info, L) */
1737 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1738 os_memset(prk
, 0, hash_len
);
1742 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1748 static void dpp_build_attr_status(struct wpabuf
*msg
,
1749 enum dpp_status_error status
)
1751 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1752 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1753 wpabuf_put_le16(msg
, 1);
1754 wpabuf_put_u8(msg
, status
);
1758 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1762 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1763 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1764 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1765 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1770 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1774 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1775 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1776 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1777 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1782 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1783 const struct wpabuf
*pi
,
1785 const u8
*r_pubkey_hash
,
1786 const u8
*i_pubkey_hash
,
1787 unsigned int neg_freq
)
1790 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1791 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1794 size_t len
[2], siv_len
, attr_len
;
1795 u8
*attr_start
, *attr_end
;
1797 /* Build DPP Authentication Request frame attributes */
1798 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1799 4 + sizeof(wrapped_data
);
1804 #endif /* CONFIG_DPP2 */
1805 #ifdef CONFIG_TESTING_OPTIONS
1806 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1808 #endif /* CONFIG_TESTING_OPTIONS */
1809 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1813 attr_start
= wpabuf_put(msg
, 0);
1815 /* Responder Bootstrapping Key Hash */
1816 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1818 /* Initiator Bootstrapping Key Hash */
1819 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1821 /* Initiator Protocol Key */
1823 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1824 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1825 wpabuf_put_buf(msg
, pi
);
1830 u8 op_class
, channel
;
1832 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1834 NUM_HOSTAPD_MODES
) {
1835 wpa_printf(MSG_INFO
,
1836 "DPP: Unsupported negotiation frequency request: %d",
1841 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1842 wpabuf_put_le16(msg
, 2);
1843 wpabuf_put_u8(msg
, op_class
);
1844 wpabuf_put_u8(msg
, channel
);
1848 /* Protocol Version */
1849 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1850 wpabuf_put_le16(msg
, 1);
1851 wpabuf_put_u8(msg
, 2);
1852 #endif /* CONFIG_DPP2 */
1854 #ifdef CONFIG_TESTING_OPTIONS
1855 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1856 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1857 goto skip_wrapped_data
;
1859 #endif /* CONFIG_TESTING_OPTIONS */
1861 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1864 #ifdef CONFIG_TESTING_OPTIONS
1865 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1866 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1869 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1870 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1871 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1873 WPA_PUT_LE16(pos
, nonce_len
- 1);
1875 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1876 pos
+= nonce_len
- 1;
1879 #endif /* CONFIG_TESTING_OPTIONS */
1882 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1884 WPA_PUT_LE16(pos
, nonce_len
);
1886 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1889 #ifdef CONFIG_TESTING_OPTIONS
1891 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1892 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1895 #endif /* CONFIG_TESTING_OPTIONS */
1897 /* I-capabilities */
1898 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1900 WPA_PUT_LE16(pos
, 1);
1902 auth
->i_capab
= auth
->allowed_roles
;
1903 *pos
++ = auth
->i_capab
;
1904 #ifdef CONFIG_TESTING_OPTIONS
1905 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1906 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1910 #endif /* CONFIG_TESTING_OPTIONS */
1912 attr_end
= wpabuf_put(msg
, 0);
1914 /* OUI, OUI type, Crypto Suite, DPP frame type */
1915 addr
[0] = wpabuf_head_u8(msg
) + 2;
1916 len
[0] = 3 + 1 + 1 + 1;
1917 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1919 /* Attributes before Wrapped Data */
1920 addr
[1] = attr_start
;
1921 len
[1] = attr_end
- attr_start
;
1922 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1924 siv_len
= pos
- clear
;
1925 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1926 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1927 2, addr
, len
, wrapped_data
) < 0) {
1931 siv_len
+= AES_BLOCK_SIZE
;
1932 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1933 wrapped_data
, siv_len
);
1935 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1936 wpabuf_put_le16(msg
, siv_len
);
1937 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1939 #ifdef CONFIG_TESTING_OPTIONS
1940 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1941 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1942 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1945 #endif /* CONFIG_TESTING_OPTIONS */
1947 wpa_hexdump_buf(MSG_DEBUG
,
1948 "DPP: Authentication Request frame attributes", msg
);
1954 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1955 enum dpp_status_error status
,
1956 const struct wpabuf
*pr
,
1958 const u8
*r_pubkey_hash
,
1959 const u8
*i_pubkey_hash
,
1960 const u8
*r_nonce
, const u8
*i_nonce
,
1961 const u8
*wrapped_r_auth
,
1962 size_t wrapped_r_auth_len
,
1966 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1967 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1968 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1969 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1971 size_t len
[2], siv_len
, attr_len
;
1972 u8
*attr_start
, *attr_end
, *pos
;
1974 auth
->waiting_auth_conf
= 1;
1975 auth
->auth_resp_tries
= 0;
1977 /* Build DPP Authentication Response frame attributes */
1978 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1979 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1982 #endif /* CONFIG_DPP2 */
1983 #ifdef CONFIG_TESTING_OPTIONS
1984 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1986 #endif /* CONFIG_TESTING_OPTIONS */
1987 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1991 attr_start
= wpabuf_put(msg
, 0);
1995 dpp_build_attr_status(msg
, status
);
1997 /* Responder Bootstrapping Key Hash */
1998 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
2000 /* Initiator Bootstrapping Key Hash (mutual authentication) */
2001 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
2003 /* Responder Protocol Key */
2005 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
2006 wpabuf_put_le16(msg
, wpabuf_len(pr
));
2007 wpabuf_put_buf(msg
, pr
);
2011 /* Protocol Version */
2012 if (auth
->peer_version
>= 2) {
2013 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
2014 wpabuf_put_le16(msg
, 1);
2015 wpabuf_put_u8(msg
, 2);
2017 #endif /* CONFIG_DPP2 */
2019 attr_end
= wpabuf_put(msg
, 0);
2021 #ifdef CONFIG_TESTING_OPTIONS
2022 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
2023 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2024 goto skip_wrapped_data
;
2026 #endif /* CONFIG_TESTING_OPTIONS */
2028 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2033 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
2035 WPA_PUT_LE16(pos
, nonce_len
);
2037 os_memcpy(pos
, r_nonce
, nonce_len
);
2043 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
2045 WPA_PUT_LE16(pos
, nonce_len
);
2047 os_memcpy(pos
, i_nonce
, nonce_len
);
2048 #ifdef CONFIG_TESTING_OPTIONS
2049 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
2050 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
2051 pos
[nonce_len
/ 2] ^= 0x01;
2053 #endif /* CONFIG_TESTING_OPTIONS */
2057 #ifdef CONFIG_TESTING_OPTIONS
2058 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
2059 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
2062 #endif /* CONFIG_TESTING_OPTIONS */
2064 /* R-capabilities */
2065 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
2067 WPA_PUT_LE16(pos
, 1);
2069 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
2071 *pos
++ = auth
->r_capab
;
2072 #ifdef CONFIG_TESTING_OPTIONS
2073 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
2074 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
2076 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
2077 wpa_printf(MSG_INFO
,
2078 "DPP: TESTING - incompatible R-capabilities");
2079 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
2080 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
2083 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
2084 DPP_CAPAB_CONFIGURATOR
;
2087 #endif /* CONFIG_TESTING_OPTIONS */
2089 if (wrapped_r_auth
) {
2091 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
2093 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
2095 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
2096 pos
+= wrapped_r_auth_len
;
2099 /* OUI, OUI type, Crypto Suite, DPP frame type */
2100 addr
[0] = wpabuf_head_u8(msg
) + 2;
2101 len
[0] = 3 + 1 + 1 + 1;
2102 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2104 /* Attributes before Wrapped Data */
2105 addr
[1] = attr_start
;
2106 len
[1] = attr_end
- attr_start
;
2107 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2109 siv_len
= pos
- clear
;
2110 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
2111 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
2112 2, addr
, len
, wrapped_data
) < 0) {
2116 siv_len
+= AES_BLOCK_SIZE
;
2117 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2118 wrapped_data
, siv_len
);
2120 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2121 wpabuf_put_le16(msg
, siv_len
);
2122 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2124 #ifdef CONFIG_TESTING_OPTIONS
2125 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
2126 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2127 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2130 #endif /* CONFIG_TESTING_OPTIONS */
2132 wpa_hexdump_buf(MSG_DEBUG
,
2133 "DPP: Authentication Response frame attributes", msg
);
2138 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
2139 u16 num_modes
, unsigned int freq
)
2144 if (!own_modes
|| !num_modes
)
2147 for (m
= 0; m
< num_modes
; m
++) {
2148 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2149 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
2152 flag
= own_modes
[m
].channels
[c
].flag
;
2153 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
2154 HOSTAPD_CHAN_NO_IR
|
2155 HOSTAPD_CHAN_RADAR
)))
2160 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
2165 static int freq_included(const unsigned int freqs
[], unsigned int num
,
2169 if (freqs
[--num
] == freq
)
2176 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
2181 for (i
= 0; i
< num
; i
++) {
2182 if (freqs
[i
] == freq
)
2185 if (i
== 0 || i
>= num
)
2187 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
2192 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
2193 struct hostapd_hw_modes
*own_modes
,
2196 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
2197 unsigned int i
, freq
;
2199 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2200 freq
= peer_bi
->freq
[i
];
2201 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2203 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2204 auth
->freq
[auth
->num_freq
++] = freq
;
2206 if (!auth
->num_freq
) {
2207 wpa_printf(MSG_INFO
,
2208 "DPP: No available channels for initiating DPP Authentication");
2211 auth
->curr_freq
= auth
->freq
[0];
2216 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2217 struct hostapd_hw_modes
*own_modes
,
2226 if (!own_modes
|| !num_modes
) {
2227 auth
->freq
[0] = 2412;
2228 auth
->freq
[1] = 2437;
2229 auth
->freq
[2] = 2462;
2234 for (m
= 0; m
< num_modes
; m
++) {
2235 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2236 freq
= own_modes
[m
].channels
[c
].freq
;
2237 flag
= own_modes
[m
].channels
[c
].flag
;
2238 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2239 HOSTAPD_CHAN_NO_IR
|
2240 HOSTAPD_CHAN_RADAR
))
2242 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2244 auth
->freq
[auth
->num_freq
++] = freq
;
2245 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2252 return auth
->num_freq
== 0 ? -1 : 0;
2256 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2257 unsigned int neg_freq
,
2258 struct hostapd_hw_modes
*own_modes
,
2262 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2269 auth
->freq
[0] = neg_freq
;
2273 if (auth
->peer_bi
->num_freq
> 0)
2274 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2276 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2280 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2281 * likely channels first. */
2282 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2283 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2284 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2287 auth
->curr_freq
= auth
->freq
[0];
2290 end
= pos
+ sizeof(freqs
);
2291 for (i
= 0; i
< auth
->num_freq
; i
++) {
2292 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2293 if (os_snprintf_error(end
- pos
, res
))
2298 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2305 static int dpp_gen_uri(struct dpp_bootstrap_info
*bi
)
2307 char macstr
[ETH_ALEN
* 2 + 10];
2310 len
= 4; /* "DPP:" */
2312 len
+= 3 + os_strlen(bi
->chan
); /* C:...; */
2313 if (is_zero_ether_addr(bi
->mac_addr
))
2316 os_snprintf(macstr
, sizeof(macstr
), "M:" COMPACT_MACSTR
";",
2317 MAC2STR(bi
->mac_addr
));
2318 len
+= os_strlen(macstr
); /* M:...; */
2320 len
+= 3 + os_strlen(bi
->info
); /* I:...; */
2321 len
+= 4 + os_strlen(bi
->pk
); /* K:...;; */
2324 bi
->uri
= os_malloc(len
+ 1);
2327 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2328 bi
->chan
? "C:" : "", bi
->chan
? bi
->chan
: "",
2329 bi
->chan
? ";" : "",
2331 bi
->info
? "I:" : "", bi
->info
? bi
->info
: "",
2332 bi
->info
? ";" : "",
2338 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2340 struct dpp_bootstrap_info
*bi
;
2343 return 0; /* already generated */
2345 bi
= os_zalloc(sizeof(*bi
));
2348 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2349 if (dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0) < 0 ||
2350 dpp_gen_uri(bi
) < 0)
2352 wpa_printf(MSG_DEBUG
,
2353 "DPP: Auto-generated own bootstrapping key info: URI %s",
2356 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2360 dpp_bootstrap_info_free(bi
);
2365 struct dpp_authentication
*
2366 dpp_alloc_auth(struct dpp_global
*dpp
, void *msg_ctx
)
2368 struct dpp_authentication
*auth
;
2370 auth
= os_zalloc(sizeof(*auth
));
2374 auth
->msg_ctx
= msg_ctx
;
2375 auth
->conf_resp_status
= 255;
2380 struct dpp_authentication
* dpp_auth_init(struct dpp_global
*dpp
, void *msg_ctx
,
2381 struct dpp_bootstrap_info
*peer_bi
,
2382 struct dpp_bootstrap_info
*own_bi
,
2383 u8 dpp_allowed_roles
,
2384 unsigned int neg_freq
,
2385 struct hostapd_hw_modes
*own_modes
,
2388 struct dpp_authentication
*auth
;
2391 struct wpabuf
*pi
= NULL
;
2392 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2393 #ifdef CONFIG_TESTING_OPTIONS
2394 u8 test_hash
[SHA256_MAC_LEN
];
2395 #endif /* CONFIG_TESTING_OPTIONS */
2397 auth
= dpp_alloc_auth(dpp
, msg_ctx
);
2400 if (peer_bi
->configurator_params
&&
2401 dpp_set_configurator(auth
, peer_bi
->configurator_params
) < 0)
2403 auth
->initiator
= 1;
2404 auth
->waiting_auth_resp
= 1;
2405 auth
->allowed_roles
= dpp_allowed_roles
;
2406 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2407 auth
->peer_bi
= peer_bi
;
2408 auth
->own_bi
= own_bi
;
2409 auth
->curve
= peer_bi
->curve
;
2411 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2412 dpp_prepare_channel_list(auth
, neg_freq
, own_modes
, num_modes
) < 0)
2415 #ifdef CONFIG_TESTING_OPTIONS
2416 if (dpp_nonce_override_len
> 0) {
2417 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2418 nonce_len
= dpp_nonce_override_len
;
2419 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2421 nonce_len
= auth
->curve
->nonce_len
;
2422 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2423 wpa_printf(MSG_ERROR
,
2424 "DPP: Failed to generate I-nonce");
2428 #else /* CONFIG_TESTING_OPTIONS */
2429 nonce_len
= auth
->curve
->nonce_len
;
2430 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2431 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2434 #endif /* CONFIG_TESTING_OPTIONS */
2435 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2437 #ifdef CONFIG_TESTING_OPTIONS
2438 if (dpp_protocol_key_override_len
) {
2439 const struct dpp_curve_params
*tmp_curve
;
2441 wpa_printf(MSG_INFO
,
2442 "DPP: TESTING - override protocol key");
2443 auth
->own_protocol_key
= dpp_set_keypair(
2444 &tmp_curve
, dpp_protocol_key_override
,
2445 dpp_protocol_key_override_len
);
2447 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2449 #else /* CONFIG_TESTING_OPTIONS */
2450 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2451 #endif /* CONFIG_TESTING_OPTIONS */
2452 if (!auth
->own_protocol_key
)
2455 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2459 /* ECDH: M = pI * BR */
2460 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2461 auth
->Mx
, &secret_len
) < 0)
2463 auth
->secret_len
= secret_len
;
2465 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2466 auth
->Mx
, auth
->secret_len
);
2467 auth
->Mx_len
= auth
->secret_len
;
2469 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2470 auth
->curve
->hash_len
) < 0)
2473 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2474 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2476 #ifdef CONFIG_TESTING_OPTIONS
2477 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2478 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2479 r_pubkey_hash
= NULL
;
2480 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2481 wpa_printf(MSG_INFO
,
2482 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2483 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2484 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2485 r_pubkey_hash
= test_hash
;
2486 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2487 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2488 i_pubkey_hash
= NULL
;
2489 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2490 wpa_printf(MSG_INFO
,
2491 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2492 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2493 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2494 i_pubkey_hash
= test_hash
;
2495 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2496 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2499 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2500 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2502 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2503 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2506 #endif /* CONFIG_TESTING_OPTIONS */
2508 if (neg_freq
&& auth
->num_freq
== 1 && auth
->freq
[0] == neg_freq
)
2510 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2511 i_pubkey_hash
, neg_freq
);
2519 dpp_auth_deinit(auth
);
2525 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2529 size_t json_len
, clear_len
;
2530 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2534 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2536 nonce_len
= auth
->curve
->nonce_len
;
2537 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2538 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2541 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2542 json_len
= os_strlen(json
);
2543 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configRequest JSON", json
, json_len
);
2545 /* { E-nonce, configAttrib }ke */
2546 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2547 clear
= wpabuf_alloc(clear_len
);
2548 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2549 #ifdef CONFIG_TESTING_OPTIONS
2550 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2552 #endif /* CONFIG_TESTING_OPTIONS */
2553 msg
= wpabuf_alloc(attr_len
);
2557 #ifdef CONFIG_TESTING_OPTIONS
2558 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2559 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2562 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2563 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2564 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2565 wpabuf_put_le16(clear
, nonce_len
- 1);
2566 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2569 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2570 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2571 goto skip_wrapped_data
;
2573 #endif /* CONFIG_TESTING_OPTIONS */
2576 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2577 wpabuf_put_le16(clear
, nonce_len
);
2578 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2580 #ifdef CONFIG_TESTING_OPTIONS
2582 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2583 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2584 goto skip_conf_attr_obj
;
2586 #endif /* CONFIG_TESTING_OPTIONS */
2589 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2590 wpabuf_put_le16(clear
, json_len
);
2591 wpabuf_put_data(clear
, json
, json_len
);
2593 #ifdef CONFIG_TESTING_OPTIONS
2595 #endif /* CONFIG_TESTING_OPTIONS */
2597 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2598 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2599 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2602 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2603 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2604 wpabuf_head(clear
), wpabuf_len(clear
),
2605 0, NULL
, NULL
, wrapped
) < 0)
2607 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2608 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2610 #ifdef CONFIG_TESTING_OPTIONS
2611 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2612 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2613 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2616 #endif /* CONFIG_TESTING_OPTIONS */
2618 wpa_hexdump_buf(MSG_DEBUG
,
2619 "DPP: Configuration Request frame attributes", msg
);
2630 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2632 /* Advertisement Protocol IE */
2633 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2634 wpabuf_put_u8(buf
, 8); /* Length */
2635 wpabuf_put_u8(buf
, 0x7f);
2636 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2637 wpabuf_put_u8(buf
, 5);
2638 wpabuf_put_be24(buf
, OUI_WFA
);
2639 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2640 wpabuf_put_u8(buf
, 0x01);
2644 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2647 wpabuf_put_le16(buf
, wpabuf_len(query
));
2648 wpabuf_put_buf(buf
, query
);
2652 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2655 struct wpabuf
*buf
, *conf_req
;
2657 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2659 wpa_printf(MSG_DEBUG
,
2660 "DPP: No configuration request data available");
2664 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2666 wpabuf_free(conf_req
);
2670 dpp_write_adv_proto(buf
);
2671 dpp_write_gas_query(buf
, conf_req
);
2672 wpabuf_free(conf_req
);
2673 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2679 struct wpabuf
* dpp_build_conf_req_helper(struct dpp_authentication
*auth
,
2681 enum dpp_netrole netrole
,
2682 const char *mud_url
, int *opclasses
)
2684 size_t len
, name_len
;
2685 const char *tech
= "infra";
2686 const char *dpp_name
;
2687 struct wpabuf
*buf
, *json
;
2689 #ifdef CONFIG_TESTING_OPTIONS
2690 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
2691 static const char *bogus_tech
= "knfra";
2693 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
2696 #endif /* CONFIG_TESTING_OPTIONS */
2698 dpp_name
= name
? name
: "Test";
2699 name_len
= os_strlen(dpp_name
);
2701 len
= 100 + name_len
* 6 + 1 + int_array_len(opclasses
) * 4;
2702 if (mud_url
&& mud_url
[0])
2703 len
+= 10 + os_strlen(mud_url
);
2704 json
= wpabuf_alloc(len
);
2708 json_start_object(json
, NULL
);
2709 if (json_add_string_escape(json
, "name", dpp_name
, name_len
) < 0) {
2713 json_value_sep(json
);
2714 json_add_string(json
, "wi-fi_tech", tech
);
2715 json_value_sep(json
);
2716 json_add_string(json
, "netRole", dpp_netrole_str(netrole
));
2717 if (mud_url
&& mud_url
[0]) {
2718 json_value_sep(json
);
2719 json_add_string(json
, "mudurl", mud_url
);
2724 json_value_sep(json
);
2725 json_start_array(json
, "bandSupport");
2726 for (i
= 0; opclasses
[i
]; i
++)
2727 wpabuf_printf(json
, "%s%u", i
? "," : "", opclasses
[i
]);
2728 json_end_array(json
);
2730 json_end_object(json
);
2732 buf
= dpp_build_conf_req(auth
, wpabuf_head(json
));
2739 static void dpp_auth_success(struct dpp_authentication
*auth
)
2741 wpa_printf(MSG_DEBUG
,
2742 "DPP: Authentication success - clear temporary keys");
2743 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2745 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2747 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2749 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2750 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2752 auth
->auth_success
= 1;
2756 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2758 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2761 size_t i
, num_elem
= 0;
2766 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2767 nonce_len
= auth
->curve
->nonce_len
;
2769 if (auth
->initiator
) {
2770 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2771 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2773 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2776 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2778 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2779 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2781 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2784 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2786 if (!pix
|| !prx
|| !brx
)
2789 addr
[num_elem
] = auth
->i_nonce
;
2790 len
[num_elem
] = nonce_len
;
2793 addr
[num_elem
] = auth
->r_nonce
;
2794 len
[num_elem
] = nonce_len
;
2797 addr
[num_elem
] = wpabuf_head(pix
);
2798 len
[num_elem
] = wpabuf_len(pix
) / 2;
2801 addr
[num_elem
] = wpabuf_head(prx
);
2802 len
[num_elem
] = wpabuf_len(prx
) / 2;
2806 addr
[num_elem
] = wpabuf_head(bix
);
2807 len
[num_elem
] = wpabuf_len(bix
) / 2;
2811 addr
[num_elem
] = wpabuf_head(brx
);
2812 len
[num_elem
] = wpabuf_len(brx
) / 2;
2815 addr
[num_elem
] = &zero
;
2819 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2820 for (i
= 0; i
< num_elem
; i
++)
2821 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2822 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2824 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2825 auth
->curve
->hash_len
);
2835 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2837 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2840 size_t i
, num_elem
= 0;
2845 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2846 nonce_len
= auth
->curve
->nonce_len
;
2848 if (auth
->initiator
) {
2849 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2850 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2852 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2857 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2859 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2860 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2862 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2867 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2869 if (!pix
|| !prx
|| !brx
)
2872 addr
[num_elem
] = auth
->r_nonce
;
2873 len
[num_elem
] = nonce_len
;
2876 addr
[num_elem
] = auth
->i_nonce
;
2877 len
[num_elem
] = nonce_len
;
2880 addr
[num_elem
] = wpabuf_head(prx
);
2881 len
[num_elem
] = wpabuf_len(prx
) / 2;
2884 addr
[num_elem
] = wpabuf_head(pix
);
2885 len
[num_elem
] = wpabuf_len(pix
) / 2;
2888 addr
[num_elem
] = wpabuf_head(brx
);
2889 len
[num_elem
] = wpabuf_len(brx
) / 2;
2893 addr
[num_elem
] = wpabuf_head(bix
);
2894 len
[num_elem
] = wpabuf_len(bix
) / 2;
2898 addr
[num_elem
] = &one
;
2902 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2903 for (i
= 0; i
< num_elem
; i
++)
2904 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2905 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2907 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2908 auth
->curve
->hash_len
);
2918 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2920 const EC_GROUP
*group
;
2922 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2923 const EC_POINT
*BI_point
;
2925 BIGNUM
*lx
, *sum
, *q
;
2926 const BIGNUM
*bR_bn
, *pR_bn
;
2929 /* L = ((bR + pR) modulo q) * BI */
2931 bnctx
= BN_CTX_new();
2935 if (!bnctx
|| !sum
|| !q
|| !lx
)
2937 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2940 BI_point
= EC_KEY_get0_public_key(BI
);
2941 group
= EC_KEY_get0_group(BI
);
2945 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2946 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2949 bR_bn
= EC_KEY_get0_private_key(bR
);
2950 pR_bn
= EC_KEY_get0_private_key(pR
);
2951 if (!bR_bn
|| !pR_bn
)
2953 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2954 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2956 l
= EC_POINT_new(group
);
2958 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2959 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2961 wpa_printf(MSG_ERROR
,
2962 "OpenSSL: failed: %s",
2963 ERR_error_string(ERR_get_error(), NULL
));
2967 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2969 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2970 auth
->Lx_len
= auth
->secret_len
;
2973 EC_POINT_clear_free(l
);
2985 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2987 const EC_GROUP
*group
;
2988 EC_POINT
*l
= NULL
, *sum
= NULL
;
2989 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2990 const EC_POINT
*BR_point
, *PR_point
;
2993 const BIGNUM
*bI_bn
;
2996 /* L = bI * (BR + PR) */
2998 bnctx
= BN_CTX_new();
3002 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
3003 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
3006 BR_point
= EC_KEY_get0_public_key(BR
);
3007 PR_point
= EC_KEY_get0_public_key(PR
);
3009 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
3012 group
= EC_KEY_get0_group(bI
);
3013 bI_bn
= EC_KEY_get0_private_key(bI
);
3014 if (!group
|| !bI_bn
)
3016 sum
= EC_POINT_new(group
);
3017 l
= EC_POINT_new(group
);
3019 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
3020 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
3021 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
3023 wpa_printf(MSG_ERROR
,
3024 "OpenSSL: failed: %s",
3025 ERR_error_string(ERR_get_error(), NULL
));
3029 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
3031 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
3032 auth
->Lx_len
= auth
->secret_len
;
3035 EC_POINT_clear_free(l
);
3036 EC_POINT_clear_free(sum
);
3046 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
3050 struct wpabuf
*msg
, *pr
= NULL
;
3051 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
3052 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
3053 size_t wrapped_r_auth_len
;
3055 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
3056 enum dpp_status_error status
= DPP_STATUS_OK
;
3057 #ifdef CONFIG_TESTING_OPTIONS
3058 u8 test_hash
[SHA256_MAC_LEN
];
3059 #endif /* CONFIG_TESTING_OPTIONS */
3061 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3065 #ifdef CONFIG_TESTING_OPTIONS
3066 if (dpp_nonce_override_len
> 0) {
3067 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
3068 nonce_len
= dpp_nonce_override_len
;
3069 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
3071 nonce_len
= auth
->curve
->nonce_len
;
3072 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3073 wpa_printf(MSG_ERROR
,
3074 "DPP: Failed to generate R-nonce");
3078 #else /* CONFIG_TESTING_OPTIONS */
3079 nonce_len
= auth
->curve
->nonce_len
;
3080 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3081 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
3084 #endif /* CONFIG_TESTING_OPTIONS */
3085 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
3087 EVP_PKEY_free(auth
->own_protocol_key
);
3088 #ifdef CONFIG_TESTING_OPTIONS
3089 if (dpp_protocol_key_override_len
) {
3090 const struct dpp_curve_params
*tmp_curve
;
3092 wpa_printf(MSG_INFO
,
3093 "DPP: TESTING - override protocol key");
3094 auth
->own_protocol_key
= dpp_set_keypair(
3095 &tmp_curve
, dpp_protocol_key_override
,
3096 dpp_protocol_key_override_len
);
3098 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3100 #else /* CONFIG_TESTING_OPTIONS */
3101 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3102 #endif /* CONFIG_TESTING_OPTIONS */
3103 if (!auth
->own_protocol_key
)
3106 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
3110 /* ECDH: N = pR * PI */
3111 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
3112 auth
->Nx
, &secret_len
) < 0)
3115 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3116 auth
->Nx
, auth
->secret_len
);
3117 auth
->Nx_len
= auth
->secret_len
;
3119 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3120 auth
->curve
->hash_len
) < 0)
3123 if (auth
->own_bi
&& auth
->peer_bi
) {
3124 /* Mutual authentication */
3125 if (dpp_auth_derive_l_responder(auth
) < 0)
3129 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3132 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3133 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
3134 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
3135 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
3137 #ifdef CONFIG_TESTING_OPTIONS
3138 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
3139 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
3140 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3142 #endif /* CONFIG_TESTING_OPTIONS */
3143 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3144 r_auth
, 4 + auth
->curve
->hash_len
,
3145 0, NULL
, NULL
, wrapped_r_auth
) < 0)
3147 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
3148 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
3149 wrapped_r_auth
, wrapped_r_auth_len
);
3150 w_r_auth
= wrapped_r_auth
;
3152 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3154 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3156 i_pubkey_hash
= NULL
;
3158 i_nonce
= auth
->i_nonce
;
3159 r_nonce
= auth
->r_nonce
;
3161 #ifdef CONFIG_TESTING_OPTIONS
3162 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3163 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3164 r_pubkey_hash
= NULL
;
3165 } else if (dpp_test
==
3166 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3167 wpa_printf(MSG_INFO
,
3168 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3169 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3170 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3171 r_pubkey_hash
= test_hash
;
3172 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3173 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3174 i_pubkey_hash
= NULL
;
3175 } else if (dpp_test
==
3176 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3177 wpa_printf(MSG_INFO
,
3178 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3180 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3182 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3183 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3184 i_pubkey_hash
= test_hash
;
3185 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
3186 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
3189 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
3190 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
3192 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
3193 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
3195 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
3196 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
3198 wrapped_r_auth_len
= 0;
3199 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3200 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3202 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
3203 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3205 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
3206 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
3208 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3209 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3212 #endif /* CONFIG_TESTING_OPTIONS */
3214 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
3215 r_pubkey_hash
, i_pubkey_hash
,
3217 w_r_auth
, wrapped_r_auth_len
,
3221 wpabuf_free(auth
->resp_msg
);
3222 auth
->resp_msg
= msg
;
3230 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3231 enum dpp_status_error status
)
3234 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3235 #ifdef CONFIG_TESTING_OPTIONS
3236 u8 test_hash
[SHA256_MAC_LEN
];
3237 #endif /* CONFIG_TESTING_OPTIONS */
3241 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3243 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3245 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3247 i_pubkey_hash
= NULL
;
3249 i_nonce
= auth
->i_nonce
;
3251 #ifdef CONFIG_TESTING_OPTIONS
3252 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3253 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3254 r_pubkey_hash
= NULL
;
3255 } else if (dpp_test
==
3256 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3257 wpa_printf(MSG_INFO
,
3258 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3259 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3260 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3261 r_pubkey_hash
= test_hash
;
3262 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3263 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3264 i_pubkey_hash
= NULL
;
3265 } else if (dpp_test
==
3266 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3267 wpa_printf(MSG_INFO
,
3268 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3270 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3272 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3273 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3274 i_pubkey_hash
= test_hash
;
3275 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3276 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3278 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3279 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3282 #endif /* CONFIG_TESTING_OPTIONS */
3284 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3285 r_pubkey_hash
, i_pubkey_hash
,
3286 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3289 wpabuf_free(auth
->resp_msg
);
3290 auth
->resp_msg
= msg
;
3295 struct dpp_authentication
*
3296 dpp_auth_req_rx(struct dpp_global
*dpp
, void *msg_ctx
, u8 dpp_allowed_roles
,
3297 int qr_mutual
, struct dpp_bootstrap_info
*peer_bi
,
3298 struct dpp_bootstrap_info
*own_bi
,
3299 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3302 EVP_PKEY
*pi
= NULL
;
3303 EVP_PKEY_CTX
*ctx
= NULL
;
3307 u8
*unwrapped
= NULL
;
3308 size_t unwrapped_len
= 0;
3309 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3311 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3312 i_bootstrap_len
, channel_len
;
3313 struct dpp_authentication
*auth
= NULL
;
3317 #endif /* CONFIG_DPP2 */
3319 #ifdef CONFIG_TESTING_OPTIONS
3320 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3321 wpa_printf(MSG_INFO
,
3322 "DPP: TESTING - stop at Authentication Request");
3325 #endif /* CONFIG_TESTING_OPTIONS */
3327 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3329 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3330 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3331 "Missing or invalid required Wrapped Data attribute");
3334 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3335 wrapped_data
, wrapped_data_len
);
3336 attr_len
= wrapped_data
- 4 - attr_start
;
3338 auth
= dpp_alloc_auth(dpp
, msg_ctx
);
3341 if (peer_bi
&& peer_bi
->configurator_params
&&
3342 dpp_set_configurator(auth
, peer_bi
->configurator_params
) < 0)
3344 auth
->peer_bi
= peer_bi
;
3345 auth
->own_bi
= own_bi
;
3346 auth
->curve
= own_bi
->curve
;
3347 auth
->curr_freq
= freq
;
3349 auth
->peer_version
= 1; /* default to the first version */
3351 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3354 if (version_len
< 1 || version
[0] == 0) {
3356 "Invalid Protocol Version attribute");
3359 auth
->peer_version
= version
[0];
3360 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3361 auth
->peer_version
);
3363 #endif /* CONFIG_DPP2 */
3365 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3370 if (channel_len
< 2) {
3371 dpp_auth_fail(auth
, "Too short Channel attribute");
3375 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3376 wpa_printf(MSG_DEBUG
,
3377 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3378 channel
[0], channel
[1], neg_freq
);
3381 "Unsupported Channel attribute value");
3385 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3386 wpa_printf(MSG_DEBUG
,
3387 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3389 auth
->curr_freq
= neg_freq
;
3393 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3397 "Missing required Initiator Protocol Key attribute");
3400 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3401 i_proto
, i_proto_len
);
3404 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3406 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3409 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3411 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3413 auth
->secret_len
= secret_len
;
3415 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3416 auth
->Mx
, auth
->secret_len
);
3417 auth
->Mx_len
= auth
->secret_len
;
3419 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3420 auth
->curve
->hash_len
) < 0)
3424 len
[0] = DPP_HDR_LEN
;
3425 addr
[1] = attr_start
;
3427 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3428 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3429 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3430 wrapped_data
, wrapped_data_len
);
3431 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3432 unwrapped
= os_malloc(unwrapped_len
);
3435 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3436 wrapped_data
, wrapped_data_len
,
3437 2, addr
, len
, unwrapped
) < 0) {
3438 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3441 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3442 unwrapped
, unwrapped_len
);
3444 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3445 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3449 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3451 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3452 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3455 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3456 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3458 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3459 DPP_ATTR_I_CAPABILITIES
,
3461 if (!i_capab
|| i_capab_len
< 1) {
3462 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3465 auth
->i_capab
= i_capab
[0];
3466 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3468 bin_clear_free(unwrapped
, unwrapped_len
);
3471 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3472 case DPP_CAPAB_ENROLLEE
:
3473 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3474 wpa_printf(MSG_DEBUG
,
3475 "DPP: Local policy does not allow Configurator role");
3476 goto not_compatible
;
3478 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3479 auth
->configurator
= 1;
3481 case DPP_CAPAB_CONFIGURATOR
:
3482 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3483 wpa_printf(MSG_DEBUG
,
3484 "DPP: Local policy does not allow Enrollee role");
3485 goto not_compatible
;
3487 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3488 auth
->configurator
= 0;
3490 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3491 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3492 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3493 auth
->configurator
= 0;
3494 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3495 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3496 auth
->configurator
= 1;
3498 wpa_printf(MSG_DEBUG
,
3499 "DPP: Local policy does not allow Configurator/Enrollee role");
3500 goto not_compatible
;
3504 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3505 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3506 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3507 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3511 auth
->peer_protocol_key
= pi
;
3513 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3514 char hex
[SHA256_MAC_LEN
* 2 + 1];
3516 wpa_printf(MSG_DEBUG
,
3517 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3518 if (dpp_auth_build_resp_status(auth
,
3519 DPP_STATUS_RESPONSE_PENDING
) < 0)
3521 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3522 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3524 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3525 auth
->response_pending
= 1;
3526 os_memcpy(auth
->waiting_pubkey_hash
,
3527 i_bootstrap
, i_bootstrap_len
);
3528 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3534 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3538 if (dpp_auth_build_resp_ok(auth
) < 0)
3544 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3545 "i-capab=0x%02x", auth
->i_capab
);
3546 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3547 auth
->configurator
= 1;
3549 auth
->configurator
= 0;
3550 auth
->peer_protocol_key
= pi
;
3552 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3555 auth
->remove_on_tx_status
= 1;
3558 bin_clear_free(unwrapped
, unwrapped_len
);
3560 EVP_PKEY_CTX_free(ctx
);
3561 dpp_auth_deinit(auth
);
3566 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3567 struct dpp_bootstrap_info
*peer_bi
)
3569 if (!auth
|| !auth
->response_pending
||
3570 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3571 SHA256_MAC_LEN
) != 0)
3574 wpa_printf(MSG_DEBUG
,
3575 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3576 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3577 auth
->peer_bi
= peer_bi
;
3579 if (dpp_auth_build_resp_ok(auth
) < 0)
3586 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3587 enum dpp_status_error status
)
3590 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3592 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3595 size_t len
[2], attr_len
;
3597 u8
*wrapped_r_nonce
;
3598 u8
*attr_start
, *attr_end
;
3599 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3600 #ifdef CONFIG_TESTING_OPTIONS
3601 u8 test_hash
[SHA256_MAC_LEN
];
3602 #endif /* CONFIG_TESTING_OPTIONS */
3604 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3606 i_auth_len
= 4 + auth
->curve
->hash_len
;
3607 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3608 /* Build DPP Authentication Confirmation frame attributes */
3609 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3610 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3611 #ifdef CONFIG_TESTING_OPTIONS
3612 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3614 #endif /* CONFIG_TESTING_OPTIONS */
3615 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3619 attr_start
= wpabuf_put(msg
, 0);
3621 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3623 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3625 i_pubkey_hash
= NULL
;
3627 #ifdef CONFIG_TESTING_OPTIONS
3628 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3629 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3631 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3632 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3635 #endif /* CONFIG_TESTING_OPTIONS */
3638 dpp_build_attr_status(msg
, status
);
3640 #ifdef CONFIG_TESTING_OPTIONS
3642 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3643 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3644 r_pubkey_hash
= NULL
;
3645 } else if (dpp_test
==
3646 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3647 wpa_printf(MSG_INFO
,
3648 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3649 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3650 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3651 r_pubkey_hash
= test_hash
;
3652 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3653 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3654 i_pubkey_hash
= NULL
;
3655 } else if (dpp_test
==
3656 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3657 wpa_printf(MSG_INFO
,
3658 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3660 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3662 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3663 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3664 i_pubkey_hash
= test_hash
;
3666 #endif /* CONFIG_TESTING_OPTIONS */
3668 /* Responder Bootstrapping Key Hash */
3669 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3671 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3672 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3674 #ifdef CONFIG_TESTING_OPTIONS
3675 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3676 goto skip_wrapped_data
;
3677 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3679 #endif /* CONFIG_TESTING_OPTIONS */
3681 attr_end
= wpabuf_put(msg
, 0);
3683 /* OUI, OUI type, Crypto Suite, DPP frame type */
3684 addr
[0] = wpabuf_head_u8(msg
) + 2;
3685 len
[0] = 3 + 1 + 1 + 1;
3686 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3688 /* Attributes before Wrapped Data */
3689 addr
[1] = attr_start
;
3690 len
[1] = attr_end
- attr_start
;
3691 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3693 if (status
== DPP_STATUS_OK
) {
3694 /* I-auth wrapped with ke */
3695 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3696 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3697 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3699 #ifdef CONFIG_TESTING_OPTIONS
3700 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3702 #endif /* CONFIG_TESTING_OPTIONS */
3704 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3706 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3707 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3708 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3711 #ifdef CONFIG_TESTING_OPTIONS
3712 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3713 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3714 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3717 #endif /* CONFIG_TESTING_OPTIONS */
3718 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3720 2, addr
, len
, wrapped_i_auth
) < 0)
3722 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3723 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3725 /* R-nonce wrapped with k2 */
3726 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3727 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3728 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3730 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3731 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3732 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3734 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3735 r_nonce
, r_nonce_len
,
3736 2, addr
, len
, wrapped_r_nonce
) < 0)
3738 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3739 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3742 #ifdef CONFIG_TESTING_OPTIONS
3743 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3744 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3745 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3748 #endif /* CONFIG_TESTING_OPTIONS */
3750 wpa_hexdump_buf(MSG_DEBUG
,
3751 "DPP: Authentication Confirmation frame attributes",
3753 if (status
== DPP_STATUS_OK
)
3754 dpp_auth_success(auth
);
3765 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3766 const u8
*attr_start
, size_t attr_len
,
3767 const u8
*wrapped_data
, u16 wrapped_data_len
,
3768 enum dpp_status_error status
)
3772 u8
*unwrapped
= NULL
;
3773 size_t unwrapped_len
= 0;
3774 const u8
*i_nonce
, *r_capab
;
3775 u16 i_nonce_len
, r_capab_len
;
3777 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3778 wpa_printf(MSG_DEBUG
,
3779 "DPP: Responder reported incompatible roles");
3780 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3781 wpa_printf(MSG_DEBUG
,
3782 "DPP: Responder reported more time needed");
3784 wpa_printf(MSG_DEBUG
,
3785 "DPP: Responder reported failure (status %d)",
3787 dpp_auth_fail(auth
, "Responder reported failure");
3792 len
[0] = DPP_HDR_LEN
;
3793 addr
[1] = attr_start
;
3795 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3796 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3797 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3798 wrapped_data
, wrapped_data_len
);
3799 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3800 unwrapped
= os_malloc(unwrapped_len
);
3803 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3804 wrapped_data
, wrapped_data_len
,
3805 2, addr
, len
, unwrapped
) < 0) {
3806 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3809 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3810 unwrapped
, unwrapped_len
);
3812 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3813 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3817 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3819 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3820 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3823 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3824 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3825 dpp_auth_fail(auth
, "I-nonce mismatch");
3829 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3830 DPP_ATTR_R_CAPABILITIES
,
3832 if (!r_capab
|| r_capab_len
< 1) {
3833 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3836 auth
->r_capab
= r_capab
[0];
3837 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3838 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3839 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3840 "r-capab=0x%02x", auth
->r_capab
);
3841 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3842 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3844 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3845 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3846 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3847 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3850 wpa_printf(MSG_DEBUG
,
3851 "DPP: Continue waiting for full DPP Authentication Response");
3852 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3853 DPP_EVENT_RESPONSE_PENDING
"%s",
3854 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3858 bin_clear_free(unwrapped
, unwrapped_len
);
3863 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3864 const u8
*attr_start
, size_t attr_len
)
3870 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3871 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3872 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3873 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3874 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3875 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3876 wrapped2_len
, r_auth_len
;
3877 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3882 #endif /* CONFIG_DPP2 */
3884 #ifdef CONFIG_TESTING_OPTIONS
3885 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3886 wpa_printf(MSG_INFO
,
3887 "DPP: TESTING - stop at Authentication Response");
3890 #endif /* CONFIG_TESTING_OPTIONS */
3892 if (!auth
->initiator
|| !auth
->peer_bi
) {
3893 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3897 auth
->waiting_auth_resp
= 0;
3899 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3901 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3903 "Missing or invalid required Wrapped Data attribute");
3906 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3907 wrapped_data
, wrapped_data_len
);
3909 attr_len
= wrapped_data
- 4 - attr_start
;
3911 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3912 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3914 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3916 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3919 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3920 r_bootstrap
, r_bootstrap_len
);
3921 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3922 SHA256_MAC_LEN
) != 0) {
3924 "Unexpected Responder Bootstrapping Key Hash value");
3925 wpa_hexdump(MSG_DEBUG
,
3926 "DPP: Expected Responder Bootstrapping Key Hash",
3927 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3931 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3932 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3935 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3937 "Invalid Initiator Bootstrapping Key Hash attribute");
3940 wpa_hexdump(MSG_MSGDUMP
,
3941 "DPP: Initiator Bootstrapping Key Hash",
3942 i_bootstrap
, i_bootstrap_len
);
3943 if (!auth
->own_bi
||
3944 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3945 SHA256_MAC_LEN
) != 0) {
3947 "Initiator Bootstrapping Key Hash attribute did not match");
3950 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3951 /* PKEX bootstrapping mandates use of mutual authentication */
3953 "Missing Initiator Bootstrapping Key Hash attribute");
3957 auth
->peer_version
= 1; /* default to the first version */
3959 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3962 if (version_len
< 1 || version
[0] == 0) {
3964 "Invalid Protocol Version attribute");
3967 auth
->peer_version
= version
[0];
3968 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3969 auth
->peer_version
);
3971 #endif /* CONFIG_DPP2 */
3973 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3975 if (!status
|| status_len
< 1) {
3977 "Missing or invalid required DPP Status attribute");
3980 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3981 auth
->auth_resp_status
= status
[0];
3982 if (status
[0] != DPP_STATUS_OK
) {
3983 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3984 attr_len
, wrapped_data
,
3985 wrapped_data_len
, status
[0]);
3989 if (!i_bootstrap
&& auth
->own_bi
) {
3990 wpa_printf(MSG_DEBUG
,
3991 "DPP: Responder decided not to use mutual authentication");
3992 auth
->own_bi
= NULL
;
3995 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3996 auth
->own_bi
!= NULL
);
3998 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
4002 "Missing required Responder Protocol Key attribute");
4005 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
4006 r_proto
, r_proto_len
);
4009 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
4011 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
4014 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
4016 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
4017 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
4020 EVP_PKEY_free(auth
->peer_protocol_key
);
4021 auth
->peer_protocol_key
= pr
;
4024 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
4025 auth
->Nx
, auth
->secret_len
);
4026 auth
->Nx_len
= auth
->secret_len
;
4028 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
4029 auth
->curve
->hash_len
) < 0)
4033 len
[0] = DPP_HDR_LEN
;
4034 addr
[1] = attr_start
;
4036 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4037 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4038 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4039 wrapped_data
, wrapped_data_len
);
4040 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4041 unwrapped
= os_malloc(unwrapped_len
);
4044 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4045 wrapped_data
, wrapped_data_len
,
4046 2, addr
, len
, unwrapped
) < 0) {
4047 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4050 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4051 unwrapped
, unwrapped_len
);
4053 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4054 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4058 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4060 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4061 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4064 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
4065 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
4067 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
4069 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
4070 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
4073 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
4074 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
4075 dpp_auth_fail(auth
, "I-nonce mismatch");
4080 /* Mutual authentication */
4081 if (dpp_auth_derive_l_initiator(auth
) < 0)
4085 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
4086 DPP_ATTR_R_CAPABILITIES
,
4088 if (!r_capab
|| r_capab_len
< 1) {
4089 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
4092 auth
->r_capab
= r_capab
[0];
4093 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
4094 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
4095 if ((auth
->allowed_roles
==
4096 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
4097 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
4098 /* Peer selected its role, so move from "either role" to the
4099 * role that is compatible with peer's selection. */
4100 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
4101 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
4102 auth
->configurator
? "Configurator" : "Enrollee");
4103 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
4104 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
4105 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
4106 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
4107 "Unexpected role in R-capabilities 0x%02x",
4109 if (role
!= DPP_CAPAB_ENROLLEE
&&
4110 role
!= DPP_CAPAB_CONFIGURATOR
)
4112 bin_clear_free(unwrapped
, unwrapped_len
);
4113 auth
->remove_on_tx_status
= 1;
4114 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
4117 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
4118 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
4119 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
4121 "Missing or invalid Secondary Wrapped Data");
4125 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4126 wrapped2
, wrapped2_len
);
4128 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
4131 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
4132 unwrapped2
= os_malloc(unwrapped2_len
);
4135 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4136 wrapped2
, wrapped2_len
,
4137 0, NULL
, NULL
, unwrapped2
) < 0) {
4138 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4141 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4142 unwrapped2
, unwrapped2_len
);
4144 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
4146 "Invalid attribute in secondary unwrapped data");
4150 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
4152 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
4154 "Missing or invalid Responder Authenticating Tag");
4157 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
4158 r_auth
, r_auth_len
);
4159 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4160 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
4162 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
4163 r_auth2
, r_auth_len
);
4164 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
4165 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
4166 bin_clear_free(unwrapped
, unwrapped_len
);
4167 bin_clear_free(unwrapped2
, unwrapped2_len
);
4168 auth
->remove_on_tx_status
= 1;
4169 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
4172 bin_clear_free(unwrapped
, unwrapped_len
);
4173 bin_clear_free(unwrapped2
, unwrapped2_len
);
4175 #ifdef CONFIG_TESTING_OPTIONS
4176 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
4177 wpa_printf(MSG_INFO
,
4178 "DPP: TESTING - Authentication Response in place of Confirm");
4179 if (dpp_auth_build_resp_ok(auth
) < 0)
4181 return wpabuf_dup(auth
->resp_msg
);
4183 #endif /* CONFIG_TESTING_OPTIONS */
4185 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
4188 bin_clear_free(unwrapped
, unwrapped_len
);
4189 bin_clear_free(unwrapped2
, unwrapped2_len
);
4195 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
4197 const u8
*attr_start
, size_t attr_len
,
4198 const u8
*wrapped_data
,
4199 u16 wrapped_data_len
,
4200 enum dpp_status_error status
)
4204 u8
*unwrapped
= NULL
;
4205 size_t unwrapped_len
= 0;
4209 /* Authentication Confirm failure cases are expected to include
4210 * {R-nonce}k2 in the Wrapped Data attribute. */
4213 len
[0] = DPP_HDR_LEN
;
4214 addr
[1] = attr_start
;
4216 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4217 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4218 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4219 wrapped_data
, wrapped_data_len
);
4220 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4221 unwrapped
= os_malloc(unwrapped_len
);
4223 dpp_auth_fail(auth
, "Authentication failed");
4226 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4227 wrapped_data
, wrapped_data_len
,
4228 2, addr
, len
, unwrapped
) < 0) {
4229 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4232 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4233 unwrapped
, unwrapped_len
);
4235 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4236 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4240 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4242 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4243 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4246 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4247 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4248 r_nonce
, r_nonce_len
);
4249 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4250 auth
->r_nonce
, r_nonce_len
);
4251 dpp_auth_fail(auth
, "R-nonce mismatch");
4255 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4256 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4257 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4258 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4261 bin_clear_free(unwrapped
, unwrapped_len
);
4266 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4267 const u8
*attr_start
, size_t attr_len
)
4269 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4270 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4274 u8
*unwrapped
= NULL
;
4275 size_t unwrapped_len
= 0;
4276 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4278 #ifdef CONFIG_TESTING_OPTIONS
4279 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4280 wpa_printf(MSG_INFO
,
4281 "DPP: TESTING - stop at Authentication Confirm");
4284 #endif /* CONFIG_TESTING_OPTIONS */
4286 if (auth
->initiator
|| !auth
->own_bi
|| !auth
->waiting_auth_conf
) {
4287 wpa_printf(MSG_DEBUG
,
4288 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4289 auth
->initiator
, !!auth
->own_bi
,
4290 auth
->waiting_auth_conf
);
4291 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4295 auth
->waiting_auth_conf
= 0;
4297 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4299 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4301 "Missing or invalid required Wrapped Data attribute");
4304 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4305 wrapped_data
, wrapped_data_len
);
4307 attr_len
= wrapped_data
- 4 - attr_start
;
4309 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4310 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4312 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4314 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4317 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4318 r_bootstrap
, r_bootstrap_len
);
4319 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4320 SHA256_MAC_LEN
) != 0) {
4321 wpa_hexdump(MSG_DEBUG
,
4322 "DPP: Expected Responder Bootstrapping Key Hash",
4323 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4325 "Responder Bootstrapping Key Hash mismatch");
4329 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4330 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4333 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4335 "Invalid Initiator Bootstrapping Key Hash attribute");
4338 wpa_hexdump(MSG_MSGDUMP
,
4339 "DPP: Initiator Bootstrapping Key Hash",
4340 i_bootstrap
, i_bootstrap_len
);
4341 if (!auth
->peer_bi
||
4342 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4343 SHA256_MAC_LEN
) != 0) {
4345 "Initiator Bootstrapping Key Hash mismatch");
4348 } else if (auth
->peer_bi
) {
4349 /* Mutual authentication and peer did not include its
4350 * Bootstrapping Key Hash attribute. */
4352 "Missing Initiator Bootstrapping Key Hash attribute");
4356 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4358 if (!status
|| status_len
< 1) {
4360 "Missing or invalid required DPP Status attribute");
4363 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4364 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4365 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4366 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4367 attr_len
, wrapped_data
,
4368 wrapped_data_len
, status
[0]);
4370 if (status
[0] != DPP_STATUS_OK
) {
4371 dpp_auth_fail(auth
, "Authentication failed");
4376 len
[0] = DPP_HDR_LEN
;
4377 addr
[1] = attr_start
;
4379 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4380 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4381 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4382 wrapped_data
, wrapped_data_len
);
4383 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4384 unwrapped
= os_malloc(unwrapped_len
);
4387 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4388 wrapped_data
, wrapped_data_len
,
4389 2, addr
, len
, unwrapped
) < 0) {
4390 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4393 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4394 unwrapped
, unwrapped_len
);
4396 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4397 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4401 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4403 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4405 "Missing or invalid Initiator Authenticating Tag");
4408 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4409 i_auth
, i_auth_len
);
4410 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4411 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4413 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4414 i_auth2
, i_auth_len
);
4415 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4416 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4420 bin_clear_free(unwrapped
, unwrapped_len
);
4421 dpp_auth_success(auth
);
4424 bin_clear_free(unwrapped
, unwrapped_len
);
4429 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4431 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4435 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4437 struct dpp_configuration
*conf
;
4441 conf
= os_zalloc(sizeof(*conf
));
4445 end
= os_strchr(type
, ' ');
4449 len
= os_strlen(type
);
4451 if (bin_str_eq(type
, len
, "psk"))
4452 conf
->akm
= DPP_AKM_PSK
;
4453 else if (bin_str_eq(type
, len
, "sae"))
4454 conf
->akm
= DPP_AKM_SAE
;
4455 else if (bin_str_eq(type
, len
, "psk-sae") ||
4456 bin_str_eq(type
, len
, "psk+sae"))
4457 conf
->akm
= DPP_AKM_PSK_SAE
;
4458 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4459 bin_str_eq(type
, len
, "dpp+sae"))
4460 conf
->akm
= DPP_AKM_SAE_DPP
;
4461 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4462 bin_str_eq(type
, len
, "dpp+psk+sae"))
4463 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4464 else if (bin_str_eq(type
, len
, "dpp"))
4465 conf
->akm
= DPP_AKM_DPP
;
4471 dpp_configuration_free(conf
);
4476 int dpp_akm_psk(enum dpp_akm akm
)
4478 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4479 akm
== DPP_AKM_PSK_SAE_DPP
;
4483 int dpp_akm_sae(enum dpp_akm akm
)
4485 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4486 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4490 int dpp_akm_legacy(enum dpp_akm akm
)
4492 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4497 int dpp_akm_dpp(enum dpp_akm akm
)
4499 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4500 akm
== DPP_AKM_PSK_SAE_DPP
;
4504 int dpp_akm_ver2(enum dpp_akm akm
)
4506 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4510 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4512 if (conf
->ssid_len
== 0)
4514 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4516 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4522 void dpp_configuration_free(struct dpp_configuration
*conf
)
4526 str_clear_free(conf
->passphrase
);
4527 os_free(conf
->group_id
);
4528 bin_clear_free(conf
, sizeof(*conf
));
4532 static int dpp_configuration_parse_helper(struct dpp_authentication
*auth
,
4533 const char *cmd
, int idx
)
4535 const char *pos
, *end
;
4536 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4537 struct dpp_configuration
*conf
= NULL
;
4539 pos
= os_strstr(cmd
, " conf=sta-");
4541 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4544 conf_sta
->netrole
= DPP_NETROLE_STA
;
4548 pos
= os_strstr(cmd
, " conf=ap-");
4550 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4553 conf_ap
->netrole
= DPP_NETROLE_AP
;
4557 pos
= os_strstr(cmd
, " conf=configurator");
4559 auth
->provision_configurator
= 1;
4564 pos
= os_strstr(cmd
, " ssid=");
4567 end
= os_strchr(pos
, ' ');
4568 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4569 conf
->ssid_len
/= 2;
4570 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4571 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4574 #ifdef CONFIG_TESTING_OPTIONS
4575 /* use a default SSID for legacy testing reasons */
4576 os_memcpy(conf
->ssid
, "test", 4);
4578 #else /* CONFIG_TESTING_OPTIONS */
4580 #endif /* CONFIG_TESTING_OPTIONS */
4583 pos
= os_strstr(cmd
, " ssid_charset=");
4586 wpa_printf(MSG_INFO
,
4587 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4590 conf
->ssid_charset
= atoi(pos
+ 14);
4593 pos
= os_strstr(cmd
, " pass=");
4598 end
= os_strchr(pos
, ' ');
4599 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4601 if (pass_len
> 63 || pass_len
< 8)
4603 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4604 if (!conf
->passphrase
||
4605 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4609 pos
= os_strstr(cmd
, " psk=");
4612 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4617 pos
= os_strstr(cmd
, " group_id=");
4619 size_t group_id_len
;
4622 end
= os_strchr(pos
, ' ');
4623 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4624 conf
->group_id
= os_malloc(group_id_len
+ 1);
4625 if (!conf
->group_id
)
4627 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4628 conf
->group_id
[group_id_len
] = '\0';
4631 pos
= os_strstr(cmd
, " expiry=");
4636 val
= strtol(pos
, NULL
, 0);
4639 conf
->netaccesskey_expiry
= val
;
4642 if (!dpp_configuration_valid(conf
))
4646 auth
->conf_sta
= conf_sta
;
4647 auth
->conf_ap
= conf_ap
;
4648 } else if (idx
== 1) {
4649 auth
->conf2_sta
= conf_sta
;
4650 auth
->conf2_ap
= conf_ap
;
4657 dpp_configuration_free(conf_sta
);
4658 dpp_configuration_free(conf_ap
);
4663 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4671 pos
= os_strstr(cmd
, " @CONF-OBJ-SEP@ ");
4673 return dpp_configuration_parse_helper(auth
, cmd
, 0);
4676 tmp
= os_malloc(len
+ 1);
4679 os_memcpy(tmp
, cmd
, len
);
4681 res
= dpp_configuration_parse_helper(auth
, cmd
, 0);
4682 str_clear_free(tmp
);
4685 res
= dpp_configuration_parse_helper(auth
, cmd
+ len
, 1);
4690 dpp_configuration_free(auth
->conf_sta
);
4691 dpp_configuration_free(auth
->conf2_sta
);
4692 dpp_configuration_free(auth
->conf_ap
);
4693 dpp_configuration_free(auth
->conf2_ap
);
4698 static struct dpp_configurator
*
4699 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4701 struct dpp_configurator
*conf
;
4706 dl_list_for_each(conf
, &dpp
->configurator
,
4707 struct dpp_configurator
, list
) {
4715 int dpp_set_configurator(struct dpp_authentication
*auth
, const char *cmd
)
4721 if (!cmd
|| auth
->configurator_set
)
4723 auth
->configurator_set
= 1;
4725 if (cmd
[0] != ' ') {
4728 len
= os_strlen(cmd
);
4729 tmp
= os_malloc(len
+ 2);
4733 os_memcpy(tmp
+ 1, cmd
, len
+ 1);
4737 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4739 pos
= os_strstr(cmd
, " configurator=");
4742 auth
->conf
= dpp_configurator_get_id(auth
->global
, atoi(pos
));
4744 wpa_printf(MSG_INFO
,
4745 "DPP: Could not find the specified configurator");
4750 pos
= os_strstr(cmd
, " conn_status=");
4753 auth
->send_conn_status
= atoi(pos
);
4756 pos
= os_strstr(cmd
, " akm_use_selector=");
4759 auth
->akm_use_selector
= atoi(pos
);
4762 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4763 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
4764 "DPP: Failed to set configurator parameters");
4774 static void dpp_free_asymmetric_key(struct dpp_asymmetric_key
*key
)
4777 struct dpp_asymmetric_key
*next
= key
->next
;
4779 EVP_PKEY_free(key
->csign
);
4780 str_clear_free(key
->config_template
);
4781 str_clear_free(key
->connector_template
);
4788 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4794 dpp_configuration_free(auth
->conf_ap
);
4795 dpp_configuration_free(auth
->conf2_ap
);
4796 dpp_configuration_free(auth
->conf_sta
);
4797 dpp_configuration_free(auth
->conf2_sta
);
4798 EVP_PKEY_free(auth
->own_protocol_key
);
4799 EVP_PKEY_free(auth
->peer_protocol_key
);
4800 wpabuf_free(auth
->req_msg
);
4801 wpabuf_free(auth
->resp_msg
);
4802 wpabuf_free(auth
->conf_req
);
4803 for (i
= 0; i
< auth
->num_conf_obj
; i
++) {
4804 struct dpp_config_obj
*conf
= &auth
->conf_obj
[i
];
4806 os_free(conf
->connector
);
4807 wpabuf_free(conf
->c_sign_key
);
4809 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
4810 wpabuf_free(auth
->net_access_key
);
4811 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4812 #ifdef CONFIG_TESTING_OPTIONS
4813 os_free(auth
->config_obj_override
);
4814 os_free(auth
->discovery_override
);
4815 os_free(auth
->groups_override
);
4816 #endif /* CONFIG_TESTING_OPTIONS */
4817 bin_clear_free(auth
, sizeof(*auth
));
4821 static struct wpabuf
*
4822 dpp_build_conf_start(struct dpp_authentication
*auth
,
4823 struct dpp_configuration
*conf
, size_t tailroom
)
4827 #ifdef CONFIG_TESTING_OPTIONS
4828 if (auth
->discovery_override
)
4829 tailroom
+= os_strlen(auth
->discovery_override
);
4830 #endif /* CONFIG_TESTING_OPTIONS */
4832 buf
= wpabuf_alloc(200 + tailroom
);
4835 json_start_object(buf
, NULL
);
4836 json_add_string(buf
, "wi-fi_tech", "infra");
4837 json_value_sep(buf
);
4838 #ifdef CONFIG_TESTING_OPTIONS
4839 if (auth
->discovery_override
) {
4840 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4841 auth
->discovery_override
);
4842 wpabuf_put_str(buf
, "\"discovery\":");
4843 wpabuf_put_str(buf
, auth
->discovery_override
);
4844 json_value_sep(buf
);
4847 #endif /* CONFIG_TESTING_OPTIONS */
4848 json_start_object(buf
, "discovery");
4849 if (((!conf
->ssid_charset
|| auth
->peer_version
< 2) &&
4850 json_add_string_escape(buf
, "ssid", conf
->ssid
,
4851 conf
->ssid_len
) < 0) ||
4852 ((conf
->ssid_charset
&& auth
->peer_version
>= 2) &&
4853 json_add_base64url(buf
, "ssid64", conf
->ssid
,
4854 conf
->ssid_len
) < 0)) {
4858 if (conf
->ssid_charset
> 0) {
4859 json_value_sep(buf
);
4860 json_add_int(buf
, "ssid_charset", conf
->ssid_charset
);
4862 json_end_object(buf
);
4863 json_value_sep(buf
);
4869 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4870 const char *kid
, const struct dpp_curve_params
*curve
)
4876 pub
= dpp_get_pubkey_point(key
, 0);
4880 json_start_object(buf
, name
);
4881 json_add_string(buf
, "kty", "EC");
4882 json_value_sep(buf
);
4883 json_add_string(buf
, "crv", curve
->jwk_crv
);
4884 json_value_sep(buf
);
4885 pos
= wpabuf_head(pub
);
4886 if (json_add_base64url(buf
, "x", pos
, curve
->prime_len
) < 0)
4888 json_value_sep(buf
);
4889 pos
+= curve
->prime_len
;
4890 if (json_add_base64url(buf
, "y", pos
, curve
->prime_len
) < 0)
4893 json_value_sep(buf
);
4894 json_add_string(buf
, "kid", kid
);
4896 json_end_object(buf
);
4904 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4905 struct dpp_configuration
*conf
)
4907 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4908 json_add_string_escape(buf
, "pass", conf
->passphrase
,
4909 os_strlen(conf
->passphrase
));
4910 } else if (conf
->psk_set
) {
4911 char psk
[2 * sizeof(conf
->psk
) + 1];
4913 wpa_snprintf_hex(psk
, sizeof(psk
),
4914 conf
->psk
, sizeof(conf
->psk
));
4915 json_add_string(buf
, "psk_hex", psk
);
4916 forced_memzero(psk
, sizeof(psk
));
4921 static const char * dpp_netrole_str(enum dpp_netrole netrole
)
4924 case DPP_NETROLE_STA
:
4926 case DPP_NETROLE_AP
:
4928 case DPP_NETROLE_CONFIGURATOR
:
4929 return "configurator";
4936 static struct wpabuf
*
4937 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
,
4938 struct dpp_configuration
*conf
)
4940 struct wpabuf
*buf
= NULL
;
4941 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4943 const struct dpp_curve_params
*curve
;
4944 struct wpabuf
*jws_prot_hdr
;
4945 size_t signed1_len
, signed2_len
, signed3_len
;
4946 struct wpabuf
*dppcon
= NULL
;
4947 unsigned char *signature
= NULL
;
4948 const unsigned char *p
;
4949 size_t signature_len
;
4950 EVP_MD_CTX
*md_ctx
= NULL
;
4951 ECDSA_SIG
*sig
= NULL
;
4953 const EVP_MD
*sign_md
;
4954 const BIGNUM
*r
, *s
;
4955 size_t extra_len
= 1000;
4958 const char *akm_str
;
4961 wpa_printf(MSG_INFO
,
4962 "DPP: No configurator specified - cannot generate DPP config object");
4965 curve
= auth
->conf
->curve
;
4966 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4967 sign_md
= EVP_sha256();
4968 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4969 sign_md
= EVP_sha384();
4970 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4971 sign_md
= EVP_sha512();
4973 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4978 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4979 wpa_printf(MSG_DEBUG
,
4980 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4984 #ifdef CONFIG_TESTING_OPTIONS
4985 if (auth
->groups_override
)
4986 extra_len
+= os_strlen(auth
->groups_override
);
4987 #endif /* CONFIG_TESTING_OPTIONS */
4990 extra_len
+= os_strlen(conf
->group_id
);
4992 /* Connector (JSON dppCon object) */
4993 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4996 #ifdef CONFIG_TESTING_OPTIONS
4997 if (auth
->groups_override
) {
4998 wpabuf_put_u8(dppcon
, '{');
4999 if (auth
->groups_override
) {
5000 wpa_printf(MSG_DEBUG
,
5001 "DPP: TESTING - groups override: '%s'",
5002 auth
->groups_override
);
5003 wpabuf_put_str(dppcon
, "\"groups\":");
5004 wpabuf_put_str(dppcon
, auth
->groups_override
);
5005 json_value_sep(dppcon
);
5009 #endif /* CONFIG_TESTING_OPTIONS */
5010 json_start_object(dppcon
, NULL
);
5011 json_start_array(dppcon
, "groups");
5012 json_start_object(dppcon
, NULL
);
5013 json_add_string(dppcon
, "groupId",
5014 conf
->group_id
? conf
->group_id
: "*");
5015 json_value_sep(dppcon
);
5016 json_add_string(dppcon
, "netRole", dpp_netrole_str(conf
->netrole
));
5017 json_end_object(dppcon
);
5018 json_end_array(dppcon
);
5019 json_value_sep(dppcon
);
5020 #ifdef CONFIG_TESTING_OPTIONS
5022 #endif /* CONFIG_TESTING_OPTIONS */
5023 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
5025 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
5028 if (conf
->netaccesskey_expiry
) {
5032 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
5033 wpa_printf(MSG_DEBUG
,
5034 "DPP: Failed to generate expiry string");
5037 os_snprintf(expiry
, sizeof(expiry
),
5038 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5039 tm
.year
, tm
.month
, tm
.day
,
5040 tm
.hour
, tm
.min
, tm
.sec
);
5041 json_value_sep(dppcon
);
5042 json_add_string(dppcon
, "expiry", expiry
);
5044 json_end_object(dppcon
);
5045 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
5046 (const char *) wpabuf_head(dppcon
));
5048 jws_prot_hdr
= wpabuf_alloc(100);
5051 json_start_object(jws_prot_hdr
, NULL
);
5052 json_add_string(jws_prot_hdr
, "typ", "dppCon");
5053 json_value_sep(jws_prot_hdr
);
5054 json_add_string(jws_prot_hdr
, "kid", auth
->conf
->kid
);
5055 json_value_sep(jws_prot_hdr
);
5056 json_add_string(jws_prot_hdr
, "alg", curve
->jws_alg
);
5057 json_end_object(jws_prot_hdr
);
5058 signed1
= base64_url_encode(wpabuf_head(jws_prot_hdr
),
5059 wpabuf_len(jws_prot_hdr
),
5061 wpabuf_free(jws_prot_hdr
);
5062 signed2
= base64_url_encode(wpabuf_head(dppcon
), wpabuf_len(dppcon
),
5064 if (!signed1
|| !signed2
)
5067 md_ctx
= EVP_MD_CTX_create();
5072 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
5073 auth
->conf
->csign
) != 1) {
5074 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
5075 ERR_error_string(ERR_get_error(), NULL
));
5078 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
5079 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
5080 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
5081 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
5082 ERR_error_string(ERR_get_error(), NULL
));
5085 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
5086 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5087 ERR_error_string(ERR_get_error(), NULL
));
5090 signature
= os_malloc(signature_len
);
5093 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
5094 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5095 ERR_error_string(ERR_get_error(), NULL
));
5098 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
5099 signature
, signature_len
);
5100 /* Convert to raw coordinates r,s */
5102 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
5105 ECDSA_SIG_get0(sig
, &r
, &s
);
5106 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
5107 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
5108 curve
->prime_len
) < 0)
5110 signature_len
= 2 * curve
->prime_len
;
5111 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
5112 signature
, signature_len
);
5113 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
5117 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
5119 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
5120 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
5123 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
5127 if (auth
->akm_use_selector
&& dpp_akm_ver2(akm
))
5128 akm_str
= dpp_akm_selector_str(akm
);
5130 akm_str
= dpp_akm_str(akm
);
5131 json_start_object(buf
, "cred");
5132 json_add_string(buf
, "akm", akm_str
);
5133 json_value_sep(buf
);
5135 dpp_build_legacy_cred_params(buf
, conf
);
5136 json_value_sep(buf
);
5138 wpabuf_put_str(buf
, "\"signedConnector\":\"");
5139 wpabuf_put_str(buf
, signed1
);
5140 wpabuf_put_u8(buf
, '.');
5141 wpabuf_put_str(buf
, signed2
);
5142 wpabuf_put_u8(buf
, '.');
5143 wpabuf_put_str(buf
, signed3
);
5144 wpabuf_put_str(buf
, "\"");
5145 json_value_sep(buf
);
5146 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
5148 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
5152 json_end_object(buf
);
5153 json_end_object(buf
);
5155 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
5156 wpabuf_head(buf
), wpabuf_len(buf
));
5159 EVP_MD_CTX_destroy(md_ctx
);
5160 ECDSA_SIG_free(sig
);
5165 wpabuf_free(dppcon
);
5168 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
5175 static struct wpabuf
*
5176 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
,
5177 struct dpp_configuration
*conf
)
5180 const char *akm_str
;
5182 buf
= dpp_build_conf_start(auth
, conf
, 1000);
5186 if (auth
->akm_use_selector
&& dpp_akm_ver2(conf
->akm
))
5187 akm_str
= dpp_akm_selector_str(conf
->akm
);
5189 akm_str
= dpp_akm_str(conf
->akm
);
5190 json_start_object(buf
, "cred");
5191 json_add_string(buf
, "akm", akm_str
);
5192 json_value_sep(buf
);
5193 dpp_build_legacy_cred_params(buf
, conf
);
5194 json_end_object(buf
);
5195 json_end_object(buf
);
5197 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
5198 wpabuf_head(buf
), wpabuf_len(buf
));
5204 static struct wpabuf
*
5205 dpp_build_conf_obj(struct dpp_authentication
*auth
, enum dpp_netrole netrole
,
5208 struct dpp_configuration
*conf
= NULL
;
5210 #ifdef CONFIG_TESTING_OPTIONS
5211 if (auth
->config_obj_override
) {
5214 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
5215 return wpabuf_alloc_copy(auth
->config_obj_override
,
5216 os_strlen(auth
->config_obj_override
));
5218 #endif /* CONFIG_TESTING_OPTIONS */
5221 if (netrole
== DPP_NETROLE_STA
)
5222 conf
= auth
->conf_sta
;
5223 else if (netrole
== DPP_NETROLE_AP
)
5224 conf
= auth
->conf_ap
;
5225 } else if (idx
== 1) {
5226 if (netrole
== DPP_NETROLE_STA
)
5227 conf
= auth
->conf2_sta
;
5228 else if (netrole
== DPP_NETROLE_AP
)
5229 conf
= auth
->conf2_ap
;
5233 wpa_printf(MSG_DEBUG
,
5234 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5235 dpp_netrole_str(netrole
));
5239 if (dpp_akm_dpp(conf
->akm
))
5240 return dpp_build_conf_obj_dpp(auth
, conf
);
5241 return dpp_build_conf_obj_legacy(auth
, conf
);
5247 static struct wpabuf
* dpp_build_conf_params(void)
5251 /* TODO: proper template values */
5252 const char *conf_template
= "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5253 const char *connector_template
= NULL
;
5255 len
= 100 + os_strlen(conf_template
);
5256 if (connector_template
)
5257 len
+= os_strlen(connector_template
);
5258 buf
= wpabuf_alloc(len
);
5263 * DPPConfigurationParameters ::= SEQUENCE {
5264 * configurationTemplate UTF8String,
5265 * connectorTemplate UTF8String OPTIONAL}
5268 asn1_put_utf8string(buf
, conf_template
);
5269 if (connector_template
)
5270 asn1_put_utf8string(buf
, connector_template
);
5271 return asn1_encaps(buf
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5275 static struct wpabuf
* dpp_build_attribute(void)
5277 struct wpabuf
*conf_params
, *attr
;
5280 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5281 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5283 * Attribute ::= SEQUENCE {
5284 * type OBJECT IDENTIFIER,
5285 * values SET SIZE(1..MAX) OF Type
5287 conf_params
= dpp_build_conf_params();
5288 conf_params
= asn1_encaps(conf_params
, ASN1_CLASS_UNIVERSAL
,
5293 attr
= wpabuf_alloc(100 + wpabuf_len(conf_params
));
5295 wpabuf_clear_free(conf_params
);
5299 asn1_put_oid(attr
, &asn1_dpp_config_params_oid
);
5300 wpabuf_put_buf(attr
, conf_params
);
5301 wpabuf_clear_free(conf_params
);
5303 return asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5307 static struct wpabuf
* dpp_build_key_alg(const struct dpp_curve_params
*curve
)
5309 const struct asn1_oid
*oid
;
5310 struct wpabuf
*params
, *res
;
5312 switch (curve
->ike_group
) {
5314 oid
= &asn1_prime256v1_oid
;
5317 oid
= &asn1_secp384r1_oid
;
5320 oid
= &asn1_secp521r1_oid
;
5323 oid
= &asn1_brainpoolP256r1_oid
;
5326 oid
= &asn1_brainpoolP384r1_oid
;
5329 oid
= &asn1_brainpoolP512r1_oid
;
5335 params
= wpabuf_alloc(20);
5338 asn1_put_oid(params
, oid
); /* namedCurve */
5340 res
= asn1_build_alg_id(&asn1_ec_public_key_oid
, params
);
5341 wpabuf_free(params
);
5346 static struct wpabuf
* dpp_build_key_pkg(struct dpp_authentication
*auth
)
5348 struct wpabuf
*key
= NULL
, *attr
, *alg
, *priv_key
= NULL
;
5350 unsigned char *der
= NULL
;
5353 eckey
= EVP_PKEY_get0_EC_KEY(auth
->conf
->csign
);
5357 EC_KEY_set_enc_flags(eckey
, EC_PKEY_NO_PUBKEY
);
5358 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5360 priv_key
= wpabuf_alloc_copy(der
, der_len
);
5363 alg
= dpp_build_key_alg(auth
->conf
->curve
);
5365 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5366 attr
= dpp_build_attribute();
5367 attr
= asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SET
);
5368 if (!priv_key
|| !attr
|| !alg
)
5372 * OneAsymmetricKey ::= SEQUENCE {
5374 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5375 * privateKey PrivateKey,
5376 * attributes [0] Attributes OPTIONAL,
5378 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5383 key
= wpabuf_alloc(100 + wpabuf_len(alg
) + wpabuf_len(priv_key
) +
5388 asn1_put_integer(key
, 1); /* version = v2(1) */
5390 /* PrivateKeyAlgorithmIdentifier */
5391 wpabuf_put_buf(key
, alg
);
5393 /* PrivateKey ::= OCTET STRING */
5394 asn1_put_octet_string(key
, priv_key
);
5396 /* [0] Attributes OPTIONAL */
5397 asn1_put_hdr(key
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0, wpabuf_len(attr
));
5398 wpabuf_put_buf(key
, attr
);
5401 wpabuf_clear_free(attr
);
5402 wpabuf_clear_free(priv_key
);
5406 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5408 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5410 * OneAsymmetricKey ::= SEQUENCE
5412 return asn1_encaps(asn1_encaps(key
,
5413 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
),
5414 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5418 static struct wpabuf
* dpp_build_pbkdf2_alg_id(const struct wpabuf
*salt
,
5421 struct wpabuf
*params
= NULL
, *buf
= NULL
, *prf
= NULL
;
5422 const struct asn1_oid
*oid
;
5425 * PBKDF2-params ::= SEQUENCE {
5427 * specified OCTET STRING,
5428 * otherSource AlgorithmIdentifier}
5429 * iterationCount INTEGER (1..MAX),
5430 * keyLength INTEGER (1..MAX),
5431 * prf AlgorithmIdentifier}
5433 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5434 * on Configurator signing key length, prf is
5435 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5439 oid
= &asn1_pbkdf2_hmac_sha256_oid
;
5440 else if (hash_len
== 48)
5441 oid
= &asn1_pbkdf2_hmac_sha384_oid
;
5442 else if (hash_len
== 64)
5443 oid
= &asn1_pbkdf2_hmac_sha512_oid
;
5446 prf
= asn1_build_alg_id(oid
, NULL
);
5449 params
= wpabuf_alloc(100 + wpabuf_len(salt
) + wpabuf_len(prf
));
5452 asn1_put_octet_string(params
, salt
); /* salt.specified */
5453 asn1_put_integer(params
, 1000); /* iterationCount */
5454 asn1_put_integer(params
, hash_len
); /* keyLength */
5455 wpabuf_put_buf(params
, prf
);
5456 params
= asn1_encaps(params
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5459 buf
= asn1_build_alg_id(&asn1_pbkdf2_oid
, params
);
5461 wpabuf_free(params
);
5467 static struct wpabuf
*
5468 dpp_build_pw_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5469 const struct wpabuf
*cont_enc_key
)
5471 struct wpabuf
*pwri
= NULL
, *enc_key
= NULL
, *key_der_alg
= NULL
,
5472 *key_enc_alg
= NULL
, *salt
;
5473 u8 kek
[DPP_MAX_HASH_LEN
];
5477 salt
= wpabuf_alloc(64);
5478 if (!salt
|| os_get_random(wpabuf_put(salt
, 64), 64) < 0)
5480 wpa_hexdump_buf(MSG_DEBUG
, "DPP: PBKDF2 salt", salt
);
5482 /* TODO: For initial testing, use ke as the key. Replace this with a
5483 * new key once that has been defined. */
5485 key_len
= auth
->curve
->hash_len
;
5486 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
5488 if (dpp_pbkdf2(hash_len
, key
, key_len
, wpabuf_head(salt
), 64, 1000,
5490 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
5493 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
5496 enc_key
= wpabuf_alloc(hash_len
+ AES_BLOCK_SIZE
);
5498 aes_siv_encrypt(kek
, hash_len
, wpabuf_head(cont_enc_key
),
5499 wpabuf_len(cont_enc_key
), 0, NULL
, NULL
,
5500 wpabuf_put(enc_key
, hash_len
+ AES_BLOCK_SIZE
)) < 0)
5502 wpa_hexdump_buf(MSG_DEBUG
, "DPP: encryptedKey", enc_key
);
5505 * PasswordRecipientInfo ::= SEQUENCE {
5506 * version CMSVersion,
5507 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5508 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5509 * encryptedKey EncryptedKey}
5511 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5512 * parameters contains PBKDF2-params SEQUENCE.
5515 key_der_alg
= dpp_build_pbkdf2_alg_id(salt
, hash_len
);
5516 key_enc_alg
= asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid
, NULL
);
5517 if (!key_der_alg
|| !key_enc_alg
)
5519 pwri
= wpabuf_alloc(100 + wpabuf_len(key_der_alg
) +
5520 wpabuf_len(key_enc_alg
) + wpabuf_len(enc_key
));
5525 asn1_put_integer(pwri
, 0);
5527 /* [0] KeyDerivationAlgorithmIdentifier */
5528 asn1_put_hdr(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0,
5529 wpabuf_len(key_der_alg
));
5530 wpabuf_put_buf(pwri
, key_der_alg
);
5532 /* KeyEncryptionAlgorithmIdentifier */
5533 wpabuf_put_buf(pwri
, key_enc_alg
);
5535 /* EncryptedKey ::= OCTET STRING */
5536 asn1_put_octet_string(pwri
, enc_key
);
5539 wpabuf_clear_free(key_der_alg
);
5540 wpabuf_free(key_enc_alg
);
5541 wpabuf_free(enc_key
);
5543 forced_memzero(kek
, sizeof(kek
));
5544 return asn1_encaps(pwri
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5548 static struct wpabuf
*
5549 dpp_build_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5550 const struct wpabuf
*cont_enc_key
)
5552 struct wpabuf
*pwri
;
5555 * RecipientInfo ::= CHOICE {
5556 * ktri KeyTransRecipientInfo,
5557 * kari [1] KeyAgreeRecipientInfo,
5558 * kekri [2] KEKRecipientInfo,
5559 * pwri [3] PasswordRecipientInfo,
5560 * ori [4] OtherRecipientInfo}
5562 * Shall always use the pwri CHOICE.
5565 pwri
= dpp_build_pw_recipient_info(auth
, hash_len
, cont_enc_key
);
5566 return asn1_encaps(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 3);
5570 static struct wpabuf
*
5571 dpp_build_enc_cont_info(struct dpp_authentication
*auth
, size_t hash_len
,
5572 const struct wpabuf
*cont_enc_key
)
5574 struct wpabuf
*key_pkg
, *enc_cont_info
= NULL
, *enc_cont
= NULL
,
5576 const struct asn1_oid
*oid
;
5577 size_t enc_cont_len
;
5580 * EncryptedContentInfo ::= SEQUENCE {
5581 * contentType ContentType,
5582 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5583 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5587 oid
= &asn1_aes_siv_cmac_aead_256_oid
;
5588 else if (hash_len
== 48)
5589 oid
= &asn1_aes_siv_cmac_aead_384_oid
;
5590 else if (hash_len
== 64)
5591 oid
= &asn1_aes_siv_cmac_aead_512_oid
;
5595 key_pkg
= dpp_build_key_pkg(auth
);
5596 enc_alg
= asn1_build_alg_id(oid
, NULL
);
5597 if (!key_pkg
|| !enc_alg
)
5600 wpa_hexdump_buf_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
5603 enc_cont_len
= wpabuf_len(key_pkg
) + AES_BLOCK_SIZE
;
5604 enc_cont
= wpabuf_alloc(enc_cont_len
);
5606 aes_siv_encrypt(wpabuf_head(cont_enc_key
), wpabuf_len(cont_enc_key
),
5607 wpabuf_head(key_pkg
), wpabuf_len(key_pkg
),
5609 wpabuf_put(enc_cont
, enc_cont_len
)) < 0)
5612 enc_cont_info
= wpabuf_alloc(100 + wpabuf_len(enc_alg
) +
5613 wpabuf_len(enc_cont
));
5617 /* ContentType ::= OBJECT IDENTIFIER */
5618 asn1_put_oid(enc_cont_info
, &asn1_dpp_asymmetric_key_package_oid
);
5620 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5621 wpabuf_put_buf(enc_cont_info
, enc_alg
);
5623 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5624 * EncryptedContent ::= OCTET STRING */
5625 asn1_put_hdr(enc_cont_info
, ASN1_CLASS_CONTEXT_SPECIFIC
, 0, 0,
5626 wpabuf_len(enc_cont
));
5627 wpabuf_put_buf(enc_cont_info
, enc_cont
);
5630 wpabuf_clear_free(key_pkg
);
5631 wpabuf_free(enc_cont
);
5632 wpabuf_free(enc_alg
);
5633 return enc_cont_info
;
5637 static struct wpabuf
* dpp_gen_random(size_t len
)
5641 key
= wpabuf_alloc(len
);
5642 if (!key
|| os_get_random(wpabuf_put(key
, len
), len
) < 0) {
5646 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: content-encryption key", key
);
5651 static struct wpabuf
* dpp_build_enveloped_data(struct dpp_authentication
*auth
)
5653 struct wpabuf
*env
= NULL
;
5654 struct wpabuf
*recipient_info
= NULL
, *enc_cont_info
= NULL
;
5655 struct wpabuf
*cont_enc_key
= NULL
;
5659 wpa_printf(MSG_DEBUG
,
5660 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5664 if (!auth
->provision_configurator
) {
5665 wpa_printf(MSG_DEBUG
,
5666 "DPP: Configurator provisioning not allowed");
5670 wpa_printf(MSG_DEBUG
, "DPP: Building DPPEnvelopedData");
5672 hash_len
= auth
->conf
->curve
->hash_len
;
5673 cont_enc_key
= dpp_gen_random(hash_len
);
5676 recipient_info
= dpp_build_recipient_info(auth
, hash_len
, cont_enc_key
);
5677 enc_cont_info
= dpp_build_enc_cont_info(auth
, hash_len
, cont_enc_key
);
5678 if (!recipient_info
|| !enc_cont_info
)
5681 env
= wpabuf_alloc(wpabuf_len(recipient_info
) +
5682 wpabuf_len(enc_cont_info
) +
5688 * DPPEnvelopedData ::= EnvelopedData
5690 * EnvelopedData ::= SEQUENCE {
5691 * version CMSVersion,
5692 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5693 * recipientInfos RecipientInfos,
5694 * encryptedContentInfo EncryptedContentInfo,
5695 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5697 * For DPP, version is 3, both originatorInfo and
5698 * unprotectedAttrs are omitted, and recipientInfos contains a single
5702 /* EnvelopedData.version = 3 */
5703 asn1_put_integer(env
, 3);
5705 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5706 asn1_put_set(env
, recipient_info
);
5708 /* EncryptedContentInfo ::= SEQUENCE */
5709 asn1_put_sequence(env
, enc_cont_info
);
5711 env
= asn1_encaps(env
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5712 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: DPPEnvelopedData", env
);
5714 wpabuf_clear_free(cont_enc_key
);
5715 wpabuf_clear_free(recipient_info
);
5716 wpabuf_free(enc_cont_info
);
5724 #endif /* CONFIG_DPP2 */
5727 static struct wpabuf
*
5728 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
5729 u16 e_nonce_len
, enum dpp_netrole netrole
)
5731 struct wpabuf
*conf
= NULL
, *conf2
= NULL
, *env_data
= NULL
;
5732 size_t clear_len
, attr_len
;
5733 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
5737 enum dpp_status_error status
;
5739 if (netrole
== DPP_NETROLE_CONFIGURATOR
) {
5741 env_data
= dpp_build_enveloped_data(auth
);
5742 #endif /* CONFIG_DPP2 */
5744 conf
= dpp_build_conf_obj(auth
, netrole
, 0);
5746 wpa_hexdump_ascii(MSG_DEBUG
,
5747 "DPP: configurationObject JSON",
5748 wpabuf_head(conf
), wpabuf_len(conf
));
5749 conf2
= dpp_build_conf_obj(auth
, netrole
, 1);
5752 status
= (conf
|| env_data
) ? DPP_STATUS_OK
:
5753 DPP_STATUS_CONFIGURE_FAILURE
;
5754 auth
->conf_resp_status
= status
;
5756 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
5757 clear_len
= 4 + e_nonce_len
;
5759 clear_len
+= 4 + wpabuf_len(conf
);
5761 clear_len
+= 4 + wpabuf_len(conf2
);
5763 clear_len
+= 4 + wpabuf_len(env_data
);
5764 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5765 netrole
== DPP_NETROLE_STA
)
5767 clear
= wpabuf_alloc(clear_len
);
5768 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
5769 #ifdef CONFIG_TESTING_OPTIONS
5770 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
5772 #endif /* CONFIG_TESTING_OPTIONS */
5773 msg
= wpabuf_alloc(attr_len
);
5777 #ifdef CONFIG_TESTING_OPTIONS
5778 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
5779 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
5782 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
5783 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
5784 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5785 wpabuf_put_le16(clear
, e_nonce_len
);
5786 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
5787 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
5790 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
5791 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
5792 goto skip_wrapped_data
;
5794 #endif /* CONFIG_TESTING_OPTIONS */
5797 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5798 wpabuf_put_le16(clear
, e_nonce_len
);
5799 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
5801 #ifdef CONFIG_TESTING_OPTIONS
5803 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
5804 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
5805 goto skip_config_obj
;
5807 #endif /* CONFIG_TESTING_OPTIONS */
5810 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5811 wpabuf_put_le16(clear
, wpabuf_len(conf
));
5812 wpabuf_put_buf(clear
, conf
);
5814 if (auth
->peer_version
>= 2 && conf2
) {
5815 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5816 wpabuf_put_le16(clear
, wpabuf_len(conf2
));
5817 wpabuf_put_buf(clear
, conf2
);
5819 wpa_printf(MSG_DEBUG
,
5820 "DPP: Second Config Object available, but peer does not support more than one");
5823 wpabuf_put_le16(clear
, DPP_ATTR_ENVELOPED_DATA
);
5824 wpabuf_put_le16(clear
, wpabuf_len(env_data
));
5825 wpabuf_put_buf(clear
, env_data
);
5828 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5829 netrole
== DPP_NETROLE_STA
) {
5830 wpa_printf(MSG_DEBUG
, "DPP: sendConnStatus");
5831 wpabuf_put_le16(clear
, DPP_ATTR_SEND_CONN_STATUS
);
5832 wpabuf_put_le16(clear
, 0);
5835 #ifdef CONFIG_TESTING_OPTIONS
5837 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
5838 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
5841 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
5842 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5845 #endif /* CONFIG_TESTING_OPTIONS */
5848 dpp_build_attr_status(msg
, status
);
5850 #ifdef CONFIG_TESTING_OPTIONS
5852 #endif /* CONFIG_TESTING_OPTIONS */
5854 addr
[0] = wpabuf_head(msg
);
5855 len
[0] = wpabuf_len(msg
);
5856 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5858 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5859 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5860 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5862 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5863 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5864 wpabuf_head(clear
), wpabuf_len(clear
),
5865 1, addr
, len
, wrapped
) < 0)
5867 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5868 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5870 #ifdef CONFIG_TESTING_OPTIONS
5871 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
5872 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
5873 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
5876 #endif /* CONFIG_TESTING_OPTIONS */
5878 wpa_hexdump_buf(MSG_DEBUG
,
5879 "DPP: Configuration Response attributes", msg
);
5881 wpabuf_clear_free(conf
);
5882 wpabuf_clear_free(conf2
);
5883 wpabuf_clear_free(env_data
);
5884 wpabuf_clear_free(clear
);
5895 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
5898 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
5899 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
5900 u8
*unwrapped
= NULL
;
5901 size_t unwrapped_len
= 0;
5902 struct wpabuf
*resp
= NULL
;
5903 struct json_token
*root
= NULL
, *token
;
5904 enum dpp_netrole netrole
;
5906 #ifdef CONFIG_TESTING_OPTIONS
5907 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
5908 wpa_printf(MSG_INFO
,
5909 "DPP: TESTING - stop at Config Request");
5912 #endif /* CONFIG_TESTING_OPTIONS */
5914 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
5915 dpp_auth_fail(auth
, "Invalid attribute in config request");
5919 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5921 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5923 "Missing or invalid required Wrapped Data attribute");
5927 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5928 wrapped_data
, wrapped_data_len
);
5929 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5930 unwrapped
= os_malloc(unwrapped_len
);
5933 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5934 wrapped_data
, wrapped_data_len
,
5935 0, NULL
, NULL
, unwrapped
) < 0) {
5936 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5939 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5940 unwrapped
, unwrapped_len
);
5942 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5943 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5947 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5948 DPP_ATTR_ENROLLEE_NONCE
,
5950 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5952 "Missing or invalid Enrollee Nonce attribute");
5955 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5956 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5958 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5959 DPP_ATTR_CONFIG_ATTR_OBJ
,
5963 "Missing or invalid Config Attributes attribute");
5966 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5967 config_attr
, config_attr_len
);
5969 root
= json_parse((const char *) config_attr
, config_attr_len
);
5971 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5975 token
= json_get_member(root
, "name");
5976 if (!token
|| token
->type
!= JSON_STRING
) {
5977 dpp_auth_fail(auth
, "No Config Attributes - name");
5980 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5982 token
= json_get_member(root
, "wi-fi_tech");
5983 if (!token
|| token
->type
!= JSON_STRING
) {
5984 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5987 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5988 if (os_strcmp(token
->string
, "infra") != 0) {
5989 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5991 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5995 token
= json_get_member(root
, "netRole");
5996 if (!token
|| token
->type
!= JSON_STRING
) {
5997 dpp_auth_fail(auth
, "No Config Attributes - netRole");
6000 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
6001 if (os_strcmp(token
->string
, "sta") == 0) {
6002 netrole
= DPP_NETROLE_STA
;
6003 } else if (os_strcmp(token
->string
, "ap") == 0) {
6004 netrole
= DPP_NETROLE_AP
;
6005 } else if (os_strcmp(token
->string
, "configurator") == 0) {
6006 netrole
= DPP_NETROLE_CONFIGURATOR
;
6008 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
6010 dpp_auth_fail(auth
, "Unsupported netRole");
6014 token
= json_get_member(root
, "mudurl");
6015 if (token
&& token
->type
== JSON_STRING
)
6016 wpa_printf(MSG_DEBUG
, "DPP: mudurl = '%s'", token
->string
);
6018 token
= json_get_member(root
, "bandSupport");
6019 if (token
&& token
->type
== JSON_ARRAY
) {
6020 wpa_printf(MSG_DEBUG
, "DPP: bandSupport");
6021 token
= token
->child
;
6023 if (token
->type
!= JSON_NUMBER
)
6024 wpa_printf(MSG_DEBUG
,
6025 "DPP: Invalid bandSupport array member type");
6027 wpa_printf(MSG_DEBUG
,
6028 "DPP: Supported global operating class: %d",
6030 token
= token
->sibling
;
6034 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, netrole
);
6043 static struct wpabuf
*
6044 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
6045 const u8
*prot_hdr
, u16 prot_hdr_len
,
6046 const EVP_MD
**ret_md
)
6048 struct json_token
*root
, *token
;
6049 struct wpabuf
*kid
= NULL
;
6051 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
6053 wpa_printf(MSG_DEBUG
,
6054 "DPP: JSON parsing failed for JWS Protected Header");
6058 if (root
->type
!= JSON_OBJECT
) {
6059 wpa_printf(MSG_DEBUG
,
6060 "DPP: JWS Protected Header root is not an object");
6064 token
= json_get_member(root
, "typ");
6065 if (!token
|| token
->type
!= JSON_STRING
) {
6066 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
6069 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
6071 if (os_strcmp(token
->string
, "dppCon") != 0) {
6072 wpa_printf(MSG_DEBUG
,
6073 "DPP: Unsupported JWS Protected Header typ=%s",
6078 token
= json_get_member(root
, "alg");
6079 if (!token
|| token
->type
!= JSON_STRING
) {
6080 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
6083 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
6085 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
6086 wpa_printf(MSG_DEBUG
,
6087 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6088 token
->string
, curve
->jws_alg
);
6091 if (os_strcmp(token
->string
, "ES256") == 0 ||
6092 os_strcmp(token
->string
, "BS256") == 0)
6093 *ret_md
= EVP_sha256();
6094 else if (os_strcmp(token
->string
, "ES384") == 0 ||
6095 os_strcmp(token
->string
, "BS384") == 0)
6096 *ret_md
= EVP_sha384();
6097 else if (os_strcmp(token
->string
, "ES512") == 0 ||
6098 os_strcmp(token
->string
, "BS512") == 0)
6099 *ret_md
= EVP_sha512();
6103 wpa_printf(MSG_DEBUG
,
6104 "DPP: Unsupported JWS Protected Header alg=%s",
6109 kid
= json_get_member_base64url(root
, "kid");
6111 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
6114 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
6123 static int dpp_parse_cred_legacy(struct dpp_config_obj
*conf
,
6124 struct json_token
*cred
)
6126 struct json_token
*pass
, *psk_hex
;
6128 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
6130 pass
= json_get_member(cred
, "pass");
6131 psk_hex
= json_get_member(cred
, "psk_hex");
6133 if (pass
&& pass
->type
== JSON_STRING
) {
6134 size_t len
= os_strlen(pass
->string
);
6136 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
6138 if (len
< 8 || len
> 63)
6140 os_strlcpy(conf
->passphrase
, pass
->string
,
6141 sizeof(conf
->passphrase
));
6142 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
6143 if (dpp_akm_sae(conf
->akm
) && !dpp_akm_psk(conf
->akm
)) {
6144 wpa_printf(MSG_DEBUG
,
6145 "DPP: Unexpected psk_hex with akm=sae");
6148 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
6149 hexstr2bin(psk_hex
->string
, conf
->psk
, PMK_LEN
) < 0) {
6150 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
6153 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
6154 conf
->psk
, PMK_LEN
);
6157 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
6161 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
[0]) {
6162 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
6170 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
6171 const struct dpp_curve_params
**key_curve
)
6173 struct json_token
*token
;
6174 const struct dpp_curve_params
*curve
;
6175 struct wpabuf
*x
= NULL
, *y
= NULL
;
6177 EVP_PKEY
*pkey
= NULL
;
6179 token
= json_get_member(jwk
, "kty");
6180 if (!token
|| token
->type
!= JSON_STRING
) {
6181 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
6184 if (os_strcmp(token
->string
, "EC") != 0) {
6185 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
6190 token
= json_get_member(jwk
, "crv");
6191 if (!token
|| token
->type
!= JSON_STRING
) {
6192 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
6195 curve
= dpp_get_curve_jwk_crv(token
->string
);
6197 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
6202 x
= json_get_member_base64url(jwk
, "x");
6204 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
6207 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
6208 if (wpabuf_len(x
) != curve
->prime_len
) {
6209 wpa_printf(MSG_DEBUG
,
6210 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
6211 (unsigned int) wpabuf_len(x
),
6212 (unsigned int) curve
->prime_len
, curve
->name
);
6216 y
= json_get_member_base64url(jwk
, "y");
6218 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
6221 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
6222 if (wpabuf_len(y
) != curve
->prime_len
) {
6223 wpa_printf(MSG_DEBUG
,
6224 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
6225 (unsigned int) wpabuf_len(y
),
6226 (unsigned int) curve
->prime_len
, curve
->name
);
6230 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6232 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
6236 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
6238 EC_GROUP_free(group
);
6249 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
6252 unsigned int year
, month
, day
, hour
, min
, sec
;
6256 /* ISO 8601 date and time:
6258 * YYYY-MM-DDTHH:MM:SSZ
6259 * YYYY-MM-DDTHH:MM:SS+03:00
6261 if (os_strlen(timestamp
) < 19) {
6262 wpa_printf(MSG_DEBUG
,
6263 "DPP: Too short timestamp - assume expired key");
6266 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
6267 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
6268 wpa_printf(MSG_DEBUG
,
6269 "DPP: Failed to parse expiration day - assume expired key");
6273 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
6274 wpa_printf(MSG_DEBUG
,
6275 "DPP: Invalid date/time information - assume expired key");
6279 pos
= timestamp
+ 19;
6280 if (*pos
== 'Z' || *pos
== '\0') {
6281 /* In UTC - no need to adjust */
6282 } else if (*pos
== '-' || *pos
== '+') {
6285 /* Adjust local time to UTC */
6286 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
6288 wpa_printf(MSG_DEBUG
,
6289 "DPP: Invalid time zone designator (%s) - assume expired key",
6294 utime
+= 3600 * hour
;
6296 utime
-= 3600 * hour
;
6304 wpa_printf(MSG_DEBUG
,
6305 "DPP: Invalid time zone designator (%s) - assume expired key",
6312 if (os_get_time(&now
) < 0) {
6313 wpa_printf(MSG_DEBUG
,
6314 "DPP: Cannot get current time - assume expired key");
6318 if (now
.sec
> utime
) {
6319 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
6328 static int dpp_parse_connector(struct dpp_authentication
*auth
,
6329 struct dpp_config_obj
*conf
,
6330 const unsigned char *payload
,
6333 struct json_token
*root
, *groups
, *netkey
, *token
;
6335 EVP_PKEY
*key
= NULL
;
6336 const struct dpp_curve_params
*curve
;
6337 unsigned int rules
= 0;
6339 root
= json_parse((const char *) payload
, payload_len
);
6341 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6345 groups
= json_get_member(root
, "groups");
6346 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6347 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
6350 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6351 struct json_token
*id
, *role
;
6353 id
= json_get_member(token
, "groupId");
6354 if (!id
|| id
->type
!= JSON_STRING
) {
6355 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
6359 role
= json_get_member(token
, "netRole");
6360 if (!role
|| role
->type
!= JSON_STRING
) {
6361 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
6364 wpa_printf(MSG_DEBUG
,
6365 "DPP: connector group: groupId='%s' netRole='%s'",
6366 id
->string
, role
->string
);
6372 wpa_printf(MSG_DEBUG
,
6373 "DPP: Connector includes no groups");
6377 token
= json_get_member(root
, "expiry");
6378 if (!token
|| token
->type
!= JSON_STRING
) {
6379 wpa_printf(MSG_DEBUG
,
6380 "DPP: No expiry string found - connector does not expire");
6382 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6383 if (dpp_key_expired(token
->string
,
6384 &auth
->net_access_key_expiry
)) {
6385 wpa_printf(MSG_DEBUG
,
6386 "DPP: Connector (netAccessKey) has expired");
6391 netkey
= json_get_member(root
, "netAccessKey");
6392 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6393 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6397 key
= dpp_parse_jwk(netkey
, &curve
);
6400 dpp_debug_print_key("DPP: Received netAccessKey", key
);
6402 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
6403 wpa_printf(MSG_DEBUG
,
6404 "DPP: netAccessKey in connector does not match own protocol key");
6405 #ifdef CONFIG_TESTING_OPTIONS
6406 if (auth
->ignore_netaccesskey_mismatch
) {
6407 wpa_printf(MSG_DEBUG
,
6408 "DPP: TESTING - skip netAccessKey mismatch");
6412 #else /* CONFIG_TESTING_OPTIONS */
6414 #endif /* CONFIG_TESTING_OPTIONS */
6425 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
6427 struct wpabuf
*uncomp
;
6429 u8 hash
[SHA256_MAC_LEN
];
6433 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
6435 uncomp
= dpp_get_pubkey_point(pub
, 1);
6438 addr
[0] = wpabuf_head(uncomp
);
6439 len
[0] = wpabuf_len(uncomp
);
6440 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
6442 res
= sha256_vector(1, addr
, len
, hash
);
6443 wpabuf_free(uncomp
);
6446 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
6447 wpa_printf(MSG_DEBUG
,
6448 "DPP: Received hash value does not match calculated public key hash value");
6449 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
6450 hash
, SHA256_MAC_LEN
);
6457 static void dpp_copy_csign(struct dpp_config_obj
*conf
, EVP_PKEY
*csign
)
6459 unsigned char *der
= NULL
;
6462 der_len
= i2d_PUBKEY(csign
, &der
);
6465 wpabuf_free(conf
->c_sign_key
);
6466 conf
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
6471 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
,
6472 struct dpp_config_obj
*conf
)
6474 unsigned char *der
= NULL
;
6478 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
6482 der_len
= i2d_ECPrivateKey(eckey
, &der
);
6487 wpabuf_free(auth
->net_access_key
);
6488 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
6494 struct dpp_signed_connector_info
{
6495 unsigned char *payload
;
6499 static enum dpp_status_error
6500 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
6501 EVP_PKEY
*csign_pub
, const char *connector
)
6503 enum dpp_status_error ret
= 255;
6504 const char *pos
, *end
, *signed_start
, *signed_end
;
6505 struct wpabuf
*kid
= NULL
;
6506 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
6507 size_t prot_hdr_len
= 0, signature_len
= 0;
6508 const EVP_MD
*sign_md
= NULL
;
6509 unsigned char *der
= NULL
;
6512 EVP_MD_CTX
*md_ctx
= NULL
;
6513 ECDSA_SIG
*sig
= NULL
;
6514 BIGNUM
*r
= NULL
, *s
= NULL
;
6515 const struct dpp_curve_params
*curve
;
6517 const EC_GROUP
*group
;
6520 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
6523 group
= EC_KEY_get0_group(eckey
);
6526 nid
= EC_GROUP_get_curve_name(group
);
6527 curve
= dpp_get_curve_nid(nid
);
6530 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
6531 os_memset(info
, 0, sizeof(*info
));
6533 signed_start
= pos
= connector
;
6534 end
= os_strchr(pos
, '.');
6536 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
6537 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6540 prot_hdr
= base64_url_decode(pos
, end
- pos
, &prot_hdr_len
);
6542 wpa_printf(MSG_DEBUG
,
6543 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
6544 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6547 wpa_hexdump_ascii(MSG_DEBUG
,
6548 "DPP: signedConnector - JWS Protected Header",
6549 prot_hdr
, prot_hdr_len
);
6550 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
6552 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6555 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
6556 wpa_printf(MSG_DEBUG
,
6557 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6558 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
6559 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6564 end
= os_strchr(pos
, '.');
6566 wpa_printf(MSG_DEBUG
,
6567 "DPP: Missing dot(2) in signedConnector");
6568 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6571 signed_end
= end
- 1;
6572 info
->payload
= base64_url_decode(pos
, end
- pos
, &info
->payload_len
);
6573 if (!info
->payload
) {
6574 wpa_printf(MSG_DEBUG
,
6575 "DPP: Failed to base64url decode signedConnector JWS Payload");
6576 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6579 wpa_hexdump_ascii(MSG_DEBUG
,
6580 "DPP: signedConnector - JWS Payload",
6581 info
->payload
, info
->payload_len
);
6583 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
6585 wpa_printf(MSG_DEBUG
,
6586 "DPP: Failed to base64url decode signedConnector signature");
6587 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6590 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
6591 signature
, signature_len
);
6593 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
6594 ret
= DPP_STATUS_NO_MATCH
;
6598 if (signature_len
& 0x01) {
6599 wpa_printf(MSG_DEBUG
,
6600 "DPP: Unexpected signedConnector signature length (%d)",
6601 (int) signature_len
);
6602 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6606 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6607 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6608 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
6609 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
6610 sig
= ECDSA_SIG_new();
6611 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
6616 der_len
= i2d_ECDSA_SIG(sig
, &der
);
6618 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
6621 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
6622 md_ctx
= EVP_MD_CTX_create();
6627 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
6628 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
6629 ERR_error_string(ERR_get_error(), NULL
));
6632 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
6633 signed_end
- signed_start
+ 1) != 1) {
6634 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
6635 ERR_error_string(ERR_get_error(), NULL
));
6638 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
6640 wpa_printf(MSG_DEBUG
,
6641 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6642 res
, ERR_error_string(ERR_get_error(), NULL
));
6643 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6647 ret
= DPP_STATUS_OK
;
6650 EVP_MD_CTX_destroy(md_ctx
);
6654 ECDSA_SIG_free(sig
);
6662 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
6663 struct dpp_config_obj
*conf
,
6664 struct json_token
*cred
)
6666 struct dpp_signed_connector_info info
;
6667 struct json_token
*token
, *csign
;
6669 EVP_PKEY
*csign_pub
= NULL
;
6670 const struct dpp_curve_params
*key_curve
= NULL
;
6671 const char *signed_connector
;
6673 os_memset(&info
, 0, sizeof(info
));
6675 if (dpp_akm_psk(conf
->akm
) || dpp_akm_sae(conf
->akm
)) {
6676 wpa_printf(MSG_DEBUG
,
6677 "DPP: Legacy credential included in Connector credential");
6678 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6682 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
6684 csign
= json_get_member(cred
, "csign");
6685 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
6686 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
6690 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
6692 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
6695 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
6697 token
= json_get_member(cred
, "signedConnector");
6698 if (!token
|| token
->type
!= JSON_STRING
) {
6699 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
6702 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
6703 token
->string
, os_strlen(token
->string
));
6704 signed_connector
= token
->string
;
6706 if (os_strchr(signed_connector
, '"') ||
6707 os_strchr(signed_connector
, '\n')) {
6708 wpa_printf(MSG_DEBUG
,
6709 "DPP: Unexpected character in signedConnector");
6713 if (dpp_process_signed_connector(&info
, csign_pub
,
6714 signed_connector
) != DPP_STATUS_OK
)
6717 if (dpp_parse_connector(auth
, conf
,
6718 info
.payload
, info
.payload_len
) < 0) {
6719 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
6723 os_free(conf
->connector
);
6724 conf
->connector
= os_strdup(signed_connector
);
6726 dpp_copy_csign(conf
, csign_pub
);
6727 dpp_copy_netaccesskey(auth
, conf
);
6731 EVP_PKEY_free(csign_pub
);
6732 os_free(info
.payload
);
6737 const char * dpp_akm_str(enum dpp_akm akm
)
6746 case DPP_AKM_PSK_SAE
:
6748 case DPP_AKM_SAE_DPP
:
6750 case DPP_AKM_PSK_SAE_DPP
:
6751 return "dpp+psk+sae";
6758 const char * dpp_akm_selector_str(enum dpp_akm akm
)
6764 return "000FAC02+000FAC06";
6767 case DPP_AKM_PSK_SAE
:
6768 return "000FAC02+000FAC06+000FAC08";
6769 case DPP_AKM_SAE_DPP
:
6770 return "506F9A02+000FAC08";
6771 case DPP_AKM_PSK_SAE_DPP
:
6772 return "506F9A02+000FAC08+000FAC02+000FAC06";
6779 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
6782 int dpp
= 0, psk
= 0, sae
= 0;
6784 if (os_strcmp(akm
, "psk") == 0)
6786 if (os_strcmp(akm
, "sae") == 0)
6788 if (os_strcmp(akm
, "psk+sae") == 0)
6789 return DPP_AKM_PSK_SAE
;
6790 if (os_strcmp(akm
, "dpp") == 0)
6792 if (os_strcmp(akm
, "dpp+sae") == 0)
6793 return DPP_AKM_SAE_DPP
;
6794 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
6795 return DPP_AKM_PSK_SAE_DPP
;
6799 if (os_strlen(pos
) < 8)
6801 if (os_strncasecmp(pos
, "506F9A02", 8) == 0)
6803 else if (os_strncasecmp(pos
, "000FAC02", 8) == 0)
6805 else if (os_strncasecmp(pos
, "000FAC06", 8) == 0)
6807 else if (os_strncasecmp(pos
, "000FAC08", 8) == 0)
6815 if (dpp
&& psk
&& sae
)
6816 return DPP_AKM_PSK_SAE_DPP
;
6818 return DPP_AKM_SAE_DPP
;
6822 return DPP_AKM_PSK_SAE
;
6828 return DPP_AKM_UNKNOWN
;
6832 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
6833 const u8
*conf_obj
, u16 conf_obj_len
)
6836 struct json_token
*root
, *token
, *discovery
, *cred
;
6837 struct dpp_config_obj
*conf
;
6838 struct wpabuf
*ssid64
= NULL
;
6840 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
6843 if (root
->type
!= JSON_OBJECT
) {
6844 dpp_auth_fail(auth
, "JSON root is not an object");
6848 token
= json_get_member(root
, "wi-fi_tech");
6849 if (!token
|| token
->type
!= JSON_STRING
) {
6850 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
6853 if (os_strcmp(token
->string
, "infra") != 0) {
6854 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
6856 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
6860 discovery
= json_get_member(root
, "discovery");
6861 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
6862 dpp_auth_fail(auth
, "No discovery object in JSON");
6866 ssid64
= json_get_member_base64url(discovery
, "ssid64");
6868 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid64",
6869 wpabuf_head(ssid64
), wpabuf_len(ssid64
));
6870 if (wpabuf_len(ssid64
) > SSID_MAX_LEN
) {
6871 dpp_auth_fail(auth
, "Too long discovery::ssid64 value");
6875 token
= json_get_member(discovery
, "ssid");
6876 if (!token
|| token
->type
!= JSON_STRING
) {
6878 "No discovery::ssid string value found");
6881 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
6882 token
->string
, os_strlen(token
->string
));
6883 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
6885 "Too long discovery::ssid string value");
6890 if (auth
->num_conf_obj
== DPP_MAX_CONF_OBJ
) {
6891 wpa_printf(MSG_DEBUG
,
6892 "DPP: No room for this many Config Objects - ignore this one");
6896 conf
= &auth
->conf_obj
[auth
->num_conf_obj
++];
6899 conf
->ssid_len
= wpabuf_len(ssid64
);
6900 os_memcpy(conf
->ssid
, wpabuf_head(ssid64
), conf
->ssid_len
);
6902 conf
->ssid_len
= os_strlen(token
->string
);
6903 os_memcpy(conf
->ssid
, token
->string
, conf
->ssid_len
);
6906 token
= json_get_member(discovery
, "ssid_charset");
6907 if (token
&& token
->type
== JSON_NUMBER
) {
6908 conf
->ssid_charset
= token
->number
;
6909 wpa_printf(MSG_DEBUG
, "DPP: ssid_charset=%d",
6910 conf
->ssid_charset
);
6913 cred
= json_get_member(root
, "cred");
6914 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
6915 dpp_auth_fail(auth
, "No cred object in JSON");
6919 token
= json_get_member(cred
, "akm");
6920 if (!token
|| token
->type
!= JSON_STRING
) {
6921 dpp_auth_fail(auth
, "No cred::akm string value found");
6924 conf
->akm
= dpp_akm_from_str(token
->string
);
6926 if (dpp_akm_legacy(conf
->akm
)) {
6927 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6929 } else if (dpp_akm_dpp(conf
->akm
)) {
6930 if (dpp_parse_cred_dpp(auth
, conf
, cred
) < 0)
6933 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
6935 dpp_auth_fail(auth
, "Unsupported akm");
6939 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
6942 wpabuf_free(ssid64
);
6950 struct dpp_enveloped_data
{
6952 size_t enc_cont_len
;
6956 size_t pbkdf2_key_len
;
6957 size_t prf_hash_len
;
6961 static int dpp_parse_recipient_infos(const u8
*pos
, size_t len
,
6962 struct dpp_enveloped_data
*data
)
6964 struct asn1_hdr hdr
;
6965 const u8
*end
= pos
+ len
;
6966 const u8
*next
, *e_end
;
6967 struct asn1_oid oid
;
6972 wpa_hexdump(MSG_MSGDUMP
, "DPP: RecipientInfos", pos
, len
);
6975 * RecipientInfo ::= CHOICE {
6976 * ktri KeyTransRecipientInfo,
6977 * kari [1] KeyAgreeRecipientInfo,
6978 * kekri [2] KEKRecipientInfo,
6979 * pwri [3] PasswordRecipientInfo,
6980 * ori [4] OtherRecipientInfo}
6982 * Shall always use the pwri CHOICE.
6985 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6986 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 3) {
6987 wpa_printf(MSG_DEBUG
,
6988 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
6989 hdr
.class, hdr
.tag
);
6992 wpa_hexdump(MSG_MSGDUMP
, "DPP: PasswordRecipientInfo",
6993 hdr
.payload
, hdr
.length
);
6995 end
= pos
+ hdr
.length
;
6998 * PasswordRecipientInfo ::= SEQUENCE {
6999 * version CMSVersion,
7000 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
7001 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
7002 * encryptedKey EncryptedKey}
7004 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
7005 * parameters contains PBKDF2-params SEQUENCE.
7008 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
7012 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7015 wpa_printf(MSG_DEBUG
, "DPP: pwri.version != 0");
7019 wpa_hexdump(MSG_MSGDUMP
, "DPP: Remaining PasswordRecipientInfo after version",
7022 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7023 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7024 wpa_printf(MSG_DEBUG
,
7025 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
7026 hdr
.class, hdr
.tag
);
7030 e_end
= pos
+ hdr
.length
;
7032 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
7033 if (asn1_get_alg_id(pos
, e_end
- pos
, &oid
, ¶ms
, ¶ms_len
,
7036 if (!asn1_oid_equal(&oid
, &asn1_pbkdf2_oid
)) {
7039 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7040 wpa_printf(MSG_DEBUG
,
7041 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7047 * PBKDF2-params ::= SEQUENCE {
7049 * specified OCTET STRING,
7050 * otherSource AlgorithmIdentifier}
7051 * iterationCount INTEGER (1..MAX),
7052 * keyLength INTEGER (1..MAX),
7053 * prf AlgorithmIdentifier}
7055 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7056 * on Configurator signing key length, prf is
7057 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7060 asn1_get_sequence(params
, params_len
, &hdr
, &e_end
) < 0)
7064 if (asn1_get_next(pos
, e_end
- pos
, &hdr
) < 0 ||
7065 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7066 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7067 wpa_printf(MSG_DEBUG
,
7068 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7069 hdr
.class, hdr
.tag
);
7072 wpa_hexdump(MSG_MSGDUMP
, "DPP: salt.specified",
7073 hdr
.payload
, hdr
.length
);
7074 if (hdr
.length
!= 64) {
7075 wpa_printf(MSG_DEBUG
, "DPP: Unexpected salt length %u",
7079 data
->salt
= hdr
.payload
;
7080 pos
= hdr
.payload
+ hdr
.length
;
7082 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7085 wpa_printf(MSG_DEBUG
, "DPP: Unexpected iterationCount %d", val
);
7089 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7091 if (val
!= 32 && val
!= 48 && val
!= 64) {
7092 wpa_printf(MSG_DEBUG
, "DPP: Unexpected keyLength %d", val
);
7095 data
->pbkdf2_key_len
= val
;
7097 if (asn1_get_sequence(pos
, e_end
- pos
, &hdr
, NULL
) < 0 ||
7098 asn1_get_oid(hdr
.payload
, hdr
.length
, &oid
, &pos
) < 0) {
7099 wpa_printf(MSG_DEBUG
, "DPP: Could not parse prf");
7102 if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha256_oid
)) {
7103 data
->prf_hash_len
= 32;
7104 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha384_oid
)) {
7105 data
->prf_hash_len
= 48;
7106 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha512_oid
)) {
7107 data
->prf_hash_len
= 64;
7111 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7112 wpa_printf(MSG_DEBUG
, "DPP: Unexpected PBKDF2-params.prf %s",
7119 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7121 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7123 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7124 * id-alg-AES-SIV-CMAC-aed-512. */
7125 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7127 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7128 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7129 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7132 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7133 wpa_printf(MSG_DEBUG
,
7134 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7140 * encryptedKey EncryptedKey
7142 * EncryptedKey ::= OCTET STRING
7144 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7145 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7146 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7147 wpa_printf(MSG_DEBUG
,
7148 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7149 hdr
.class, hdr
.tag
);
7152 wpa_hexdump(MSG_MSGDUMP
, "DPP: pwri.encryptedKey",
7153 hdr
.payload
, hdr
.length
);
7154 data
->enc_key
= hdr
.payload
;
7155 data
->enc_key_len
= hdr
.length
;
7161 static int dpp_parse_encrypted_content_info(const u8
*pos
, const u8
*end
,
7162 struct dpp_enveloped_data
*data
)
7164 struct asn1_hdr hdr
;
7165 struct asn1_oid oid
;
7168 * EncryptedContentInfo ::= SEQUENCE {
7169 * contentType ContentType,
7170 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7171 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7173 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7175 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContentInfo",
7176 hdr
.payload
, hdr
.length
);
7178 wpa_hexdump(MSG_DEBUG
,
7179 "DPP: Unexpected extra data after EncryptedContentInfo",
7187 /* ContentType ::= OBJECT IDENTIFIER */
7188 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0) {
7189 wpa_printf(MSG_DEBUG
, "DPP: Could not parse ContentType");
7192 if (!asn1_oid_equal(&oid
, &asn1_dpp_asymmetric_key_package_oid
)) {
7195 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7196 wpa_printf(MSG_DEBUG
, "DPP: Unexpected ContentType %s", buf
);
7200 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7201 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7203 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7204 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7205 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7208 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7209 wpa_printf(MSG_DEBUG
,
7210 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7214 /* ignore optional parameters */
7216 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7217 * EncryptedContent ::= OCTET STRING */
7218 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7219 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7220 wpa_printf(MSG_DEBUG
,
7221 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7222 hdr
.class, hdr
.tag
);
7225 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContent",
7226 hdr
.payload
, hdr
.length
);
7227 data
->enc_cont
= hdr
.payload
;
7228 data
->enc_cont_len
= hdr
.length
;
7233 static int dpp_parse_enveloped_data(const u8
*env_data
, size_t env_data_len
,
7234 struct dpp_enveloped_data
*data
)
7236 struct asn1_hdr hdr
;
7237 const u8
*pos
, *end
;
7240 os_memset(data
, 0, sizeof(*data
));
7243 * DPPEnvelopedData ::= EnvelopedData
7245 * EnvelopedData ::= SEQUENCE {
7246 * version CMSVersion,
7247 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7248 * recipientInfos RecipientInfos,
7249 * encryptedContentInfo EncryptedContentInfo,
7250 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7252 * CMSVersion ::= INTEGER
7254 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7256 * For DPP, version is 3, both originatorInfo and
7257 * unprotectedAttrs are omitted, and recipientInfos contains a single
7260 if (asn1_get_sequence(env_data
, env_data_len
, &hdr
, &end
) < 0)
7263 if (end
< env_data
+ env_data_len
) {
7264 wpa_hexdump(MSG_DEBUG
,
7265 "DPP: Unexpected extra data after DPPEnvelopedData",
7266 end
, env_data
+ env_data_len
- end
);
7270 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7273 wpa_printf(MSG_DEBUG
, "DPP: EnvelopedData.version != 3");
7277 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7278 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7279 wpa_printf(MSG_DEBUG
,
7280 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7281 hdr
.class, hdr
.tag
);
7285 if (dpp_parse_recipient_infos(hdr
.payload
, hdr
.length
, data
) < 0)
7287 return dpp_parse_encrypted_content_info(hdr
.payload
+ hdr
.length
, end
,
7292 static struct dpp_asymmetric_key
*
7293 dpp_parse_one_asymmetric_key(const u8
*buf
, size_t len
)
7295 struct asn1_hdr hdr
;
7296 const u8
*pos
= buf
, *end
= buf
+ len
, *next
;
7300 struct asn1_oid oid
;
7302 struct dpp_asymmetric_key
*key
;
7305 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: OneAsymmetricKey", buf
, len
);
7307 key
= os_zalloc(sizeof(*key
));
7312 * OneAsymmetricKey ::= SEQUENCE {
7314 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7315 * privateKey PrivateKey,
7316 * attributes [0] Attributes OPTIONAL,
7318 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7322 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
7326 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7327 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7330 wpa_printf(MSG_DEBUG
,
7331 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7336 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7337 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, ¶ms
, ¶ms_len
,
7340 if (!asn1_oid_equal(&oid
, &asn1_ec_public_key_oid
)) {
7341 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7342 wpa_printf(MSG_DEBUG
,
7343 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7347 wpa_hexdump(MSG_MSGDUMP
, "DPP: PrivateKeyAlgorithmIdentifier params",
7348 params
, params_len
);
7350 * ECParameters ::= CHOICE {
7351 * namedCurve OBJECT IDENTIFIER
7352 * -- implicitCurve NULL
7353 * -- specifiedCurve SpecifiedECDomain}
7355 if (!params
|| asn1_get_oid(params
, params_len
, &oid
, &next
) < 0) {
7356 wpa_printf(MSG_DEBUG
,
7357 "DPP: Could not parse ECParameters.namedCurve");
7360 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7361 wpa_printf(MSG_MSGDUMP
, "DPP: namedCurve %s", txt
);
7362 /* Assume the curve is identified within ECPrivateKey, so that this
7363 * separate indication is not really needed. */
7366 * PrivateKey ::= OCTET STRING
7367 * (Contains DER encoding of ECPrivateKey)
7369 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7370 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7371 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7372 wpa_printf(MSG_DEBUG
,
7373 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7374 hdr
.class, hdr
.tag
);
7377 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: PrivateKey",
7378 hdr
.payload
, hdr
.length
);
7379 pos
= hdr
.payload
+ hdr
.length
;
7380 eckey
= d2i_ECPrivateKey(NULL
, &hdr
.payload
, hdr
.length
);
7382 wpa_printf(MSG_INFO
,
7383 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7384 ERR_error_string(ERR_get_error(), NULL
));
7387 key
->csign
= EVP_PKEY_new();
7388 if (!key
->csign
|| EVP_PKEY_assign_EC_KEY(key
->csign
, eckey
) != 1) {
7392 if (wpa_debug_show_keys
)
7393 dpp_debug_print_key("DPP: Received c-sign-key", key
->csign
);
7396 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7398 * Exactly one instance of type Attribute in OneAsymmetricKey.
7400 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7401 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7402 wpa_printf(MSG_DEBUG
,
7403 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7404 hdr
.class, hdr
.tag
);
7407 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: Attributes",
7408 hdr
.payload
, hdr
.length
);
7409 if (hdr
.payload
+ hdr
.length
< end
) {
7410 wpa_hexdump_key(MSG_MSGDUMP
,
7411 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7412 hdr
.payload
+ hdr
.length
,
7413 end
- (hdr
.payload
+ hdr
.length
));
7416 end
= hdr
.payload
+ hdr
.length
;
7418 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7419 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7420 wpa_printf(MSG_DEBUG
,
7421 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7422 hdr
.class, hdr
.tag
);
7425 if (hdr
.payload
+ hdr
.length
< end
) {
7426 wpa_hexdump_key(MSG_MSGDUMP
,
7427 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7428 hdr
.payload
+ hdr
.length
,
7429 end
- (hdr
.payload
+ hdr
.length
));
7432 end
= hdr
.payload
+ hdr
.length
;
7435 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7436 * aa-DPPConfigurationParameters,
7437 * ... -- For local profiles
7440 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7441 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7443 * Attribute ::= SEQUENCE {
7444 * type OBJECT IDENTIFIER,
7445 * values SET SIZE(1..MAX) OF Type
7447 * Exactly one instance of ATTRIBUTE in attrValues.
7449 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7452 wpa_hexdump_key(MSG_MSGDUMP
,
7453 "DPP: Ignore additional data at the end of ATTRIBUTE",
7459 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0)
7461 if (!asn1_oid_equal(&oid
, &asn1_dpp_config_params_oid
)) {
7462 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7463 wpa_printf(MSG_DEBUG
,
7464 "DPP: Unexpected Attribute identifier %s", txt
);
7468 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7469 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7470 wpa_printf(MSG_DEBUG
,
7471 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7472 hdr
.class, hdr
.tag
);
7476 end
= hdr
.payload
+ hdr
.length
;
7479 * DPPConfigurationParameters ::= SEQUENCE {
7480 * configurationTemplate UTF8String,
7481 * connectorTemplate UTF8String OPTIONAL}
7484 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPConfigurationParameters",
7486 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7489 wpa_hexdump_key(MSG_MSGDUMP
,
7490 "DPP: Ignore additional data after DPPConfigurationParameters",
7496 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7497 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7498 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7499 wpa_printf(MSG_DEBUG
,
7500 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7501 hdr
.class, hdr
.tag
);
7504 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: configurationTemplate",
7505 hdr
.payload
, hdr
.length
);
7506 key
->config_template
= os_zalloc(hdr
.length
+ 1);
7507 if (!key
->config_template
)
7509 os_memcpy(key
->config_template
, hdr
.payload
, hdr
.length
);
7511 pos
= hdr
.payload
+ hdr
.length
;
7514 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7515 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7516 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7517 wpa_printf(MSG_DEBUG
,
7518 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7519 hdr
.class, hdr
.tag
);
7522 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: connectorTemplate",
7523 hdr
.payload
, hdr
.length
);
7524 key
->connector_template
= os_zalloc(hdr
.length
+ 1);
7525 if (!key
->connector_template
)
7527 os_memcpy(key
->connector_template
, hdr
.payload
, hdr
.length
);
7532 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse OneAsymmetricKey");
7533 dpp_free_asymmetric_key(key
);
7538 static struct dpp_asymmetric_key
*
7539 dpp_parse_dpp_asymmetric_key_package(const u8
*key_pkg
, size_t key_pkg_len
)
7541 struct asn1_hdr hdr
;
7542 const u8
*pos
= key_pkg
, *end
= key_pkg
+ key_pkg_len
;
7543 struct dpp_asymmetric_key
*first
= NULL
, *last
= NULL
, *key
;
7545 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
7546 key_pkg
, key_pkg_len
);
7549 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7551 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7554 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0 ||
7555 !(key
= dpp_parse_one_asymmetric_key(hdr
.payload
,
7557 dpp_free_asymmetric_key(first
);
7572 static int dpp_conf_resp_env_data(struct dpp_authentication
*auth
,
7573 const u8
*env_data
, size_t env_data_len
)
7577 u8 kek
[DPP_MAX_HASH_LEN
];
7578 u8 cont_encr_key
[DPP_MAX_HASH_LEN
];
7579 size_t cont_encr_key_len
;
7583 struct dpp_enveloped_data data
;
7584 struct dpp_asymmetric_key
*keys
;
7586 wpa_hexdump(MSG_DEBUG
, "DPP: DPPEnvelopedData", env_data
, env_data_len
);
7588 if (dpp_parse_enveloped_data(env_data
, env_data_len
, &data
) < 0)
7591 /* TODO: For initial testing, use ke as the key. Replace this with a
7592 * new key once that has been defined. */
7594 key_len
= auth
->curve
->hash_len
;
7595 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
7597 if (dpp_pbkdf2(data
.prf_hash_len
, key
, key_len
, data
.salt
, 64, 1000,
7598 kek
, data
.pbkdf2_key_len
)) {
7599 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
7602 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
7603 kek
, data
.pbkdf2_key_len
);
7605 if (data
.enc_key_len
< AES_BLOCK_SIZE
||
7606 data
.enc_key_len
> sizeof(cont_encr_key
) + AES_BLOCK_SIZE
) {
7607 wpa_printf(MSG_DEBUG
, "DPP: Invalid encryptedKey length");
7610 res
= aes_siv_decrypt(kek
, data
.pbkdf2_key_len
,
7611 data
.enc_key
, data
.enc_key_len
,
7612 0, NULL
, NULL
, cont_encr_key
);
7613 forced_memzero(kek
, data
.pbkdf2_key_len
);
7615 wpa_printf(MSG_DEBUG
,
7616 "DPP: AES-SIV decryption of encryptedKey failed");
7619 cont_encr_key_len
= data
.enc_key_len
- AES_BLOCK_SIZE
;
7620 wpa_hexdump_key(MSG_DEBUG
, "DPP: content-encryption key",
7621 cont_encr_key
, cont_encr_key_len
);
7623 if (data
.enc_cont_len
< AES_BLOCK_SIZE
)
7625 key_pkg_len
= data
.enc_cont_len
- AES_BLOCK_SIZE
;
7626 key_pkg
= os_malloc(key_pkg_len
);
7629 res
= aes_siv_decrypt(cont_encr_key
, cont_encr_key_len
,
7630 data
.enc_cont
, data
.enc_cont_len
,
7631 0, NULL
, NULL
, key_pkg
);
7632 forced_memzero(cont_encr_key
, cont_encr_key_len
);
7634 bin_clear_free(key_pkg
, key_pkg_len
);
7635 wpa_printf(MSG_DEBUG
,
7636 "DPP: AES-SIV decryption of encryptedContent failed");
7640 keys
= dpp_parse_dpp_asymmetric_key_package(key_pkg
, key_pkg_len
);
7641 bin_clear_free(key_pkg
, key_pkg_len
);
7642 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
7643 auth
->conf_key_pkg
= keys
;
7645 return keys
!= NULL
;;
7648 #endif /* CONFIG_DPP2 */
7651 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
7652 const struct wpabuf
*resp
)
7654 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
7655 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
7660 u8
*unwrapped
= NULL
;
7661 size_t unwrapped_len
= 0;
7664 auth
->conf_resp_status
= 255;
7666 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
7667 dpp_auth_fail(auth
, "Invalid attribute in config response");
7671 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7672 DPP_ATTR_WRAPPED_DATA
,
7674 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7676 "Missing or invalid required Wrapped Data attribute");
7680 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7681 wrapped_data
, wrapped_data_len
);
7682 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7683 unwrapped
= os_malloc(unwrapped_len
);
7687 addr
[0] = wpabuf_head(resp
);
7688 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
7689 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
7691 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7692 wrapped_data
, wrapped_data_len
,
7693 1, addr
, len
, unwrapped
) < 0) {
7694 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7697 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7698 unwrapped
, unwrapped_len
);
7700 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7701 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7705 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7706 DPP_ATTR_ENROLLEE_NONCE
,
7708 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7710 "Missing or invalid Enrollee Nonce attribute");
7713 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7714 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7715 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7719 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7720 DPP_ATTR_STATUS
, &status_len
);
7721 if (!status
|| status_len
< 1) {
7723 "Missing or invalid required DPP Status attribute");
7726 auth
->conf_resp_status
= status
[0];
7727 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7728 if (status
[0] != DPP_STATUS_OK
) {
7729 dpp_auth_fail(auth
, "Configurator rejected configuration");
7733 env_data
= dpp_get_attr(unwrapped
, unwrapped_len
,
7734 DPP_ATTR_ENVELOPED_DATA
, &env_data_len
);
7737 dpp_conf_resp_env_data(auth
, env_data
, env_data_len
) < 0)
7739 #endif /* CONFIG_DPP2 */
7741 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONFIG_OBJ
,
7743 if (!conf_obj
&& !env_data
) {
7745 "Missing required Configuration Object attribute");
7749 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
7750 conf_obj
, conf_obj_len
);
7751 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
7753 conf_obj
= dpp_get_attr_next(conf_obj
, unwrapped
, unwrapped_len
,
7754 DPP_ATTR_CONFIG_OBJ
,
7759 status
= dpp_get_attr(unwrapped
, unwrapped_len
,
7760 DPP_ATTR_SEND_CONN_STATUS
, &status_len
);
7762 wpa_printf(MSG_DEBUG
,
7763 "DPP: Configurator requested connection status result");
7764 auth
->conn_status_requested
= 1;
7766 #endif /* CONFIG_DPP2 */
7778 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
7780 const u8
*attr_start
, size_t attr_len
)
7782 const u8
*wrapped_data
, *status
, *e_nonce
;
7783 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7786 u8
*unwrapped
= NULL
;
7787 size_t unwrapped_len
= 0;
7788 enum dpp_status_error ret
= 256;
7790 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7792 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7794 "Missing or invalid required Wrapped Data attribute");
7797 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7798 wrapped_data
, wrapped_data_len
);
7800 attr_len
= wrapped_data
- 4 - attr_start
;
7803 len
[0] = DPP_HDR_LEN
;
7804 addr
[1] = attr_start
;
7806 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7807 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7808 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7809 wrapped_data
, wrapped_data_len
);
7810 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7811 unwrapped
= os_malloc(unwrapped_len
);
7814 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7815 wrapped_data
, wrapped_data_len
,
7816 2, addr
, len
, unwrapped
) < 0) {
7817 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7820 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7821 unwrapped
, unwrapped_len
);
7823 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7824 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7828 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7829 DPP_ATTR_ENROLLEE_NONCE
,
7831 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7833 "Missing or invalid Enrollee Nonce attribute");
7836 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7837 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7838 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7839 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7840 auth
->e_nonce
, e_nonce_len
);
7844 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
7846 if (!status
|| status_len
< 1) {
7848 "Missing or invalid required DPP Status attribute");
7851 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7855 bin_clear_free(unwrapped
, unwrapped_len
);
7860 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
7861 enum dpp_status_error status
)
7863 struct wpabuf
*msg
, *clear
;
7864 size_t nonce_len
, clear_len
, attr_len
;
7869 nonce_len
= auth
->curve
->nonce_len
;
7870 clear_len
= 5 + 4 + nonce_len
;
7871 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7872 clear
= wpabuf_alloc(clear_len
);
7873 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
7878 dpp_build_attr_status(clear
, status
);
7881 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
7882 wpabuf_put_le16(clear
, nonce_len
);
7883 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
7885 /* OUI, OUI type, Crypto Suite, DPP frame type */
7886 addr
[0] = wpabuf_head_u8(msg
) + 2;
7887 len
[0] = 3 + 1 + 1 + 1;
7888 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7890 /* Attributes before Wrapped Data (none) */
7891 addr
[1] = wpabuf_put(msg
, 0);
7893 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7896 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7897 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7898 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7900 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7901 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
7902 wpabuf_head(clear
), wpabuf_len(clear
),
7903 2, addr
, len
, wrapped
) < 0)
7906 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
7916 static int valid_channel_list(const char *val
)
7919 if (!((*val
>= '0' && *val
<= '9') ||
7920 *val
== '/' || *val
== ','))
7929 enum dpp_status_error
dpp_conn_status_result_rx(struct dpp_authentication
*auth
,
7931 const u8
*attr_start
,
7933 u8
*ssid
, size_t *ssid_len
,
7934 char **channel_list
)
7936 const u8
*wrapped_data
, *status
, *e_nonce
;
7937 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7940 u8
*unwrapped
= NULL
;
7941 size_t unwrapped_len
= 0;
7942 enum dpp_status_error ret
= 256;
7943 struct json_token
*root
= NULL
, *token
;
7944 struct wpabuf
*ssid64
;
7947 *channel_list
= NULL
;
7949 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7951 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7953 "Missing or invalid required Wrapped Data attribute");
7956 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7957 wrapped_data
, wrapped_data_len
);
7959 attr_len
= wrapped_data
- 4 - attr_start
;
7962 len
[0] = DPP_HDR_LEN
;
7963 addr
[1] = attr_start
;
7965 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7966 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7967 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7968 wrapped_data
, wrapped_data_len
);
7969 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7970 unwrapped
= os_malloc(unwrapped_len
);
7973 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7974 wrapped_data
, wrapped_data_len
,
7975 2, addr
, len
, unwrapped
) < 0) {
7976 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7979 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7980 unwrapped
, unwrapped_len
);
7982 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7983 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7987 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7988 DPP_ATTR_ENROLLEE_NONCE
,
7990 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7992 "Missing or invalid Enrollee Nonce attribute");
7995 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7996 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7997 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7998 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7999 auth
->e_nonce
, e_nonce_len
);
8003 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONN_STATUS
,
8007 "Missing required DPP Connection Status attribute");
8010 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
8011 status
, status_len
);
8013 root
= json_parse((const char *) status
, status_len
);
8015 dpp_auth_fail(auth
, "Could not parse connStatus");
8019 ssid64
= json_get_member_base64url(root
, "ssid64");
8020 if (ssid64
&& wpabuf_len(ssid64
) <= SSID_MAX_LEN
) {
8021 *ssid_len
= wpabuf_len(ssid64
);
8022 os_memcpy(ssid
, wpabuf_head(ssid64
), *ssid_len
);
8024 wpabuf_free(ssid64
);
8026 token
= json_get_member(root
, "channelList");
8027 if (token
&& token
->type
== JSON_STRING
&&
8028 valid_channel_list(token
->string
))
8029 *channel_list
= os_strdup(token
->string
);
8031 token
= json_get_member(root
, "result");
8032 if (!token
|| token
->type
!= JSON_NUMBER
) {
8033 dpp_auth_fail(auth
, "No connStatus - result");
8036 wpa_printf(MSG_DEBUG
, "DPP: result %d", token
->number
);
8037 ret
= token
->number
;
8041 bin_clear_free(unwrapped
, unwrapped_len
);
8046 struct wpabuf
* dpp_build_conn_status_result(struct dpp_authentication
*auth
,
8047 enum dpp_status_error result
,
8048 const u8
*ssid
, size_t ssid_len
,
8049 const char *channel_list
)
8051 struct wpabuf
*msg
= NULL
, *clear
= NULL
, *json
;
8052 size_t nonce_len
, clear_len
, attr_len
;
8057 json
= wpabuf_alloc(1000);
8060 json_start_object(json
, NULL
);
8061 json_add_int(json
, "result", result
);
8063 json_value_sep(json
);
8064 if (json_add_base64url(json
, "ssid64", ssid
, ssid_len
) < 0)
8068 json_value_sep(json
);
8069 json_add_string(json
, "channelList", channel_list
);
8071 json_end_object(json
);
8072 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
8073 wpabuf_head(json
), wpabuf_len(json
));
8075 nonce_len
= auth
->curve
->nonce_len
;
8076 clear_len
= 5 + 4 + nonce_len
+ 4 + wpabuf_len(json
);
8077 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8078 clear
= wpabuf_alloc(clear_len
);
8079 msg
= dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT
, attr_len
);
8084 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
8085 wpabuf_put_le16(clear
, nonce_len
);
8086 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
8088 /* DPP Connection Status */
8089 wpabuf_put_le16(clear
, DPP_ATTR_CONN_STATUS
);
8090 wpabuf_put_le16(clear
, wpabuf_len(json
));
8091 wpabuf_put_buf(clear
, json
);
8093 /* OUI, OUI type, Crypto Suite, DPP frame type */
8094 addr
[0] = wpabuf_head_u8(msg
) + 2;
8095 len
[0] = 3 + 1 + 1 + 1;
8096 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8098 /* Attributes before Wrapped Data (none) */
8099 addr
[1] = wpabuf_put(msg
, 0);
8101 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8104 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8105 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8106 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8108 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8109 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
8110 wpabuf_head(clear
), wpabuf_len(clear
),
8111 2, addr
, len
, wrapped
) < 0)
8114 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Connection Status Result attributes",
8126 #endif /* CONFIG_DPP2 */
8129 void dpp_configurator_free(struct dpp_configurator
*conf
)
8133 EVP_PKEY_free(conf
->csign
);
8139 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
8143 int key_len
, ret
= -1;
8144 unsigned char *key
= NULL
;
8149 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
8153 key_len
= i2d_ECPrivateKey(eckey
, &key
);
8155 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
8163 static int dpp_configurator_gen_kid(struct dpp_configurator
*conf
)
8165 struct wpabuf
*csign_pub
= NULL
;
8166 u8 kid_hash
[SHA256_MAC_LEN
];
8171 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
8173 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
8177 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8178 addr
[0] = wpabuf_head(csign_pub
);
8179 len
[0] = wpabuf_len(csign_pub
);
8180 res
= sha256_vector(1, addr
, len
, kid_hash
);
8181 wpabuf_free(csign_pub
);
8183 wpa_printf(MSG_DEBUG
,
8184 "DPP: Failed to derive kid for C-sign-key");
8188 conf
->kid
= base64_url_encode(kid_hash
, sizeof(kid_hash
), NULL
);
8189 return conf
->kid
? 0 : -1;
8193 struct dpp_configurator
*
8194 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
8197 struct dpp_configurator
*conf
;
8199 conf
= os_zalloc(sizeof(*conf
));
8204 conf
->curve
= &dpp_curves
[0];
8206 conf
->curve
= dpp_get_curve_name(curve
);
8208 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8215 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
8218 conf
->csign
= dpp_gen_keypair(conf
->curve
);
8223 if (dpp_configurator_gen_kid(conf
) < 0)
8227 dpp_configurator_free(conf
);
8232 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
8233 const char *curve
, int ap
)
8235 struct wpabuf
*conf_obj
;
8239 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
8244 auth
->curve
= &dpp_curves
[0];
8246 auth
->curve
= dpp_get_curve_name(curve
);
8248 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8253 wpa_printf(MSG_DEBUG
,
8254 "DPP: Building own configuration/connector with curve %s",
8257 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
8258 if (!auth
->own_protocol_key
)
8260 dpp_copy_netaccesskey(auth
, &auth
->conf_obj
[0]);
8261 auth
->peer_protocol_key
= auth
->own_protocol_key
;
8262 dpp_copy_csign(&auth
->conf_obj
[0], auth
->conf
->csign
);
8264 conf_obj
= dpp_build_conf_obj(auth
, ap
, 0);
8266 wpabuf_free(auth
->conf_obj
[0].c_sign_key
);
8267 auth
->conf_obj
[0].c_sign_key
= NULL
;
8270 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
8271 wpabuf_len(conf_obj
));
8273 wpabuf_free(conf_obj
);
8274 auth
->peer_protocol_key
= NULL
;
8279 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
8281 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
8282 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
8286 static int dpp_connector_compatible_group(struct json_token
*root
,
8287 const char *group_id
,
8288 const char *net_role
)
8290 struct json_token
*groups
, *token
;
8292 groups
= json_get_member(root
, "groups");
8293 if (!groups
|| groups
->type
!= JSON_ARRAY
)
8296 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8297 struct json_token
*id
, *role
;
8299 id
= json_get_member(token
, "groupId");
8300 if (!id
|| id
->type
!= JSON_STRING
)
8303 role
= json_get_member(token
, "netRole");
8304 if (!role
|| role
->type
!= JSON_STRING
)
8307 if (os_strcmp(id
->string
, "*") != 0 &&
8308 os_strcmp(group_id
, "*") != 0 &&
8309 os_strcmp(id
->string
, group_id
) != 0)
8312 if (dpp_compatible_netrole(role
->string
, net_role
))
8320 static int dpp_connector_match_groups(struct json_token
*own_root
,
8321 struct json_token
*peer_root
)
8323 struct json_token
*groups
, *token
;
8325 groups
= json_get_member(peer_root
, "groups");
8326 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
8327 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
8331 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8332 struct json_token
*id
, *role
;
8334 id
= json_get_member(token
, "groupId");
8335 if (!id
|| id
->type
!= JSON_STRING
) {
8336 wpa_printf(MSG_DEBUG
,
8337 "DPP: Missing peer groupId string");
8341 role
= json_get_member(token
, "netRole");
8342 if (!role
|| role
->type
!= JSON_STRING
) {
8343 wpa_printf(MSG_DEBUG
,
8344 "DPP: Missing peer groups::netRole string");
8347 wpa_printf(MSG_DEBUG
,
8348 "DPP: peer connector group: groupId='%s' netRole='%s'",
8349 id
->string
, role
->string
);
8350 if (dpp_connector_compatible_group(own_root
, id
->string
,
8352 wpa_printf(MSG_DEBUG
,
8353 "DPP: Compatible group/netRole in own connector");
8362 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
8363 unsigned int hash_len
)
8365 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
8366 const char *info
= "DPP PMK";
8369 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8371 /* HKDF-Extract(<>, N.x) */
8372 os_memset(salt
, 0, hash_len
);
8373 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
8375 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8378 /* HKDF-Expand(PRK, info, L) */
8379 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
8380 os_memset(prk
, 0, hash_len
);
8384 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8390 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
8391 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
8393 struct wpabuf
*nkx
, *pkx
;
8397 u8 hash
[SHA256_MAC_LEN
];
8399 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8400 nkx
= dpp_get_pubkey_point(own_key
, 0);
8401 pkx
= dpp_get_pubkey_point(peer_key
, 0);
8404 addr
[0] = wpabuf_head(nkx
);
8405 len
[0] = wpabuf_len(nkx
) / 2;
8406 addr
[1] = wpabuf_head(pkx
);
8407 len
[1] = wpabuf_len(pkx
) / 2;
8408 if (len
[0] != len
[1])
8410 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
8411 addr
[0] = wpabuf_head(pkx
);
8412 addr
[1] = wpabuf_head(nkx
);
8414 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
8415 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
8416 res
= sha256_vector(2, addr
, len
, hash
);
8419 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
8420 os_memcpy(pmkid
, hash
, PMKID_LEN
);
8421 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
8430 enum dpp_status_error
8431 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
8432 const u8
*net_access_key
, size_t net_access_key_len
,
8433 const u8
*csign_key
, size_t csign_key_len
,
8434 const u8
*peer_connector
, size_t peer_connector_len
,
8437 struct json_token
*root
= NULL
, *netkey
, *token
;
8438 struct json_token
*own_root
= NULL
;
8439 enum dpp_status_error ret
= 255, res
;
8440 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
8441 struct wpabuf
*own_key_pub
= NULL
;
8442 const struct dpp_curve_params
*curve
, *own_curve
;
8443 struct dpp_signed_connector_info info
;
8444 const unsigned char *p
;
8445 EVP_PKEY
*csign
= NULL
;
8446 char *signed_connector
= NULL
;
8447 const char *pos
, *end
;
8448 unsigned char *own_conn
= NULL
;
8449 size_t own_conn_len
;
8451 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
8453 os_memset(intro
, 0, sizeof(*intro
));
8454 os_memset(&info
, 0, sizeof(info
));
8459 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
8461 wpa_printf(MSG_ERROR
,
8462 "DPP: Failed to parse local C-sign-key information");
8466 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
8467 net_access_key_len
);
8469 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8473 pos
= os_strchr(own_connector
, '.');
8475 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
8479 end
= os_strchr(pos
, '.');
8481 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
8484 own_conn
= base64_url_decode(pos
, end
- pos
, &own_conn_len
);
8486 wpa_printf(MSG_DEBUG
,
8487 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8491 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
8493 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
8497 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
8498 peer_connector
, peer_connector_len
);
8499 signed_connector
= os_malloc(peer_connector_len
+ 1);
8500 if (!signed_connector
)
8502 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
8503 signed_connector
[peer_connector_len
] = '\0';
8505 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
8506 if (res
!= DPP_STATUS_OK
) {
8511 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
8513 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
8514 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8518 if (!dpp_connector_match_groups(own_root
, root
)) {
8519 wpa_printf(MSG_DEBUG
,
8520 "DPP: Peer connector does not include compatible group netrole with own connector");
8521 ret
= DPP_STATUS_NO_MATCH
;
8525 token
= json_get_member(root
, "expiry");
8526 if (!token
|| token
->type
!= JSON_STRING
) {
8527 wpa_printf(MSG_DEBUG
,
8528 "DPP: No expiry string found - connector does not expire");
8530 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
8531 if (dpp_key_expired(token
->string
, expiry
)) {
8532 wpa_printf(MSG_DEBUG
,
8533 "DPP: Connector (netAccessKey) has expired");
8534 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8539 netkey
= json_get_member(root
, "netAccessKey");
8540 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
8541 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
8542 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8546 peer_key
= dpp_parse_jwk(netkey
, &curve
);
8548 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8551 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
8553 if (own_curve
!= curve
) {
8554 wpa_printf(MSG_DEBUG
,
8555 "DPP: Mismatching netAccessKey curves (%s != %s)",
8556 own_curve
->name
, curve
->name
);
8557 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8561 /* ECDH: N = nk * PK */
8562 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
8565 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
8568 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8569 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
8570 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
8573 intro
->pmk_len
= curve
->hash_len
;
8575 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8576 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
8577 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
8581 ret
= DPP_STATUS_OK
;
8583 if (ret
!= DPP_STATUS_OK
)
8584 os_memset(intro
, 0, sizeof(*intro
));
8585 os_memset(Nx
, 0, sizeof(Nx
));
8587 os_free(signed_connector
);
8588 os_free(info
.payload
);
8589 EVP_PKEY_free(own_key
);
8590 wpabuf_free(own_key_pub
);
8591 EVP_PKEY_free(peer_key
);
8592 EVP_PKEY_free(csign
);
8594 json_free(own_root
);
8599 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
8603 size_t len
= curve
->prime_len
;
8607 switch (curve
->ike_group
) {
8609 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
8610 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
8613 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
8614 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
8617 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
8618 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
8621 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
8622 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
8625 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
8626 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
8629 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
8630 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
8636 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8639 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
8640 EC_GROUP_free(group
);
8645 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
8646 const u8
*mac_init
, const char *code
,
8647 const char *identifier
, BN_CTX
*bnctx
,
8648 EC_GROUP
**ret_group
)
8650 u8 hash
[DPP_MAX_HASH_LEN
];
8653 unsigned int num_elem
= 0;
8654 EC_POINT
*Qi
= NULL
;
8655 EVP_PKEY
*Pi
= NULL
;
8656 EC_KEY
*Pi_ec
= NULL
;
8657 const EC_POINT
*Pi_point
;
8658 BIGNUM
*hash_bn
= NULL
;
8659 const EC_GROUP
*group
= NULL
;
8660 EC_GROUP
*group2
= NULL
;
8662 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8664 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
8665 addr
[num_elem
] = mac_init
;
8666 len
[num_elem
] = ETH_ALEN
;
8669 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8671 addr
[num_elem
] = (const u8
*) identifier
;
8672 len
[num_elem
] = os_strlen(identifier
);
8675 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8676 addr
[num_elem
] = (const u8
*) code
;
8677 len
[num_elem
] = os_strlen(code
);
8679 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8681 wpa_hexdump_key(MSG_DEBUG
,
8682 "DPP: H(MAC-Initiator | [identifier |] code)",
8683 hash
, curve
->hash_len
);
8684 Pi
= dpp_pkex_get_role_elem(curve
, 1);
8687 dpp_debug_print_key("DPP: Pi", Pi
);
8688 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
8691 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
8693 group
= EC_KEY_get0_group(Pi_ec
);
8696 group2
= EC_GROUP_dup(group
);
8699 Qi
= EC_POINT_new(group2
);
8701 EC_GROUP_free(group2
);
8704 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8706 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
8708 if (EC_POINT_is_at_infinity(group
, Qi
)) {
8709 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
8712 dpp_debug_print_point("DPP: Qi", group
, Qi
);
8716 BN_clear_free(hash_bn
);
8717 if (ret_group
&& Qi
)
8718 *ret_group
= group2
;
8720 EC_GROUP_free(group2
);
8729 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
8730 const u8
*mac_resp
, const char *code
,
8731 const char *identifier
, BN_CTX
*bnctx
,
8732 EC_GROUP
**ret_group
)
8734 u8 hash
[DPP_MAX_HASH_LEN
];
8737 unsigned int num_elem
= 0;
8738 EC_POINT
*Qr
= NULL
;
8739 EVP_PKEY
*Pr
= NULL
;
8740 EC_KEY
*Pr_ec
= NULL
;
8741 const EC_POINT
*Pr_point
;
8742 BIGNUM
*hash_bn
= NULL
;
8743 const EC_GROUP
*group
= NULL
;
8744 EC_GROUP
*group2
= NULL
;
8746 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8748 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
8749 addr
[num_elem
] = mac_resp
;
8750 len
[num_elem
] = ETH_ALEN
;
8753 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8755 addr
[num_elem
] = (const u8
*) identifier
;
8756 len
[num_elem
] = os_strlen(identifier
);
8759 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8760 addr
[num_elem
] = (const u8
*) code
;
8761 len
[num_elem
] = os_strlen(code
);
8763 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8765 wpa_hexdump_key(MSG_DEBUG
,
8766 "DPP: H(MAC-Responder | [identifier |] code)",
8767 hash
, curve
->hash_len
);
8768 Pr
= dpp_pkex_get_role_elem(curve
, 0);
8771 dpp_debug_print_key("DPP: Pr", Pr
);
8772 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
8775 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
8777 group
= EC_KEY_get0_group(Pr_ec
);
8780 group2
= EC_GROUP_dup(group
);
8783 Qr
= EC_POINT_new(group2
);
8785 EC_GROUP_free(group2
);
8788 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8790 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
8792 if (EC_POINT_is_at_infinity(group
, Qr
)) {
8793 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
8796 dpp_debug_print_point("DPP: Qr", group
, Qr
);
8800 BN_clear_free(hash_bn
);
8801 if (ret_group
&& Qr
)
8802 *ret_group
= group2
;
8804 EC_GROUP_free(group2
);
8813 #ifdef CONFIG_TESTING_OPTIONS
8814 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
8815 const struct dpp_curve_params
*curve
)
8823 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8828 point
= EC_POINT_new(group
);
8831 if (!ctx
|| !point
|| !x
|| !y
)
8834 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
8837 /* Generate a random y coordinate that results in a point that is not
8840 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
8843 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
8845 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
8846 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8847 * return an error from EC_POINT_set_affine_coordinates_GFp()
8848 * when the point is not on the curve. */
8850 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
8852 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
8855 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
8859 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
8860 curve
->prime_len
) < 0 ||
8861 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
8862 curve
->prime_len
) < 0)
8868 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
8871 EC_POINT_free(point
);
8873 EC_GROUP_free(group
);
8877 #endif /* CONFIG_TESTING_OPTIONS */
8880 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
8882 EC_KEY
*X_ec
= NULL
;
8883 const EC_POINT
*X_point
;
8884 BN_CTX
*bnctx
= NULL
;
8885 EC_GROUP
*group
= NULL
;
8886 EC_POINT
*Qi
= NULL
, *M
= NULL
;
8887 struct wpabuf
*M_buf
= NULL
;
8888 BIGNUM
*Mx
= NULL
, *My
= NULL
;
8889 struct wpabuf
*msg
= NULL
;
8891 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8893 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
8895 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8896 bnctx
= BN_CTX_new();
8899 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
8900 pkex
->identifier
, bnctx
, &group
);
8904 /* Generate a random ephemeral keypair x/X */
8905 #ifdef CONFIG_TESTING_OPTIONS
8906 if (dpp_pkex_ephemeral_key_override_len
) {
8907 const struct dpp_curve_params
*tmp_curve
;
8909 wpa_printf(MSG_INFO
,
8910 "DPP: TESTING - override ephemeral key x/X");
8911 pkex
->x
= dpp_set_keypair(&tmp_curve
,
8912 dpp_pkex_ephemeral_key_override
,
8913 dpp_pkex_ephemeral_key_override_len
);
8915 pkex
->x
= dpp_gen_keypair(curve
);
8917 #else /* CONFIG_TESTING_OPTIONS */
8918 pkex
->x
= dpp_gen_keypair(curve
);
8919 #endif /* CONFIG_TESTING_OPTIONS */
8924 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
8927 X_point
= EC_KEY_get0_public_key(X_ec
);
8930 dpp_debug_print_point("DPP: X", group
, X_point
);
8931 M
= EC_POINT_new(group
);
8934 if (!M
|| !Mx
|| !My
||
8935 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
8936 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
8938 dpp_debug_print_point("DPP: M", group
, M
);
8940 /* Initiator -> Responder: group, [identifier,] M */
8942 if (pkex
->identifier
)
8943 attr_len
+= 4 + os_strlen(pkex
->identifier
);
8944 attr_len
+= 4 + 2 * curve
->prime_len
;
8945 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
8949 #ifdef CONFIG_TESTING_OPTIONS
8950 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
8951 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
8952 goto skip_finite_cyclic_group
;
8954 #endif /* CONFIG_TESTING_OPTIONS */
8956 /* Finite Cyclic Group attribute */
8957 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
8958 wpabuf_put_le16(msg
, 2);
8959 wpabuf_put_le16(msg
, curve
->ike_group
);
8961 #ifdef CONFIG_TESTING_OPTIONS
8962 skip_finite_cyclic_group
:
8963 #endif /* CONFIG_TESTING_OPTIONS */
8965 /* Code Identifier attribute */
8966 if (pkex
->identifier
) {
8967 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
8968 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
8969 wpabuf_put_str(msg
, pkex
->identifier
);
8972 #ifdef CONFIG_TESTING_OPTIONS
8973 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8974 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
8977 #endif /* CONFIG_TESTING_OPTIONS */
8979 /* M in Encrypted Key attribute */
8980 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
8981 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
8983 #ifdef CONFIG_TESTING_OPTIONS
8984 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8985 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
8986 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
8990 #endif /* CONFIG_TESTING_OPTIONS */
8992 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
8993 curve
->prime_len
) < 0 ||
8994 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
8995 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
8996 curve
->prime_len
) < 0)
9007 EC_GROUP_free(group
);
9010 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
9017 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
9019 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
9023 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
9025 const char *identifier
,
9028 struct dpp_pkex
*pkex
;
9030 #ifdef CONFIG_TESTING_OPTIONS
9031 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
9032 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
9033 MAC2STR(dpp_pkex_own_mac_override
));
9034 own_mac
= dpp_pkex_own_mac_override
;
9036 #endif /* CONFIG_TESTING_OPTIONS */
9038 pkex
= os_zalloc(sizeof(*pkex
));
9041 pkex
->msg_ctx
= msg_ctx
;
9042 pkex
->initiator
= 1;
9044 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9046 pkex
->identifier
= os_strdup(identifier
);
9047 if (!pkex
->identifier
)
9050 pkex
->code
= os_strdup(code
);
9053 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
9054 if (!pkex
->exchange_req
)
9058 dpp_pkex_free(pkex
);
9063 static struct wpabuf
*
9064 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
9065 enum dpp_status_error status
,
9066 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
9068 struct wpabuf
*msg
= NULL
;
9070 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9072 /* Initiator -> Responder: DPP Status, [identifier,] N */
9074 if (pkex
->identifier
)
9075 attr_len
+= 4 + os_strlen(pkex
->identifier
);
9076 attr_len
+= 4 + 2 * curve
->prime_len
;
9077 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
9081 #ifdef CONFIG_TESTING_OPTIONS
9082 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
9083 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
9087 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
9088 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
9091 #endif /* CONFIG_TESTING_OPTIONS */
9094 dpp_build_attr_status(msg
, status
);
9096 #ifdef CONFIG_TESTING_OPTIONS
9098 #endif /* CONFIG_TESTING_OPTIONS */
9100 /* Code Identifier attribute */
9101 if (pkex
->identifier
) {
9102 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
9103 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
9104 wpabuf_put_str(msg
, pkex
->identifier
);
9107 if (status
!= DPP_STATUS_OK
)
9108 goto skip_encrypted_key
;
9110 #ifdef CONFIG_TESTING_OPTIONS
9111 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9112 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
9113 goto skip_encrypted_key
;
9115 #endif /* CONFIG_TESTING_OPTIONS */
9117 /* N in Encrypted Key attribute */
9118 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
9119 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
9121 #ifdef CONFIG_TESTING_OPTIONS
9122 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9123 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
9124 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
9126 goto skip_encrypted_key
;
9128 #endif /* CONFIG_TESTING_OPTIONS */
9130 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
9131 curve
->prime_len
) < 0 ||
9132 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
9133 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
9134 curve
->prime_len
) < 0)
9138 if (status
== DPP_STATUS_BAD_GROUP
) {
9139 /* Finite Cyclic Group attribute */
9140 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
9141 wpabuf_put_le16(msg
, 2);
9142 wpabuf_put_le16(msg
, curve
->ike_group
);
9152 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
9153 const u8
*Mx
, size_t Mx_len
,
9154 const u8
*Nx
, size_t Nx_len
,
9156 const u8
*Kx
, size_t Kx_len
,
9157 u8
*z
, unsigned int hash_len
)
9159 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
9164 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9167 /* HKDF-Extract(<>, IKM=K.x) */
9168 os_memset(salt
, 0, hash_len
);
9169 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
9171 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
9173 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
9174 info
= os_malloc(info_len
);
9178 os_memcpy(pos
, mac_init
, ETH_ALEN
);
9180 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
9182 os_memcpy(pos
, Mx
, Mx_len
);
9184 os_memcpy(pos
, Nx
, Nx_len
);
9186 os_memcpy(pos
, code
, os_strlen(code
));
9188 /* HKDF-Expand(PRK, info, L) */
9190 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9192 else if (hash_len
== 48)
9193 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9195 else if (hash_len
== 64)
9196 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9201 os_memset(prk
, 0, hash_len
);
9205 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
9211 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
9212 const char *identifier
)
9214 if (!attr_id
&& identifier
) {
9215 wpa_printf(MSG_DEBUG
,
9216 "DPP: No PKEX code identifier received, but expected one");
9220 if (attr_id
&& !identifier
) {
9221 wpa_printf(MSG_DEBUG
,
9222 "DPP: PKEX code identifier received, but not expecting one");
9226 if (attr_id
&& identifier
&&
9227 (os_strlen(identifier
) != attr_id_len
||
9228 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
9229 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
9237 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
9238 struct dpp_bootstrap_info
*bi
,
9241 const char *identifier
,
9243 const u8
*buf
, size_t len
)
9245 const u8
*attr_group
, *attr_id
, *attr_key
;
9246 u16 attr_group_len
, attr_id_len
, attr_key_len
;
9247 const struct dpp_curve_params
*curve
= bi
->curve
;
9249 struct dpp_pkex
*pkex
= NULL
;
9250 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
9251 BN_CTX
*bnctx
= NULL
;
9252 EC_GROUP
*group
= NULL
;
9253 BIGNUM
*Mx
= NULL
, *My
= NULL
;
9254 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
9255 const EC_POINT
*Y_point
;
9256 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9257 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9261 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
9262 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9263 "PKEX counter t limit reached - ignore message");
9267 #ifdef CONFIG_TESTING_OPTIONS
9268 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9269 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9270 MAC2STR(dpp_pkex_peer_mac_override
));
9271 peer_mac
= dpp_pkex_peer_mac_override
;
9273 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
9274 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
9275 MAC2STR(dpp_pkex_own_mac_override
));
9276 own_mac
= dpp_pkex_own_mac_override
;
9278 #endif /* CONFIG_TESTING_OPTIONS */
9281 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
9283 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
9286 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
9288 if (!attr_group
|| attr_group_len
!= 2) {
9289 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9290 "Missing or invalid Finite Cyclic Group attribute");
9293 ike_group
= WPA_GET_LE16(attr_group
);
9294 if (ike_group
!= curve
->ike_group
) {
9295 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9296 "Mismatching PKEX curve: peer=%u own=%u",
9297 ike_group
, curve
->ike_group
);
9298 pkex
= os_zalloc(sizeof(*pkex
));
9303 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
9304 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
9305 if (!pkex
->exchange_resp
)
9310 /* M in Encrypted Key attribute */
9311 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
9313 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
9314 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
9315 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9316 "Missing Encrypted Key attribute");
9320 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9321 bnctx
= BN_CTX_new();
9324 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
9330 X
= EC_POINT_new(group
);
9331 M
= EC_POINT_new(group
);
9332 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9333 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9334 if (!X
|| !M
|| !Mx
|| !My
||
9335 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
9336 EC_POINT_is_at_infinity(group
, M
) ||
9337 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
9338 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
9339 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
9340 EC_POINT_is_at_infinity(group
, X
) ||
9341 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
9342 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9343 "Invalid Encrypted Key value");
9347 dpp_debug_print_point("DPP: M", group
, M
);
9348 dpp_debug_print_point("DPP: X'", group
, X
);
9350 pkex
= os_zalloc(sizeof(*pkex
));
9353 pkex
->t
= bi
->pkex_t
;
9354 pkex
->msg_ctx
= msg_ctx
;
9356 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9357 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9359 pkex
->identifier
= os_strdup(identifier
);
9360 if (!pkex
->identifier
)
9363 pkex
->code
= os_strdup(code
);
9367 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
9369 X_ec
= EC_KEY_new();
9371 EC_KEY_set_group(X_ec
, group
) != 1 ||
9372 EC_KEY_set_public_key(X_ec
, X
) != 1)
9374 pkex
->x
= EVP_PKEY_new();
9376 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
9379 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9380 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
9384 /* Generate a random ephemeral keypair y/Y */
9385 #ifdef CONFIG_TESTING_OPTIONS
9386 if (dpp_pkex_ephemeral_key_override_len
) {
9387 const struct dpp_curve_params
*tmp_curve
;
9389 wpa_printf(MSG_INFO
,
9390 "DPP: TESTING - override ephemeral key y/Y");
9391 pkex
->y
= dpp_set_keypair(&tmp_curve
,
9392 dpp_pkex_ephemeral_key_override
,
9393 dpp_pkex_ephemeral_key_override_len
);
9395 pkex
->y
= dpp_gen_keypair(curve
);
9397 #else /* CONFIG_TESTING_OPTIONS */
9398 pkex
->y
= dpp_gen_keypair(curve
);
9399 #endif /* CONFIG_TESTING_OPTIONS */
9404 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
9407 Y_point
= EC_KEY_get0_public_key(Y_ec
);
9410 dpp_debug_print_point("DPP: Y", group
, Y_point
);
9411 N
= EC_POINT_new(group
);
9414 if (!N
|| !Nx
|| !Ny
||
9415 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
9416 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
9418 dpp_debug_print_point("DPP: N", group
, N
);
9420 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
9422 if (!pkex
->exchange_resp
)
9426 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
9429 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9432 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9434 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
9435 pkex
->Mx
, curve
->prime_len
,
9436 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
9437 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
9438 os_memset(Kx
, 0, Kx_len
);
9442 pkex
->exchange_done
= 1;
9457 EC_GROUP_free(group
);
9460 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
9461 dpp_pkex_free(pkex
);
9467 static struct wpabuf
*
9468 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
9469 const struct wpabuf
*A_pub
, const u8
*u
)
9471 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9472 struct wpabuf
*msg
= NULL
;
9473 size_t clear_len
, attr_len
;
9474 struct wpabuf
*clear
= NULL
;
9480 /* {A, u, [bootstrapping info]}z */
9481 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9482 clear
= wpabuf_alloc(clear_len
);
9483 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9484 #ifdef CONFIG_TESTING_OPTIONS
9485 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
9487 #endif /* CONFIG_TESTING_OPTIONS */
9488 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
9492 #ifdef CONFIG_TESTING_OPTIONS
9493 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9494 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9495 goto skip_bootstrap_key
;
9497 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9498 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9499 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9500 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9501 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9503 goto skip_bootstrap_key
;
9505 #endif /* CONFIG_TESTING_OPTIONS */
9507 /* A in Bootstrap Key attribute */
9508 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9509 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
9510 wpabuf_put_buf(clear
, A_pub
);
9512 #ifdef CONFIG_TESTING_OPTIONS
9514 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
9515 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
9516 goto skip_i_auth_tag
;
9518 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
9519 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
9520 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9521 wpabuf_put_le16(clear
, curve
->hash_len
);
9522 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
9523 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
9524 goto skip_i_auth_tag
;
9526 #endif /* CONFIG_TESTING_OPTIONS */
9528 /* u in I-Auth tag attribute */
9529 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9530 wpabuf_put_le16(clear
, curve
->hash_len
);
9531 wpabuf_put_data(clear
, u
, curve
->hash_len
);
9533 #ifdef CONFIG_TESTING_OPTIONS
9535 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
9536 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9537 goto skip_wrapped_data
;
9539 #endif /* CONFIG_TESTING_OPTIONS */
9541 addr
[0] = wpabuf_head_u8(msg
) + 2;
9542 len
[0] = DPP_HDR_LEN
;
9545 len
[1] = sizeof(octet
);
9546 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9547 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9549 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9550 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9551 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9553 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9554 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9555 wpabuf_head(clear
), wpabuf_len(clear
),
9556 2, addr
, len
, wrapped
) < 0)
9558 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9559 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9561 #ifdef CONFIG_TESTING_OPTIONS
9562 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
9563 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9564 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9567 #endif /* CONFIG_TESTING_OPTIONS */
9580 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
9582 const u8
*buf
, size_t buflen
)
9584 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
9585 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
9586 EC_GROUP
*group
= NULL
;
9587 BN_CTX
*bnctx
= NULL
;
9588 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9589 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9590 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
9591 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9592 EC_KEY
*Y_ec
= NULL
;
9593 size_t Jx_len
, Kx_len
;
9594 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9597 u8 u
[DPP_MAX_HASH_LEN
];
9600 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
9603 #ifdef CONFIG_TESTING_OPTIONS
9604 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
9605 wpa_printf(MSG_INFO
,
9606 "DPP: TESTING - stop at PKEX Exchange Response");
9611 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9612 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9613 MAC2STR(dpp_pkex_peer_mac_override
));
9614 peer_mac
= dpp_pkex_peer_mac_override
;
9616 #endif /* CONFIG_TESTING_OPTIONS */
9618 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9620 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
9622 if (!attr_status
|| attr_status_len
!= 1) {
9623 dpp_pkex_fail(pkex
, "No DPP Status attribute");
9626 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
9628 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
9629 attr_group
= dpp_get_attr(buf
, buflen
,
9630 DPP_ATTR_FINITE_CYCLIC_GROUP
,
9632 if (attr_group
&& attr_group_len
== 2) {
9633 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9634 "Peer indicated mismatching PKEX group - proposed %u",
9635 WPA_GET_LE16(attr_group
));
9640 if (attr_status
[0] != DPP_STATUS_OK
) {
9641 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
9646 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
9648 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
9649 pkex
->identifier
)) {
9650 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
9654 /* N in Encrypted Key attribute */
9655 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
9657 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
9658 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
9662 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9663 bnctx
= BN_CTX_new();
9666 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
9667 pkex
->identifier
, bnctx
, &group
);
9672 Y
= EC_POINT_new(group
);
9673 N
= EC_POINT_new(group
);
9674 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9675 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9676 if (!Y
|| !N
|| !Nx
|| !Ny
||
9677 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
9678 EC_POINT_is_at_infinity(group
, N
) ||
9679 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
9680 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
9681 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
9682 EC_POINT_is_at_infinity(group
, Y
) ||
9683 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
9684 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
9688 dpp_debug_print_point("DPP: N", group
, N
);
9689 dpp_debug_print_point("DPP: Y'", group
, Y
);
9691 pkex
->exchange_done
= 1;
9693 /* ECDH: J = a * Y’ */
9694 Y_ec
= EC_KEY_new();
9696 EC_KEY_set_group(Y_ec
, group
) != 1 ||
9697 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
9699 pkex
->y
= EVP_PKEY_new();
9701 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
9703 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
9706 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9709 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9710 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9711 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9712 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9713 if (!A_pub
|| !Y_pub
|| !X_pub
)
9715 addr
[0] = pkex
->own_mac
;
9717 addr
[1] = wpabuf_head(A_pub
);
9718 len
[1] = wpabuf_len(A_pub
) / 2;
9719 addr
[2] = wpabuf_head(Y_pub
);
9720 len
[2] = wpabuf_len(Y_pub
) / 2;
9721 addr
[3] = wpabuf_head(X_pub
);
9722 len
[3] = wpabuf_len(X_pub
) / 2;
9723 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9725 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
9728 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
9731 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9734 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9736 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
9737 pkex
->Mx
, curve
->prime_len
,
9738 attr_key
/* N.x */, attr_key_len
/ 2,
9739 pkex
->code
, Kx
, Kx_len
,
9740 pkex
->z
, curve
->hash_len
);
9741 os_memset(Kx
, 0, Kx_len
);
9745 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
9760 EC_GROUP_free(group
);
9763 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
9768 static struct wpabuf
*
9769 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
9770 const struct wpabuf
*B_pub
, const u8
*v
)
9772 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9773 struct wpabuf
*msg
= NULL
;
9778 struct wpabuf
*clear
= NULL
;
9779 size_t clear_len
, attr_len
;
9781 /* {B, v [bootstrapping info]}z */
9782 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9783 clear
= wpabuf_alloc(clear_len
);
9784 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9785 #ifdef CONFIG_TESTING_OPTIONS
9786 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
9788 #endif /* CONFIG_TESTING_OPTIONS */
9789 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
9793 #ifdef CONFIG_TESTING_OPTIONS
9794 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9795 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9796 goto skip_bootstrap_key
;
9798 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9799 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9800 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9801 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9802 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9804 goto skip_bootstrap_key
;
9806 #endif /* CONFIG_TESTING_OPTIONS */
9808 /* B in Bootstrap Key attribute */
9809 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9810 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
9811 wpabuf_put_buf(clear
, B_pub
);
9813 #ifdef CONFIG_TESTING_OPTIONS
9815 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
9816 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
9817 goto skip_r_auth_tag
;
9819 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
9820 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
9821 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9822 wpabuf_put_le16(clear
, curve
->hash_len
);
9823 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
9824 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
9825 goto skip_r_auth_tag
;
9827 #endif /* CONFIG_TESTING_OPTIONS */
9829 /* v in R-Auth tag attribute */
9830 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9831 wpabuf_put_le16(clear
, curve
->hash_len
);
9832 wpabuf_put_data(clear
, v
, curve
->hash_len
);
9834 #ifdef CONFIG_TESTING_OPTIONS
9836 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
9837 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9838 goto skip_wrapped_data
;
9840 #endif /* CONFIG_TESTING_OPTIONS */
9842 addr
[0] = wpabuf_head_u8(msg
) + 2;
9843 len
[0] = DPP_HDR_LEN
;
9846 len
[1] = sizeof(octet
);
9847 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9848 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9850 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9851 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9852 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9854 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9855 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9856 wpabuf_head(clear
), wpabuf_len(clear
),
9857 2, addr
, len
, wrapped
) < 0)
9859 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9860 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9862 #ifdef CONFIG_TESTING_OPTIONS
9863 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
9864 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9865 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9868 #endif /* CONFIG_TESTING_OPTIONS */
9881 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
9883 const u8
*buf
, size_t buflen
)
9885 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9886 size_t Jx_len
, Lx_len
;
9887 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
9888 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
9889 const u8
*wrapped_data
, *b_key
, *peer_u
;
9890 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
9894 u8
*unwrapped
= NULL
;
9895 size_t unwrapped_len
= 0;
9896 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9897 struct wpabuf
*B_pub
= NULL
;
9898 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
9900 #ifdef CONFIG_TESTING_OPTIONS
9901 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
9902 wpa_printf(MSG_INFO
,
9903 "DPP: TESTING - stop at PKEX CR Request");
9907 #endif /* CONFIG_TESTING_OPTIONS */
9909 if (!pkex
->exchange_done
|| pkex
->failed
||
9910 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
9913 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
9915 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
9917 "Missing or invalid required Wrapped Data attribute");
9921 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9922 wrapped_data
, wrapped_data_len
);
9923 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
9924 unwrapped
= os_malloc(unwrapped_len
);
9929 len
[0] = DPP_HDR_LEN
;
9932 len
[1] = sizeof(octet
);
9933 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9934 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9936 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
9937 wrapped_data
, wrapped_data_len
,
9938 2, addr
, len
, unwrapped
) < 0) {
9940 "AES-SIV decryption failed - possible PKEX code mismatch");
9945 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
9946 unwrapped
, unwrapped_len
);
9948 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
9949 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
9953 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
9955 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
9956 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
9959 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
9961 if (!pkex
->peer_bootstrap_key
) {
9962 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
9965 dpp_debug_print_key("DPP: Peer bootstrap public key",
9966 pkex
->peer_bootstrap_key
);
9968 /* ECDH: J' = y * A' */
9969 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
9972 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9975 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9976 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
9977 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9978 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9979 if (!A_pub
|| !Y_pub
|| !X_pub
)
9981 addr
[0] = pkex
->peer_mac
;
9983 addr
[1] = wpabuf_head(A_pub
);
9984 len
[1] = wpabuf_len(A_pub
) / 2;
9985 addr
[2] = wpabuf_head(Y_pub
);
9986 len
[2] = wpabuf_len(Y_pub
) / 2;
9987 addr
[3] = wpabuf_head(X_pub
);
9988 len
[3] = wpabuf_len(X_pub
) / 2;
9989 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9992 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
9994 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
9995 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
9996 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
9997 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
9998 u
, curve
->hash_len
);
9999 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
10003 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
10005 /* ECDH: L = b * X' */
10006 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
10009 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
10012 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
10013 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
10016 addr
[0] = pkex
->own_mac
;
10018 addr
[1] = wpabuf_head(B_pub
);
10019 len
[1] = wpabuf_len(B_pub
) / 2;
10020 addr
[2] = wpabuf_head(X_pub
);
10021 len
[2] = wpabuf_len(X_pub
) / 2;
10022 addr
[3] = wpabuf_head(Y_pub
);
10023 len
[3] = wpabuf_len(Y_pub
) / 2;
10024 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
10026 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
10028 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
10033 os_free(unwrapped
);
10034 wpabuf_free(A_pub
);
10035 wpabuf_free(B_pub
);
10036 wpabuf_free(X_pub
);
10037 wpabuf_free(Y_pub
);
10040 wpa_printf(MSG_DEBUG
,
10041 "DPP: PKEX Commit-Reveal Request processing failed");
10046 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
10047 const u8
*buf
, size_t buflen
)
10049 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
10050 const u8
*wrapped_data
, *b_key
, *peer_v
;
10051 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
10055 u8
*unwrapped
= NULL
;
10056 size_t unwrapped_len
= 0;
10058 u8 v
[DPP_MAX_HASH_LEN
];
10060 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
10061 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
10063 #ifdef CONFIG_TESTING_OPTIONS
10064 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
10065 wpa_printf(MSG_INFO
,
10066 "DPP: TESTING - stop at PKEX CR Response");
10070 #endif /* CONFIG_TESTING_OPTIONS */
10072 if (!pkex
->exchange_done
|| pkex
->failed
||
10073 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
10076 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
10077 &wrapped_data_len
);
10078 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
10079 dpp_pkex_fail(pkex
,
10080 "Missing or invalid required Wrapped Data attribute");
10084 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
10085 wrapped_data
, wrapped_data_len
);
10086 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
10087 unwrapped
= os_malloc(unwrapped_len
);
10092 len
[0] = DPP_HDR_LEN
;
10095 len
[1] = sizeof(octet
);
10096 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
10097 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
10099 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
10100 wrapped_data
, wrapped_data_len
,
10101 2, addr
, len
, unwrapped
) < 0) {
10102 dpp_pkex_fail(pkex
,
10103 "AES-SIV decryption failed - possible PKEX code mismatch");
10107 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
10108 unwrapped
, unwrapped_len
);
10110 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
10111 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
10115 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
10117 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
10118 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
10121 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
10123 if (!pkex
->peer_bootstrap_key
) {
10124 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
10127 dpp_debug_print_key("DPP: Peer bootstrap public key",
10128 pkex
->peer_bootstrap_key
);
10130 /* ECDH: L' = x * B' */
10131 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
10134 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
10137 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10138 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
10139 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
10140 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
10141 if (!B_pub
|| !X_pub
|| !Y_pub
)
10143 addr
[0] = pkex
->peer_mac
;
10145 addr
[1] = wpabuf_head(B_pub
);
10146 len
[1] = wpabuf_len(B_pub
) / 2;
10147 addr
[2] = wpabuf_head(X_pub
);
10148 len
[2] = wpabuf_len(X_pub
) / 2;
10149 addr
[3] = wpabuf_head(Y_pub
);
10150 len
[3] = wpabuf_len(Y_pub
) / 2;
10151 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
10154 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
10156 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
10157 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
10158 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
10159 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
10160 v
, curve
->hash_len
);
10161 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
10165 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
10169 wpabuf_free(B_pub
);
10170 wpabuf_free(X_pub
);
10171 wpabuf_free(Y_pub
);
10172 os_free(unwrapped
);
10179 void dpp_pkex_free(struct dpp_pkex
*pkex
)
10184 os_free(pkex
->identifier
);
10185 os_free(pkex
->code
);
10186 EVP_PKEY_free(pkex
->x
);
10187 EVP_PKEY_free(pkex
->y
);
10188 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
10189 wpabuf_free(pkex
->exchange_req
);
10190 wpabuf_free(pkex
->exchange_resp
);
10195 #ifdef CONFIG_TESTING_OPTIONS
10196 char * dpp_corrupt_connector_signature(const char *connector
)
10198 char *tmp
, *pos
, *signed3
= NULL
;
10199 unsigned char *signature
= NULL
;
10200 size_t signature_len
= 0, signed3_len
;
10202 tmp
= os_zalloc(os_strlen(connector
) + 5);
10205 os_memcpy(tmp
, connector
, os_strlen(connector
));
10207 pos
= os_strchr(tmp
, '.');
10211 pos
= os_strchr(pos
+ 1, '.');
10216 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
10218 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
10219 if (!signature
|| signature_len
== 0)
10221 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
10222 signature
, signature_len
);
10223 signature
[signature_len
- 1] ^= 0x01;
10224 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
10225 signature
, signature_len
);
10226 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
10229 os_memcpy(pos
, signed3
, signed3_len
);
10230 pos
[signed3_len
] = '\0';
10231 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
10235 os_free(signature
);
10243 #endif /* CONFIG_TESTING_OPTIONS */
10248 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
10249 size_t net_access_key_len
)
10251 struct wpabuf
*pub
= NULL
;
10253 struct dpp_pfs
*pfs
;
10255 pfs
= os_zalloc(sizeof(*pfs
));
10259 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
10260 net_access_key_len
);
10262 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
10265 EVP_PKEY_free(own_key
);
10267 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
10271 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
10272 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
10276 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
10279 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
10280 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
10281 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
10282 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
10283 wpabuf_put_buf(pfs
->ie
, pub
);
10285 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
10296 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
10298 if (peer_ie_len
< 2)
10300 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
10301 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
10305 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
10307 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
10308 if (!pfs
->secret
) {
10309 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
10312 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
10317 void dpp_pfs_free(struct dpp_pfs
*pfs
)
10321 crypto_ecdh_deinit(pfs
->ecdh
);
10322 wpabuf_free(pfs
->ie
);
10323 wpabuf_clear_free(pfs
->secret
);
10327 #endif /* CONFIG_DPP2 */
10330 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
10332 struct dpp_bootstrap_info
*bi
;
10333 unsigned int max_id
= 0;
10335 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10336 if (bi
->id
> max_id
)
10343 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
10345 struct dpp_bootstrap_info
*bi
, *tmp
;
10351 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
10352 struct dpp_bootstrap_info
, list
) {
10353 if (id
&& bi
->id
!= id
)
10357 if (dpp
->remove_bi
)
10358 dpp
->remove_bi(dpp
->cb_ctx
, bi
);
10359 #endif /* CONFIG_DPP2 */
10360 dl_list_del(&bi
->list
);
10361 dpp_bootstrap_info_free(bi
);
10365 return 0; /* flush succeeds regardless of entries found */
10366 return found
? 0 : -1;
10370 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
10373 struct dpp_bootstrap_info
*bi
;
10378 bi
= dpp_parse_uri(uri
);
10382 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10383 bi
->id
= dpp_next_id(dpp
);
10384 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10389 struct dpp_bootstrap_info
* dpp_add_nfc_uri(struct dpp_global
*dpp
,
10392 struct dpp_bootstrap_info
*bi
;
10397 bi
= dpp_parse_uri(uri
);
10401 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10402 bi
->id
= dpp_next_id(dpp
);
10403 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10408 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
10410 char *mac
= NULL
, *info
= NULL
, *curve
= NULL
;
10412 u8
*privkey
= NULL
;
10413 size_t privkey_len
= 0;
10415 struct dpp_bootstrap_info
*bi
;
10420 bi
= os_zalloc(sizeof(*bi
));
10424 if (os_strstr(cmd
, "type=qrcode"))
10425 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10426 else if (os_strstr(cmd
, "type=pkex"))
10427 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10428 else if (os_strstr(cmd
, "type=nfc-uri"))
10429 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10433 bi
->chan
= get_param(cmd
, " chan=");
10434 mac
= get_param(cmd
, " mac=");
10435 info
= get_param(cmd
, " info=");
10436 curve
= get_param(cmd
, " curve=");
10437 key
= get_param(cmd
, " key=");
10440 privkey_len
= os_strlen(key
) / 2;
10441 privkey
= os_malloc(privkey_len
);
10443 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10447 if (dpp_keygen(bi
, curve
, privkey
, privkey_len
) < 0 ||
10448 dpp_parse_uri_chan_list(bi
, bi
->chan
) < 0 ||
10449 dpp_parse_uri_mac(bi
, mac
) < 0 ||
10450 dpp_parse_uri_info(bi
, info
) < 0 ||
10451 dpp_gen_uri(bi
) < 0)
10454 bi
->id
= dpp_next_id(dpp
);
10455 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10462 str_clear_free(key
);
10463 bin_clear_free(privkey
, privkey_len
);
10464 dpp_bootstrap_info_free(bi
);
10469 struct dpp_bootstrap_info
*
10470 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
10472 struct dpp_bootstrap_info
*bi
;
10477 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10485 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
10487 unsigned int id_val
;
10489 if (os_strcmp(id
, "*") == 0) {
10497 return dpp_bootstrap_del(dpp
, id_val
);
10501 struct dpp_bootstrap_info
*
10502 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
10505 struct dpp_bootstrap_info
*bi
;
10507 bi
= os_zalloc(sizeof(*bi
));
10510 bi
->id
= dpp_next_id(dpp
);
10511 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10512 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
10514 bi
->freq
[0] = freq
;
10515 bi
->curve
= pkex
->own_bi
->curve
;
10516 bi
->pubkey
= pkex
->peer_bootstrap_key
;
10517 pkex
->peer_bootstrap_key
= NULL
;
10518 if (dpp_bootstrap_key_hash(bi
) < 0) {
10519 dpp_bootstrap_info_free(bi
);
10522 dpp_pkex_free(pkex
);
10523 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10528 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
10530 struct dpp_bootstrap_info
*bi
;
10532 bi
= dpp_bootstrap_get_id(dpp
, id
);
10539 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
10540 char *reply
, int reply_size
)
10542 struct dpp_bootstrap_info
*bi
;
10543 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
10545 bi
= dpp_bootstrap_get_id(dpp
, id
);
10548 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
10550 return os_snprintf(reply
, reply_size
, "type=%s\n"
10551 "mac_addr=" MACSTR
"\n"
10557 dpp_bootstrap_type_txt(bi
->type
),
10558 MAC2STR(bi
->mac_addr
),
10559 bi
->info
? bi
->info
: "",
10561 bi
->num_freq
== 1 ? bi
->freq
[0] : 0,
10567 int dpp_bootstrap_set(struct dpp_global
*dpp
, int id
, const char *params
)
10569 struct dpp_bootstrap_info
*bi
;
10571 bi
= dpp_bootstrap_get_id(dpp
, id
);
10575 str_clear_free(bi
->configurator_params
);
10578 bi
->configurator_params
= os_strdup(params
);
10579 return bi
->configurator_params
? 0 : -1;
10582 bi
->configurator_params
= NULL
;
10587 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
10588 const u8
*r_bootstrap
,
10589 struct dpp_bootstrap_info
**own_bi
,
10590 struct dpp_bootstrap_info
**peer_bi
)
10592 struct dpp_bootstrap_info
*bi
;
10599 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10600 if (!*own_bi
&& bi
->own
&&
10601 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
10602 SHA256_MAC_LEN
) == 0) {
10603 wpa_printf(MSG_DEBUG
,
10604 "DPP: Found matching own bootstrapping information");
10608 if (!*peer_bi
&& !bi
->own
&&
10609 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
10610 SHA256_MAC_LEN
) == 0) {
10611 wpa_printf(MSG_DEBUG
,
10612 "DPP: Found matching peer bootstrapping information");
10616 if (*own_bi
&& *peer_bi
)
10623 struct dpp_bootstrap_info
* dpp_bootstrap_find_chirp(struct dpp_global
*dpp
,
10626 struct dpp_bootstrap_info
*bi
;
10631 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10632 if (!bi
->own
&& os_memcmp(bi
->pubkey_hash_chirp
, hash
,
10633 SHA256_MAC_LEN
) == 0)
10639 #endif /* CONFIG_DPP2 */
10642 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info
*own_bi
,
10643 struct dpp_bootstrap_info
*peer_bi
)
10645 unsigned int i
, freq
= 0;
10646 enum hostapd_hw_mode mode
;
10647 u8 op_class
, channel
;
10650 if (peer_bi
->num_freq
== 0)
10651 return 0; /* no channel preference/constraint */
10653 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
10654 if (own_bi
->num_freq
== 0 ||
10655 freq_included(own_bi
->freq
, own_bi
->num_freq
,
10656 peer_bi
->freq
[i
])) {
10657 freq
= peer_bi
->freq
[i
];
10662 wpa_printf(MSG_DEBUG
, "DPP: No common channel found");
10666 mode
= ieee80211_freq_to_channel_ext(freq
, 0, 0, &op_class
, &channel
);
10667 if (mode
== NUM_HOSTAPD_MODES
) {
10668 wpa_printf(MSG_DEBUG
,
10669 "DPP: Could not determine operating class or channel number for %u MHz",
10673 wpa_printf(MSG_DEBUG
,
10674 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10675 freq
, op_class
, channel
);
10676 os_snprintf(chan
, sizeof(chan
), "%u/%u", op_class
, channel
);
10677 os_free(own_bi
->chan
);
10678 own_bi
->chan
= os_strdup(chan
);
10679 own_bi
->freq
[0] = freq
;
10680 own_bi
->num_freq
= 1;
10681 os_free(peer_bi
->chan
);
10682 peer_bi
->chan
= os_strdup(chan
);
10683 peer_bi
->freq
[0] = freq
;
10684 peer_bi
->num_freq
= 1;
10686 return dpp_gen_uri(own_bi
);
10690 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info
*own_bi
,
10691 struct dpp_bootstrap_info
*peer_bi
)
10693 if (peer_bi
->curve
== own_bi
->curve
)
10696 wpa_printf(MSG_DEBUG
,
10697 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10699 EVP_PKEY_free(own_bi
->pubkey
);
10700 own_bi
->pubkey
= NULL
;
10702 if (dpp_keygen(own_bi
, peer_bi
->curve
->name
, NULL
, 0) < 0 ||
10703 dpp_gen_uri(own_bi
) < 0)
10708 dl_list_del(&own_bi
->list
);
10709 dpp_bootstrap_info_free(own_bi
);
10714 int dpp_nfc_update_bi(struct dpp_bootstrap_info
*own_bi
,
10715 struct dpp_bootstrap_info
*peer_bi
)
10717 if (dpp_nfc_update_bi_channel(own_bi
, peer_bi
) < 0 ||
10718 dpp_nfc_update_bi_key(own_bi
, peer_bi
) < 0)
10724 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
10726 struct dpp_configurator
*conf
;
10727 unsigned int max_id
= 0;
10729 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
10731 if (conf
->id
> max_id
)
10738 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
10740 char *curve
= NULL
;
10742 u8
*privkey
= NULL
;
10743 size_t privkey_len
= 0;
10745 struct dpp_configurator
*conf
= NULL
;
10747 curve
= get_param(cmd
, " curve=");
10748 key
= get_param(cmd
, " key=");
10751 privkey_len
= os_strlen(key
) / 2;
10752 privkey
= os_malloc(privkey_len
);
10754 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10758 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
10762 conf
->id
= dpp_next_configurator_id(dpp
);
10763 dl_list_add(&dpp
->configurator
, &conf
->list
);
10768 str_clear_free(key
);
10769 bin_clear_free(privkey
, privkey_len
);
10770 dpp_configurator_free(conf
);
10775 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
10777 struct dpp_configurator
*conf
, *tmp
;
10783 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
10784 struct dpp_configurator
, list
) {
10785 if (id
&& conf
->id
!= id
)
10788 dl_list_del(&conf
->list
);
10789 dpp_configurator_free(conf
);
10793 return 0; /* flush succeeds regardless of entries found */
10794 return found
? 0 : -1;
10798 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
10800 unsigned int id_val
;
10802 if (os_strcmp(id
, "*") == 0) {
10810 return dpp_configurator_del(dpp
, id_val
);
10814 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
10815 char *buf
, size_t buflen
)
10817 struct dpp_configurator
*conf
;
10819 conf
= dpp_configurator_get_id(dpp
, id
);
10823 return dpp_configurator_get_key(conf
, buf
, buflen
);
10829 int dpp_configurator_from_backup(struct dpp_global
*dpp
,
10830 struct dpp_asymmetric_key
*key
)
10832 struct dpp_configurator
*conf
;
10833 const EC_KEY
*eckey
;
10834 const EC_GROUP
*group
;
10836 const struct dpp_curve_params
*curve
;
10840 eckey
= EVP_PKEY_get0_EC_KEY(key
->csign
);
10843 group
= EC_KEY_get0_group(eckey
);
10846 nid
= EC_GROUP_get_curve_name(group
);
10847 curve
= dpp_get_curve_nid(nid
);
10849 wpa_printf(MSG_INFO
, "DPP: Unsupported group in c-sign-key");
10853 conf
= os_zalloc(sizeof(*conf
));
10856 conf
->curve
= curve
;
10857 conf
->csign
= key
->csign
;
10860 if (dpp_configurator_gen_kid(conf
) < 0) {
10861 dpp_configurator_free(conf
);
10865 conf
->id
= dpp_next_configurator_id(dpp
);
10866 dl_list_add(&dpp
->configurator
, &conf
->list
);
10871 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
10872 void *timeout_ctx
);
10875 static void dpp_connection_free(struct dpp_connection
*conn
)
10877 if (conn
->sock
>= 0) {
10878 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
10880 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
10881 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10884 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout
,
10886 wpabuf_free(conn
->msg
);
10887 wpabuf_free(conn
->msg_out
);
10888 dpp_auth_deinit(conn
->auth
);
10893 static void dpp_connection_remove(struct dpp_connection
*conn
)
10895 dl_list_del(&conn
->list
);
10896 dpp_connection_free(conn
);
10900 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
10902 struct dpp_connection
*conn
, *tmp
;
10904 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
10906 dpp_connection_remove(conn
);
10910 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
10912 struct dpp_connection
*conn
, *tmp
;
10914 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
10916 dpp_connection_remove(conn
);
10921 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
10923 struct dpp_relay_controller
*ctrl
, *tmp
;
10928 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
10929 struct dpp_relay_controller
, list
) {
10930 dl_list_del(&ctrl
->list
);
10931 dpp_relay_controller_free(ctrl
);
10935 #endif /* CONFIG_DPP2 */
10938 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
10940 struct dpp_global
*dpp
;
10942 dpp
= os_zalloc(sizeof(*dpp
));
10945 dpp
->msg_ctx
= config
->msg_ctx
;
10947 dpp
->cb_ctx
= config
->cb_ctx
;
10948 dpp
->process_conf_obj
= config
->process_conf_obj
;
10949 dpp
->remove_bi
= config
->remove_bi
;
10950 #endif /* CONFIG_DPP2 */
10952 dl_list_init(&dpp
->bootstrap
);
10953 dl_list_init(&dpp
->configurator
);
10955 dl_list_init(&dpp
->controllers
);
10956 dl_list_init(&dpp
->tcp_init
);
10957 #endif /* CONFIG_DPP2 */
10963 void dpp_global_clear(struct dpp_global
*dpp
)
10968 dpp_bootstrap_del(dpp
, 0);
10969 dpp_configurator_del(dpp
, 0);
10971 dpp_tcp_init_flush(dpp
);
10972 dpp_relay_flush_controllers(dpp
);
10973 dpp_controller_stop(dpp
);
10974 #endif /* CONFIG_DPP2 */
10978 void dpp_global_deinit(struct dpp_global
*dpp
)
10980 dpp_global_clear(dpp
);
10987 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
10988 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
10989 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
10993 int dpp_relay_add_controller(struct dpp_global
*dpp
,
10994 struct dpp_relay_config
*config
)
10996 struct dpp_relay_controller
*ctrl
;
11001 ctrl
= os_zalloc(sizeof(*ctrl
));
11004 dl_list_init(&ctrl
->conn
);
11005 ctrl
->global
= dpp
;
11006 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
11007 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
11008 ctrl
->cb_ctx
= config
->cb_ctx
;
11009 ctrl
->tx
= config
->tx
;
11010 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
11011 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
11016 static struct dpp_relay_controller
*
11017 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
11019 struct dpp_relay_controller
*ctrl
;
11024 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
11026 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
11034 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
11036 struct dpp_authentication
*auth
= conn
->auth
;
11038 if (auth
->peer_version
>= 2 &&
11039 auth
->conf_resp_status
== DPP_STATUS_OK
) {
11040 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
11041 auth
->waiting_conf_result
= 1;
11045 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
11046 dpp_connection_remove(conn
);
11050 static int dpp_tcp_send(struct dpp_connection
*conn
)
11054 if (!conn
->msg_out
) {
11055 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
11056 conn
->write_eloop
= 0;
11059 res
= send(conn
->sock
,
11060 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
11061 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
11063 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
11065 dpp_connection_remove(conn
);
11069 conn
->msg_out_pos
+= res
;
11070 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
11071 wpa_printf(MSG_DEBUG
,
11072 "DPP: %u/%u bytes of message sent to Controller",
11073 (unsigned int) conn
->msg_out_pos
,
11074 (unsigned int) wpabuf_len(conn
->msg_out
));
11075 if (!conn
->write_eloop
&&
11076 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11077 dpp_conn_tx_ready
, conn
, NULL
) == 0)
11078 conn
->write_eloop
= 1;
11082 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
11083 wpabuf_free(conn
->msg_out
);
11084 conn
->msg_out
= NULL
;
11085 conn
->msg_out_pos
= 0;
11086 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
11087 conn
->write_eloop
= 0;
11088 if (!conn
->read_eloop
&&
11089 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
11090 dpp_controller_rx
, conn
, NULL
) == 0)
11091 conn
->read_eloop
= 1;
11092 if (conn
->on_tcp_tx_complete_remove
) {
11093 dpp_connection_remove(conn
);
11094 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
11096 dpp_controller_gas_done(conn
);
11097 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
11098 conn
->on_tcp_tx_complete_auth_ok
= 0;
11099 dpp_controller_auth_success(conn
, 1);
11106 static int dpp_tcp_send_msg(struct dpp_connection
*conn
,
11107 const struct wpabuf
*msg
)
11109 wpabuf_free(conn
->msg_out
);
11110 conn
->msg_out_pos
= 0;
11111 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11112 if (!conn
->msg_out
)
11114 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
11115 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
11116 wpabuf_len(msg
) - 1);
11118 if (dpp_tcp_send(conn
) == 1) {
11119 if (!conn
->write_eloop
) {
11120 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11124 conn
->write_eloop
= 1;
11132 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
11134 struct dpp_authentication
*auth
= conn
->auth
;
11135 struct wpabuf
*buf
;
11136 int netrole_ap
= 0; /* TODO: make this configurable */
11138 buf
= dpp_build_conf_req_helper(auth
, "Test", netrole_ap
, NULL
, NULL
);
11140 wpa_printf(MSG_DEBUG
,
11141 "DPP: No configuration request data available");
11145 dpp_tcp_send_msg(conn
, buf
);
11150 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
11153 struct dpp_authentication
*auth
= conn
->auth
;
11158 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
11159 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
11160 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
11161 #ifdef CONFIG_TESTING_OPTIONS
11162 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
11163 wpa_printf(MSG_INFO
,
11164 "DPP: TESTING - stop at Authentication Confirm");
11165 if (auth
->configurator
) {
11166 /* Prevent GAS response */
11167 auth
->auth_success
= 0;
11171 #endif /* CONFIG_TESTING_OPTIONS */
11173 if (!auth
->configurator
)
11174 dpp_controller_start_gas_client(conn
);
11178 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
11180 struct dpp_connection
*conn
= eloop_ctx
;
11182 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
11183 dpp_tcp_send(conn
);
11187 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
11188 const struct hostapd_ip_addr
*ipaddr
,
11191 struct sockaddr_in
*dst
;
11193 struct sockaddr_in6
*dst6
;
11194 #endif /* CONFIG_IPV6 */
11196 switch (ipaddr
->af
) {
11198 dst
= (struct sockaddr_in
*) addr
;
11199 os_memset(dst
, 0, sizeof(*dst
));
11200 dst
->sin_family
= AF_INET
;
11201 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
11202 dst
->sin_port
= htons(port
);
11203 *addrlen
= sizeof(*dst
);
11207 dst6
= (struct sockaddr_in6
*) addr
;
11208 os_memset(dst6
, 0, sizeof(*dst6
));
11209 dst6
->sin6_family
= AF_INET6
;
11210 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
11211 sizeof(struct in6_addr
));
11212 dst6
->sin6_port
= htons(port
);
11213 *addrlen
= sizeof(*dst6
);
11215 #endif /* CONFIG_IPV6 */
11224 static struct dpp_connection
*
11225 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
11228 struct dpp_connection
*conn
;
11229 struct sockaddr_storage addr
;
11233 if (dl_list_len(&ctrl
->conn
) >= 15) {
11234 wpa_printf(MSG_DEBUG
,
11235 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11239 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
11240 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
11243 conn
= os_zalloc(sizeof(*conn
));
11247 conn
->global
= ctrl
->global
;
11248 conn
->relay
= ctrl
;
11249 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
11252 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
11253 if (conn
->sock
< 0)
11255 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
11256 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
11258 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
11259 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11264 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
11265 if (errno
!= EINPROGRESS
) {
11266 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
11272 * Continue connecting in the background; eloop will call us
11273 * once the connection is ready (or failed).
11277 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11278 dpp_conn_tx_ready
, conn
, NULL
) < 0)
11280 conn
->write_eloop
= 1;
11282 /* TODO: eloop timeout to clear a connection if it does not complete
11285 dl_list_add(&ctrl
->conn
, &conn
->list
);
11288 dpp_connection_free(conn
);
11293 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
11295 struct wpabuf
*msg
;
11297 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
11300 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
11301 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
11302 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
11303 wpabuf_put_data(msg
, buf
, len
);
11304 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11309 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
11310 const u8
*buf
, size_t len
)
11312 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11314 wpa_printf(MSG_DEBUG
,
11315 "DPP: Continue already established Relay/Controller connection for this session");
11316 wpabuf_free(conn
->msg_out
);
11317 conn
->msg_out_pos
= 0;
11318 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11319 if (!conn
->msg_out
) {
11320 dpp_connection_remove(conn
);
11324 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11326 if (type
== DPP_PA_CONFIGURATION_RESULT
)
11327 conn
->on_tcp_tx_complete_remove
= 1;
11328 dpp_tcp_send(conn
);
11333 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
11334 const u8
*buf
, size_t len
, unsigned int freq
,
11335 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
11337 struct dpp_relay_controller
*ctrl
;
11338 struct dpp_connection
*conn
;
11339 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11341 /* Check if there is an already started session for this peer and if so,
11342 * continue that session (send this over TCP) and return 0.
11344 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
11345 type
!= DPP_PA_PEER_DISCOVERY_RESP
&&
11346 type
!= DPP_PA_PRESENCE_ANNOUNCEMENT
) {
11347 dl_list_for_each(ctrl
, &dpp
->controllers
,
11348 struct dpp_relay_controller
, list
) {
11349 dl_list_for_each(conn
, &ctrl
->conn
,
11350 struct dpp_connection
, list
) {
11351 if (os_memcmp(src
, conn
->mac_addr
,
11353 return dpp_relay_tx(conn
, hdr
, buf
, len
);
11361 if (type
== DPP_PA_PRESENCE_ANNOUNCEMENT
) {
11362 /* TODO: Could send this to all configured Controllers. For now,
11363 * only the first Controller is supported. */
11364 ctrl
= dl_list_first(&dpp
->controllers
,
11365 struct dpp_relay_controller
, list
);
11367 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
11372 wpa_printf(MSG_DEBUG
,
11373 "DPP: Authentication Request for a configured Controller");
11374 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
11378 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11379 if (!conn
->msg_out
) {
11380 dpp_connection_remove(conn
);
11383 /* Message will be sent in dpp_conn_tx_ready() */
11389 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
11392 struct dpp_relay_controller
*ctrl
;
11393 struct dpp_connection
*conn
, *found
= NULL
;
11394 struct wpabuf
*msg
;
11396 /* Check if there is a successfully completed authentication for this
11397 * and if so, continue that session (send this over TCP) and return 0.
11399 dl_list_for_each(ctrl
, &dpp
->controllers
,
11400 struct dpp_relay_controller
, list
) {
11403 dl_list_for_each(conn
, &ctrl
->conn
,
11404 struct dpp_connection
, list
) {
11405 if (os_memcmp(src
, conn
->mac_addr
,
11416 msg
= wpabuf_alloc(4 + 1 + data_len
);
11419 wpabuf_put_be32(msg
, 1 + data_len
);
11420 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
11421 wpabuf_put_data(msg
, data
, data_len
);
11422 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11424 wpabuf_free(conn
->msg_out
);
11425 conn
->msg_out_pos
= 0;
11426 conn
->msg_out
= msg
;
11427 dpp_tcp_send(conn
);
11432 static void dpp_controller_free(struct dpp_controller
*ctrl
)
11434 struct dpp_connection
*conn
, *tmp
;
11439 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
11441 dpp_connection_remove(conn
);
11443 if (ctrl
->sock
>= 0) {
11445 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
11447 os_free(ctrl
->configurator_params
);
11452 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
11453 const u8
*hdr
, const u8
*buf
, size_t len
)
11455 const u8
*r_bootstrap
, *i_bootstrap
;
11456 u16 r_bootstrap_len
, i_bootstrap_len
;
11457 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
11462 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
11464 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
11466 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
11467 wpa_printf(MSG_INFO
,
11468 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11471 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
11472 r_bootstrap
, r_bootstrap_len
);
11474 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
11476 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
11477 wpa_printf(MSG_INFO
,
11478 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11481 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
11482 i_bootstrap
, i_bootstrap_len
);
11484 /* Try to find own and peer bootstrapping key matches based on the
11485 * received hash values */
11486 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
11487 &own_bi
, &peer_bi
);
11489 wpa_printf(MSG_INFO
,
11490 "No matching own bootstrapping key found - ignore message");
11495 wpa_printf(MSG_INFO
,
11496 "Already in DPP authentication exchange - ignore new one");
11500 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
,
11501 conn
->ctrl
->global
->msg_ctx
,
11502 conn
->ctrl
->allowed_roles
,
11503 conn
->ctrl
->qr_mutual
,
11504 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
11506 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
11510 if (dpp_set_configurator(conn
->auth
,
11511 conn
->ctrl
->configurator_params
) < 0) {
11512 dpp_connection_remove(conn
);
11516 return dpp_tcp_send_msg(conn
, conn
->auth
->resp_msg
);
11520 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
11521 const u8
*hdr
, const u8
*buf
, size_t len
)
11523 struct dpp_authentication
*auth
= conn
->auth
;
11524 struct wpabuf
*msg
;
11530 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
11532 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
11534 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
11535 wpa_printf(MSG_DEBUG
,
11536 "DPP: Start wait for full response");
11539 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
11540 dpp_connection_remove(conn
);
11544 conn
->on_tcp_tx_complete_auth_ok
= 1;
11545 res
= dpp_tcp_send_msg(conn
, msg
);
11551 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
11552 const u8
*hdr
, const u8
*buf
, size_t len
)
11554 struct dpp_authentication
*auth
= conn
->auth
;
11556 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
11559 wpa_printf(MSG_DEBUG
,
11560 "DPP: No DPP Authentication in progress - drop");
11564 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
11565 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
11569 dpp_controller_auth_success(conn
, 0);
11574 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
11577 struct dpp_connection
*conn
= eloop_ctx
;
11579 if (!conn
->auth
->waiting_conf_result
)
11582 wpa_printf(MSG_DEBUG
,
11583 "DPP: Timeout while waiting for Connection Status Result");
11584 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11585 DPP_EVENT_CONN_STATUS_RESULT
"timeout");
11586 dpp_connection_remove(conn
);
11590 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
11591 const u8
*hdr
, const u8
*buf
,
11594 struct dpp_authentication
*auth
= conn
->auth
;
11595 enum dpp_status_error status
;
11600 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
11602 if (!auth
|| !auth
->waiting_conf_result
) {
11603 wpa_printf(MSG_DEBUG
,
11604 "DPP: No DPP Configuration waiting for result - drop");
11608 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
11609 if (status
== DPP_STATUS_OK
&& auth
->send_conn_status
) {
11610 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11611 DPP_EVENT_CONF_SENT
"wait_conn_status=1");
11612 wpa_printf(MSG_DEBUG
, "DPP: Wait for Connection Status Result");
11613 eloop_cancel_timeout(
11614 dpp_controller_conn_status_result_wait_timeout
,
11616 eloop_register_timeout(
11617 16, 0, dpp_controller_conn_status_result_wait_timeout
,
11621 if (status
== DPP_STATUS_OK
)
11622 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11623 DPP_EVENT_CONF_SENT
);
11625 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11626 DPP_EVENT_CONF_FAILED
);
11627 return -1; /* to remove the completed connection */
11631 static int dpp_controller_rx_conn_status_result(struct dpp_connection
*conn
,
11632 const u8
*hdr
, const u8
*buf
,
11635 struct dpp_authentication
*auth
= conn
->auth
;
11636 enum dpp_status_error status
;
11637 u8 ssid
[SSID_MAX_LEN
];
11638 size_t ssid_len
= 0;
11639 char *channel_list
= NULL
;
11644 wpa_printf(MSG_DEBUG
, "DPP: Connection Status Result");
11646 if (!auth
|| !auth
->waiting_conn_status_result
) {
11647 wpa_printf(MSG_DEBUG
,
11648 "DPP: No DPP Configuration waiting for connection status result - drop");
11652 status
= dpp_conn_status_result_rx(auth
, hdr
, buf
, len
,
11653 ssid
, &ssid_len
, &channel_list
);
11654 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11655 DPP_EVENT_CONN_STATUS_RESULT
11656 "result=%d ssid=%s channel_list=%s",
11657 status
, wpa_ssid_txt(ssid
, ssid_len
),
11658 channel_list
? channel_list
: "N/A");
11659 os_free(channel_list
);
11660 return -1; /* to remove the completed connection */
11664 static int dpp_controller_rx_presence_announcement(struct dpp_connection
*conn
,
11665 const u8
*hdr
, const u8
*buf
,
11668 const u8
*r_bootstrap
;
11669 u16 r_bootstrap_len
;
11670 struct dpp_bootstrap_info
*peer_bi
;
11671 struct dpp_authentication
*auth
;
11672 struct dpp_global
*dpp
= conn
->ctrl
->global
;
11675 wpa_printf(MSG_DEBUG
,
11676 "DPP: Ignore Presence Announcement during ongoing Authentication");
11680 wpa_printf(MSG_DEBUG
, "DPP: Presence Announcement");
11682 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
11684 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
11685 wpa_msg(dpp
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
11686 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11689 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
11690 r_bootstrap
, r_bootstrap_len
);
11691 peer_bi
= dpp_bootstrap_find_chirp(dpp
, r_bootstrap
);
11693 wpa_printf(MSG_DEBUG
,
11694 "DPP: No matching bootstrapping information found");
11698 auth
= dpp_auth_init(dpp
, dpp
->msg_ctx
, peer_bi
, NULL
,
11699 DPP_CAPAB_CONFIGURATOR
, -1, NULL
, 0);
11702 if (dpp_set_configurator(conn
->auth
,
11703 conn
->ctrl
->configurator_params
) < 0) {
11704 dpp_auth_deinit(auth
);
11705 dpp_connection_remove(conn
);
11710 return dpp_tcp_send_msg(conn
, conn
->auth
->req_msg
);
11714 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
11717 const u8
*pos
, *end
;
11720 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
11724 if (end
- pos
< DPP_HDR_LEN
||
11725 WPA_GET_BE24(pos
) != OUI_WFA
||
11726 pos
[3] != DPP_OUI_TYPE
) {
11727 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
11732 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
11737 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
11738 pos
+= DPP_HDR_LEN
;
11740 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
11742 if (dpp_check_attrs(pos
, end
- pos
) < 0)
11746 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11747 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11748 conn
->freq
, msg
, len
);
11753 case DPP_PA_AUTHENTICATION_REQ
:
11754 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
11755 case DPP_PA_AUTHENTICATION_RESP
:
11756 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
11757 case DPP_PA_AUTHENTICATION_CONF
:
11758 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
11759 case DPP_PA_CONFIGURATION_RESULT
:
11760 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
11761 case DPP_PA_CONNECTION_STATUS_RESULT
:
11762 return dpp_controller_rx_conn_status_result(conn
, msg
, pos
,
11764 case DPP_PA_PRESENCE_ANNOUNCEMENT
:
11765 return dpp_controller_rx_presence_announcement(conn
, msg
, pos
,
11768 /* TODO: missing messages types */
11769 wpa_printf(MSG_DEBUG
,
11770 "DPP: Unsupported frame subtype %d", type
);
11776 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
11779 const u8
*pos
, *end
, *next
;
11781 const u8
*adv_proto
;
11783 struct wpabuf
*resp
, *buf
;
11784 struct dpp_authentication
*auth
= conn
->auth
;
11789 wpa_printf(MSG_DEBUG
,
11790 "DPP: Received DPP Configuration Request over TCP");
11792 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
11793 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11800 dialog_token
= *pos
++;
11803 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11804 slen
> end
- pos
|| slen
< 2)
11808 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11810 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11811 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11812 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11816 /* Query Request */
11819 slen
= WPA_GET_LE16(pos
);
11821 if (slen
> end
- pos
)
11824 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
11828 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
11834 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
11836 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
11837 wpabuf_put_u8(buf
, dialog_token
);
11838 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
11839 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
11841 dpp_write_adv_proto(buf
);
11842 dpp_write_gas_query(buf
, resp
);
11845 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11847 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
11848 wpabuf_free(conn
->msg_out
);
11849 conn
->msg_out_pos
= 0;
11850 conn
->msg_out
= buf
;
11851 conn
->on_tcp_tx_complete_gas_done
= 1;
11852 dpp_tcp_send(conn
);
11857 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
11859 struct dpp_authentication
*auth
= conn
->auth
;
11861 struct wpabuf
*msg
;
11862 enum dpp_status_error status
;
11864 wpa_printf(MSG_DEBUG
,
11865 "DPP: Configuration Response for local stack from TCP");
11867 res
= dpp_conf_resp_rx(auth
, resp
);
11870 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
11874 if (conn
->global
->process_conf_obj
)
11875 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
11880 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
11883 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
11884 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
11885 msg
= dpp_build_conf_result(auth
, status
);
11889 conn
->on_tcp_tx_complete_remove
= 1;
11890 res
= dpp_tcp_send_msg(conn
, msg
);
11893 /* This exchange will be terminated in the TX status handler */
11899 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
11902 struct wpabuf
*buf
;
11904 const u8
*pos
, *end
, *next
, *adv_proto
;
11910 wpa_printf(MSG_DEBUG
,
11911 "DPP: Received DPP Configuration Response over TCP");
11916 dialog_token
= *pos
++;
11917 status
= WPA_GET_LE16(pos
);
11918 if (status
!= WLAN_STATUS_SUCCESS
) {
11919 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
11923 pos
+= 2; /* ignore GAS Comeback Delay */
11927 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11928 slen
> end
- pos
|| slen
< 2)
11932 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11934 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11935 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11936 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11940 /* Query Response */
11943 slen
= WPA_GET_LE16(pos
);
11945 if (slen
> end
- pos
)
11948 buf
= wpabuf_alloc(slen
);
11951 wpabuf_put_data(buf
, pos
, slen
);
11953 if (!conn
->relay
&& !conn
->ctrl
)
11954 return dpp_tcp_rx_gas_resp(conn
, buf
);
11956 if (!conn
->relay
) {
11957 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11961 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11962 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11963 dialog_token
, 0, buf
);
11969 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
11971 struct dpp_connection
*conn
= eloop_ctx
;
11975 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
11978 if (conn
->msg_len_octets
< 4) {
11981 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
11982 4 - conn
->msg_len_octets
, 0);
11984 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
11986 dpp_connection_remove(conn
);
11990 wpa_printf(MSG_DEBUG
,
11991 "DPP: No more data available over TCP");
11992 dpp_connection_remove(conn
);
11995 wpa_printf(MSG_DEBUG
,
11996 "DPP: Received %d/%d octet(s) of message length field",
11997 res
, (int) (4 - conn
->msg_len_octets
));
11998 conn
->msg_len_octets
+= res
;
12000 if (conn
->msg_len_octets
< 4) {
12001 wpa_printf(MSG_DEBUG
,
12002 "DPP: Need %d more octets of message length field",
12003 (int) (4 - conn
->msg_len_octets
));
12007 msglen
= WPA_GET_BE32(conn
->msg_len
);
12008 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
12009 if (msglen
> 65535) {
12010 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
12011 dpp_connection_remove(conn
);
12015 wpabuf_free(conn
->msg
);
12016 conn
->msg
= wpabuf_alloc(msglen
);
12020 wpa_printf(MSG_DEBUG
,
12021 "DPP: No buffer available for receiving the message");
12022 dpp_connection_remove(conn
);
12026 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
12027 (unsigned int) wpabuf_tailroom(conn
->msg
));
12029 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
12031 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
12032 dpp_connection_remove(conn
);
12036 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
12037 dpp_connection_remove(conn
);
12040 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
12041 wpabuf_put(conn
->msg
, res
);
12043 if (wpabuf_tailroom(conn
->msg
) > 0) {
12044 wpa_printf(MSG_DEBUG
,
12045 "DPP: Need %u more octets of message payload",
12046 (unsigned int) wpabuf_tailroom(conn
->msg
));
12050 conn
->msg_len_octets
= 0;
12051 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
12052 if (wpabuf_len(conn
->msg
) < 1) {
12053 dpp_connection_remove(conn
);
12057 pos
= wpabuf_head(conn
->msg
);
12059 case WLAN_PA_VENDOR_SPECIFIC
:
12060 if (dpp_controller_rx_action(conn
, pos
+ 1,
12061 wpabuf_len(conn
->msg
) - 1) < 0)
12062 dpp_connection_remove(conn
);
12064 case WLAN_PA_GAS_INITIAL_REQ
:
12065 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
12066 wpabuf_len(conn
->msg
) - 1) < 0)
12067 dpp_connection_remove(conn
);
12069 case WLAN_PA_GAS_INITIAL_RESP
:
12070 if (dpp_rx_gas_resp(conn
, pos
+ 1,
12071 wpabuf_len(conn
->msg
) - 1) < 0)
12072 dpp_connection_remove(conn
);
12075 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
12082 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
12084 struct dpp_controller
*ctrl
= eloop_ctx
;
12085 struct sockaddr_in addr
;
12086 socklen_t addr_len
= sizeof(addr
);
12088 struct dpp_connection
*conn
;
12090 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
12092 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
12094 wpa_printf(MSG_DEBUG
,
12095 "DPP: Failed to accept new connection: %s",
12099 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
12100 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
12102 conn
= os_zalloc(sizeof(*conn
));
12106 conn
->global
= ctrl
->global
;
12110 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12111 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12116 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
12117 dpp_controller_rx
, conn
, NULL
) < 0)
12119 conn
->read_eloop
= 1;
12121 /* TODO: eloop timeout to expire connections that do not complete in
12122 * reasonable time */
12123 dl_list_add(&ctrl
->conn
, &conn
->list
);
12132 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
12133 const struct hostapd_ip_addr
*addr
, int port
)
12135 struct dpp_connection
*conn
;
12136 struct sockaddr_storage saddr
;
12138 const u8
*hdr
, *pos
, *end
;
12141 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
12142 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
12143 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
12145 dpp_auth_deinit(auth
);
12149 conn
= os_zalloc(sizeof(*conn
));
12151 dpp_auth_deinit(auth
);
12155 conn
->global
= dpp
;
12157 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12158 if (conn
->sock
< 0)
12161 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12162 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12167 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
12168 if (errno
!= EINPROGRESS
) {
12169 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
12175 * Continue connecting in the background; eloop will call us
12176 * once the connection is ready (or failed).
12180 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
12181 dpp_conn_tx_ready
, conn
, NULL
) < 0)
12183 conn
->write_eloop
= 1;
12185 hdr
= wpabuf_head(auth
->req_msg
);
12186 end
= hdr
+ wpabuf_len(auth
->req_msg
);
12187 hdr
+= 2; /* skip Category and Actiom */
12188 pos
= hdr
+ DPP_HDR_LEN
;
12189 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
12190 if (!conn
->msg_out
)
12192 /* Message will be sent in dpp_conn_tx_ready() */
12194 /* TODO: eloop timeout to clear a connection if it does not complete
12196 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
12199 dpp_connection_free(conn
);
12204 int dpp_controller_start(struct dpp_global
*dpp
,
12205 struct dpp_controller_config
*config
)
12207 struct dpp_controller
*ctrl
;
12209 struct sockaddr_in sin
;
12212 if (!dpp
|| dpp
->controller
)
12215 ctrl
= os_zalloc(sizeof(*ctrl
));
12218 ctrl
->global
= dpp
;
12219 if (config
->configurator_params
)
12220 ctrl
->configurator_params
=
12221 os_strdup(config
->configurator_params
);
12222 dl_list_init(&ctrl
->conn
);
12223 /* TODO: configure these somehow */
12224 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
12225 ctrl
->qr_mutual
= 0;
12227 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12228 if (ctrl
->sock
< 0)
12231 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
12232 &on
, sizeof(on
)) < 0) {
12233 wpa_printf(MSG_DEBUG
,
12234 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12236 /* try to continue anyway */
12239 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
12240 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12246 os_memset(&sin
, 0, sizeof(sin
));
12247 sin
.sin_family
= AF_INET
;
12248 sin
.sin_addr
.s_addr
= INADDR_ANY
;
12249 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
12250 sin
.sin_port
= htons(port
);
12251 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
12252 wpa_printf(MSG_INFO
,
12253 "DPP: Failed to bind Controller TCP port: %s",
12257 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
12258 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
12259 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
12260 dpp_controller_tcp_cb
, ctrl
, NULL
))
12263 dpp
->controller
= ctrl
;
12264 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
12267 dpp_controller_free(ctrl
);
12272 void dpp_controller_stop(struct dpp_global
*dpp
)
12275 dpp_controller_free(dpp
->controller
);
12276 dpp
->controller
= NULL
;
12281 struct wpabuf
* dpp_build_presence_announcement(struct dpp_bootstrap_info
*bi
)
12283 struct wpabuf
*msg
;
12285 wpa_printf(MSG_DEBUG
, "DPP: Build Presence Announcement frame");
12287 msg
= dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT
, 4 + SHA256_MAC_LEN
);
12291 /* Responder Bootstrapping Key Hash */
12292 dpp_build_attr_r_bootstrap_key_hash(msg
, bi
->pubkey_hash_chirp
);
12293 wpa_hexdump_buf(MSG_DEBUG
,
12294 "DPP: Presence Announcement frame attributes", msg
);
12298 #endif /* CONFIG_DPP2 */