2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, 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"
32 #include "drivers/driver.h"
36 #ifdef CONFIG_TESTING_OPTIONS
37 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
38 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
39 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
40 u8 dpp_pkex_ephemeral_key_override
[600];
41 size_t dpp_pkex_ephemeral_key_override_len
= 0;
42 u8 dpp_protocol_key_override
[600];
43 size_t dpp_protocol_key_override_len
= 0;
44 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
45 size_t dpp_nonce_override_len
= 0;
47 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
48 const struct dpp_curve_params
*curve
);
49 #endif /* CONFIG_TESTING_OPTIONS */
51 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
52 (defined(LIBRESSL_VERSION_NUMBER) && \
53 LIBRESSL_VERSION_NUMBER < 0x20700000L)
54 /* Compatibility wrappers for older versions. */
56 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
64 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
76 struct dpp_connection
{
78 struct dpp_controller
*ctrl
;
79 struct dpp_relay_controller
*relay
;
80 struct dpp_global
*global
;
81 struct dpp_authentication
*auth
;
83 u8 mac_addr
[ETH_ALEN
];
86 size_t msg_len_octets
;
88 struct wpabuf
*msg_out
;
90 unsigned int read_eloop
:1;
91 unsigned int write_eloop
:1;
92 unsigned int on_tcp_tx_complete_gas_done
:1;
93 unsigned int on_tcp_tx_complete_remove
:1;
94 unsigned int on_tcp_tx_complete_auth_ok
:1;
97 /* Remote Controller */
98 struct dpp_relay_controller
{
100 struct dpp_global
*global
;
101 u8 pkhash
[SHA256_MAC_LEN
];
102 struct hostapd_ip_addr ipaddr
;
104 void (*tx
)(void *ctx
, const u8
*addr
, unsigned int freq
, const u8
*msg
,
106 void (*gas_resp_tx
)(void *ctx
, const u8
*addr
, u8 dialog_token
,
107 int prot
, struct wpabuf
*buf
);
108 struct dl_list conn
; /* struct dpp_connection */
111 /* Local Controller */
112 struct dpp_controller
{
113 struct dpp_global
*global
;
117 struct dl_list conn
; /* struct dpp_connection */
118 char *configurator_params
;
123 struct dl_list bootstrap
; /* struct dpp_bootstrap_info */
124 struct dl_list configurator
; /* struct dpp_configurator */
126 struct dl_list controllers
; /* struct dpp_relay_controller */
127 struct dpp_controller
*controller
;
128 struct dl_list tcp_init
; /* struct dpp_connection */
130 int (*process_conf_obj
)(void *ctx
, struct dpp_authentication
*auth
);
131 #endif /* CONFIG_DPP2 */
134 static const struct dpp_curve_params dpp_curves
[] = {
135 /* The mandatory to support and the default NIST P-256 curve needs to
136 * be the first entry on this list. */
137 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
138 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
139 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
140 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
141 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
142 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
143 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
147 /* Role-specific elements for PKEX */
150 static const u8 pkex_init_x_p256
[32] = {
151 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
152 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
153 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
154 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
156 static const u8 pkex_init_y_p256
[32] = {
157 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
158 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
159 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
160 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
162 static const u8 pkex_resp_x_p256
[32] = {
163 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
164 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
165 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
166 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
168 static const u8 pkex_resp_y_p256
[32] = {
169 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
170 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
171 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
172 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
176 static const u8 pkex_init_x_p384
[48] = {
177 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
178 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
179 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
180 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
181 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
182 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
184 static const u8 pkex_init_y_p384
[48] = {
185 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
186 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
187 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
188 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
189 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
190 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
192 static const u8 pkex_resp_x_p384
[48] = {
193 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
194 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
195 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
196 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
197 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
198 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
200 static const u8 pkex_resp_y_p384
[48] = {
201 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
202 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
203 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
204 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
205 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
206 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
210 static const u8 pkex_init_x_p521
[66] = {
211 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
212 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
213 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
214 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
215 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
216 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
217 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
218 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
221 static const u8 pkex_init_y_p521
[66] = {
222 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
223 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
224 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
225 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
226 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
227 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
228 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
229 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
232 static const u8 pkex_resp_x_p521
[66] = {
233 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
234 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
235 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
236 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
237 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
238 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
239 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
240 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
243 static const u8 pkex_resp_y_p521
[66] = {
244 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
245 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
246 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
247 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
248 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
249 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
250 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
251 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
255 /* Brainpool P-256r1 */
256 static const u8 pkex_init_x_bp_p256r1
[32] = {
257 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
258 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
259 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
260 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
262 static const u8 pkex_init_y_bp_p256r1
[32] = {
263 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
264 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
265 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
266 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
268 static const u8 pkex_resp_x_bp_p256r1
[32] = {
269 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
270 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
271 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
272 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
274 static const u8 pkex_resp_y_bp_p256r1
[32] = {
275 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
276 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
277 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
278 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
281 /* Brainpool P-384r1 */
282 static const u8 pkex_init_x_bp_p384r1
[48] = {
283 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
284 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
285 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
286 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
287 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
288 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
290 static const u8 pkex_init_y_bp_p384r1
[48] = {
291 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
292 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
293 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
294 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
295 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
296 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
298 static const u8 pkex_resp_x_bp_p384r1
[48] = {
299 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
300 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
301 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
302 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
303 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
304 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
306 static const u8 pkex_resp_y_bp_p384r1
[48] = {
307 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
308 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
309 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
310 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
311 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
312 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
315 /* Brainpool P-512r1 */
316 static const u8 pkex_init_x_bp_p512r1
[64] = {
317 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
318 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
319 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
320 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
321 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
322 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
323 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
324 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
326 static const u8 pkex_init_y_bp_p512r1
[64] = {
327 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
328 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
329 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
330 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
331 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
332 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
333 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
334 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
336 static const u8 pkex_resp_x_bp_p512r1
[64] = {
337 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
338 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
339 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
340 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
341 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
342 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
343 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
344 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
346 static const u8 pkex_resp_y_bp_p512r1
[64] = {
347 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
348 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
349 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
350 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
351 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
352 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
353 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
354 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
358 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
359 const EC_POINT
*point
)
363 char *x_str
= NULL
, *y_str
= NULL
;
365 if (!wpa_debug_show_keys
)
371 if (!ctx
|| !x
|| !y
||
372 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
375 x_str
= BN_bn2hex(x
);
376 y_str
= BN_bn2hex(y
);
377 if (!x_str
|| !y_str
)
380 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
391 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
392 size_t num_elem
, const u8
*addr
[], const size_t *len
,
395 if (curve
->hash_len
== 32)
396 return sha256_vector(num_elem
, addr
, len
, mac
);
397 if (curve
->hash_len
== 48)
398 return sha384_vector(num_elem
, addr
, len
, mac
);
399 if (curve
->hash_len
== 64)
400 return sha512_vector(num_elem
, addr
, len
, mac
);
405 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
406 const char *label
, u8
*out
, size_t outlen
)
409 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
410 (const u8
*) label
, os_strlen(label
),
413 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
414 (const u8
*) label
, os_strlen(label
),
417 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
418 (const u8
*) label
, os_strlen(label
),
424 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
425 size_t num_elem
, const u8
*addr
[],
426 const size_t *len
, u8
*mac
)
429 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
432 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
435 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
441 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
442 const u8
*data
, size_t data_len
, u8
*mac
)
445 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
447 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
449 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
454 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
456 int num_bytes
, offset
;
458 num_bytes
= BN_num_bytes(bn
);
459 if ((size_t) num_bytes
> len
)
461 offset
= len
- num_bytes
;
462 os_memset(pos
, 0, offset
);
463 BN_bn2bin(bn
, pos
+ offset
);
468 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
475 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
478 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
479 len
= i2o_ECPublicKey(eckey
, NULL
);
481 wpa_printf(MSG_ERROR
,
482 "DDP: Failed to determine public key encoding length");
487 buf
= wpabuf_alloc(len
);
493 pos
= wpabuf_put(buf
, len
);
494 res
= i2o_ECPublicKey(eckey
, &pos
);
497 wpa_printf(MSG_ERROR
,
498 "DDP: Failed to encode public key (res=%d/%d)",
505 /* Remove 0x04 prefix to match DPP definition */
506 pos
= wpabuf_mhead(buf
);
507 os_memmove(pos
, pos
+ 1, len
- 1);
515 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
516 const u8
*buf_x
, const u8
*buf_y
,
519 EC_KEY
*eckey
= NULL
;
521 EC_POINT
*point
= NULL
;
522 BIGNUM
*x
= NULL
, *y
= NULL
;
523 EVP_PKEY
*pkey
= NULL
;
527 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
531 point
= EC_POINT_new(group
);
532 x
= BN_bin2bn(buf_x
, len
, NULL
);
533 y
= BN_bin2bn(buf_y
, len
, NULL
);
534 if (!point
|| !x
|| !y
) {
535 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
539 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
540 wpa_printf(MSG_ERROR
,
541 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
542 ERR_error_string(ERR_get_error(), NULL
));
546 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
547 EC_POINT_is_at_infinity(group
, point
)) {
548 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
551 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
553 eckey
= EC_KEY_new();
555 EC_KEY_set_group(eckey
, group
) != 1 ||
556 EC_KEY_set_public_key(eckey
, point
) != 1) {
557 wpa_printf(MSG_ERROR
,
558 "DPP: Failed to set EC_KEY: %s",
559 ERR_error_string(ERR_get_error(), NULL
));
562 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
564 pkey
= EVP_PKEY_new();
565 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
566 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
574 EC_POINT_free(point
);
584 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
585 const u8
*buf
, size_t len
)
588 const EC_GROUP
*group
;
589 EVP_PKEY
*pkey
= NULL
;
594 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
596 wpa_printf(MSG_ERROR
,
597 "DPP: Could not get EC_KEY from group_key");
601 group
= EC_KEY_get0_group(eckey
);
603 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
606 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
613 static int dpp_ecdh(EVP_PKEY
*own
, EVP_PKEY
*peer
,
614 u8
*secret
, size_t *secret_len
)
622 ctx
= EVP_PKEY_CTX_new(own
, NULL
);
624 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_CTX_new failed: %s",
625 ERR_error_string(ERR_get_error(), NULL
));
629 if (EVP_PKEY_derive_init(ctx
) != 1) {
630 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive_init failed: %s",
631 ERR_error_string(ERR_get_error(), NULL
));
635 if (EVP_PKEY_derive_set_peer(ctx
, peer
) != 1) {
636 wpa_printf(MSG_ERROR
,
637 "DPP: EVP_PKEY_derive_set_peet failed: %s",
638 ERR_error_string(ERR_get_error(), NULL
));
642 if (EVP_PKEY_derive(ctx
, NULL
, secret_len
) != 1) {
643 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive(NULL) failed: %s",
644 ERR_error_string(ERR_get_error(), NULL
));
648 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
650 int level
= *secret_len
> 200 ? MSG_ERROR
: MSG_DEBUG
;
652 /* It looks like OpenSSL can return unexpectedly large buffer
653 * need for shared secret from EVP_PKEY_derive(NULL) in some
654 * cases. For example, group 19 has shown cases where secret_len
655 * is set to 72 even though the actual length ends up being
656 * updated to 32 when EVP_PKEY_derive() is called with a buffer
657 * for the value. Work around this by trying to fetch the value
658 * and continue if it is within supported range even when the
659 * initial buffer need is claimed to be larger. */
661 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
663 if (*secret_len
> 200)
665 if (EVP_PKEY_derive(ctx
, buf
, secret_len
) != 1) {
666 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
667 ERR_error_string(ERR_get_error(), NULL
));
670 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
671 wpa_printf(MSG_ERROR
,
672 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
676 wpa_hexdump_key(MSG_DEBUG
, "DPP: Unexpected secret_len change",
678 os_memcpy(secret
, buf
, *secret_len
);
679 forced_memzero(buf
, sizeof(buf
));
683 if (EVP_PKEY_derive(ctx
, secret
, secret_len
) != 1) {
684 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
685 ERR_error_string(ERR_get_error(), NULL
));
693 EVP_PKEY_CTX_free(ctx
);
698 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
700 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
704 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
709 msg
= wpabuf_alloc(8 + len
);
712 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
713 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
714 wpabuf_put_be24(msg
, OUI_WFA
);
715 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
716 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
717 wpabuf_put_u8(msg
, type
);
722 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
725 const u8
*pos
= buf
, *end
= buf
+ len
;
727 while (end
- pos
>= 4) {
728 id
= WPA_GET_LE16(pos
);
730 alen
= WPA_GET_LE16(pos
);
732 if (alen
> end
- pos
)
745 int dpp_check_attrs(const u8
*buf
, size_t len
)
748 int wrapped_data
= 0;
752 while (end
- pos
>= 4) {
755 id
= WPA_GET_LE16(pos
);
757 alen
= WPA_GET_LE16(pos
);
759 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
761 if (alen
> end
- pos
) {
762 wpa_printf(MSG_DEBUG
,
763 "DPP: Truncated message - not enough room for the attribute - dropped");
767 wpa_printf(MSG_DEBUG
,
768 "DPP: An unexpected attribute included after the Wrapped Data attribute");
771 if (id
== DPP_ATTR_WRAPPED_DATA
)
777 wpa_printf(MSG_DEBUG
,
778 "DPP: Unexpected octets (%d) after the last attribute",
787 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
793 EVP_PKEY_free(info
->pubkey
);
798 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
801 case DPP_BOOTSTRAP_QR_CODE
:
803 case DPP_BOOTSTRAP_PKEX
:
810 static int dpp_uri_valid_info(const char *info
)
813 unsigned char val
= *info
++;
815 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
823 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
825 bi
->uri
= os_strdup(uri
);
826 return bi
->uri
? 0 : -1;
830 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
831 const char *chan_list
)
833 const char *pos
= chan_list
, *pos2
;
834 int opclass
= -1, channel
, freq
;
836 while (pos
&& *pos
&& *pos
!= ';') {
838 while (*pos2
>= '0' && *pos2
<= '9')
849 while (*pos
>= '0' && *pos
<= '9')
851 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
852 wpa_printf(MSG_DEBUG
,
853 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
854 opclass
, channel
, freq
);
856 wpa_printf(MSG_DEBUG
,
857 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
859 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
860 wpa_printf(MSG_DEBUG
,
861 "DPP: Too many channels in URI channel-list - ignore list");
865 bi
->freq
[bi
->num_freq
++] = freq
;
868 if (*pos
== ';' || *pos
== '\0')
877 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
882 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
887 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
888 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
892 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
898 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
905 end
= os_strchr(info
, ';');
907 end
= info
+ os_strlen(info
);
908 bi
->info
= os_malloc(end
- info
+ 1);
911 os_memcpy(bi
->info
, info
, end
- info
);
912 bi
->info
[end
- info
] = '\0';
913 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
914 if (!dpp_uri_valid_info(bi
->info
)) {
915 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
923 static const struct dpp_curve_params
*
924 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
929 for (i
= 0; dpp_curves
[i
].name
; i
++) {
930 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
931 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
932 return &dpp_curves
[i
];
938 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
944 for (i
= 0; dpp_curves
[i
].name
; i
++) {
945 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
947 return &dpp_curves
[i
];
953 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
959 const unsigned char *p
;
961 X509_PUBKEY
*pub
= NULL
;
963 const unsigned char *pk
;
966 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
967 (defined(LIBRESSL_VERSION_NUMBER) && \
968 LIBRESSL_VERSION_NUMBER < 0x20800000L)
971 const ASN1_OBJECT
*pa_oid
;
975 const ASN1_OBJECT
*poid
;
978 end
= os_strchr(info
, ';');
982 data
= base64_decode((const unsigned char *) info
, end
- info
,
985 wpa_printf(MSG_DEBUG
,
986 "DPP: Invalid base64 encoding on URI public-key");
989 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
992 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
993 bi
->pubkey_hash
) < 0) {
994 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
998 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
999 bi
->pubkey_hash
, SHA256_MAC_LEN
);
1001 /* DER encoded ASN.1 SubjectPublicKeyInfo
1003 * SubjectPublicKeyInfo ::= SEQUENCE {
1004 * algorithm AlgorithmIdentifier,
1005 * subjectPublicKey BIT STRING }
1007 * AlgorithmIdentifier ::= SEQUENCE {
1008 * algorithm OBJECT IDENTIFIER,
1009 * parameters ANY DEFINED BY algorithm OPTIONAL }
1011 * subjectPublicKey = compressed format public key per ANSI X9.63
1012 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1013 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1014 * prime256v1 (1.2.840.10045.3.1.7)
1018 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
1022 wpa_printf(MSG_DEBUG
,
1023 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1027 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
1028 wpa_printf(MSG_DEBUG
,
1029 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1030 EVP_PKEY_free(pkey
);
1034 res
= X509_PUBKEY_set(&pub
, pkey
);
1036 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
1040 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
1042 wpa_printf(MSG_DEBUG
,
1043 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1046 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
1047 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1048 wpa_printf(MSG_DEBUG
,
1049 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1052 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
1053 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
1054 wpa_printf(MSG_DEBUG
,
1055 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1059 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
1060 if (ptype
!= V_ASN1_OBJECT
) {
1061 wpa_printf(MSG_DEBUG
,
1062 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1066 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
1067 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1068 wpa_printf(MSG_DEBUG
,
1069 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1072 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
1073 bi
->curve
= dpp_get_curve_oid(poid
);
1075 wpa_printf(MSG_DEBUG
,
1076 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1081 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
1083 X509_PUBKEY_free(pub
);
1087 X509_PUBKEY_free(pub
);
1088 EVP_PKEY_free(pkey
);
1093 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1095 const char *pos
= uri
;
1097 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1098 struct dpp_bootstrap_info
*bi
;
1100 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1102 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1103 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1109 end
= os_strchr(pos
, ';');
1114 /* Handle terminating ";;" and ignore unexpected ";"
1115 * for parsing robustness. */
1120 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1121 chan_list
= pos
+ 2;
1122 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1124 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1126 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1129 wpa_hexdump_ascii(MSG_DEBUG
,
1130 "DPP: Ignore unrecognized URI parameter",
1136 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1140 bi
= os_zalloc(sizeof(*bi
));
1144 if (dpp_clone_uri(bi
, uri
) < 0 ||
1145 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1146 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1147 dpp_parse_uri_info(bi
, info
) < 0 ||
1148 dpp_parse_uri_pk(bi
, pk
) < 0) {
1149 dpp_bootstrap_info_free(bi
);
1157 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1159 struct dpp_bootstrap_info
*bi
;
1161 bi
= dpp_parse_uri(uri
);
1163 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1168 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1175 unsigned char *der
= NULL
;
1177 const EC_GROUP
*group
;
1178 const EC_POINT
*point
;
1180 out
= BIO_new(BIO_s_mem());
1184 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1185 rlen
= BIO_ctrl_pending(out
);
1186 txt
= os_malloc(rlen
+ 1);
1188 res
= BIO_read(out
, txt
, rlen
);
1191 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1197 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1201 group
= EC_KEY_get0_group(eckey
);
1202 point
= EC_KEY_get0_public_key(eckey
);
1204 dpp_debug_print_point(title
, group
, point
);
1206 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1208 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1212 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1214 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1222 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1224 EVP_PKEY_CTX
*kctx
= NULL
;
1225 EC_KEY
*ec_params
= NULL
;
1226 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1229 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1231 nid
= OBJ_txt2nid(curve
->name
);
1232 if (nid
== NID_undef
) {
1233 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1237 ec_params
= EC_KEY_new_by_curve_name(nid
);
1239 wpa_printf(MSG_ERROR
,
1240 "DPP: Failed to generate EC_KEY parameters");
1243 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1244 params
= EVP_PKEY_new();
1245 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1246 wpa_printf(MSG_ERROR
,
1247 "DPP: Failed to generate EVP_PKEY parameters");
1251 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1253 EVP_PKEY_keygen_init(kctx
) != 1 ||
1254 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1255 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1260 if (wpa_debug_show_keys
)
1261 dpp_debug_print_key("Own generated key", key
);
1264 EC_KEY_free(ec_params
);
1265 EVP_PKEY_free(params
);
1266 EVP_PKEY_CTX_free(kctx
);
1271 static const struct dpp_curve_params
*
1272 dpp_get_curve_name(const char *name
)
1276 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1277 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1278 (dpp_curves
[i
].jwk_crv
&&
1279 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1280 return &dpp_curves
[i
];
1286 static const struct dpp_curve_params
*
1287 dpp_get_curve_jwk_crv(const char *name
)
1291 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1292 if (dpp_curves
[i
].jwk_crv
&&
1293 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1294 return &dpp_curves
[i
];
1300 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1301 const u8
*privkey
, size_t privkey_len
)
1305 const EC_GROUP
*group
;
1308 pkey
= EVP_PKEY_new();
1311 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1313 wpa_printf(MSG_INFO
,
1314 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1315 ERR_error_string(ERR_get_error(), NULL
));
1316 EVP_PKEY_free(pkey
);
1319 group
= EC_KEY_get0_group(eckey
);
1322 EVP_PKEY_free(pkey
);
1325 nid
= EC_GROUP_get_curve_name(group
);
1326 *curve
= dpp_get_curve_nid(nid
);
1328 wpa_printf(MSG_INFO
,
1329 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1332 EVP_PKEY_free(pkey
);
1336 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1338 EVP_PKEY_free(pkey
);
1346 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1347 * as an OID identifying the curve */
1349 /* Compressed format public key per ANSI X9.63 */
1350 ASN1_BIT_STRING
*pub_key
;
1351 } DPP_BOOTSTRAPPING_KEY
;
1353 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1354 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1355 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1356 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1358 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1361 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1363 unsigned char *der
= NULL
;
1366 struct wpabuf
*ret
= NULL
;
1368 const EC_GROUP
*group
;
1369 const EC_POINT
*point
;
1371 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1375 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1379 group
= EC_KEY_get0_group(eckey
);
1380 point
= EC_KEY_get0_public_key(eckey
);
1381 if (!group
|| !point
)
1383 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1384 nid
= EC_GROUP_get_curve_name(group
);
1386 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1388 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1389 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1392 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1397 der
= OPENSSL_malloc(len
);
1400 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1403 OPENSSL_free(bootstrap
->pub_key
->data
);
1404 bootstrap
->pub_key
->data
= der
;
1406 bootstrap
->pub_key
->length
= len
;
1407 /* No unused bits */
1408 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1409 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1411 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1413 wpa_printf(MSG_ERROR
,
1414 "DDP: Failed to build DER encoded public key");
1418 ret
= wpabuf_alloc_copy(der
, der_len
);
1420 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1428 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1435 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1438 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1441 addr
[0] = wpabuf_head(der
);
1442 len
[0] = wpabuf_len(der
);
1443 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1445 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1447 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1454 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1455 const u8
*privkey
, size_t privkey_len
)
1457 unsigned char *base64
= NULL
;
1460 struct wpabuf
*der
= NULL
;
1465 bi
->curve
= &dpp_curves
[0];
1467 bi
->curve
= dpp_get_curve_name(curve
);
1469 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1475 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1477 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1482 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1485 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1488 addr
[0] = wpabuf_head(der
);
1489 len
= wpabuf_len(der
);
1490 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1492 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1495 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1498 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1503 pos
= (char *) base64
;
1506 pos
= os_strchr(pos
, '\n');
1509 os_memmove(pos
, pos
+ 1, end
- pos
);
1511 return (char *) base64
;
1519 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1520 unsigned int hash_len
)
1522 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1523 const char *info
= "first intermediate key";
1526 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1528 /* HKDF-Extract(<>, M.x) */
1529 os_memset(salt
, 0, hash_len
);
1530 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1532 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1535 /* HKDF-Expand(PRK, info, L) */
1536 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1537 os_memset(prk
, 0, hash_len
);
1541 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1547 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1548 unsigned int hash_len
)
1550 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1551 const char *info
= "second intermediate key";
1554 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1556 /* HKDF-Extract(<>, N.x) */
1557 os_memset(salt
, 0, hash_len
);
1558 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1561 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1564 /* HKDF-Expand(PRK, info, L) */
1565 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1566 os_memset(prk
, 0, hash_len
);
1570 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1576 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1577 unsigned int hash_len
)
1580 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1581 const char *info_ke
= "DPP Key";
1582 u8 prk
[DPP_MAX_HASH_LEN
];
1586 size_t num_elem
= 0;
1588 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1589 wpa_printf(MSG_DEBUG
,
1590 "DPP: Mx/Nx not available - cannot derive ke");
1594 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1596 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1597 nonce_len
= auth
->curve
->nonce_len
;
1598 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1599 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1600 addr
[num_elem
] = auth
->Mx
;
1601 len
[num_elem
] = auth
->Mx_len
;
1603 addr
[num_elem
] = auth
->Nx
;
1604 len
[num_elem
] = auth
->Nx_len
;
1606 if (auth
->peer_bi
&& auth
->own_bi
) {
1607 if (!auth
->Lx_len
) {
1608 wpa_printf(MSG_DEBUG
,
1609 "DPP: Lx not available - cannot derive ke");
1612 addr
[num_elem
] = auth
->Lx
;
1613 len
[num_elem
] = auth
->secret_len
;
1616 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1617 num_elem
, addr
, len
, prk
);
1620 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1623 /* HKDF-Expand(PRK, info, L) */
1624 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1625 os_memset(prk
, 0, hash_len
);
1629 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1635 static void dpp_build_attr_status(struct wpabuf
*msg
,
1636 enum dpp_status_error status
)
1638 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1639 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1640 wpabuf_put_le16(msg
, 1);
1641 wpabuf_put_u8(msg
, status
);
1645 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1649 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1650 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1651 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1652 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1657 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1661 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1662 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1663 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1664 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1669 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1670 const struct wpabuf
*pi
,
1672 const u8
*r_pubkey_hash
,
1673 const u8
*i_pubkey_hash
,
1674 unsigned int neg_freq
)
1677 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1678 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1681 size_t len
[2], siv_len
, attr_len
;
1682 u8
*attr_start
, *attr_end
;
1684 /* Build DPP Authentication Request frame attributes */
1685 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1686 4 + sizeof(wrapped_data
);
1691 #endif /* CONFIG_DPP2 */
1692 #ifdef CONFIG_TESTING_OPTIONS
1693 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1695 #endif /* CONFIG_TESTING_OPTIONS */
1696 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1700 attr_start
= wpabuf_put(msg
, 0);
1702 /* Responder Bootstrapping Key Hash */
1703 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1705 /* Initiator Bootstrapping Key Hash */
1706 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1708 /* Initiator Protocol Key */
1710 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1711 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1712 wpabuf_put_buf(msg
, pi
);
1717 u8 op_class
, channel
;
1719 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1721 NUM_HOSTAPD_MODES
) {
1722 wpa_printf(MSG_INFO
,
1723 "DPP: Unsupported negotiation frequency request: %d",
1728 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1729 wpabuf_put_le16(msg
, 2);
1730 wpabuf_put_u8(msg
, op_class
);
1731 wpabuf_put_u8(msg
, channel
);
1735 /* Protocol Version */
1736 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1737 wpabuf_put_le16(msg
, 1);
1738 wpabuf_put_u8(msg
, 2);
1739 #endif /* CONFIG_DPP2 */
1741 #ifdef CONFIG_TESTING_OPTIONS
1742 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1743 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1744 goto skip_wrapped_data
;
1746 #endif /* CONFIG_TESTING_OPTIONS */
1748 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1751 #ifdef CONFIG_TESTING_OPTIONS
1752 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1753 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1756 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1757 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1758 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1760 WPA_PUT_LE16(pos
, nonce_len
- 1);
1762 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1763 pos
+= nonce_len
- 1;
1766 #endif /* CONFIG_TESTING_OPTIONS */
1769 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1771 WPA_PUT_LE16(pos
, nonce_len
);
1773 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1776 #ifdef CONFIG_TESTING_OPTIONS
1778 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1779 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1782 #endif /* CONFIG_TESTING_OPTIONS */
1784 /* I-capabilities */
1785 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1787 WPA_PUT_LE16(pos
, 1);
1789 auth
->i_capab
= auth
->allowed_roles
;
1790 *pos
++ = auth
->i_capab
;
1791 #ifdef CONFIG_TESTING_OPTIONS
1792 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1793 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1797 #endif /* CONFIG_TESTING_OPTIONS */
1799 attr_end
= wpabuf_put(msg
, 0);
1801 /* OUI, OUI type, Crypto Suite, DPP frame type */
1802 addr
[0] = wpabuf_head_u8(msg
) + 2;
1803 len
[0] = 3 + 1 + 1 + 1;
1804 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1806 /* Attributes before Wrapped Data */
1807 addr
[1] = attr_start
;
1808 len
[1] = attr_end
- attr_start
;
1809 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1811 siv_len
= pos
- clear
;
1812 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1813 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1814 2, addr
, len
, wrapped_data
) < 0) {
1818 siv_len
+= AES_BLOCK_SIZE
;
1819 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1820 wrapped_data
, siv_len
);
1822 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1823 wpabuf_put_le16(msg
, siv_len
);
1824 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1826 #ifdef CONFIG_TESTING_OPTIONS
1827 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1828 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1829 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1832 #endif /* CONFIG_TESTING_OPTIONS */
1834 wpa_hexdump_buf(MSG_DEBUG
,
1835 "DPP: Authentication Request frame attributes", msg
);
1841 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1842 enum dpp_status_error status
,
1843 const struct wpabuf
*pr
,
1845 const u8
*r_pubkey_hash
,
1846 const u8
*i_pubkey_hash
,
1847 const u8
*r_nonce
, const u8
*i_nonce
,
1848 const u8
*wrapped_r_auth
,
1849 size_t wrapped_r_auth_len
,
1853 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1854 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1855 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1856 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1858 size_t len
[2], siv_len
, attr_len
;
1859 u8
*attr_start
, *attr_end
, *pos
;
1861 auth
->waiting_auth_conf
= 1;
1862 auth
->auth_resp_tries
= 0;
1864 /* Build DPP Authentication Response frame attributes */
1865 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1866 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1869 #endif /* CONFIG_DPP2 */
1870 #ifdef CONFIG_TESTING_OPTIONS
1871 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1873 #endif /* CONFIG_TESTING_OPTIONS */
1874 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1878 attr_start
= wpabuf_put(msg
, 0);
1882 dpp_build_attr_status(msg
, status
);
1884 /* Responder Bootstrapping Key Hash */
1885 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1887 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1888 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1890 /* Responder Protocol Key */
1892 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1893 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1894 wpabuf_put_buf(msg
, pr
);
1898 /* Protocol Version */
1899 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1900 wpabuf_put_le16(msg
, 1);
1901 wpabuf_put_u8(msg
, 2);
1902 #endif /* CONFIG_DPP2 */
1904 attr_end
= wpabuf_put(msg
, 0);
1906 #ifdef CONFIG_TESTING_OPTIONS
1907 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1908 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1909 goto skip_wrapped_data
;
1911 #endif /* CONFIG_TESTING_OPTIONS */
1913 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1918 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1920 WPA_PUT_LE16(pos
, nonce_len
);
1922 os_memcpy(pos
, r_nonce
, nonce_len
);
1928 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1930 WPA_PUT_LE16(pos
, nonce_len
);
1932 os_memcpy(pos
, i_nonce
, nonce_len
);
1933 #ifdef CONFIG_TESTING_OPTIONS
1934 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1935 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1936 pos
[nonce_len
/ 2] ^= 0x01;
1938 #endif /* CONFIG_TESTING_OPTIONS */
1942 #ifdef CONFIG_TESTING_OPTIONS
1943 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1944 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1947 #endif /* CONFIG_TESTING_OPTIONS */
1949 /* R-capabilities */
1950 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1952 WPA_PUT_LE16(pos
, 1);
1954 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1956 *pos
++ = auth
->r_capab
;
1957 #ifdef CONFIG_TESTING_OPTIONS
1958 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1959 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1961 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1962 wpa_printf(MSG_INFO
,
1963 "DPP: TESTING - incompatible R-capabilities");
1964 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1965 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1968 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1969 DPP_CAPAB_CONFIGURATOR
;
1972 #endif /* CONFIG_TESTING_OPTIONS */
1974 if (wrapped_r_auth
) {
1976 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1978 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1980 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1981 pos
+= wrapped_r_auth_len
;
1984 /* OUI, OUI type, Crypto Suite, DPP frame type */
1985 addr
[0] = wpabuf_head_u8(msg
) + 2;
1986 len
[0] = 3 + 1 + 1 + 1;
1987 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1989 /* Attributes before Wrapped Data */
1990 addr
[1] = attr_start
;
1991 len
[1] = attr_end
- attr_start
;
1992 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1994 siv_len
= pos
- clear
;
1995 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1996 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1997 2, addr
, len
, wrapped_data
) < 0) {
2001 siv_len
+= AES_BLOCK_SIZE
;
2002 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2003 wrapped_data
, siv_len
);
2005 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2006 wpabuf_put_le16(msg
, siv_len
);
2007 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2009 #ifdef CONFIG_TESTING_OPTIONS
2010 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
2011 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2012 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2015 #endif /* CONFIG_TESTING_OPTIONS */
2017 wpa_hexdump_buf(MSG_DEBUG
,
2018 "DPP: Authentication Response frame attributes", msg
);
2023 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
2024 u16 num_modes
, unsigned int freq
)
2029 if (!own_modes
|| !num_modes
)
2032 for (m
= 0; m
< num_modes
; m
++) {
2033 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2034 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
2037 flag
= own_modes
[m
].channels
[c
].flag
;
2038 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
2039 HOSTAPD_CHAN_NO_IR
|
2040 HOSTAPD_CHAN_RADAR
)))
2045 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
2050 static int freq_included(const unsigned int freqs
[], unsigned int num
,
2054 if (freqs
[--num
] == freq
)
2061 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
2066 for (i
= 0; i
< num
; i
++) {
2067 if (freqs
[i
] == freq
)
2070 if (i
== 0 || i
>= num
)
2072 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
2077 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
2078 struct hostapd_hw_modes
*own_modes
,
2081 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
2082 unsigned int i
, freq
;
2084 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2085 freq
= peer_bi
->freq
[i
];
2086 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2088 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2089 auth
->freq
[auth
->num_freq
++] = freq
;
2091 if (!auth
->num_freq
) {
2092 wpa_printf(MSG_INFO
,
2093 "DPP: No available channels for initiating DPP Authentication");
2096 auth
->curr_freq
= auth
->freq
[0];
2101 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2102 struct hostapd_hw_modes
*own_modes
,
2111 if (!own_modes
|| !num_modes
) {
2112 auth
->freq
[0] = 2412;
2113 auth
->freq
[1] = 2437;
2114 auth
->freq
[2] = 2462;
2119 for (m
= 0; m
< num_modes
; m
++) {
2120 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2121 freq
= own_modes
[m
].channels
[c
].freq
;
2122 flag
= own_modes
[m
].channels
[c
].flag
;
2123 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2124 HOSTAPD_CHAN_NO_IR
|
2125 HOSTAPD_CHAN_RADAR
))
2127 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2129 auth
->freq
[auth
->num_freq
++] = freq
;
2130 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2137 return auth
->num_freq
== 0 ? -1 : 0;
2141 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2142 struct hostapd_hw_modes
*own_modes
,
2146 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2149 if (auth
->peer_bi
->num_freq
> 0)
2150 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2152 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2156 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2157 * likely channels first. */
2158 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2159 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2160 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2163 auth
->curr_freq
= auth
->freq
[0];
2166 end
= pos
+ sizeof(freqs
);
2167 for (i
= 0; i
< auth
->num_freq
; i
++) {
2168 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2169 if (os_snprintf_error(end
- pos
, res
))
2174 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2181 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2183 struct dpp_bootstrap_info
*bi
;
2188 return 0; /* already generated */
2190 bi
= os_zalloc(sizeof(*bi
));
2193 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2194 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2198 len
= 4; /* "DPP:" */
2199 len
+= 4 + os_strlen(pk
);
2200 bi
->uri
= os_malloc(len
+ 1);
2203 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2204 wpa_printf(MSG_DEBUG
,
2205 "DPP: Auto-generated own bootstrapping key info: URI %s",
2208 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2215 dpp_bootstrap_info_free(bi
);
2220 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2221 struct dpp_bootstrap_info
*peer_bi
,
2222 struct dpp_bootstrap_info
*own_bi
,
2223 u8 dpp_allowed_roles
,
2224 unsigned int neg_freq
,
2225 struct hostapd_hw_modes
*own_modes
,
2228 struct dpp_authentication
*auth
;
2231 struct wpabuf
*pi
= NULL
;
2232 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2233 #ifdef CONFIG_TESTING_OPTIONS
2234 u8 test_hash
[SHA256_MAC_LEN
];
2235 #endif /* CONFIG_TESTING_OPTIONS */
2237 auth
= os_zalloc(sizeof(*auth
));
2240 auth
->msg_ctx
= msg_ctx
;
2241 auth
->initiator
= 1;
2242 auth
->waiting_auth_resp
= 1;
2243 auth
->allowed_roles
= dpp_allowed_roles
;
2244 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2245 auth
->peer_bi
= peer_bi
;
2246 auth
->own_bi
= own_bi
;
2247 auth
->curve
= peer_bi
->curve
;
2249 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2250 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2253 #ifdef CONFIG_TESTING_OPTIONS
2254 if (dpp_nonce_override_len
> 0) {
2255 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2256 nonce_len
= dpp_nonce_override_len
;
2257 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2259 nonce_len
= auth
->curve
->nonce_len
;
2260 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2261 wpa_printf(MSG_ERROR
,
2262 "DPP: Failed to generate I-nonce");
2266 #else /* CONFIG_TESTING_OPTIONS */
2267 nonce_len
= auth
->curve
->nonce_len
;
2268 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2269 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2272 #endif /* CONFIG_TESTING_OPTIONS */
2273 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2275 #ifdef CONFIG_TESTING_OPTIONS
2276 if (dpp_protocol_key_override_len
) {
2277 const struct dpp_curve_params
*tmp_curve
;
2279 wpa_printf(MSG_INFO
,
2280 "DPP: TESTING - override protocol key");
2281 auth
->own_protocol_key
= dpp_set_keypair(
2282 &tmp_curve
, dpp_protocol_key_override
,
2283 dpp_protocol_key_override_len
);
2285 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2287 #else /* CONFIG_TESTING_OPTIONS */
2288 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2289 #endif /* CONFIG_TESTING_OPTIONS */
2290 if (!auth
->own_protocol_key
)
2293 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2297 /* ECDH: M = pI * BR */
2298 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2299 auth
->Mx
, &secret_len
) < 0)
2301 auth
->secret_len
= secret_len
;
2303 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2304 auth
->Mx
, auth
->secret_len
);
2305 auth
->Mx_len
= auth
->secret_len
;
2307 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2308 auth
->curve
->hash_len
) < 0)
2311 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2312 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2314 #ifdef CONFIG_TESTING_OPTIONS
2315 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2316 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2317 r_pubkey_hash
= NULL
;
2318 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2319 wpa_printf(MSG_INFO
,
2320 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2321 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2322 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2323 r_pubkey_hash
= test_hash
;
2324 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2325 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2326 i_pubkey_hash
= NULL
;
2327 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2328 wpa_printf(MSG_INFO
,
2329 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2330 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2331 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2332 i_pubkey_hash
= test_hash
;
2333 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2334 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2337 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2338 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2340 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2341 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2344 #endif /* CONFIG_TESTING_OPTIONS */
2346 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2347 i_pubkey_hash
, neg_freq
);
2355 dpp_auth_deinit(auth
);
2361 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2365 size_t json_len
, clear_len
;
2366 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2370 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2372 nonce_len
= auth
->curve
->nonce_len
;
2373 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2374 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2377 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2378 json_len
= os_strlen(json
);
2379 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2381 /* { E-nonce, configAttrib }ke */
2382 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2383 clear
= wpabuf_alloc(clear_len
);
2384 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2385 #ifdef CONFIG_TESTING_OPTIONS
2386 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2388 #endif /* CONFIG_TESTING_OPTIONS */
2389 msg
= wpabuf_alloc(attr_len
);
2393 #ifdef CONFIG_TESTING_OPTIONS
2394 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2395 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2398 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2399 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2400 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2401 wpabuf_put_le16(clear
, nonce_len
- 1);
2402 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2405 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2406 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2407 goto skip_wrapped_data
;
2409 #endif /* CONFIG_TESTING_OPTIONS */
2412 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2413 wpabuf_put_le16(clear
, nonce_len
);
2414 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2416 #ifdef CONFIG_TESTING_OPTIONS
2418 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2419 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2420 goto skip_conf_attr_obj
;
2422 #endif /* CONFIG_TESTING_OPTIONS */
2425 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2426 wpabuf_put_le16(clear
, json_len
);
2427 wpabuf_put_data(clear
, json
, json_len
);
2429 #ifdef CONFIG_TESTING_OPTIONS
2431 #endif /* CONFIG_TESTING_OPTIONS */
2433 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2434 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2435 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2438 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2439 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2440 wpabuf_head(clear
), wpabuf_len(clear
),
2441 0, NULL
, NULL
, wrapped
) < 0)
2443 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2444 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2446 #ifdef CONFIG_TESTING_OPTIONS
2447 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2448 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2449 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2452 #endif /* CONFIG_TESTING_OPTIONS */
2454 wpa_hexdump_buf(MSG_DEBUG
,
2455 "DPP: Configuration Request frame attributes", msg
);
2466 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2468 /* Advertisement Protocol IE */
2469 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2470 wpabuf_put_u8(buf
, 8); /* Length */
2471 wpabuf_put_u8(buf
, 0x7f);
2472 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2473 wpabuf_put_u8(buf
, 5);
2474 wpabuf_put_be24(buf
, OUI_WFA
);
2475 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2476 wpabuf_put_u8(buf
, 0x01);
2480 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2483 wpabuf_put_le16(buf
, wpabuf_len(query
));
2484 wpabuf_put_buf(buf
, query
);
2488 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2491 struct wpabuf
*buf
, *conf_req
;
2493 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2495 wpa_printf(MSG_DEBUG
,
2496 "DPP: No configuration request data available");
2500 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2502 wpabuf_free(conf_req
);
2506 dpp_write_adv_proto(buf
);
2507 dpp_write_gas_query(buf
, conf_req
);
2508 wpabuf_free(conf_req
);
2509 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2515 static void dpp_auth_success(struct dpp_authentication
*auth
)
2517 wpa_printf(MSG_DEBUG
,
2518 "DPP: Authentication success - clear temporary keys");
2519 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2521 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2523 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2525 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2526 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2528 auth
->auth_success
= 1;
2532 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2534 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2537 size_t i
, num_elem
= 0;
2542 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2543 nonce_len
= auth
->curve
->nonce_len
;
2545 if (auth
->initiator
) {
2546 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2547 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2549 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2552 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2554 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2555 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2557 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2560 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2562 if (!pix
|| !prx
|| !brx
)
2565 addr
[num_elem
] = auth
->i_nonce
;
2566 len
[num_elem
] = nonce_len
;
2569 addr
[num_elem
] = auth
->r_nonce
;
2570 len
[num_elem
] = nonce_len
;
2573 addr
[num_elem
] = wpabuf_head(pix
);
2574 len
[num_elem
] = wpabuf_len(pix
) / 2;
2577 addr
[num_elem
] = wpabuf_head(prx
);
2578 len
[num_elem
] = wpabuf_len(prx
) / 2;
2582 addr
[num_elem
] = wpabuf_head(bix
);
2583 len
[num_elem
] = wpabuf_len(bix
) / 2;
2587 addr
[num_elem
] = wpabuf_head(brx
);
2588 len
[num_elem
] = wpabuf_len(brx
) / 2;
2591 addr
[num_elem
] = &zero
;
2595 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2596 for (i
= 0; i
< num_elem
; i
++)
2597 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2598 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2600 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2601 auth
->curve
->hash_len
);
2611 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2613 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2616 size_t i
, num_elem
= 0;
2621 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2622 nonce_len
= auth
->curve
->nonce_len
;
2624 if (auth
->initiator
) {
2625 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2626 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2628 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2633 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2635 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2636 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2638 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2643 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2645 if (!pix
|| !prx
|| !brx
)
2648 addr
[num_elem
] = auth
->r_nonce
;
2649 len
[num_elem
] = nonce_len
;
2652 addr
[num_elem
] = auth
->i_nonce
;
2653 len
[num_elem
] = nonce_len
;
2656 addr
[num_elem
] = wpabuf_head(prx
);
2657 len
[num_elem
] = wpabuf_len(prx
) / 2;
2660 addr
[num_elem
] = wpabuf_head(pix
);
2661 len
[num_elem
] = wpabuf_len(pix
) / 2;
2664 addr
[num_elem
] = wpabuf_head(brx
);
2665 len
[num_elem
] = wpabuf_len(brx
) / 2;
2669 addr
[num_elem
] = wpabuf_head(bix
);
2670 len
[num_elem
] = wpabuf_len(bix
) / 2;
2674 addr
[num_elem
] = &one
;
2678 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2679 for (i
= 0; i
< num_elem
; i
++)
2680 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2681 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2683 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2684 auth
->curve
->hash_len
);
2694 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2696 const EC_GROUP
*group
;
2698 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2699 const EC_POINT
*BI_point
;
2701 BIGNUM
*lx
, *sum
, *q
;
2702 const BIGNUM
*bR_bn
, *pR_bn
;
2705 /* L = ((bR + pR) modulo q) * BI */
2707 bnctx
= BN_CTX_new();
2711 if (!bnctx
|| !sum
|| !q
|| !lx
)
2713 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2716 BI_point
= EC_KEY_get0_public_key(BI
);
2717 group
= EC_KEY_get0_group(BI
);
2721 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2722 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2725 bR_bn
= EC_KEY_get0_private_key(bR
);
2726 pR_bn
= EC_KEY_get0_private_key(pR
);
2727 if (!bR_bn
|| !pR_bn
)
2729 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2730 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2732 l
= EC_POINT_new(group
);
2734 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2735 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2737 wpa_printf(MSG_ERROR
,
2738 "OpenSSL: failed: %s",
2739 ERR_error_string(ERR_get_error(), NULL
));
2743 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2745 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2746 auth
->Lx_len
= auth
->secret_len
;
2749 EC_POINT_clear_free(l
);
2761 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2763 const EC_GROUP
*group
;
2764 EC_POINT
*l
= NULL
, *sum
= NULL
;
2765 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2766 const EC_POINT
*BR_point
, *PR_point
;
2769 const BIGNUM
*bI_bn
;
2772 /* L = bI * (BR + PR) */
2774 bnctx
= BN_CTX_new();
2778 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2779 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2782 BR_point
= EC_KEY_get0_public_key(BR
);
2783 PR_point
= EC_KEY_get0_public_key(PR
);
2785 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2788 group
= EC_KEY_get0_group(bI
);
2789 bI_bn
= EC_KEY_get0_private_key(bI
);
2790 if (!group
|| !bI_bn
)
2792 sum
= EC_POINT_new(group
);
2793 l
= EC_POINT_new(group
);
2795 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2796 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2797 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2799 wpa_printf(MSG_ERROR
,
2800 "OpenSSL: failed: %s",
2801 ERR_error_string(ERR_get_error(), NULL
));
2805 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2807 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2808 auth
->Lx_len
= auth
->secret_len
;
2811 EC_POINT_clear_free(l
);
2812 EC_POINT_clear_free(sum
);
2822 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2826 struct wpabuf
*msg
, *pr
= NULL
;
2827 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2828 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2829 size_t wrapped_r_auth_len
;
2831 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2832 enum dpp_status_error status
= DPP_STATUS_OK
;
2833 #ifdef CONFIG_TESTING_OPTIONS
2834 u8 test_hash
[SHA256_MAC_LEN
];
2835 #endif /* CONFIG_TESTING_OPTIONS */
2837 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2841 #ifdef CONFIG_TESTING_OPTIONS
2842 if (dpp_nonce_override_len
> 0) {
2843 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2844 nonce_len
= dpp_nonce_override_len
;
2845 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2847 nonce_len
= auth
->curve
->nonce_len
;
2848 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2849 wpa_printf(MSG_ERROR
,
2850 "DPP: Failed to generate R-nonce");
2854 #else /* CONFIG_TESTING_OPTIONS */
2855 nonce_len
= auth
->curve
->nonce_len
;
2856 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2857 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2860 #endif /* CONFIG_TESTING_OPTIONS */
2861 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2863 EVP_PKEY_free(auth
->own_protocol_key
);
2864 #ifdef CONFIG_TESTING_OPTIONS
2865 if (dpp_protocol_key_override_len
) {
2866 const struct dpp_curve_params
*tmp_curve
;
2868 wpa_printf(MSG_INFO
,
2869 "DPP: TESTING - override protocol key");
2870 auth
->own_protocol_key
= dpp_set_keypair(
2871 &tmp_curve
, dpp_protocol_key_override
,
2872 dpp_protocol_key_override_len
);
2874 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2876 #else /* CONFIG_TESTING_OPTIONS */
2877 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2878 #endif /* CONFIG_TESTING_OPTIONS */
2879 if (!auth
->own_protocol_key
)
2882 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2886 /* ECDH: N = pR * PI */
2887 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
2888 auth
->Nx
, &secret_len
) < 0)
2891 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2892 auth
->Nx
, auth
->secret_len
);
2893 auth
->Nx_len
= auth
->secret_len
;
2895 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2896 auth
->curve
->hash_len
) < 0)
2899 if (auth
->own_bi
&& auth
->peer_bi
) {
2900 /* Mutual authentication */
2901 if (dpp_auth_derive_l_responder(auth
) < 0)
2905 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2908 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2909 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2910 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2911 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2913 #ifdef CONFIG_TESTING_OPTIONS
2914 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2915 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2916 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2918 #endif /* CONFIG_TESTING_OPTIONS */
2919 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2920 r_auth
, 4 + auth
->curve
->hash_len
,
2921 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2923 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2924 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2925 wrapped_r_auth
, wrapped_r_auth_len
);
2926 w_r_auth
= wrapped_r_auth
;
2928 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2930 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2932 i_pubkey_hash
= NULL
;
2934 i_nonce
= auth
->i_nonce
;
2935 r_nonce
= auth
->r_nonce
;
2937 #ifdef CONFIG_TESTING_OPTIONS
2938 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2939 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2940 r_pubkey_hash
= NULL
;
2941 } else if (dpp_test
==
2942 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2943 wpa_printf(MSG_INFO
,
2944 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2945 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2946 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2947 r_pubkey_hash
= test_hash
;
2948 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2949 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2950 i_pubkey_hash
= NULL
;
2951 } else if (dpp_test
==
2952 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2953 wpa_printf(MSG_INFO
,
2954 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2956 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2958 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2959 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2960 i_pubkey_hash
= test_hash
;
2961 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2962 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2965 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2966 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2968 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2969 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2971 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2972 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2974 wrapped_r_auth_len
= 0;
2975 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2976 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2978 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2979 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2981 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2982 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2984 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2985 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2988 #endif /* CONFIG_TESTING_OPTIONS */
2990 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2991 r_pubkey_hash
, i_pubkey_hash
,
2993 w_r_auth
, wrapped_r_auth_len
,
2997 wpabuf_free(auth
->resp_msg
);
2998 auth
->resp_msg
= msg
;
3006 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3007 enum dpp_status_error status
)
3010 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3011 #ifdef CONFIG_TESTING_OPTIONS
3012 u8 test_hash
[SHA256_MAC_LEN
];
3013 #endif /* CONFIG_TESTING_OPTIONS */
3017 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3019 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3021 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3023 i_pubkey_hash
= NULL
;
3025 i_nonce
= auth
->i_nonce
;
3027 #ifdef CONFIG_TESTING_OPTIONS
3028 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3029 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3030 r_pubkey_hash
= NULL
;
3031 } else if (dpp_test
==
3032 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3033 wpa_printf(MSG_INFO
,
3034 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3035 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3036 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3037 r_pubkey_hash
= test_hash
;
3038 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3039 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3040 i_pubkey_hash
= NULL
;
3041 } else if (dpp_test
==
3042 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3043 wpa_printf(MSG_INFO
,
3044 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3046 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3048 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3049 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3050 i_pubkey_hash
= test_hash
;
3051 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3052 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3054 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3055 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3058 #endif /* CONFIG_TESTING_OPTIONS */
3060 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3061 r_pubkey_hash
, i_pubkey_hash
,
3062 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3065 wpabuf_free(auth
->resp_msg
);
3066 auth
->resp_msg
= msg
;
3071 struct dpp_authentication
*
3072 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3073 struct dpp_bootstrap_info
*peer_bi
,
3074 struct dpp_bootstrap_info
*own_bi
,
3075 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3078 EVP_PKEY
*pi
= NULL
;
3079 EVP_PKEY_CTX
*ctx
= NULL
;
3083 u8
*unwrapped
= NULL
;
3084 size_t unwrapped_len
= 0;
3085 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3087 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3088 i_bootstrap_len
, channel_len
;
3089 struct dpp_authentication
*auth
= NULL
;
3093 #endif /* CONFIG_DPP2 */
3095 #ifdef CONFIG_TESTING_OPTIONS
3096 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3097 wpa_printf(MSG_INFO
,
3098 "DPP: TESTING - stop at Authentication Request");
3101 #endif /* CONFIG_TESTING_OPTIONS */
3103 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3105 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3106 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3107 "Missing or invalid required Wrapped Data attribute");
3110 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3111 wrapped_data
, wrapped_data_len
);
3112 attr_len
= wrapped_data
- 4 - attr_start
;
3114 auth
= os_zalloc(sizeof(*auth
));
3117 auth
->msg_ctx
= msg_ctx
;
3118 auth
->peer_bi
= peer_bi
;
3119 auth
->own_bi
= own_bi
;
3120 auth
->curve
= own_bi
->curve
;
3121 auth
->curr_freq
= freq
;
3123 auth
->peer_version
= 1; /* default to the first version */
3125 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3128 if (version_len
< 1 || version
[0] == 0) {
3130 "Invalid Protocol Version attribute");
3133 auth
->peer_version
= version
[0];
3134 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3135 auth
->peer_version
);
3137 #endif /* CONFIG_DPP2 */
3139 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3144 if (channel_len
< 2) {
3145 dpp_auth_fail(auth
, "Too short Channel attribute");
3149 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3150 wpa_printf(MSG_DEBUG
,
3151 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3152 channel
[0], channel
[1], neg_freq
);
3155 "Unsupported Channel attribute value");
3159 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3160 wpa_printf(MSG_DEBUG
,
3161 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3163 auth
->curr_freq
= neg_freq
;
3167 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3171 "Missing required Initiator Protocol Key attribute");
3174 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3175 i_proto
, i_proto_len
);
3178 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3180 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3183 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3185 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3187 auth
->secret_len
= secret_len
;
3189 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3190 auth
->Mx
, auth
->secret_len
);
3191 auth
->Mx_len
= auth
->secret_len
;
3193 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3194 auth
->curve
->hash_len
) < 0)
3198 len
[0] = DPP_HDR_LEN
;
3199 addr
[1] = attr_start
;
3201 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3202 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3203 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3204 wrapped_data
, wrapped_data_len
);
3205 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3206 unwrapped
= os_malloc(unwrapped_len
);
3209 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3210 wrapped_data
, wrapped_data_len
,
3211 2, addr
, len
, unwrapped
) < 0) {
3212 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3215 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3216 unwrapped
, unwrapped_len
);
3218 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3219 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3223 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3225 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3226 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3229 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3230 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3232 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3233 DPP_ATTR_I_CAPABILITIES
,
3235 if (!i_capab
|| i_capab_len
< 1) {
3236 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3239 auth
->i_capab
= i_capab
[0];
3240 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3242 bin_clear_free(unwrapped
, unwrapped_len
);
3245 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3246 case DPP_CAPAB_ENROLLEE
:
3247 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3248 wpa_printf(MSG_DEBUG
,
3249 "DPP: Local policy does not allow Configurator role");
3250 goto not_compatible
;
3252 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3253 auth
->configurator
= 1;
3255 case DPP_CAPAB_CONFIGURATOR
:
3256 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3257 wpa_printf(MSG_DEBUG
,
3258 "DPP: Local policy does not allow Enrollee role");
3259 goto not_compatible
;
3261 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3262 auth
->configurator
= 0;
3264 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3265 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3266 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3267 auth
->configurator
= 0;
3268 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3269 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3270 auth
->configurator
= 1;
3272 wpa_printf(MSG_DEBUG
,
3273 "DPP: Local policy does not allow Configurator/Enrollee role");
3274 goto not_compatible
;
3278 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3279 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3280 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3281 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3285 auth
->peer_protocol_key
= pi
;
3287 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3288 char hex
[SHA256_MAC_LEN
* 2 + 1];
3290 wpa_printf(MSG_DEBUG
,
3291 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3292 if (dpp_auth_build_resp_status(auth
,
3293 DPP_STATUS_RESPONSE_PENDING
) < 0)
3295 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3296 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3298 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3299 auth
->response_pending
= 1;
3300 os_memcpy(auth
->waiting_pubkey_hash
,
3301 i_bootstrap
, i_bootstrap_len
);
3302 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3308 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3312 if (dpp_auth_build_resp_ok(auth
) < 0)
3318 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3319 "i-capab=0x%02x", auth
->i_capab
);
3320 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3321 auth
->configurator
= 1;
3323 auth
->configurator
= 0;
3324 auth
->peer_protocol_key
= pi
;
3326 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3329 auth
->remove_on_tx_status
= 1;
3332 bin_clear_free(unwrapped
, unwrapped_len
);
3334 EVP_PKEY_CTX_free(ctx
);
3335 dpp_auth_deinit(auth
);
3340 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3341 struct dpp_bootstrap_info
*peer_bi
)
3343 if (!auth
|| !auth
->response_pending
||
3344 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3345 SHA256_MAC_LEN
) != 0)
3348 wpa_printf(MSG_DEBUG
,
3349 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3350 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3351 auth
->peer_bi
= peer_bi
;
3353 if (dpp_auth_build_resp_ok(auth
) < 0)
3360 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3361 enum dpp_status_error status
)
3364 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3366 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3369 size_t len
[2], attr_len
;
3371 u8
*wrapped_r_nonce
;
3372 u8
*attr_start
, *attr_end
;
3373 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3374 #ifdef CONFIG_TESTING_OPTIONS
3375 u8 test_hash
[SHA256_MAC_LEN
];
3376 #endif /* CONFIG_TESTING_OPTIONS */
3378 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3380 i_auth_len
= 4 + auth
->curve
->hash_len
;
3381 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3382 /* Build DPP Authentication Confirmation frame attributes */
3383 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3384 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3385 #ifdef CONFIG_TESTING_OPTIONS
3386 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3388 #endif /* CONFIG_TESTING_OPTIONS */
3389 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3393 attr_start
= wpabuf_put(msg
, 0);
3395 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3397 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3399 i_pubkey_hash
= NULL
;
3401 #ifdef CONFIG_TESTING_OPTIONS
3402 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3403 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3405 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3406 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3409 #endif /* CONFIG_TESTING_OPTIONS */
3412 dpp_build_attr_status(msg
, status
);
3414 #ifdef CONFIG_TESTING_OPTIONS
3416 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3417 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3418 r_pubkey_hash
= NULL
;
3419 } else if (dpp_test
==
3420 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3421 wpa_printf(MSG_INFO
,
3422 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3423 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3424 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3425 r_pubkey_hash
= test_hash
;
3426 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3427 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3428 i_pubkey_hash
= NULL
;
3429 } else if (dpp_test
==
3430 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3431 wpa_printf(MSG_INFO
,
3432 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3434 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3436 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3437 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3438 i_pubkey_hash
= test_hash
;
3440 #endif /* CONFIG_TESTING_OPTIONS */
3442 /* Responder Bootstrapping Key Hash */
3443 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3445 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3446 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3448 #ifdef CONFIG_TESTING_OPTIONS
3449 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3450 goto skip_wrapped_data
;
3451 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3453 #endif /* CONFIG_TESTING_OPTIONS */
3455 attr_end
= wpabuf_put(msg
, 0);
3457 /* OUI, OUI type, Crypto Suite, DPP frame type */
3458 addr
[0] = wpabuf_head_u8(msg
) + 2;
3459 len
[0] = 3 + 1 + 1 + 1;
3460 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3462 /* Attributes before Wrapped Data */
3463 addr
[1] = attr_start
;
3464 len
[1] = attr_end
- attr_start
;
3465 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3467 if (status
== DPP_STATUS_OK
) {
3468 /* I-auth wrapped with ke */
3469 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3470 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3471 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3473 #ifdef CONFIG_TESTING_OPTIONS
3474 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3476 #endif /* CONFIG_TESTING_OPTIONS */
3478 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3480 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3481 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3482 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3485 #ifdef CONFIG_TESTING_OPTIONS
3486 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3487 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3488 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3491 #endif /* CONFIG_TESTING_OPTIONS */
3492 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3494 2, addr
, len
, wrapped_i_auth
) < 0)
3496 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3497 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3499 /* R-nonce wrapped with k2 */
3500 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3501 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3502 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3504 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3505 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3506 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3508 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3509 r_nonce
, r_nonce_len
,
3510 2, addr
, len
, wrapped_r_nonce
) < 0)
3512 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3513 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3516 #ifdef CONFIG_TESTING_OPTIONS
3517 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3518 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3519 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3522 #endif /* CONFIG_TESTING_OPTIONS */
3524 wpa_hexdump_buf(MSG_DEBUG
,
3525 "DPP: Authentication Confirmation frame attributes",
3527 if (status
== DPP_STATUS_OK
)
3528 dpp_auth_success(auth
);
3539 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3540 const u8
*attr_start
, size_t attr_len
,
3541 const u8
*wrapped_data
, u16 wrapped_data_len
,
3542 enum dpp_status_error status
)
3546 u8
*unwrapped
= NULL
;
3547 size_t unwrapped_len
= 0;
3548 const u8
*i_nonce
, *r_capab
;
3549 u16 i_nonce_len
, r_capab_len
;
3551 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3552 wpa_printf(MSG_DEBUG
,
3553 "DPP: Responder reported incompatible roles");
3554 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3555 wpa_printf(MSG_DEBUG
,
3556 "DPP: Responder reported more time needed");
3558 wpa_printf(MSG_DEBUG
,
3559 "DPP: Responder reported failure (status %d)",
3561 dpp_auth_fail(auth
, "Responder reported failure");
3566 len
[0] = DPP_HDR_LEN
;
3567 addr
[1] = attr_start
;
3569 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3570 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3571 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3572 wrapped_data
, wrapped_data_len
);
3573 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3574 unwrapped
= os_malloc(unwrapped_len
);
3577 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3578 wrapped_data
, wrapped_data_len
,
3579 2, addr
, len
, unwrapped
) < 0) {
3580 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3583 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3584 unwrapped
, unwrapped_len
);
3586 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3587 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3591 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3593 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3594 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3597 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3598 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3599 dpp_auth_fail(auth
, "I-nonce mismatch");
3603 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3604 DPP_ATTR_R_CAPABILITIES
,
3606 if (!r_capab
|| r_capab_len
< 1) {
3607 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3610 auth
->r_capab
= r_capab
[0];
3611 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3612 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3613 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3614 "r-capab=0x%02x", auth
->r_capab
);
3615 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3616 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3618 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3619 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3620 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3621 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3624 wpa_printf(MSG_DEBUG
,
3625 "DPP: Continue waiting for full DPP Authentication Response");
3626 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3627 DPP_EVENT_RESPONSE_PENDING
"%s",
3628 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3632 bin_clear_free(unwrapped
, unwrapped_len
);
3637 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3638 const u8
*attr_start
, size_t attr_len
)
3644 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3645 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3646 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3647 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3648 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3649 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3650 wrapped2_len
, r_auth_len
;
3651 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3656 #endif /* CONFIG_DPP2 */
3658 #ifdef CONFIG_TESTING_OPTIONS
3659 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3660 wpa_printf(MSG_INFO
,
3661 "DPP: TESTING - stop at Authentication Response");
3664 #endif /* CONFIG_TESTING_OPTIONS */
3666 if (!auth
->initiator
|| !auth
->peer_bi
) {
3667 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3671 auth
->waiting_auth_resp
= 0;
3673 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3675 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3677 "Missing or invalid required Wrapped Data attribute");
3680 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3681 wrapped_data
, wrapped_data_len
);
3683 attr_len
= wrapped_data
- 4 - attr_start
;
3685 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3686 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3688 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3690 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3693 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3694 r_bootstrap
, r_bootstrap_len
);
3695 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3696 SHA256_MAC_LEN
) != 0) {
3698 "Unexpected Responder Bootstrapping Key Hash value");
3699 wpa_hexdump(MSG_DEBUG
,
3700 "DPP: Expected Responder Bootstrapping Key Hash",
3701 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3705 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3706 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3709 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3711 "Invalid Initiator Bootstrapping Key Hash attribute");
3714 wpa_hexdump(MSG_MSGDUMP
,
3715 "DPP: Initiator Bootstrapping Key Hash",
3716 i_bootstrap
, i_bootstrap_len
);
3717 if (!auth
->own_bi
||
3718 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3719 SHA256_MAC_LEN
) != 0) {
3721 "Initiator Bootstrapping Key Hash attribute did not match");
3724 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3725 /* PKEX bootstrapping mandates use of mutual authentication */
3727 "Missing Initiator Bootstrapping Key Hash attribute");
3731 auth
->peer_version
= 1; /* default to the first version */
3733 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3736 if (version_len
< 1 || version
[0] == 0) {
3738 "Invalid Protocol Version attribute");
3741 auth
->peer_version
= version
[0];
3742 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3743 auth
->peer_version
);
3745 #endif /* CONFIG_DPP2 */
3747 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3749 if (!status
|| status_len
< 1) {
3751 "Missing or invalid required DPP Status attribute");
3754 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3755 auth
->auth_resp_status
= status
[0];
3756 if (status
[0] != DPP_STATUS_OK
) {
3757 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3758 attr_len
, wrapped_data
,
3759 wrapped_data_len
, status
[0]);
3763 if (!i_bootstrap
&& auth
->own_bi
) {
3764 wpa_printf(MSG_DEBUG
,
3765 "DPP: Responder decided not to use mutual authentication");
3766 auth
->own_bi
= NULL
;
3769 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3770 auth
->own_bi
!= NULL
);
3772 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3776 "Missing required Responder Protocol Key attribute");
3779 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3780 r_proto
, r_proto_len
);
3783 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3785 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3788 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3790 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
3791 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3794 EVP_PKEY_free(auth
->peer_protocol_key
);
3795 auth
->peer_protocol_key
= pr
;
3798 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3799 auth
->Nx
, auth
->secret_len
);
3800 auth
->Nx_len
= auth
->secret_len
;
3802 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3803 auth
->curve
->hash_len
) < 0)
3807 len
[0] = DPP_HDR_LEN
;
3808 addr
[1] = attr_start
;
3810 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3811 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3812 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3813 wrapped_data
, wrapped_data_len
);
3814 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3815 unwrapped
= os_malloc(unwrapped_len
);
3818 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3819 wrapped_data
, wrapped_data_len
,
3820 2, addr
, len
, unwrapped
) < 0) {
3821 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3824 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3825 unwrapped
, unwrapped_len
);
3827 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3828 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3832 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3834 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3835 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3838 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3839 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3841 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3843 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3844 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3847 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3848 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3849 dpp_auth_fail(auth
, "I-nonce mismatch");
3854 /* Mutual authentication */
3855 if (dpp_auth_derive_l_initiator(auth
) < 0)
3859 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3860 DPP_ATTR_R_CAPABILITIES
,
3862 if (!r_capab
|| r_capab_len
< 1) {
3863 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3866 auth
->r_capab
= r_capab
[0];
3867 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3868 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3869 if ((auth
->allowed_roles
==
3870 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3871 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3872 /* Peer selected its role, so move from "either role" to the
3873 * role that is compatible with peer's selection. */
3874 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3875 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3876 auth
->configurator
? "Configurator" : "Enrollee");
3877 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3878 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3879 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3880 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3881 "Unexpected role in R-capabilities 0x%02x",
3883 if (role
!= DPP_CAPAB_ENROLLEE
&&
3884 role
!= DPP_CAPAB_CONFIGURATOR
)
3886 bin_clear_free(unwrapped
, unwrapped_len
);
3887 auth
->remove_on_tx_status
= 1;
3888 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3891 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3892 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3893 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3895 "Missing or invalid Secondary Wrapped Data");
3899 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3900 wrapped2
, wrapped2_len
);
3902 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3905 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3906 unwrapped2
= os_malloc(unwrapped2_len
);
3909 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3910 wrapped2
, wrapped2_len
,
3911 0, NULL
, NULL
, unwrapped2
) < 0) {
3912 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3915 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3916 unwrapped2
, unwrapped2_len
);
3918 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3920 "Invalid attribute in secondary unwrapped data");
3924 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3926 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3928 "Missing or invalid Responder Authenticating Tag");
3931 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3932 r_auth
, r_auth_len
);
3933 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3934 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3936 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3937 r_auth2
, r_auth_len
);
3938 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3939 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3940 bin_clear_free(unwrapped
, unwrapped_len
);
3941 bin_clear_free(unwrapped2
, unwrapped2_len
);
3942 auth
->remove_on_tx_status
= 1;
3943 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3946 bin_clear_free(unwrapped
, unwrapped_len
);
3947 bin_clear_free(unwrapped2
, unwrapped2_len
);
3949 #ifdef CONFIG_TESTING_OPTIONS
3950 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3951 wpa_printf(MSG_INFO
,
3952 "DPP: TESTING - Authentication Response in place of Confirm");
3953 if (dpp_auth_build_resp_ok(auth
) < 0)
3955 return wpabuf_dup(auth
->resp_msg
);
3957 #endif /* CONFIG_TESTING_OPTIONS */
3959 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3962 bin_clear_free(unwrapped
, unwrapped_len
);
3963 bin_clear_free(unwrapped2
, unwrapped2_len
);
3969 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3971 const u8
*attr_start
, size_t attr_len
,
3972 const u8
*wrapped_data
,
3973 u16 wrapped_data_len
,
3974 enum dpp_status_error status
)
3978 u8
*unwrapped
= NULL
;
3979 size_t unwrapped_len
= 0;
3983 /* Authentication Confirm failure cases are expected to include
3984 * {R-nonce}k2 in the Wrapped Data attribute. */
3987 len
[0] = DPP_HDR_LEN
;
3988 addr
[1] = attr_start
;
3990 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3991 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3992 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3993 wrapped_data
, wrapped_data_len
);
3994 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3995 unwrapped
= os_malloc(unwrapped_len
);
3997 dpp_auth_fail(auth
, "Authentication failed");
4000 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4001 wrapped_data
, wrapped_data_len
,
4002 2, addr
, len
, unwrapped
) < 0) {
4003 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4006 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4007 unwrapped
, unwrapped_len
);
4009 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4010 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4014 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4016 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4017 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4020 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4021 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4022 r_nonce
, r_nonce_len
);
4023 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4024 auth
->r_nonce
, r_nonce_len
);
4025 dpp_auth_fail(auth
, "R-nonce mismatch");
4029 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4030 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4031 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4032 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4035 bin_clear_free(unwrapped
, unwrapped_len
);
4040 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4041 const u8
*attr_start
, size_t attr_len
)
4043 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4044 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4048 u8
*unwrapped
= NULL
;
4049 size_t unwrapped_len
= 0;
4050 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4052 #ifdef CONFIG_TESTING_OPTIONS
4053 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4054 wpa_printf(MSG_INFO
,
4055 "DPP: TESTING - stop at Authentication Confirm");
4058 #endif /* CONFIG_TESTING_OPTIONS */
4060 if (auth
->initiator
|| !auth
->own_bi
) {
4061 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4065 auth
->waiting_auth_conf
= 0;
4067 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4069 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4071 "Missing or invalid required Wrapped Data attribute");
4074 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4075 wrapped_data
, wrapped_data_len
);
4077 attr_len
= wrapped_data
- 4 - attr_start
;
4079 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4080 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4082 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4084 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4087 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4088 r_bootstrap
, r_bootstrap_len
);
4089 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4090 SHA256_MAC_LEN
) != 0) {
4091 wpa_hexdump(MSG_DEBUG
,
4092 "DPP: Expected Responder Bootstrapping Key Hash",
4093 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4095 "Responder Bootstrapping Key Hash mismatch");
4099 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4100 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4103 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4105 "Invalid Initiator Bootstrapping Key Hash attribute");
4108 wpa_hexdump(MSG_MSGDUMP
,
4109 "DPP: Initiator Bootstrapping Key Hash",
4110 i_bootstrap
, i_bootstrap_len
);
4111 if (!auth
->peer_bi
||
4112 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4113 SHA256_MAC_LEN
) != 0) {
4115 "Initiator Bootstrapping Key Hash mismatch");
4118 } else if (auth
->peer_bi
) {
4119 /* Mutual authentication and peer did not include its
4120 * Bootstrapping Key Hash attribute. */
4122 "Missing Initiator Bootstrapping Key Hash attribute");
4126 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4128 if (!status
|| status_len
< 1) {
4130 "Missing or invalid required DPP Status attribute");
4133 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4134 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4135 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4136 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4137 attr_len
, wrapped_data
,
4138 wrapped_data_len
, status
[0]);
4140 if (status
[0] != DPP_STATUS_OK
) {
4141 dpp_auth_fail(auth
, "Authentication failed");
4146 len
[0] = DPP_HDR_LEN
;
4147 addr
[1] = attr_start
;
4149 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4150 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4151 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4152 wrapped_data
, wrapped_data_len
);
4153 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4154 unwrapped
= os_malloc(unwrapped_len
);
4157 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4158 wrapped_data
, wrapped_data_len
,
4159 2, addr
, len
, unwrapped
) < 0) {
4160 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4163 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4164 unwrapped
, unwrapped_len
);
4166 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4167 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4171 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4173 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4175 "Missing or invalid Initiator Authenticating Tag");
4178 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4179 i_auth
, i_auth_len
);
4180 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4181 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4183 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4184 i_auth2
, i_auth_len
);
4185 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4186 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4190 bin_clear_free(unwrapped
, unwrapped_len
);
4191 dpp_auth_success(auth
);
4194 bin_clear_free(unwrapped
, unwrapped_len
);
4199 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4201 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4205 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4207 struct dpp_configuration
*conf
;
4211 conf
= os_zalloc(sizeof(*conf
));
4215 end
= os_strchr(type
, ' ');
4219 len
= os_strlen(type
);
4221 if (bin_str_eq(type
, len
, "psk"))
4222 conf
->akm
= DPP_AKM_PSK
;
4223 else if (bin_str_eq(type
, len
, "sae"))
4224 conf
->akm
= DPP_AKM_SAE
;
4225 else if (bin_str_eq(type
, len
, "psk-sae") ||
4226 bin_str_eq(type
, len
, "psk+sae"))
4227 conf
->akm
= DPP_AKM_PSK_SAE
;
4228 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4229 bin_str_eq(type
, len
, "dpp+sae"))
4230 conf
->akm
= DPP_AKM_SAE_DPP
;
4231 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4232 bin_str_eq(type
, len
, "dpp+psk+sae"))
4233 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4234 else if (bin_str_eq(type
, len
, "dpp"))
4235 conf
->akm
= DPP_AKM_DPP
;
4241 dpp_configuration_free(conf
);
4246 int dpp_akm_psk(enum dpp_akm akm
)
4248 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4249 akm
== DPP_AKM_PSK_SAE_DPP
;
4253 int dpp_akm_sae(enum dpp_akm akm
)
4255 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4256 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4260 int dpp_akm_legacy(enum dpp_akm akm
)
4262 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4267 int dpp_akm_dpp(enum dpp_akm akm
)
4269 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4270 akm
== DPP_AKM_PSK_SAE_DPP
;
4274 int dpp_akm_ver2(enum dpp_akm akm
)
4276 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4280 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4282 if (conf
->ssid_len
== 0)
4284 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4286 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4292 void dpp_configuration_free(struct dpp_configuration
*conf
)
4296 str_clear_free(conf
->passphrase
);
4297 os_free(conf
->group_id
);
4298 bin_clear_free(conf
, sizeof(*conf
));
4302 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4305 const char *pos
, *end
;
4306 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4307 struct dpp_configuration
*conf
= NULL
;
4309 pos
= os_strstr(cmd
, " conf=sta-");
4311 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4317 pos
= os_strstr(cmd
, " conf=ap-");
4319 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4328 pos
= os_strstr(cmd
, " ssid=");
4331 end
= os_strchr(pos
, ' ');
4332 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4333 conf
->ssid_len
/= 2;
4334 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4335 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4338 #ifdef CONFIG_TESTING_OPTIONS
4339 /* use a default SSID for legacy testing reasons */
4340 os_memcpy(conf
->ssid
, "test", 4);
4342 #else /* CONFIG_TESTING_OPTIONS */
4344 #endif /* CONFIG_TESTING_OPTIONS */
4347 pos
= os_strstr(cmd
, " pass=");
4352 end
= os_strchr(pos
, ' ');
4353 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4355 if (pass_len
> 63 || pass_len
< 8)
4357 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4358 if (!conf
->passphrase
||
4359 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4363 pos
= os_strstr(cmd
, " psk=");
4366 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4371 pos
= os_strstr(cmd
, " group_id=");
4373 size_t group_id_len
;
4376 end
= os_strchr(pos
, ' ');
4377 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4378 conf
->group_id
= os_malloc(group_id_len
+ 1);
4379 if (!conf
->group_id
)
4381 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4382 conf
->group_id
[group_id_len
] = '\0';
4385 pos
= os_strstr(cmd
, " expiry=");
4390 val
= strtol(pos
, NULL
, 0);
4393 conf
->netaccesskey_expiry
= val
;
4396 if (!dpp_configuration_valid(conf
))
4399 auth
->conf_sta
= conf_sta
;
4400 auth
->conf_ap
= conf_ap
;
4404 dpp_configuration_free(conf_sta
);
4405 dpp_configuration_free(conf_ap
);
4410 static struct dpp_configurator
*
4411 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4413 struct dpp_configurator
*conf
;
4418 dl_list_for_each(conf
, &dpp
->configurator
,
4419 struct dpp_configurator
, list
) {
4427 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4428 struct dpp_authentication
*auth
,
4436 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4438 pos
= os_strstr(cmd
, " configurator=");
4441 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4443 wpa_printf(MSG_INFO
,
4444 "DPP: Could not find the specified configurator");
4449 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4450 wpa_msg(msg_ctx
, MSG_INFO
,
4451 "DPP: Failed to set configurator parameters");
4458 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4462 dpp_configuration_free(auth
->conf_ap
);
4463 dpp_configuration_free(auth
->conf_sta
);
4464 EVP_PKEY_free(auth
->own_protocol_key
);
4465 EVP_PKEY_free(auth
->peer_protocol_key
);
4466 wpabuf_free(auth
->req_msg
);
4467 wpabuf_free(auth
->resp_msg
);
4468 wpabuf_free(auth
->conf_req
);
4469 os_free(auth
->connector
);
4470 wpabuf_free(auth
->net_access_key
);
4471 wpabuf_free(auth
->c_sign_key
);
4472 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4473 #ifdef CONFIG_TESTING_OPTIONS
4474 os_free(auth
->config_obj_override
);
4475 os_free(auth
->discovery_override
);
4476 os_free(auth
->groups_override
);
4477 #endif /* CONFIG_TESTING_OPTIONS */
4478 bin_clear_free(auth
, sizeof(*auth
));
4482 static struct wpabuf
*
4483 dpp_build_conf_start(struct dpp_authentication
*auth
,
4484 struct dpp_configuration
*conf
, size_t tailroom
)
4487 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4489 #ifdef CONFIG_TESTING_OPTIONS
4490 if (auth
->discovery_override
)
4491 tailroom
+= os_strlen(auth
->discovery_override
);
4492 #endif /* CONFIG_TESTING_OPTIONS */
4494 buf
= wpabuf_alloc(200 + tailroom
);
4497 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4498 #ifdef CONFIG_TESTING_OPTIONS
4499 if (auth
->discovery_override
) {
4500 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4501 auth
->discovery_override
);
4502 wpabuf_put_str(buf
, auth
->discovery_override
);
4503 wpabuf_put_u8(buf
, ',');
4506 #endif /* CONFIG_TESTING_OPTIONS */
4507 wpabuf_put_str(buf
, "{\"ssid\":\"");
4508 json_escape_string(ssid
, sizeof(ssid
),
4509 (const char *) conf
->ssid
, conf
->ssid_len
);
4510 wpabuf_put_str(buf
, ssid
);
4511 wpabuf_put_str(buf
, "\"},");
4517 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4518 const char *kid
, const struct dpp_curve_params
*curve
)
4522 char *x
= NULL
, *y
= NULL
;
4525 pub
= dpp_get_pubkey_point(key
, 0);
4528 pos
= wpabuf_head(pub
);
4529 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4530 pos
+= curve
->prime_len
;
4531 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4535 wpabuf_put_str(buf
, "\"");
4536 wpabuf_put_str(buf
, name
);
4537 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4538 wpabuf_put_str(buf
, curve
->jwk_crv
);
4539 wpabuf_put_str(buf
, "\",\"x\":\"");
4540 wpabuf_put_str(buf
, x
);
4541 wpabuf_put_str(buf
, "\",\"y\":\"");
4542 wpabuf_put_str(buf
, y
);
4544 wpabuf_put_str(buf
, "\",\"kid\":\"");
4545 wpabuf_put_str(buf
, kid
);
4547 wpabuf_put_str(buf
, "\"}");
4557 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4558 struct dpp_configuration
*conf
)
4560 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4561 char pass
[63 * 6 + 1];
4563 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4564 os_strlen(conf
->passphrase
));
4565 wpabuf_put_str(buf
, "\"pass\":\"");
4566 wpabuf_put_str(buf
, pass
);
4567 wpabuf_put_str(buf
, "\"");
4568 os_memset(pass
, 0, sizeof(pass
));
4569 } else if (conf
->psk_set
) {
4570 char psk
[2 * sizeof(conf
->psk
) + 1];
4572 wpa_snprintf_hex(psk
, sizeof(psk
),
4573 conf
->psk
, sizeof(conf
->psk
));
4574 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4575 wpabuf_put_str(buf
, psk
);
4576 wpabuf_put_str(buf
, "\"");
4577 os_memset(psk
, 0, sizeof(psk
));
4582 static struct wpabuf
*
4583 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4584 struct dpp_configuration
*conf
)
4586 struct wpabuf
*buf
= NULL
;
4587 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4589 const struct dpp_curve_params
*curve
;
4590 char jws_prot_hdr
[100];
4591 size_t signed1_len
, signed2_len
, signed3_len
;
4592 struct wpabuf
*dppcon
= NULL
;
4593 unsigned char *signature
= NULL
;
4594 const unsigned char *p
;
4595 size_t signature_len
;
4596 EVP_MD_CTX
*md_ctx
= NULL
;
4597 ECDSA_SIG
*sig
= NULL
;
4599 const EVP_MD
*sign_md
;
4600 const BIGNUM
*r
, *s
;
4601 size_t extra_len
= 1000;
4606 wpa_printf(MSG_INFO
,
4607 "DPP: No configurator specified - cannot generate DPP config object");
4610 curve
= auth
->conf
->curve
;
4611 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4612 sign_md
= EVP_sha256();
4613 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4614 sign_md
= EVP_sha384();
4615 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4616 sign_md
= EVP_sha512();
4618 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4623 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4624 wpa_printf(MSG_DEBUG
,
4625 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4629 #ifdef CONFIG_TESTING_OPTIONS
4630 if (auth
->groups_override
)
4631 extra_len
+= os_strlen(auth
->groups_override
);
4632 #endif /* CONFIG_TESTING_OPTIONS */
4635 extra_len
+= os_strlen(conf
->group_id
);
4637 /* Connector (JSON dppCon object) */
4638 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4641 #ifdef CONFIG_TESTING_OPTIONS
4642 if (auth
->groups_override
) {
4643 wpabuf_put_u8(dppcon
, '{');
4644 if (auth
->groups_override
) {
4645 wpa_printf(MSG_DEBUG
,
4646 "DPP: TESTING - groups override: '%s'",
4647 auth
->groups_override
);
4648 wpabuf_put_str(dppcon
, "\"groups\":");
4649 wpabuf_put_str(dppcon
, auth
->groups_override
);
4650 wpabuf_put_u8(dppcon
, ',');
4654 #endif /* CONFIG_TESTING_OPTIONS */
4655 wpabuf_printf(dppcon
, "{\"groups\":[{\"groupId\":\"%s\",",
4656 conf
->group_id
? conf
->group_id
: "*");
4657 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4658 #ifdef CONFIG_TESTING_OPTIONS
4660 #endif /* CONFIG_TESTING_OPTIONS */
4661 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4663 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4666 if (conf
->netaccesskey_expiry
) {
4669 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4670 wpa_printf(MSG_DEBUG
,
4671 "DPP: Failed to generate expiry string");
4674 wpabuf_printf(dppcon
,
4675 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4676 tm
.year
, tm
.month
, tm
.day
,
4677 tm
.hour
, tm
.min
, tm
.sec
);
4679 wpabuf_put_u8(dppcon
, '}');
4680 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4681 (const char *) wpabuf_head(dppcon
));
4683 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4684 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4685 auth
->conf
->kid
, curve
->jws_alg
);
4686 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4687 os_strlen(jws_prot_hdr
),
4689 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4692 if (!signed1
|| !signed2
)
4695 md_ctx
= EVP_MD_CTX_create();
4700 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4701 auth
->conf
->csign
) != 1) {
4702 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4703 ERR_error_string(ERR_get_error(), NULL
));
4706 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4707 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4708 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4709 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4710 ERR_error_string(ERR_get_error(), NULL
));
4713 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4714 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4715 ERR_error_string(ERR_get_error(), NULL
));
4718 signature
= os_malloc(signature_len
);
4721 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4722 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4723 ERR_error_string(ERR_get_error(), NULL
));
4726 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4727 signature
, signature_len
);
4728 /* Convert to raw coordinates r,s */
4730 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4733 ECDSA_SIG_get0(sig
, &r
, &s
);
4734 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4735 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4736 curve
->prime_len
) < 0)
4738 signature_len
= 2 * curve
->prime_len
;
4739 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4740 signature
, signature_len
);
4741 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4746 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
4748 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4749 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4752 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4756 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm
));
4758 dpp_build_legacy_cred_params(buf
, conf
);
4759 wpabuf_put_str(buf
, ",");
4761 wpabuf_put_str(buf
, "\"signedConnector\":\"");
4762 wpabuf_put_str(buf
, signed1
);
4763 wpabuf_put_u8(buf
, '.');
4764 wpabuf_put_str(buf
, signed2
);
4765 wpabuf_put_u8(buf
, '.');
4766 wpabuf_put_str(buf
, signed3
);
4767 wpabuf_put_str(buf
, "\",");
4768 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4770 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4774 wpabuf_put_str(buf
, "}}");
4776 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4777 wpabuf_head(buf
), wpabuf_len(buf
));
4780 EVP_MD_CTX_destroy(md_ctx
);
4781 ECDSA_SIG_free(sig
);
4786 wpabuf_free(dppcon
);
4789 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4796 static struct wpabuf
*
4797 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4798 struct dpp_configuration
*conf
)
4802 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4806 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4807 dpp_build_legacy_cred_params(buf
, conf
);
4808 wpabuf_put_str(buf
, "}}");
4810 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4811 wpabuf_head(buf
), wpabuf_len(buf
));
4817 static struct wpabuf
*
4818 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4820 struct dpp_configuration
*conf
;
4822 #ifdef CONFIG_TESTING_OPTIONS
4823 if (auth
->config_obj_override
) {
4824 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4825 return wpabuf_alloc_copy(auth
->config_obj_override
,
4826 os_strlen(auth
->config_obj_override
));
4828 #endif /* CONFIG_TESTING_OPTIONS */
4830 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4832 wpa_printf(MSG_DEBUG
,
4833 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4838 if (dpp_akm_dpp(conf
->akm
))
4839 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4840 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4844 static struct wpabuf
*
4845 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4846 u16 e_nonce_len
, int ap
)
4848 struct wpabuf
*conf
;
4849 size_t clear_len
, attr_len
;
4850 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4854 enum dpp_status_error status
;
4856 conf
= dpp_build_conf_obj(auth
, ap
);
4858 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4859 wpabuf_head(conf
), wpabuf_len(conf
));
4861 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4862 auth
->conf_resp_status
= status
;
4864 /* { E-nonce, configurationObject}ke */
4865 clear_len
= 4 + e_nonce_len
;
4867 clear_len
+= 4 + wpabuf_len(conf
);
4868 clear
= wpabuf_alloc(clear_len
);
4869 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4870 #ifdef CONFIG_TESTING_OPTIONS
4871 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4873 #endif /* CONFIG_TESTING_OPTIONS */
4874 msg
= wpabuf_alloc(attr_len
);
4878 #ifdef CONFIG_TESTING_OPTIONS
4879 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4880 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4883 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4884 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4885 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4886 wpabuf_put_le16(clear
, e_nonce_len
);
4887 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4888 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4891 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4892 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4893 goto skip_wrapped_data
;
4895 #endif /* CONFIG_TESTING_OPTIONS */
4898 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4899 wpabuf_put_le16(clear
, e_nonce_len
);
4900 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4902 #ifdef CONFIG_TESTING_OPTIONS
4904 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4905 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4906 goto skip_config_obj
;
4908 #endif /* CONFIG_TESTING_OPTIONS */
4911 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4912 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4913 wpabuf_put_buf(clear
, conf
);
4916 #ifdef CONFIG_TESTING_OPTIONS
4918 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4919 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4922 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4923 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4926 #endif /* CONFIG_TESTING_OPTIONS */
4929 dpp_build_attr_status(msg
, status
);
4931 #ifdef CONFIG_TESTING_OPTIONS
4933 #endif /* CONFIG_TESTING_OPTIONS */
4935 addr
[0] = wpabuf_head(msg
);
4936 len
[0] = wpabuf_len(msg
);
4937 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4939 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4940 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4941 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4943 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4944 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4945 wpabuf_head(clear
), wpabuf_len(clear
),
4946 1, addr
, len
, wrapped
) < 0)
4948 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4949 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4951 #ifdef CONFIG_TESTING_OPTIONS
4952 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4953 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4954 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4957 #endif /* CONFIG_TESTING_OPTIONS */
4959 wpa_hexdump_buf(MSG_DEBUG
,
4960 "DPP: Configuration Response attributes", msg
);
4974 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4977 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4978 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4979 u8
*unwrapped
= NULL
;
4980 size_t unwrapped_len
= 0;
4981 struct wpabuf
*resp
= NULL
;
4982 struct json_token
*root
= NULL
, *token
;
4985 #ifdef CONFIG_TESTING_OPTIONS
4986 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4987 wpa_printf(MSG_INFO
,
4988 "DPP: TESTING - stop at Config Request");
4991 #endif /* CONFIG_TESTING_OPTIONS */
4993 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4994 dpp_auth_fail(auth
, "Invalid attribute in config request");
4998 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5000 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5002 "Missing or invalid required Wrapped Data attribute");
5006 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5007 wrapped_data
, wrapped_data_len
);
5008 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5009 unwrapped
= os_malloc(unwrapped_len
);
5012 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5013 wrapped_data
, wrapped_data_len
,
5014 0, NULL
, NULL
, unwrapped
) < 0) {
5015 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5018 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5019 unwrapped
, unwrapped_len
);
5021 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5022 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5026 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5027 DPP_ATTR_ENROLLEE_NONCE
,
5029 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5031 "Missing or invalid Enrollee Nonce attribute");
5034 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5035 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5037 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5038 DPP_ATTR_CONFIG_ATTR_OBJ
,
5042 "Missing or invalid Config Attributes attribute");
5045 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5046 config_attr
, config_attr_len
);
5048 root
= json_parse((const char *) config_attr
, config_attr_len
);
5050 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5054 token
= json_get_member(root
, "name");
5055 if (!token
|| token
->type
!= JSON_STRING
) {
5056 dpp_auth_fail(auth
, "No Config Attributes - name");
5059 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5061 token
= json_get_member(root
, "wi-fi_tech");
5062 if (!token
|| token
->type
!= JSON_STRING
) {
5063 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5066 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5067 if (os_strcmp(token
->string
, "infra") != 0) {
5068 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5070 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5074 token
= json_get_member(root
, "netRole");
5075 if (!token
|| token
->type
!= JSON_STRING
) {
5076 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5079 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5080 if (os_strcmp(token
->string
, "sta") == 0) {
5082 } else if (os_strcmp(token
->string
, "ap") == 0) {
5085 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5087 dpp_auth_fail(auth
, "Unsupported netRole");
5091 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
5100 static struct wpabuf
*
5101 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
5102 const u8
*prot_hdr
, u16 prot_hdr_len
,
5103 const EVP_MD
**ret_md
)
5105 struct json_token
*root
, *token
;
5106 struct wpabuf
*kid
= NULL
;
5108 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
5110 wpa_printf(MSG_DEBUG
,
5111 "DPP: JSON parsing failed for JWS Protected Header");
5115 if (root
->type
!= JSON_OBJECT
) {
5116 wpa_printf(MSG_DEBUG
,
5117 "DPP: JWS Protected Header root is not an object");
5121 token
= json_get_member(root
, "typ");
5122 if (!token
|| token
->type
!= JSON_STRING
) {
5123 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
5126 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
5128 if (os_strcmp(token
->string
, "dppCon") != 0) {
5129 wpa_printf(MSG_DEBUG
,
5130 "DPP: Unsupported JWS Protected Header typ=%s",
5135 token
= json_get_member(root
, "alg");
5136 if (!token
|| token
->type
!= JSON_STRING
) {
5137 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
5140 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
5142 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5143 wpa_printf(MSG_DEBUG
,
5144 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5145 token
->string
, curve
->jws_alg
);
5148 if (os_strcmp(token
->string
, "ES256") == 0 ||
5149 os_strcmp(token
->string
, "BS256") == 0)
5150 *ret_md
= EVP_sha256();
5151 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5152 os_strcmp(token
->string
, "BS384") == 0)
5153 *ret_md
= EVP_sha384();
5154 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5155 os_strcmp(token
->string
, "BS512") == 0)
5156 *ret_md
= EVP_sha512();
5160 wpa_printf(MSG_DEBUG
,
5161 "DPP: Unsupported JWS Protected Header alg=%s",
5166 kid
= json_get_member_base64url(root
, "kid");
5168 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5171 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5180 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
5181 struct json_token
*cred
)
5183 struct json_token
*pass
, *psk_hex
;
5185 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5187 pass
= json_get_member(cred
, "pass");
5188 psk_hex
= json_get_member(cred
, "psk_hex");
5190 if (pass
&& pass
->type
== JSON_STRING
) {
5191 size_t len
= os_strlen(pass
->string
);
5193 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5195 if (len
< 8 || len
> 63)
5197 os_strlcpy(auth
->passphrase
, pass
->string
,
5198 sizeof(auth
->passphrase
));
5199 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5200 if (dpp_akm_sae(auth
->akm
) && !dpp_akm_psk(auth
->akm
)) {
5201 wpa_printf(MSG_DEBUG
,
5202 "DPP: Unexpected psk_hex with akm=sae");
5205 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5206 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
5207 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5210 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5211 auth
->psk
, PMK_LEN
);
5214 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5218 if (dpp_akm_sae(auth
->akm
) && !auth
->passphrase
[0]) {
5219 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5227 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5228 const struct dpp_curve_params
**key_curve
)
5230 struct json_token
*token
;
5231 const struct dpp_curve_params
*curve
;
5232 struct wpabuf
*x
= NULL
, *y
= NULL
;
5234 EVP_PKEY
*pkey
= NULL
;
5236 token
= json_get_member(jwk
, "kty");
5237 if (!token
|| token
->type
!= JSON_STRING
) {
5238 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5241 if (os_strcmp(token
->string
, "EC") != 0) {
5242 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5247 token
= json_get_member(jwk
, "crv");
5248 if (!token
|| token
->type
!= JSON_STRING
) {
5249 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5252 curve
= dpp_get_curve_jwk_crv(token
->string
);
5254 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5259 x
= json_get_member_base64url(jwk
, "x");
5261 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5264 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5265 if (wpabuf_len(x
) != curve
->prime_len
) {
5266 wpa_printf(MSG_DEBUG
,
5267 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5268 (unsigned int) wpabuf_len(x
),
5269 (unsigned int) curve
->prime_len
, curve
->name
);
5273 y
= json_get_member_base64url(jwk
, "y");
5275 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5278 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5279 if (wpabuf_len(y
) != curve
->prime_len
) {
5280 wpa_printf(MSG_DEBUG
,
5281 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5282 (unsigned int) wpabuf_len(y
),
5283 (unsigned int) curve
->prime_len
, curve
->name
);
5287 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5289 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5293 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5295 EC_GROUP_free(group
);
5306 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5309 unsigned int year
, month
, day
, hour
, min
, sec
;
5313 /* ISO 8601 date and time:
5315 * YYYY-MM-DDTHH:MM:SSZ
5316 * YYYY-MM-DDTHH:MM:SS+03:00
5318 if (os_strlen(timestamp
) < 19) {
5319 wpa_printf(MSG_DEBUG
,
5320 "DPP: Too short timestamp - assume expired key");
5323 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5324 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5325 wpa_printf(MSG_DEBUG
,
5326 "DPP: Failed to parse expiration day - assume expired key");
5330 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5331 wpa_printf(MSG_DEBUG
,
5332 "DPP: Invalid date/time information - assume expired key");
5336 pos
= timestamp
+ 19;
5337 if (*pos
== 'Z' || *pos
== '\0') {
5338 /* In UTC - no need to adjust */
5339 } else if (*pos
== '-' || *pos
== '+') {
5342 /* Adjust local time to UTC */
5343 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5345 wpa_printf(MSG_DEBUG
,
5346 "DPP: Invalid time zone designator (%s) - assume expired key",
5351 utime
+= 3600 * hour
;
5353 utime
-= 3600 * hour
;
5361 wpa_printf(MSG_DEBUG
,
5362 "DPP: Invalid time zone designator (%s) - assume expired key",
5369 if (os_get_time(&now
) < 0) {
5370 wpa_printf(MSG_DEBUG
,
5371 "DPP: Cannot get current time - assume expired key");
5375 if (now
.sec
> utime
) {
5376 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5385 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5386 const unsigned char *payload
,
5389 struct json_token
*root
, *groups
, *netkey
, *token
;
5391 EVP_PKEY
*key
= NULL
;
5392 const struct dpp_curve_params
*curve
;
5393 unsigned int rules
= 0;
5395 root
= json_parse((const char *) payload
, payload_len
);
5397 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5401 groups
= json_get_member(root
, "groups");
5402 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5403 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5406 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5407 struct json_token
*id
, *role
;
5409 id
= json_get_member(token
, "groupId");
5410 if (!id
|| id
->type
!= JSON_STRING
) {
5411 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5415 role
= json_get_member(token
, "netRole");
5416 if (!role
|| role
->type
!= JSON_STRING
) {
5417 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5420 wpa_printf(MSG_DEBUG
,
5421 "DPP: connector group: groupId='%s' netRole='%s'",
5422 id
->string
, role
->string
);
5428 wpa_printf(MSG_DEBUG
,
5429 "DPP: Connector includes no groups");
5433 token
= json_get_member(root
, "expiry");
5434 if (!token
|| token
->type
!= JSON_STRING
) {
5435 wpa_printf(MSG_DEBUG
,
5436 "DPP: No expiry string found - connector does not expire");
5438 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5439 if (dpp_key_expired(token
->string
,
5440 &auth
->net_access_key_expiry
)) {
5441 wpa_printf(MSG_DEBUG
,
5442 "DPP: Connector (netAccessKey) has expired");
5447 netkey
= json_get_member(root
, "netAccessKey");
5448 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5449 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5453 key
= dpp_parse_jwk(netkey
, &curve
);
5456 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5458 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5459 wpa_printf(MSG_DEBUG
,
5460 "DPP: netAccessKey in connector does not match own protocol key");
5461 #ifdef CONFIG_TESTING_OPTIONS
5462 if (auth
->ignore_netaccesskey_mismatch
) {
5463 wpa_printf(MSG_DEBUG
,
5464 "DPP: TESTING - skip netAccessKey mismatch");
5468 #else /* CONFIG_TESTING_OPTIONS */
5470 #endif /* CONFIG_TESTING_OPTIONS */
5481 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5483 struct wpabuf
*uncomp
;
5485 u8 hash
[SHA256_MAC_LEN
];
5489 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5491 uncomp
= dpp_get_pubkey_point(pub
, 1);
5494 addr
[0] = wpabuf_head(uncomp
);
5495 len
[0] = wpabuf_len(uncomp
);
5496 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5498 res
= sha256_vector(1, addr
, len
, hash
);
5499 wpabuf_free(uncomp
);
5502 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5503 wpa_printf(MSG_DEBUG
,
5504 "DPP: Received hash value does not match calculated public key hash value");
5505 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5506 hash
, SHA256_MAC_LEN
);
5513 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5515 unsigned char *der
= NULL
;
5518 der_len
= i2d_PUBKEY(csign
, &der
);
5521 wpabuf_free(auth
->c_sign_key
);
5522 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5527 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5529 unsigned char *der
= NULL
;
5533 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5537 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5542 wpabuf_free(auth
->net_access_key
);
5543 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5549 struct dpp_signed_connector_info
{
5550 unsigned char *payload
;
5554 static enum dpp_status_error
5555 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5556 EVP_PKEY
*csign_pub
, const char *connector
)
5558 enum dpp_status_error ret
= 255;
5559 const char *pos
, *end
, *signed_start
, *signed_end
;
5560 struct wpabuf
*kid
= NULL
;
5561 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5562 size_t prot_hdr_len
= 0, signature_len
= 0;
5563 const EVP_MD
*sign_md
= NULL
;
5564 unsigned char *der
= NULL
;
5567 EVP_MD_CTX
*md_ctx
= NULL
;
5568 ECDSA_SIG
*sig
= NULL
;
5569 BIGNUM
*r
= NULL
, *s
= NULL
;
5570 const struct dpp_curve_params
*curve
;
5572 const EC_GROUP
*group
;
5575 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5578 group
= EC_KEY_get0_group(eckey
);
5581 nid
= EC_GROUP_get_curve_name(group
);
5582 curve
= dpp_get_curve_nid(nid
);
5585 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5586 os_memset(info
, 0, sizeof(*info
));
5588 signed_start
= pos
= connector
;
5589 end
= os_strchr(pos
, '.');
5591 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5592 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5595 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5596 end
- pos
, &prot_hdr_len
);
5598 wpa_printf(MSG_DEBUG
,
5599 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5600 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5603 wpa_hexdump_ascii(MSG_DEBUG
,
5604 "DPP: signedConnector - JWS Protected Header",
5605 prot_hdr
, prot_hdr_len
);
5606 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5608 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5611 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5612 wpa_printf(MSG_DEBUG
,
5613 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5614 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5615 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5620 end
= os_strchr(pos
, '.');
5622 wpa_printf(MSG_DEBUG
,
5623 "DPP: Missing dot(2) in signedConnector");
5624 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5627 signed_end
= end
- 1;
5628 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5629 end
- pos
, &info
->payload_len
);
5630 if (!info
->payload
) {
5631 wpa_printf(MSG_DEBUG
,
5632 "DPP: Failed to base64url decode signedConnector JWS Payload");
5633 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5636 wpa_hexdump_ascii(MSG_DEBUG
,
5637 "DPP: signedConnector - JWS Payload",
5638 info
->payload
, info
->payload_len
);
5640 signature
= base64_url_decode((const unsigned char *) pos
,
5641 os_strlen(pos
), &signature_len
);
5643 wpa_printf(MSG_DEBUG
,
5644 "DPP: Failed to base64url decode signedConnector signature");
5645 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5648 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5649 signature
, signature_len
);
5651 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5652 ret
= DPP_STATUS_NO_MATCH
;
5656 if (signature_len
& 0x01) {
5657 wpa_printf(MSG_DEBUG
,
5658 "DPP: Unexpected signedConnector signature length (%d)",
5659 (int) signature_len
);
5660 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5664 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5665 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5666 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5667 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5668 sig
= ECDSA_SIG_new();
5669 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5674 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5676 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5679 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5680 md_ctx
= EVP_MD_CTX_create();
5685 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5686 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5687 ERR_error_string(ERR_get_error(), NULL
));
5690 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5691 signed_end
- signed_start
+ 1) != 1) {
5692 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5693 ERR_error_string(ERR_get_error(), NULL
));
5696 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5698 wpa_printf(MSG_DEBUG
,
5699 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5700 res
, ERR_error_string(ERR_get_error(), NULL
));
5701 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5705 ret
= DPP_STATUS_OK
;
5708 EVP_MD_CTX_destroy(md_ctx
);
5712 ECDSA_SIG_free(sig
);
5720 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5721 struct json_token
*cred
)
5723 struct dpp_signed_connector_info info
;
5724 struct json_token
*token
, *csign
;
5726 EVP_PKEY
*csign_pub
= NULL
;
5727 const struct dpp_curve_params
*key_curve
= NULL
;
5728 const char *signed_connector
;
5730 os_memset(&info
, 0, sizeof(info
));
5732 if (dpp_akm_psk(auth
->akm
) || dpp_akm_sae(auth
->akm
)) {
5733 wpa_printf(MSG_DEBUG
,
5734 "DPP: Legacy credential included in Connector credential");
5735 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5739 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5741 csign
= json_get_member(cred
, "csign");
5742 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5743 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5747 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5749 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5752 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5754 token
= json_get_member(cred
, "signedConnector");
5755 if (!token
|| token
->type
!= JSON_STRING
) {
5756 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5759 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5760 token
->string
, os_strlen(token
->string
));
5761 signed_connector
= token
->string
;
5763 if (os_strchr(signed_connector
, '"') ||
5764 os_strchr(signed_connector
, '\n')) {
5765 wpa_printf(MSG_DEBUG
,
5766 "DPP: Unexpected character in signedConnector");
5770 if (dpp_process_signed_connector(&info
, csign_pub
,
5771 signed_connector
) != DPP_STATUS_OK
)
5774 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5775 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5779 os_free(auth
->connector
);
5780 auth
->connector
= os_strdup(signed_connector
);
5782 dpp_copy_csign(auth
, csign_pub
);
5783 dpp_copy_netaccesskey(auth
);
5787 EVP_PKEY_free(csign_pub
);
5788 os_free(info
.payload
);
5793 const char * dpp_akm_str(enum dpp_akm akm
)
5802 case DPP_AKM_PSK_SAE
:
5804 case DPP_AKM_SAE_DPP
:
5806 case DPP_AKM_PSK_SAE_DPP
:
5807 return "dpp+psk+sae";
5814 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5816 if (os_strcmp(akm
, "psk") == 0)
5818 if (os_strcmp(akm
, "sae") == 0)
5820 if (os_strcmp(akm
, "psk+sae") == 0)
5821 return DPP_AKM_PSK_SAE
;
5822 if (os_strcmp(akm
, "dpp") == 0)
5824 if (os_strcmp(akm
, "dpp+sae") == 0)
5825 return DPP_AKM_SAE_DPP
;
5826 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
5827 return DPP_AKM_PSK_SAE_DPP
;
5828 return DPP_AKM_UNKNOWN
;
5832 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5833 const u8
*conf_obj
, u16 conf_obj_len
)
5836 struct json_token
*root
, *token
, *discovery
, *cred
;
5838 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5841 if (root
->type
!= JSON_OBJECT
) {
5842 dpp_auth_fail(auth
, "JSON root is not an object");
5846 token
= json_get_member(root
, "wi-fi_tech");
5847 if (!token
|| token
->type
!= JSON_STRING
) {
5848 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5851 if (os_strcmp(token
->string
, "infra") != 0) {
5852 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5854 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5858 discovery
= json_get_member(root
, "discovery");
5859 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5860 dpp_auth_fail(auth
, "No discovery object in JSON");
5864 token
= json_get_member(discovery
, "ssid");
5865 if (!token
|| token
->type
!= JSON_STRING
) {
5866 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5869 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5870 token
->string
, os_strlen(token
->string
));
5871 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5872 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5875 auth
->ssid_len
= os_strlen(token
->string
);
5876 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5878 cred
= json_get_member(root
, "cred");
5879 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5880 dpp_auth_fail(auth
, "No cred object in JSON");
5884 token
= json_get_member(cred
, "akm");
5885 if (!token
|| token
->type
!= JSON_STRING
) {
5886 dpp_auth_fail(auth
, "No cred::akm string value found");
5889 auth
->akm
= dpp_akm_from_str(token
->string
);
5891 if (dpp_akm_legacy(auth
->akm
)) {
5892 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5894 } else if (dpp_akm_dpp(auth
->akm
)) {
5895 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5898 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5900 dpp_auth_fail(auth
, "Unsupported akm");
5904 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5912 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5913 const struct wpabuf
*resp
)
5915 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5916 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5919 u8
*unwrapped
= NULL
;
5920 size_t unwrapped_len
= 0;
5923 auth
->conf_resp_status
= 255;
5925 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5926 dpp_auth_fail(auth
, "Invalid attribute in config response");
5930 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5931 DPP_ATTR_WRAPPED_DATA
,
5933 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5935 "Missing or invalid required Wrapped Data attribute");
5939 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5940 wrapped_data
, wrapped_data_len
);
5941 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5942 unwrapped
= os_malloc(unwrapped_len
);
5946 addr
[0] = wpabuf_head(resp
);
5947 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5948 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5950 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5951 wrapped_data
, wrapped_data_len
,
5952 1, addr
, len
, unwrapped
) < 0) {
5953 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5956 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5957 unwrapped
, unwrapped_len
);
5959 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5960 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5964 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5965 DPP_ATTR_ENROLLEE_NONCE
,
5967 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5969 "Missing or invalid Enrollee Nonce attribute");
5972 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5973 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5974 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5978 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5979 DPP_ATTR_STATUS
, &status_len
);
5980 if (!status
|| status_len
< 1) {
5982 "Missing or invalid required DPP Status attribute");
5985 auth
->conf_resp_status
= status
[0];
5986 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5987 if (status
[0] != DPP_STATUS_OK
) {
5988 dpp_auth_fail(auth
, "Configurator rejected configuration");
5992 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5993 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5996 "Missing required Configuration Object attribute");
5999 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
6000 conf_obj
, conf_obj_len
);
6001 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
6014 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
6016 const u8
*attr_start
, size_t attr_len
)
6018 const u8
*wrapped_data
, *status
, *e_nonce
;
6019 u16 wrapped_data_len
, status_len
, e_nonce_len
;
6022 u8
*unwrapped
= NULL
;
6023 size_t unwrapped_len
= 0;
6024 enum dpp_status_error ret
= 256;
6026 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
6028 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6030 "Missing or invalid required Wrapped Data attribute");
6033 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
6034 wrapped_data
, wrapped_data_len
);
6036 attr_len
= wrapped_data
- 4 - attr_start
;
6039 len
[0] = DPP_HDR_LEN
;
6040 addr
[1] = attr_start
;
6042 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6043 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6044 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6045 wrapped_data
, wrapped_data_len
);
6046 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6047 unwrapped
= os_malloc(unwrapped_len
);
6050 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6051 wrapped_data
, wrapped_data_len
,
6052 2, addr
, len
, unwrapped
) < 0) {
6053 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6056 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6057 unwrapped
, unwrapped_len
);
6059 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6060 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6064 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6065 DPP_ATTR_ENROLLEE_NONCE
,
6067 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6069 "Missing or invalid Enrollee Nonce attribute");
6072 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6073 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6074 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6075 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
6076 auth
->e_nonce
, e_nonce_len
);
6080 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
6082 if (!status
|| status_len
< 1) {
6084 "Missing or invalid required DPP Status attribute");
6087 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
6091 bin_clear_free(unwrapped
, unwrapped_len
);
6096 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
6097 enum dpp_status_error status
)
6099 struct wpabuf
*msg
, *clear
;
6100 size_t nonce_len
, clear_len
, attr_len
;
6105 nonce_len
= auth
->curve
->nonce_len
;
6106 clear_len
= 5 + 4 + nonce_len
;
6107 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6108 clear
= wpabuf_alloc(clear_len
);
6109 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
6114 dpp_build_attr_status(clear
, status
);
6117 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
6118 wpabuf_put_le16(clear
, nonce_len
);
6119 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
6121 /* OUI, OUI type, Crypto Suite, DPP frame type */
6122 addr
[0] = wpabuf_head_u8(msg
) + 2;
6123 len
[0] = 3 + 1 + 1 + 1;
6124 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6126 /* Attributes before Wrapped Data (none) */
6127 addr
[1] = wpabuf_put(msg
, 0);
6129 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6132 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6133 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6134 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6136 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6137 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
6138 wpabuf_head(clear
), wpabuf_len(clear
),
6139 2, addr
, len
, wrapped
) < 0)
6142 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
6151 #endif /* CONFIG_DPP2 */
6154 void dpp_configurator_free(struct dpp_configurator
*conf
)
6158 EVP_PKEY_free(conf
->csign
);
6164 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
6168 int key_len
, ret
= -1;
6169 unsigned char *key
= NULL
;
6174 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
6178 key_len
= i2d_ECPrivateKey(eckey
, &key
);
6180 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
6188 struct dpp_configurator
*
6189 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
6192 struct dpp_configurator
*conf
;
6193 struct wpabuf
*csign_pub
= NULL
;
6194 u8 kid_hash
[SHA256_MAC_LEN
];
6198 conf
= os_zalloc(sizeof(*conf
));
6203 conf
->curve
= &dpp_curves
[0];
6205 conf
->curve
= dpp_get_curve_name(curve
);
6207 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6214 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
6217 conf
->csign
= dpp_gen_keypair(conf
->curve
);
6222 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
6224 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
6228 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6229 addr
[0] = wpabuf_head(csign_pub
);
6230 len
[0] = wpabuf_len(csign_pub
);
6231 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
6232 wpa_printf(MSG_DEBUG
,
6233 "DPP: Failed to derive kid for C-sign-key");
6237 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
6242 wpabuf_free(csign_pub
);
6245 dpp_configurator_free(conf
);
6251 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
6252 const char *curve
, int ap
)
6254 struct wpabuf
*conf_obj
;
6258 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
6263 auth
->curve
= &dpp_curves
[0];
6265 auth
->curve
= dpp_get_curve_name(curve
);
6267 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6272 wpa_printf(MSG_DEBUG
,
6273 "DPP: Building own configuration/connector with curve %s",
6276 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
6277 if (!auth
->own_protocol_key
)
6279 dpp_copy_netaccesskey(auth
);
6280 auth
->peer_protocol_key
= auth
->own_protocol_key
;
6281 dpp_copy_csign(auth
, auth
->conf
->csign
);
6283 conf_obj
= dpp_build_conf_obj(auth
, ap
);
6286 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
6287 wpabuf_len(conf_obj
));
6289 wpabuf_free(conf_obj
);
6290 auth
->peer_protocol_key
= NULL
;
6295 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
6297 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
6298 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
6302 static int dpp_connector_compatible_group(struct json_token
*root
,
6303 const char *group_id
,
6304 const char *net_role
)
6306 struct json_token
*groups
, *token
;
6308 groups
= json_get_member(root
, "groups");
6309 if (!groups
|| groups
->type
!= JSON_ARRAY
)
6312 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6313 struct json_token
*id
, *role
;
6315 id
= json_get_member(token
, "groupId");
6316 if (!id
|| id
->type
!= JSON_STRING
)
6319 role
= json_get_member(token
, "netRole");
6320 if (!role
|| role
->type
!= JSON_STRING
)
6323 if (os_strcmp(id
->string
, "*") != 0 &&
6324 os_strcmp(group_id
, "*") != 0 &&
6325 os_strcmp(id
->string
, group_id
) != 0)
6328 if (dpp_compatible_netrole(role
->string
, net_role
))
6336 static int dpp_connector_match_groups(struct json_token
*own_root
,
6337 struct json_token
*peer_root
)
6339 struct json_token
*groups
, *token
;
6341 groups
= json_get_member(peer_root
, "groups");
6342 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6343 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
6347 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6348 struct json_token
*id
, *role
;
6350 id
= json_get_member(token
, "groupId");
6351 if (!id
|| id
->type
!= JSON_STRING
) {
6352 wpa_printf(MSG_DEBUG
,
6353 "DPP: Missing peer groupId string");
6357 role
= json_get_member(token
, "netRole");
6358 if (!role
|| role
->type
!= JSON_STRING
) {
6359 wpa_printf(MSG_DEBUG
,
6360 "DPP: Missing peer groups::netRole string");
6363 wpa_printf(MSG_DEBUG
,
6364 "DPP: peer connector group: groupId='%s' netRole='%s'",
6365 id
->string
, role
->string
);
6366 if (dpp_connector_compatible_group(own_root
, id
->string
,
6368 wpa_printf(MSG_DEBUG
,
6369 "DPP: Compatible group/netRole in own connector");
6378 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
6379 unsigned int hash_len
)
6381 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6382 const char *info
= "DPP PMK";
6385 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6387 /* HKDF-Extract(<>, N.x) */
6388 os_memset(salt
, 0, hash_len
);
6389 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
6391 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6394 /* HKDF-Expand(PRK, info, L) */
6395 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
6396 os_memset(prk
, 0, hash_len
);
6400 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6406 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
6407 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
6409 struct wpabuf
*nkx
, *pkx
;
6413 u8 hash
[SHA256_MAC_LEN
];
6415 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6416 nkx
= dpp_get_pubkey_point(own_key
, 0);
6417 pkx
= dpp_get_pubkey_point(peer_key
, 0);
6420 addr
[0] = wpabuf_head(nkx
);
6421 len
[0] = wpabuf_len(nkx
) / 2;
6422 addr
[1] = wpabuf_head(pkx
);
6423 len
[1] = wpabuf_len(pkx
) / 2;
6424 if (len
[0] != len
[1])
6426 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
6427 addr
[0] = wpabuf_head(pkx
);
6428 addr
[1] = wpabuf_head(nkx
);
6430 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
6431 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
6432 res
= sha256_vector(2, addr
, len
, hash
);
6435 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
6436 os_memcpy(pmkid
, hash
, PMKID_LEN
);
6437 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
6446 enum dpp_status_error
6447 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
6448 const u8
*net_access_key
, size_t net_access_key_len
,
6449 const u8
*csign_key
, size_t csign_key_len
,
6450 const u8
*peer_connector
, size_t peer_connector_len
,
6453 struct json_token
*root
= NULL
, *netkey
, *token
;
6454 struct json_token
*own_root
= NULL
;
6455 enum dpp_status_error ret
= 255, res
;
6456 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
6457 struct wpabuf
*own_key_pub
= NULL
;
6458 const struct dpp_curve_params
*curve
, *own_curve
;
6459 struct dpp_signed_connector_info info
;
6460 const unsigned char *p
;
6461 EVP_PKEY
*csign
= NULL
;
6462 char *signed_connector
= NULL
;
6463 const char *pos
, *end
;
6464 unsigned char *own_conn
= NULL
;
6465 size_t own_conn_len
;
6467 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
6469 os_memset(intro
, 0, sizeof(*intro
));
6470 os_memset(&info
, 0, sizeof(info
));
6475 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
6477 wpa_printf(MSG_ERROR
,
6478 "DPP: Failed to parse local C-sign-key information");
6482 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
6483 net_access_key_len
);
6485 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
6489 pos
= os_strchr(own_connector
, '.');
6491 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
6495 end
= os_strchr(pos
, '.');
6497 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
6500 own_conn
= base64_url_decode((const unsigned char *) pos
,
6501 end
- pos
, &own_conn_len
);
6503 wpa_printf(MSG_DEBUG
,
6504 "DPP: Failed to base64url decode own signedConnector JWS Payload");
6508 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
6510 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
6514 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
6515 peer_connector
, peer_connector_len
);
6516 signed_connector
= os_malloc(peer_connector_len
+ 1);
6517 if (!signed_connector
)
6519 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
6520 signed_connector
[peer_connector_len
] = '\0';
6522 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
6523 if (res
!= DPP_STATUS_OK
) {
6528 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
6530 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6531 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6535 if (!dpp_connector_match_groups(own_root
, root
)) {
6536 wpa_printf(MSG_DEBUG
,
6537 "DPP: Peer connector does not include compatible group netrole with own connector");
6538 ret
= DPP_STATUS_NO_MATCH
;
6542 token
= json_get_member(root
, "expiry");
6543 if (!token
|| token
->type
!= JSON_STRING
) {
6544 wpa_printf(MSG_DEBUG
,
6545 "DPP: No expiry string found - connector does not expire");
6547 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6548 if (dpp_key_expired(token
->string
, expiry
)) {
6549 wpa_printf(MSG_DEBUG
,
6550 "DPP: Connector (netAccessKey) has expired");
6551 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6556 netkey
= json_get_member(root
, "netAccessKey");
6557 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6558 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6559 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6563 peer_key
= dpp_parse_jwk(netkey
, &curve
);
6565 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6568 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
6570 if (own_curve
!= curve
) {
6571 wpa_printf(MSG_DEBUG
,
6572 "DPP: Mismatching netAccessKey curves (%s != %s)",
6573 own_curve
->name
, curve
->name
);
6574 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6578 /* ECDH: N = nk * PK */
6579 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
6582 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
6585 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6586 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
6587 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
6590 intro
->pmk_len
= curve
->hash_len
;
6592 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6593 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
6594 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
6598 ret
= DPP_STATUS_OK
;
6600 if (ret
!= DPP_STATUS_OK
)
6601 os_memset(intro
, 0, sizeof(*intro
));
6602 os_memset(Nx
, 0, sizeof(Nx
));
6604 os_free(signed_connector
);
6605 os_free(info
.payload
);
6606 EVP_PKEY_free(own_key
);
6607 wpabuf_free(own_key_pub
);
6608 EVP_PKEY_free(peer_key
);
6609 EVP_PKEY_free(csign
);
6611 json_free(own_root
);
6616 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
6620 size_t len
= curve
->prime_len
;
6624 switch (curve
->ike_group
) {
6626 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
6627 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
6630 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
6631 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
6634 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
6635 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
6638 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
6639 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6642 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6643 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6646 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6647 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6653 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6656 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
6657 EC_GROUP_free(group
);
6662 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6663 const u8
*mac_init
, const char *code
,
6664 const char *identifier
, BN_CTX
*bnctx
,
6665 EC_GROUP
**ret_group
)
6667 u8 hash
[DPP_MAX_HASH_LEN
];
6670 unsigned int num_elem
= 0;
6671 EC_POINT
*Qi
= NULL
;
6672 EVP_PKEY
*Pi
= NULL
;
6673 EC_KEY
*Pi_ec
= NULL
;
6674 const EC_POINT
*Pi_point
;
6675 BIGNUM
*hash_bn
= NULL
;
6676 const EC_GROUP
*group
= NULL
;
6677 EC_GROUP
*group2
= NULL
;
6679 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6681 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6682 addr
[num_elem
] = mac_init
;
6683 len
[num_elem
] = ETH_ALEN
;
6686 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6688 addr
[num_elem
] = (const u8
*) identifier
;
6689 len
[num_elem
] = os_strlen(identifier
);
6692 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6693 addr
[num_elem
] = (const u8
*) code
;
6694 len
[num_elem
] = os_strlen(code
);
6696 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6698 wpa_hexdump_key(MSG_DEBUG
,
6699 "DPP: H(MAC-Initiator | [identifier |] code)",
6700 hash
, curve
->hash_len
);
6701 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6704 dpp_debug_print_key("DPP: Pi", Pi
);
6705 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6708 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6710 group
= EC_KEY_get0_group(Pi_ec
);
6713 group2
= EC_GROUP_dup(group
);
6716 Qi
= EC_POINT_new(group2
);
6718 EC_GROUP_free(group2
);
6721 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6723 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6725 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6726 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6729 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6733 BN_clear_free(hash_bn
);
6734 if (ret_group
&& Qi
)
6735 *ret_group
= group2
;
6737 EC_GROUP_free(group2
);
6746 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6747 const u8
*mac_resp
, const char *code
,
6748 const char *identifier
, BN_CTX
*bnctx
,
6749 EC_GROUP
**ret_group
)
6751 u8 hash
[DPP_MAX_HASH_LEN
];
6754 unsigned int num_elem
= 0;
6755 EC_POINT
*Qr
= NULL
;
6756 EVP_PKEY
*Pr
= NULL
;
6757 EC_KEY
*Pr_ec
= NULL
;
6758 const EC_POINT
*Pr_point
;
6759 BIGNUM
*hash_bn
= NULL
;
6760 const EC_GROUP
*group
= NULL
;
6761 EC_GROUP
*group2
= NULL
;
6763 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6765 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6766 addr
[num_elem
] = mac_resp
;
6767 len
[num_elem
] = ETH_ALEN
;
6770 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6772 addr
[num_elem
] = (const u8
*) identifier
;
6773 len
[num_elem
] = os_strlen(identifier
);
6776 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6777 addr
[num_elem
] = (const u8
*) code
;
6778 len
[num_elem
] = os_strlen(code
);
6780 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6782 wpa_hexdump_key(MSG_DEBUG
,
6783 "DPP: H(MAC-Responder | [identifier |] code)",
6784 hash
, curve
->hash_len
);
6785 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6788 dpp_debug_print_key("DPP: Pr", Pr
);
6789 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6792 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6794 group
= EC_KEY_get0_group(Pr_ec
);
6797 group2
= EC_GROUP_dup(group
);
6800 Qr
= EC_POINT_new(group2
);
6802 EC_GROUP_free(group2
);
6805 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6807 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6809 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6810 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6813 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6817 BN_clear_free(hash_bn
);
6818 if (ret_group
&& Qr
)
6819 *ret_group
= group2
;
6821 EC_GROUP_free(group2
);
6830 #ifdef CONFIG_TESTING_OPTIONS
6831 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6832 const struct dpp_curve_params
*curve
)
6840 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6845 point
= EC_POINT_new(group
);
6848 if (!ctx
|| !point
|| !x
|| !y
)
6851 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6854 /* Generate a random y coordinate that results in a point that is not
6857 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6860 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6862 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6863 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6864 * return an error from EC_POINT_set_affine_coordinates_GFp()
6865 * when the point is not on the curve. */
6867 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6869 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6872 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6876 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6877 curve
->prime_len
) < 0 ||
6878 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6879 curve
->prime_len
) < 0)
6885 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6888 EC_POINT_free(point
);
6890 EC_GROUP_free(group
);
6894 #endif /* CONFIG_TESTING_OPTIONS */
6897 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6899 EC_KEY
*X_ec
= NULL
;
6900 const EC_POINT
*X_point
;
6901 BN_CTX
*bnctx
= NULL
;
6902 EC_GROUP
*group
= NULL
;
6903 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6904 struct wpabuf
*M_buf
= NULL
;
6905 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6906 struct wpabuf
*msg
= NULL
;
6908 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6910 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6912 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6913 bnctx
= BN_CTX_new();
6916 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6917 pkex
->identifier
, bnctx
, &group
);
6921 /* Generate a random ephemeral keypair x/X */
6922 #ifdef CONFIG_TESTING_OPTIONS
6923 if (dpp_pkex_ephemeral_key_override_len
) {
6924 const struct dpp_curve_params
*tmp_curve
;
6926 wpa_printf(MSG_INFO
,
6927 "DPP: TESTING - override ephemeral key x/X");
6928 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6929 dpp_pkex_ephemeral_key_override
,
6930 dpp_pkex_ephemeral_key_override_len
);
6932 pkex
->x
= dpp_gen_keypair(curve
);
6934 #else /* CONFIG_TESTING_OPTIONS */
6935 pkex
->x
= dpp_gen_keypair(curve
);
6936 #endif /* CONFIG_TESTING_OPTIONS */
6941 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6944 X_point
= EC_KEY_get0_public_key(X_ec
);
6947 dpp_debug_print_point("DPP: X", group
, X_point
);
6948 M
= EC_POINT_new(group
);
6951 if (!M
|| !Mx
|| !My
||
6952 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6953 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6955 dpp_debug_print_point("DPP: M", group
, M
);
6957 /* Initiator -> Responder: group, [identifier,] M */
6959 if (pkex
->identifier
)
6960 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6961 attr_len
+= 4 + 2 * curve
->prime_len
;
6962 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6966 #ifdef CONFIG_TESTING_OPTIONS
6967 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6968 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6969 goto skip_finite_cyclic_group
;
6971 #endif /* CONFIG_TESTING_OPTIONS */
6973 /* Finite Cyclic Group attribute */
6974 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6975 wpabuf_put_le16(msg
, 2);
6976 wpabuf_put_le16(msg
, curve
->ike_group
);
6978 #ifdef CONFIG_TESTING_OPTIONS
6979 skip_finite_cyclic_group
:
6980 #endif /* CONFIG_TESTING_OPTIONS */
6982 /* Code Identifier attribute */
6983 if (pkex
->identifier
) {
6984 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6985 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6986 wpabuf_put_str(msg
, pkex
->identifier
);
6989 #ifdef CONFIG_TESTING_OPTIONS
6990 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6991 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6994 #endif /* CONFIG_TESTING_OPTIONS */
6996 /* M in Encrypted Key attribute */
6997 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6998 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7000 #ifdef CONFIG_TESTING_OPTIONS
7001 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
7002 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7003 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7007 #endif /* CONFIG_TESTING_OPTIONS */
7009 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
7010 curve
->prime_len
) < 0 ||
7011 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
7012 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
7013 curve
->prime_len
) < 0)
7024 EC_GROUP_free(group
);
7027 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
7034 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
7036 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
7040 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
7042 const char *identifier
,
7045 struct dpp_pkex
*pkex
;
7047 #ifdef CONFIG_TESTING_OPTIONS
7048 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7049 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7050 MAC2STR(dpp_pkex_own_mac_override
));
7051 own_mac
= dpp_pkex_own_mac_override
;
7053 #endif /* CONFIG_TESTING_OPTIONS */
7055 pkex
= os_zalloc(sizeof(*pkex
));
7058 pkex
->msg_ctx
= msg_ctx
;
7059 pkex
->initiator
= 1;
7061 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7063 pkex
->identifier
= os_strdup(identifier
);
7064 if (!pkex
->identifier
)
7067 pkex
->code
= os_strdup(code
);
7070 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
7071 if (!pkex
->exchange_req
)
7075 dpp_pkex_free(pkex
);
7080 static struct wpabuf
*
7081 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
7082 enum dpp_status_error status
,
7083 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
7085 struct wpabuf
*msg
= NULL
;
7087 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7089 /* Initiator -> Responder: DPP Status, [identifier,] N */
7091 if (pkex
->identifier
)
7092 attr_len
+= 4 + os_strlen(pkex
->identifier
);
7093 attr_len
+= 4 + 2 * curve
->prime_len
;
7094 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
7098 #ifdef CONFIG_TESTING_OPTIONS
7099 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
7100 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
7104 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
7105 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
7108 #endif /* CONFIG_TESTING_OPTIONS */
7111 dpp_build_attr_status(msg
, status
);
7113 #ifdef CONFIG_TESTING_OPTIONS
7115 #endif /* CONFIG_TESTING_OPTIONS */
7117 /* Code Identifier attribute */
7118 if (pkex
->identifier
) {
7119 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
7120 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
7121 wpabuf_put_str(msg
, pkex
->identifier
);
7124 if (status
!= DPP_STATUS_OK
)
7125 goto skip_encrypted_key
;
7127 #ifdef CONFIG_TESTING_OPTIONS
7128 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7129 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
7130 goto skip_encrypted_key
;
7132 #endif /* CONFIG_TESTING_OPTIONS */
7134 /* N in Encrypted Key attribute */
7135 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
7136 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7138 #ifdef CONFIG_TESTING_OPTIONS
7139 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7140 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7141 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7143 goto skip_encrypted_key
;
7145 #endif /* CONFIG_TESTING_OPTIONS */
7147 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
7148 curve
->prime_len
) < 0 ||
7149 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
7150 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
7151 curve
->prime_len
) < 0)
7155 if (status
== DPP_STATUS_BAD_GROUP
) {
7156 /* Finite Cyclic Group attribute */
7157 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7158 wpabuf_put_le16(msg
, 2);
7159 wpabuf_put_le16(msg
, curve
->ike_group
);
7169 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
7170 const u8
*Mx
, size_t Mx_len
,
7171 const u8
*Nx
, size_t Nx_len
,
7173 const u8
*Kx
, size_t Kx_len
,
7174 u8
*z
, unsigned int hash_len
)
7176 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7181 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7184 /* HKDF-Extract(<>, IKM=K.x) */
7185 os_memset(salt
, 0, hash_len
);
7186 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
7188 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
7190 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
7191 info
= os_malloc(info_len
);
7195 os_memcpy(pos
, mac_init
, ETH_ALEN
);
7197 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
7199 os_memcpy(pos
, Mx
, Mx_len
);
7201 os_memcpy(pos
, Nx
, Nx_len
);
7203 os_memcpy(pos
, code
, os_strlen(code
));
7205 /* HKDF-Expand(PRK, info, L) */
7207 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7209 else if (hash_len
== 48)
7210 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7212 else if (hash_len
== 64)
7213 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7218 os_memset(prk
, 0, hash_len
);
7222 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
7228 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
7229 const char *identifier
)
7231 if (!attr_id
&& identifier
) {
7232 wpa_printf(MSG_DEBUG
,
7233 "DPP: No PKEX code identifier received, but expected one");
7237 if (attr_id
&& !identifier
) {
7238 wpa_printf(MSG_DEBUG
,
7239 "DPP: PKEX code identifier received, but not expecting one");
7243 if (attr_id
&& identifier
&&
7244 (os_strlen(identifier
) != attr_id_len
||
7245 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
7246 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
7254 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
7255 struct dpp_bootstrap_info
*bi
,
7258 const char *identifier
,
7260 const u8
*buf
, size_t len
)
7262 const u8
*attr_group
, *attr_id
, *attr_key
;
7263 u16 attr_group_len
, attr_id_len
, attr_key_len
;
7264 const struct dpp_curve_params
*curve
= bi
->curve
;
7266 struct dpp_pkex
*pkex
= NULL
;
7267 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
7268 BN_CTX
*bnctx
= NULL
;
7269 EC_GROUP
*group
= NULL
;
7270 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7271 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
7272 const EC_POINT
*Y_point
;
7273 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7274 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7278 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
7279 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7280 "PKEX counter t limit reached - ignore message");
7284 #ifdef CONFIG_TESTING_OPTIONS
7285 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7286 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7287 MAC2STR(dpp_pkex_peer_mac_override
));
7288 peer_mac
= dpp_pkex_peer_mac_override
;
7290 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7291 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7292 MAC2STR(dpp_pkex_own_mac_override
));
7293 own_mac
= dpp_pkex_own_mac_override
;
7295 #endif /* CONFIG_TESTING_OPTIONS */
7298 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
7300 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
7303 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
7305 if (!attr_group
|| attr_group_len
!= 2) {
7306 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7307 "Missing or invalid Finite Cyclic Group attribute");
7310 ike_group
= WPA_GET_LE16(attr_group
);
7311 if (ike_group
!= curve
->ike_group
) {
7312 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7313 "Mismatching PKEX curve: peer=%u own=%u",
7314 ike_group
, curve
->ike_group
);
7315 pkex
= os_zalloc(sizeof(*pkex
));
7320 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
7321 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
7322 if (!pkex
->exchange_resp
)
7327 /* M in Encrypted Key attribute */
7328 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
7330 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
7331 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
7332 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7333 "Missing Encrypted Key attribute");
7337 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7338 bnctx
= BN_CTX_new();
7341 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
7347 X
= EC_POINT_new(group
);
7348 M
= EC_POINT_new(group
);
7349 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7350 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7351 if (!X
|| !M
|| !Mx
|| !My
||
7352 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
7353 EC_POINT_is_at_infinity(group
, M
) ||
7354 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
7355 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
7356 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
7357 EC_POINT_is_at_infinity(group
, X
) ||
7358 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
7359 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7360 "Invalid Encrypted Key value");
7364 dpp_debug_print_point("DPP: M", group
, M
);
7365 dpp_debug_print_point("DPP: X'", group
, X
);
7367 pkex
= os_zalloc(sizeof(*pkex
));
7370 pkex
->t
= bi
->pkex_t
;
7371 pkex
->msg_ctx
= msg_ctx
;
7373 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7374 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7376 pkex
->identifier
= os_strdup(identifier
);
7377 if (!pkex
->identifier
)
7380 pkex
->code
= os_strdup(code
);
7384 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
7386 X_ec
= EC_KEY_new();
7388 EC_KEY_set_group(X_ec
, group
) != 1 ||
7389 EC_KEY_set_public_key(X_ec
, X
) != 1)
7391 pkex
->x
= EVP_PKEY_new();
7393 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
7396 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7397 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
7401 /* Generate a random ephemeral keypair y/Y */
7402 #ifdef CONFIG_TESTING_OPTIONS
7403 if (dpp_pkex_ephemeral_key_override_len
) {
7404 const struct dpp_curve_params
*tmp_curve
;
7406 wpa_printf(MSG_INFO
,
7407 "DPP: TESTING - override ephemeral key y/Y");
7408 pkex
->y
= dpp_set_keypair(&tmp_curve
,
7409 dpp_pkex_ephemeral_key_override
,
7410 dpp_pkex_ephemeral_key_override_len
);
7412 pkex
->y
= dpp_gen_keypair(curve
);
7414 #else /* CONFIG_TESTING_OPTIONS */
7415 pkex
->y
= dpp_gen_keypair(curve
);
7416 #endif /* CONFIG_TESTING_OPTIONS */
7421 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
7424 Y_point
= EC_KEY_get0_public_key(Y_ec
);
7427 dpp_debug_print_point("DPP: Y", group
, Y_point
);
7428 N
= EC_POINT_new(group
);
7431 if (!N
|| !Nx
|| !Ny
||
7432 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
7433 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
7435 dpp_debug_print_point("DPP: N", group
, N
);
7437 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
7439 if (!pkex
->exchange_resp
)
7443 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
7446 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7449 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7451 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
7452 pkex
->Mx
, curve
->prime_len
,
7453 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
7454 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
7455 os_memset(Kx
, 0, Kx_len
);
7459 pkex
->exchange_done
= 1;
7474 EC_GROUP_free(group
);
7477 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
7478 dpp_pkex_free(pkex
);
7484 static struct wpabuf
*
7485 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
7486 const struct wpabuf
*A_pub
, const u8
*u
)
7488 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7489 struct wpabuf
*msg
= NULL
;
7490 size_t clear_len
, attr_len
;
7491 struct wpabuf
*clear
= NULL
;
7497 /* {A, u, [bootstrapping info]}z */
7498 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7499 clear
= wpabuf_alloc(clear_len
);
7500 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7501 #ifdef CONFIG_TESTING_OPTIONS
7502 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
7504 #endif /* CONFIG_TESTING_OPTIONS */
7505 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
7509 #ifdef CONFIG_TESTING_OPTIONS
7510 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7511 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7512 goto skip_bootstrap_key
;
7514 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7515 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7516 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7517 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7518 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7520 goto skip_bootstrap_key
;
7522 #endif /* CONFIG_TESTING_OPTIONS */
7524 /* A in Bootstrap Key attribute */
7525 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7526 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
7527 wpabuf_put_buf(clear
, A_pub
);
7529 #ifdef CONFIG_TESTING_OPTIONS
7531 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
7532 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
7533 goto skip_i_auth_tag
;
7535 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
7536 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
7537 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7538 wpabuf_put_le16(clear
, curve
->hash_len
);
7539 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
7540 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
7541 goto skip_i_auth_tag
;
7543 #endif /* CONFIG_TESTING_OPTIONS */
7545 /* u in I-Auth tag attribute */
7546 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7547 wpabuf_put_le16(clear
, curve
->hash_len
);
7548 wpabuf_put_data(clear
, u
, curve
->hash_len
);
7550 #ifdef CONFIG_TESTING_OPTIONS
7552 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
7553 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7554 goto skip_wrapped_data
;
7556 #endif /* CONFIG_TESTING_OPTIONS */
7558 addr
[0] = wpabuf_head_u8(msg
) + 2;
7559 len
[0] = DPP_HDR_LEN
;
7562 len
[1] = sizeof(octet
);
7563 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7564 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7566 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7567 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7568 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7570 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7571 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7572 wpabuf_head(clear
), wpabuf_len(clear
),
7573 2, addr
, len
, wrapped
) < 0)
7575 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7576 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7578 #ifdef CONFIG_TESTING_OPTIONS
7579 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
7580 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7581 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7584 #endif /* CONFIG_TESTING_OPTIONS */
7597 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
7599 const u8
*buf
, size_t buflen
)
7601 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
7602 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
7603 EC_GROUP
*group
= NULL
;
7604 BN_CTX
*bnctx
= NULL
;
7605 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7606 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7607 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
7608 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7609 EC_KEY
*Y_ec
= NULL
;
7610 size_t Jx_len
, Kx_len
;
7611 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7614 u8 u
[DPP_MAX_HASH_LEN
];
7617 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7620 #ifdef CONFIG_TESTING_OPTIONS
7621 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
7622 wpa_printf(MSG_INFO
,
7623 "DPP: TESTING - stop at PKEX Exchange Response");
7628 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7629 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7630 MAC2STR(dpp_pkex_peer_mac_override
));
7631 peer_mac
= dpp_pkex_peer_mac_override
;
7633 #endif /* CONFIG_TESTING_OPTIONS */
7635 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7637 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
7639 if (!attr_status
|| attr_status_len
!= 1) {
7640 dpp_pkex_fail(pkex
, "No DPP Status attribute");
7643 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
7645 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
7646 attr_group
= dpp_get_attr(buf
, buflen
,
7647 DPP_ATTR_FINITE_CYCLIC_GROUP
,
7649 if (attr_group
&& attr_group_len
== 2) {
7650 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7651 "Peer indicated mismatching PKEX group - proposed %u",
7652 WPA_GET_LE16(attr_group
));
7657 if (attr_status
[0] != DPP_STATUS_OK
) {
7658 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7663 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7665 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
7666 pkex
->identifier
)) {
7667 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7671 /* N in Encrypted Key attribute */
7672 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7674 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7675 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7679 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7680 bnctx
= BN_CTX_new();
7683 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7684 pkex
->identifier
, bnctx
, &group
);
7689 Y
= EC_POINT_new(group
);
7690 N
= EC_POINT_new(group
);
7691 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7692 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7693 if (!Y
|| !N
|| !Nx
|| !Ny
||
7694 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7695 EC_POINT_is_at_infinity(group
, N
) ||
7696 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7697 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7698 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7699 EC_POINT_is_at_infinity(group
, Y
) ||
7700 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7701 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7705 dpp_debug_print_point("DPP: N", group
, N
);
7706 dpp_debug_print_point("DPP: Y'", group
, Y
);
7708 pkex
->exchange_done
= 1;
7710 /* ECDH: J = a * Y’ */
7711 Y_ec
= EC_KEY_new();
7713 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7714 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7716 pkex
->y
= EVP_PKEY_new();
7718 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7720 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
7723 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7726 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7727 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7728 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7729 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7730 if (!A_pub
|| !Y_pub
|| !X_pub
)
7732 addr
[0] = pkex
->own_mac
;
7734 addr
[1] = wpabuf_head(A_pub
);
7735 len
[1] = wpabuf_len(A_pub
) / 2;
7736 addr
[2] = wpabuf_head(Y_pub
);
7737 len
[2] = wpabuf_len(Y_pub
) / 2;
7738 addr
[3] = wpabuf_head(X_pub
);
7739 len
[3] = wpabuf_len(X_pub
) / 2;
7740 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7742 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7745 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
7748 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7751 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7753 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7754 pkex
->Mx
, curve
->prime_len
,
7755 attr_key
/* N.x */, attr_key_len
/ 2,
7756 pkex
->code
, Kx
, Kx_len
,
7757 pkex
->z
, curve
->hash_len
);
7758 os_memset(Kx
, 0, Kx_len
);
7762 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7777 EC_GROUP_free(group
);
7780 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7785 static struct wpabuf
*
7786 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7787 const struct wpabuf
*B_pub
, const u8
*v
)
7789 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7790 struct wpabuf
*msg
= NULL
;
7795 struct wpabuf
*clear
= NULL
;
7796 size_t clear_len
, attr_len
;
7798 /* {B, v [bootstrapping info]}z */
7799 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7800 clear
= wpabuf_alloc(clear_len
);
7801 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7802 #ifdef CONFIG_TESTING_OPTIONS
7803 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7805 #endif /* CONFIG_TESTING_OPTIONS */
7806 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7810 #ifdef CONFIG_TESTING_OPTIONS
7811 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7812 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7813 goto skip_bootstrap_key
;
7815 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7816 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7817 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7818 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7819 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7821 goto skip_bootstrap_key
;
7823 #endif /* CONFIG_TESTING_OPTIONS */
7825 /* B in Bootstrap Key attribute */
7826 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7827 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7828 wpabuf_put_buf(clear
, B_pub
);
7830 #ifdef CONFIG_TESTING_OPTIONS
7832 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7833 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7834 goto skip_r_auth_tag
;
7836 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7837 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7838 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7839 wpabuf_put_le16(clear
, curve
->hash_len
);
7840 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7841 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7842 goto skip_r_auth_tag
;
7844 #endif /* CONFIG_TESTING_OPTIONS */
7846 /* v in R-Auth tag attribute */
7847 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7848 wpabuf_put_le16(clear
, curve
->hash_len
);
7849 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7851 #ifdef CONFIG_TESTING_OPTIONS
7853 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7854 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7855 goto skip_wrapped_data
;
7857 #endif /* CONFIG_TESTING_OPTIONS */
7859 addr
[0] = wpabuf_head_u8(msg
) + 2;
7860 len
[0] = DPP_HDR_LEN
;
7863 len
[1] = sizeof(octet
);
7864 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7865 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7867 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7868 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7869 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7871 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7872 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7873 wpabuf_head(clear
), wpabuf_len(clear
),
7874 2, addr
, len
, wrapped
) < 0)
7876 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7877 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7879 #ifdef CONFIG_TESTING_OPTIONS
7880 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7881 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7882 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7885 #endif /* CONFIG_TESTING_OPTIONS */
7898 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7900 const u8
*buf
, size_t buflen
)
7902 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7903 size_t Jx_len
, Lx_len
;
7904 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7905 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7906 const u8
*wrapped_data
, *b_key
, *peer_u
;
7907 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7911 u8
*unwrapped
= NULL
;
7912 size_t unwrapped_len
= 0;
7913 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7914 struct wpabuf
*B_pub
= NULL
;
7915 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7917 #ifdef CONFIG_TESTING_OPTIONS
7918 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7919 wpa_printf(MSG_INFO
,
7920 "DPP: TESTING - stop at PKEX CR Request");
7924 #endif /* CONFIG_TESTING_OPTIONS */
7926 if (!pkex
->exchange_done
|| pkex
->failed
||
7927 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7930 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7932 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7934 "Missing or invalid required Wrapped Data attribute");
7938 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7939 wrapped_data
, wrapped_data_len
);
7940 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7941 unwrapped
= os_malloc(unwrapped_len
);
7946 len
[0] = DPP_HDR_LEN
;
7949 len
[1] = sizeof(octet
);
7950 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7951 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7953 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7954 wrapped_data
, wrapped_data_len
,
7955 2, addr
, len
, unwrapped
) < 0) {
7957 "AES-SIV decryption failed - possible PKEX code mismatch");
7962 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7963 unwrapped
, unwrapped_len
);
7965 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7966 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7970 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7972 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7973 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7976 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7978 if (!pkex
->peer_bootstrap_key
) {
7979 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7982 dpp_debug_print_key("DPP: Peer bootstrap public key",
7983 pkex
->peer_bootstrap_key
);
7985 /* ECDH: J' = y * A' */
7986 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
7989 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7992 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
7993 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
7994 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7995 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7996 if (!A_pub
|| !Y_pub
|| !X_pub
)
7998 addr
[0] = pkex
->peer_mac
;
8000 addr
[1] = wpabuf_head(A_pub
);
8001 len
[1] = wpabuf_len(A_pub
) / 2;
8002 addr
[2] = wpabuf_head(Y_pub
);
8003 len
[2] = wpabuf_len(Y_pub
) / 2;
8004 addr
[3] = wpabuf_head(X_pub
);
8005 len
[3] = wpabuf_len(X_pub
) / 2;
8006 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
8009 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
8011 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
8012 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
8013 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
8014 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
8015 u
, curve
->hash_len
);
8016 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
8020 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
8022 /* ECDH: L = b * X' */
8023 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
8026 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8029 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8030 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
8033 addr
[0] = pkex
->own_mac
;
8035 addr
[1] = wpabuf_head(B_pub
);
8036 len
[1] = wpabuf_len(B_pub
) / 2;
8037 addr
[2] = wpabuf_head(X_pub
);
8038 len
[2] = wpabuf_len(X_pub
) / 2;
8039 addr
[3] = wpabuf_head(Y_pub
);
8040 len
[3] = wpabuf_len(Y_pub
) / 2;
8041 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8043 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
8045 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
8057 wpa_printf(MSG_DEBUG
,
8058 "DPP: PKEX Commit-Reveal Request processing failed");
8063 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
8064 const u8
*buf
, size_t buflen
)
8066 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8067 const u8
*wrapped_data
, *b_key
, *peer_v
;
8068 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
8072 u8
*unwrapped
= NULL
;
8073 size_t unwrapped_len
= 0;
8075 u8 v
[DPP_MAX_HASH_LEN
];
8077 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
8078 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8080 #ifdef CONFIG_TESTING_OPTIONS
8081 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
8082 wpa_printf(MSG_INFO
,
8083 "DPP: TESTING - stop at PKEX CR Response");
8087 #endif /* CONFIG_TESTING_OPTIONS */
8089 if (!pkex
->exchange_done
|| pkex
->failed
||
8090 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8093 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8095 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8097 "Missing or invalid required Wrapped Data attribute");
8101 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8102 wrapped_data
, wrapped_data_len
);
8103 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8104 unwrapped
= os_malloc(unwrapped_len
);
8109 len
[0] = DPP_HDR_LEN
;
8112 len
[1] = sizeof(octet
);
8113 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8114 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8116 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8117 wrapped_data
, wrapped_data_len
,
8118 2, addr
, len
, unwrapped
) < 0) {
8120 "AES-SIV decryption failed - possible PKEX code mismatch");
8124 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8125 unwrapped
, unwrapped_len
);
8127 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8128 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8132 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8134 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8135 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8138 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8140 if (!pkex
->peer_bootstrap_key
) {
8141 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8144 dpp_debug_print_key("DPP: Peer bootstrap public key",
8145 pkex
->peer_bootstrap_key
);
8147 /* ECDH: L' = x * B' */
8148 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
8151 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8154 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8155 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8156 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8157 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8158 if (!B_pub
|| !X_pub
|| !Y_pub
)
8160 addr
[0] = pkex
->peer_mac
;
8162 addr
[1] = wpabuf_head(B_pub
);
8163 len
[1] = wpabuf_len(B_pub
) / 2;
8164 addr
[2] = wpabuf_head(X_pub
);
8165 len
[2] = wpabuf_len(X_pub
) / 2;
8166 addr
[3] = wpabuf_head(Y_pub
);
8167 len
[3] = wpabuf_len(Y_pub
) / 2;
8168 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8171 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
8173 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
8174 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
8175 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
8176 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
8177 v
, curve
->hash_len
);
8178 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
8182 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
8196 void dpp_pkex_free(struct dpp_pkex
*pkex
)
8201 os_free(pkex
->identifier
);
8202 os_free(pkex
->code
);
8203 EVP_PKEY_free(pkex
->x
);
8204 EVP_PKEY_free(pkex
->y
);
8205 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
8206 wpabuf_free(pkex
->exchange_req
);
8207 wpabuf_free(pkex
->exchange_resp
);
8212 #ifdef CONFIG_TESTING_OPTIONS
8213 char * dpp_corrupt_connector_signature(const char *connector
)
8215 char *tmp
, *pos
, *signed3
= NULL
;
8216 unsigned char *signature
= NULL
;
8217 size_t signature_len
= 0, signed3_len
;
8219 tmp
= os_zalloc(os_strlen(connector
) + 5);
8222 os_memcpy(tmp
, connector
, os_strlen(connector
));
8224 pos
= os_strchr(tmp
, '.');
8228 pos
= os_strchr(pos
+ 1, '.');
8233 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
8235 signature
= base64_url_decode((const unsigned char *) pos
,
8236 os_strlen(pos
), &signature_len
);
8237 if (!signature
|| signature_len
== 0)
8239 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
8240 signature
, signature_len
);
8241 signature
[signature_len
- 1] ^= 0x01;
8242 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
8243 signature
, signature_len
);
8244 signed3
= (char *) base64_url_encode(signature
, signature_len
,
8248 os_memcpy(pos
, signed3
, signed3_len
);
8249 pos
[signed3_len
] = '\0';
8250 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
8262 #endif /* CONFIG_TESTING_OPTIONS */
8267 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
8268 size_t net_access_key_len
)
8270 struct wpabuf
*pub
= NULL
;
8272 struct dpp_pfs
*pfs
;
8274 pfs
= os_zalloc(sizeof(*pfs
));
8278 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
8279 net_access_key_len
);
8281 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8284 EVP_PKEY_free(own_key
);
8286 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
8290 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
8291 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
8295 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
8298 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
8299 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
8300 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
8301 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
8302 wpabuf_put_buf(pfs
->ie
, pub
);
8304 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
8315 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
8317 if (peer_ie_len
< 2)
8319 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
8320 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
8324 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
8326 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
8328 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
8331 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
8336 void dpp_pfs_free(struct dpp_pfs
*pfs
)
8340 crypto_ecdh_deinit(pfs
->ecdh
);
8341 wpabuf_free(pfs
->ie
);
8342 wpabuf_clear_free(pfs
->secret
);
8346 #endif /* CONFIG_DPP2 */
8349 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
8351 struct dpp_bootstrap_info
*bi
;
8352 unsigned int max_id
= 0;
8354 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8355 if (bi
->id
> max_id
)
8362 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
8364 struct dpp_bootstrap_info
*bi
, *tmp
;
8370 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
8371 struct dpp_bootstrap_info
, list
) {
8372 if (id
&& bi
->id
!= id
)
8375 dl_list_del(&bi
->list
);
8376 dpp_bootstrap_info_free(bi
);
8380 return 0; /* flush succeeds regardless of entries found */
8381 return found
? 0 : -1;
8385 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
8388 struct dpp_bootstrap_info
*bi
;
8393 bi
= dpp_parse_qr_code(uri
);
8397 bi
->id
= dpp_next_id(dpp
);
8398 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8403 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
8405 char *chan
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
, *curve
= NULL
;
8408 size_t privkey_len
= 0;
8411 struct dpp_bootstrap_info
*bi
;
8416 bi
= os_zalloc(sizeof(*bi
));
8420 if (os_strstr(cmd
, "type=qrcode"))
8421 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
8422 else if (os_strstr(cmd
, "type=pkex"))
8423 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8427 chan
= get_param(cmd
, " chan=");
8428 mac
= get_param(cmd
, " mac=");
8429 info
= get_param(cmd
, " info=");
8430 curve
= get_param(cmd
, " curve=");
8431 key
= get_param(cmd
, " key=");
8434 privkey_len
= os_strlen(key
) / 2;
8435 privkey
= os_malloc(privkey_len
);
8437 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8441 pk
= dpp_keygen(bi
, curve
, privkey
, privkey_len
);
8445 len
= 4; /* "DPP:" */
8447 if (dpp_parse_uri_chan_list(bi
, chan
) < 0)
8449 len
+= 3 + os_strlen(chan
); /* C:...; */
8452 if (dpp_parse_uri_mac(bi
, mac
) < 0)
8454 len
+= 3 + os_strlen(mac
); /* M:...; */
8457 if (dpp_parse_uri_info(bi
, info
) < 0)
8459 len
+= 3 + os_strlen(info
); /* I:...; */
8461 len
+= 4 + os_strlen(pk
);
8462 bi
->uri
= os_malloc(len
+ 1);
8465 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8466 chan
? "C:" : "", chan
? chan
: "", chan
? ";" : "",
8467 mac
? "M:" : "", mac
? mac
: "", mac
? ";" : "",
8468 info
? "I:" : "", info
? info
: "", info
? ";" : "",
8470 bi
->id
= dpp_next_id(dpp
);
8471 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8480 str_clear_free(key
);
8481 bin_clear_free(privkey
, privkey_len
);
8482 dpp_bootstrap_info_free(bi
);
8487 struct dpp_bootstrap_info
*
8488 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
8490 struct dpp_bootstrap_info
*bi
;
8495 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8503 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
8505 unsigned int id_val
;
8507 if (os_strcmp(id
, "*") == 0) {
8515 return dpp_bootstrap_del(dpp
, id_val
);
8519 struct dpp_bootstrap_info
*
8520 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
8523 struct dpp_bootstrap_info
*bi
;
8525 bi
= os_zalloc(sizeof(*bi
));
8528 bi
->id
= dpp_next_id(dpp
);
8529 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8530 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
8533 bi
->curve
= pkex
->own_bi
->curve
;
8534 bi
->pubkey
= pkex
->peer_bootstrap_key
;
8535 pkex
->peer_bootstrap_key
= NULL
;
8536 if (dpp_bootstrap_key_hash(bi
) < 0) {
8537 dpp_bootstrap_info_free(bi
);
8540 dpp_pkex_free(pkex
);
8541 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8546 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
8548 struct dpp_bootstrap_info
*bi
;
8550 bi
= dpp_bootstrap_get_id(dpp
, id
);
8557 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
8558 char *reply
, int reply_size
)
8560 struct dpp_bootstrap_info
*bi
;
8561 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
8563 bi
= dpp_bootstrap_get_id(dpp
, id
);
8566 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
8568 return os_snprintf(reply
, reply_size
, "type=%s\n"
8569 "mac_addr=" MACSTR
"\n"
8574 dpp_bootstrap_type_txt(bi
->type
),
8575 MAC2STR(bi
->mac_addr
),
8576 bi
->info
? bi
->info
: "",
8583 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
8584 const u8
*r_bootstrap
,
8585 struct dpp_bootstrap_info
**own_bi
,
8586 struct dpp_bootstrap_info
**peer_bi
)
8588 struct dpp_bootstrap_info
*bi
;
8595 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8596 if (!*own_bi
&& bi
->own
&&
8597 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
8598 SHA256_MAC_LEN
) == 0) {
8599 wpa_printf(MSG_DEBUG
,
8600 "DPP: Found matching own bootstrapping information");
8604 if (!*peer_bi
&& !bi
->own
&&
8605 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
8606 SHA256_MAC_LEN
) == 0) {
8607 wpa_printf(MSG_DEBUG
,
8608 "DPP: Found matching peer bootstrapping information");
8612 if (*own_bi
&& *peer_bi
)
8619 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
8621 struct dpp_configurator
*conf
;
8622 unsigned int max_id
= 0;
8624 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
8626 if (conf
->id
> max_id
)
8633 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
8638 size_t privkey_len
= 0;
8640 struct dpp_configurator
*conf
= NULL
;
8642 curve
= get_param(cmd
, " curve=");
8643 key
= get_param(cmd
, " key=");
8646 privkey_len
= os_strlen(key
) / 2;
8647 privkey
= os_malloc(privkey_len
);
8649 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8653 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
8657 conf
->id
= dpp_next_configurator_id(dpp
);
8658 dl_list_add(&dpp
->configurator
, &conf
->list
);
8663 str_clear_free(key
);
8664 bin_clear_free(privkey
, privkey_len
);
8665 dpp_configurator_free(conf
);
8670 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
8672 struct dpp_configurator
*conf
, *tmp
;
8678 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
8679 struct dpp_configurator
, list
) {
8680 if (id
&& conf
->id
!= id
)
8683 dl_list_del(&conf
->list
);
8684 dpp_configurator_free(conf
);
8688 return 0; /* flush succeeds regardless of entries found */
8689 return found
? 0 : -1;
8693 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
8695 unsigned int id_val
;
8697 if (os_strcmp(id
, "*") == 0) {
8705 return dpp_configurator_del(dpp
, id_val
);
8709 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
8710 char *buf
, size_t buflen
)
8712 struct dpp_configurator
*conf
;
8714 conf
= dpp_configurator_get_id(dpp
, id
);
8718 return dpp_configurator_get_key(conf
, buf
, buflen
);
8724 static void dpp_connection_free(struct dpp_connection
*conn
)
8726 if (conn
->sock
>= 0) {
8727 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
8729 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
8730 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8733 wpabuf_free(conn
->msg
);
8734 wpabuf_free(conn
->msg_out
);
8735 dpp_auth_deinit(conn
->auth
);
8740 static void dpp_connection_remove(struct dpp_connection
*conn
)
8742 dl_list_del(&conn
->list
);
8743 dpp_connection_free(conn
);
8747 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
8749 struct dpp_connection
*conn
, *tmp
;
8751 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
8753 dpp_connection_remove(conn
);
8757 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
8759 struct dpp_connection
*conn
, *tmp
;
8761 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
8763 dpp_connection_remove(conn
);
8768 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
8770 struct dpp_relay_controller
*ctrl
, *tmp
;
8775 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
8776 struct dpp_relay_controller
, list
) {
8777 dl_list_del(&ctrl
->list
);
8778 dpp_relay_controller_free(ctrl
);
8782 #endif /* CONFIG_DPP2 */
8785 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
8787 struct dpp_global
*dpp
;
8789 dpp
= os_zalloc(sizeof(*dpp
));
8792 dpp
->msg_ctx
= config
->msg_ctx
;
8794 dpp
->cb_ctx
= config
->cb_ctx
;
8795 dpp
->process_conf_obj
= config
->process_conf_obj
;
8796 #endif /* CONFIG_DPP2 */
8798 dl_list_init(&dpp
->bootstrap
);
8799 dl_list_init(&dpp
->configurator
);
8801 dl_list_init(&dpp
->controllers
);
8802 dl_list_init(&dpp
->tcp_init
);
8803 #endif /* CONFIG_DPP2 */
8809 void dpp_global_clear(struct dpp_global
*dpp
)
8814 dpp_bootstrap_del(dpp
, 0);
8815 dpp_configurator_del(dpp
, 0);
8817 dpp_tcp_init_flush(dpp
);
8818 dpp_relay_flush_controllers(dpp
);
8819 dpp_controller_stop(dpp
);
8820 #endif /* CONFIG_DPP2 */
8824 void dpp_global_deinit(struct dpp_global
*dpp
)
8826 dpp_global_clear(dpp
);
8833 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
8834 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
8835 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
8839 int dpp_relay_add_controller(struct dpp_global
*dpp
,
8840 struct dpp_relay_config
*config
)
8842 struct dpp_relay_controller
*ctrl
;
8847 ctrl
= os_zalloc(sizeof(*ctrl
));
8850 dl_list_init(&ctrl
->conn
);
8852 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
8853 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
8854 ctrl
->cb_ctx
= config
->cb_ctx
;
8855 ctrl
->tx
= config
->tx
;
8856 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
8857 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
8862 static struct dpp_relay_controller
*
8863 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
8865 struct dpp_relay_controller
*ctrl
;
8870 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
8872 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
8880 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
8882 struct dpp_authentication
*auth
= conn
->auth
;
8884 if (auth
->peer_version
>= 2 &&
8885 auth
->conf_resp_status
== DPP_STATUS_OK
) {
8886 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
8887 auth
->waiting_conf_result
= 1;
8891 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
8892 dpp_connection_remove(conn
);
8896 static int dpp_tcp_send(struct dpp_connection
*conn
)
8900 if (!conn
->msg_out
) {
8901 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8902 conn
->write_eloop
= 0;
8905 res
= send(conn
->sock
,
8906 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
8907 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
8909 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
8911 dpp_connection_remove(conn
);
8915 conn
->msg_out_pos
+= res
;
8916 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
8917 wpa_printf(MSG_DEBUG
,
8918 "DPP: %u/%u bytes of message sent to Controller",
8919 (unsigned int) conn
->msg_out_pos
,
8920 (unsigned int) wpabuf_len(conn
->msg_out
));
8921 if (!conn
->write_eloop
&&
8922 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
8923 dpp_conn_tx_ready
, conn
, NULL
) == 0)
8924 conn
->write_eloop
= 1;
8928 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
8929 wpabuf_free(conn
->msg_out
);
8930 conn
->msg_out
= NULL
;
8931 conn
->msg_out_pos
= 0;
8932 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8933 conn
->write_eloop
= 0;
8934 if (!conn
->read_eloop
&&
8935 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
8936 dpp_controller_rx
, conn
, NULL
) == 0)
8937 conn
->read_eloop
= 1;
8938 if (conn
->on_tcp_tx_complete_remove
) {
8939 dpp_connection_remove(conn
);
8940 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
8942 dpp_controller_gas_done(conn
);
8943 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
8944 conn
->on_tcp_tx_complete_auth_ok
= 0;
8945 dpp_controller_auth_success(conn
, 1);
8952 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
8954 struct dpp_authentication
*auth
= conn
->auth
;
8957 int netrole_ap
= 0; /* TODO: make this configurable */
8959 os_snprintf(json
, sizeof(json
),
8960 "{\"name\":\"Test\","
8961 "\"wi-fi_tech\":\"infra\","
8962 "\"netRole\":\"%s\"}",
8963 netrole_ap
? "ap" : "sta");
8964 #ifdef CONFIG_TESTING_OPTIONS
8965 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
8966 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
8967 json
[29] = 'k'; /* replace "infra" with "knfra" */
8969 #endif /* CONFIG_TESTING_OPTIONS */
8970 wpa_printf(MSG_DEBUG
, "DPP: GAS Config Attributes: %s", json
);
8972 buf
= dpp_build_conf_req(auth
, json
);
8974 wpa_printf(MSG_DEBUG
,
8975 "DPP: No configuration request data available");
8979 wpabuf_free(conn
->msg_out
);
8980 conn
->msg_out_pos
= 0;
8981 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
8982 if (!conn
->msg_out
) {
8986 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
8987 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
8988 wpabuf_len(buf
) - 1);
8991 if (dpp_tcp_send(conn
) == 1) {
8992 if (!conn
->write_eloop
) {
8993 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
8997 conn
->write_eloop
= 1;
9003 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
9006 struct dpp_authentication
*auth
= conn
->auth
;
9011 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
9012 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
9013 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
9014 #ifdef CONFIG_TESTING_OPTIONS
9015 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
9016 wpa_printf(MSG_INFO
,
9017 "DPP: TESTING - stop at Authentication Confirm");
9018 if (auth
->configurator
) {
9019 /* Prevent GAS response */
9020 auth
->auth_success
= 0;
9024 #endif /* CONFIG_TESTING_OPTIONS */
9026 if (!auth
->configurator
)
9027 dpp_controller_start_gas_client(conn
);
9031 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
9033 struct dpp_connection
*conn
= eloop_ctx
;
9035 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
9040 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
9041 const struct hostapd_ip_addr
*ipaddr
,
9044 struct sockaddr_in
*dst
;
9046 struct sockaddr_in6
*dst6
;
9047 #endif /* CONFIG_IPV6 */
9049 switch (ipaddr
->af
) {
9051 dst
= (struct sockaddr_in
*) addr
;
9052 os_memset(dst
, 0, sizeof(*dst
));
9053 dst
->sin_family
= AF_INET
;
9054 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
9055 dst
->sin_port
= htons(port
);
9056 *addrlen
= sizeof(*dst
);
9060 dst6
= (struct sockaddr_in6
*) addr
;
9061 os_memset(dst6
, 0, sizeof(*dst6
));
9062 dst6
->sin6_family
= AF_INET6
;
9063 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
9064 sizeof(struct in6_addr
));
9065 dst6
->sin6_port
= htons(port
);
9066 *addrlen
= sizeof(*dst6
);
9068 #endif /* CONFIG_IPV6 */
9077 static struct dpp_connection
*
9078 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
9081 struct dpp_connection
*conn
;
9082 struct sockaddr_storage addr
;
9086 if (dl_list_len(&ctrl
->conn
) >= 15) {
9087 wpa_printf(MSG_DEBUG
,
9088 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9092 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
9093 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
9096 conn
= os_zalloc(sizeof(*conn
));
9100 conn
->global
= ctrl
->global
;
9102 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
9105 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9108 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
9109 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
9111 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9112 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9117 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
9118 if (errno
!= EINPROGRESS
) {
9119 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9125 * Continue connecting in the background; eloop will call us
9126 * once the connection is ready (or failed).
9130 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9131 dpp_conn_tx_ready
, conn
, NULL
) < 0)
9133 conn
->write_eloop
= 1;
9135 /* TODO: eloop timeout to clear a connection if it does not complete
9138 dl_list_add(&ctrl
->conn
, &conn
->list
);
9141 dpp_connection_free(conn
);
9146 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
9150 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
9153 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
9154 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
9155 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
9156 wpabuf_put_data(msg
, buf
, len
);
9157 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9162 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
9163 const u8
*buf
, size_t len
)
9165 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9167 wpa_printf(MSG_DEBUG
,
9168 "DPP: Continue already established Relay/Controller connection for this session");
9169 wpabuf_free(conn
->msg_out
);
9170 conn
->msg_out_pos
= 0;
9171 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9172 if (!conn
->msg_out
) {
9173 dpp_connection_remove(conn
);
9177 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9179 if (type
== DPP_PA_CONFIGURATION_RESULT
)
9180 conn
->on_tcp_tx_complete_remove
= 1;
9186 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
9187 const u8
*buf
, size_t len
, unsigned int freq
,
9188 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
9190 struct dpp_relay_controller
*ctrl
;
9191 struct dpp_connection
*conn
;
9192 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9194 /* Check if there is an already started session for this peer and if so,
9195 * continue that session (send this over TCP) and return 0.
9197 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
9198 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
9199 dl_list_for_each(ctrl
, &dpp
->controllers
,
9200 struct dpp_relay_controller
, list
) {
9201 dl_list_for_each(conn
, &ctrl
->conn
,
9202 struct dpp_connection
, list
) {
9203 if (os_memcmp(src
, conn
->mac_addr
,
9205 return dpp_relay_tx(conn
, hdr
, buf
, len
);
9213 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
9217 wpa_printf(MSG_DEBUG
,
9218 "DPP: Authentication Request for a configured Controller");
9219 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
9223 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9224 if (!conn
->msg_out
) {
9225 dpp_connection_remove(conn
);
9228 /* Message will be sent in dpp_conn_tx_ready() */
9234 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
9237 struct dpp_relay_controller
*ctrl
;
9238 struct dpp_connection
*conn
, *found
= NULL
;
9241 /* Check if there is a successfully completed authentication for this
9242 * and if so, continue that session (send this over TCP) and return 0.
9244 dl_list_for_each(ctrl
, &dpp
->controllers
,
9245 struct dpp_relay_controller
, list
) {
9248 dl_list_for_each(conn
, &ctrl
->conn
,
9249 struct dpp_connection
, list
) {
9250 if (os_memcmp(src
, conn
->mac_addr
,
9261 msg
= wpabuf_alloc(4 + 1 + data_len
);
9264 wpabuf_put_be32(msg
, 1 + data_len
);
9265 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
9266 wpabuf_put_data(msg
, data
, data_len
);
9267 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9269 wpabuf_free(conn
->msg_out
);
9270 conn
->msg_out_pos
= 0;
9271 conn
->msg_out
= msg
;
9277 static void dpp_controller_free(struct dpp_controller
*ctrl
)
9279 struct dpp_connection
*conn
, *tmp
;
9284 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
9286 dpp_connection_remove(conn
);
9288 if (ctrl
->sock
>= 0) {
9290 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
9292 os_free(ctrl
->configurator_params
);
9297 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
9298 const u8
*hdr
, const u8
*buf
, size_t len
)
9300 const u8
*r_bootstrap
, *i_bootstrap
;
9301 u16 r_bootstrap_len
, i_bootstrap_len
;
9302 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
9307 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
9309 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
9311 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
9312 wpa_printf(MSG_INFO
,
9313 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9316 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
9317 r_bootstrap
, r_bootstrap_len
);
9319 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
9321 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
9322 wpa_printf(MSG_INFO
,
9323 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9326 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
9327 i_bootstrap
, i_bootstrap_len
);
9329 /* Try to find own and peer bootstrapping key matches based on the
9330 * received hash values */
9331 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
9334 wpa_printf(MSG_INFO
,
9335 "No matching own bootstrapping key found - ignore message");
9340 wpa_printf(MSG_INFO
,
9341 "Already in DPP authentication exchange - ignore new one");
9345 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
9346 conn
->ctrl
->allowed_roles
,
9347 conn
->ctrl
->qr_mutual
,
9348 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
9350 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
9354 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
9356 conn
->ctrl
->configurator_params
) < 0) {
9357 dpp_connection_remove(conn
);
9361 wpabuf_free(conn
->msg_out
);
9362 conn
->msg_out_pos
= 0;
9363 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
9366 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
9367 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
9368 wpabuf_len(conn
->auth
->resp_msg
) - 1);
9370 if (dpp_tcp_send(conn
) == 1) {
9371 if (!conn
->write_eloop
) {
9372 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9376 conn
->write_eloop
= 1;
9384 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
9385 const u8
*hdr
, const u8
*buf
, size_t len
)
9387 struct dpp_authentication
*auth
= conn
->auth
;
9393 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
9395 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
9397 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
9398 wpa_printf(MSG_DEBUG
,
9399 "DPP: Start wait for full response");
9402 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
9403 dpp_connection_remove(conn
);
9407 wpabuf_free(conn
->msg_out
);
9408 conn
->msg_out_pos
= 0;
9409 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9410 if (!conn
->msg_out
) {
9414 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
9415 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
9416 wpabuf_len(msg
) - 1);
9419 conn
->on_tcp_tx_complete_auth_ok
= 1;
9420 if (dpp_tcp_send(conn
) == 1) {
9421 if (!conn
->write_eloop
) {
9422 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9426 conn
->write_eloop
= 1;
9434 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
9435 const u8
*hdr
, const u8
*buf
, size_t len
)
9437 struct dpp_authentication
*auth
= conn
->auth
;
9439 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
9442 wpa_printf(MSG_DEBUG
,
9443 "DPP: No DPP Authentication in progress - drop");
9447 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
9448 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
9452 dpp_controller_auth_success(conn
, 0);
9457 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
9458 const u8
*hdr
, const u8
*buf
,
9461 struct dpp_authentication
*auth
= conn
->auth
;
9462 enum dpp_status_error status
;
9467 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
9469 if (!auth
|| !auth
->waiting_conf_result
) {
9470 wpa_printf(MSG_DEBUG
,
9471 "DPP: No DPP Configuration waiting for result - drop");
9475 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
9476 if (status
== DPP_STATUS_OK
)
9477 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9478 DPP_EVENT_CONF_SENT
);
9480 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9481 DPP_EVENT_CONF_FAILED
);
9482 return -1; /* to remove the completed connection */
9486 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
9489 const u8
*pos
, *end
;
9492 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
9496 if (end
- pos
< DPP_HDR_LEN
||
9497 WPA_GET_BE24(pos
) != OUI_WFA
||
9498 pos
[3] != DPP_OUI_TYPE
) {
9499 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
9504 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
9509 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
9512 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
9514 if (dpp_check_attrs(pos
, end
- pos
) < 0)
9518 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9519 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9520 conn
->freq
, msg
, len
);
9525 case DPP_PA_AUTHENTICATION_REQ
:
9526 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
9527 case DPP_PA_AUTHENTICATION_RESP
:
9528 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
9529 case DPP_PA_AUTHENTICATION_CONF
:
9530 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
9531 case DPP_PA_CONFIGURATION_RESULT
:
9532 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
9534 /* TODO: missing messages types */
9535 wpa_printf(MSG_DEBUG
,
9536 "DPP: Unsupported frame subtype %d", type
);
9542 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
9545 const u8
*pos
, *end
, *next
;
9547 const u8
*adv_proto
;
9549 struct wpabuf
*resp
, *buf
;
9550 struct dpp_authentication
*auth
= conn
->auth
;
9555 wpa_printf(MSG_DEBUG
,
9556 "DPP: Received DPP Configuration Request over TCP");
9558 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
9559 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9566 dialog_token
= *pos
++;
9569 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9570 slen
> end
- pos
|| slen
< 2)
9574 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9576 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9577 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9578 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9585 slen
= WPA_GET_LE16(pos
);
9587 if (slen
> end
- pos
)
9590 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
9594 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
9600 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
9602 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
9603 wpabuf_put_u8(buf
, dialog_token
);
9604 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
9605 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
9607 dpp_write_adv_proto(buf
);
9608 dpp_write_gas_query(buf
, resp
);
9611 /* Send Config Response over TCP; GAS fragmentation is taken care of by
9613 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
9614 wpabuf_free(conn
->msg_out
);
9615 conn
->msg_out_pos
= 0;
9616 conn
->msg_out
= buf
;
9617 conn
->on_tcp_tx_complete_gas_done
= 1;
9623 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
9625 struct dpp_authentication
*auth
= conn
->auth
;
9627 struct wpabuf
*msg
, *encaps
;
9628 enum dpp_status_error status
;
9630 wpa_printf(MSG_DEBUG
,
9631 "DPP: Configuration Response for local stack from TCP");
9633 res
= dpp_conf_resp_rx(auth
, resp
);
9636 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
9640 if (conn
->global
->process_conf_obj
)
9641 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
9646 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
9650 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
9651 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
9652 msg
= dpp_build_conf_result(auth
, status
);
9656 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9661 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
9662 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
9664 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
9666 wpabuf_free(conn
->msg_out
);
9667 conn
->msg_out_pos
= 0;
9668 conn
->msg_out
= encaps
;
9669 conn
->on_tcp_tx_complete_remove
= 1;
9672 /* This exchange will be terminated in the TX status handler */
9675 #else /* CONFIG_DPP2 */
9677 #endif /* CONFIG_DPP2 */
9681 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
9686 const u8
*pos
, *end
, *next
, *adv_proto
;
9692 wpa_printf(MSG_DEBUG
,
9693 "DPP: Received DPP Configuration Response over TCP");
9698 dialog_token
= *pos
++;
9699 status
= WPA_GET_LE16(pos
);
9700 if (status
!= WLAN_STATUS_SUCCESS
) {
9701 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
9705 pos
+= 2; /* ignore GAS Comeback Delay */
9709 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9710 slen
> end
- pos
|| slen
< 2)
9714 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9716 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9717 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9718 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9722 /* Query Response */
9725 slen
= WPA_GET_LE16(pos
);
9727 if (slen
> end
- pos
)
9730 buf
= wpabuf_alloc(slen
);
9733 wpabuf_put_data(buf
, pos
, slen
);
9735 if (!conn
->relay
&& !conn
->ctrl
)
9736 return dpp_tcp_rx_gas_resp(conn
, buf
);
9739 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9743 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9744 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9745 dialog_token
, 0, buf
);
9751 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
9753 struct dpp_connection
*conn
= eloop_ctx
;
9757 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
9760 if (conn
->msg_len_octets
< 4) {
9763 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
9764 4 - conn
->msg_len_octets
, 0);
9766 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
9768 dpp_connection_remove(conn
);
9772 wpa_printf(MSG_DEBUG
,
9773 "DPP: No more data available over TCP");
9774 dpp_connection_remove(conn
);
9777 wpa_printf(MSG_DEBUG
,
9778 "DPP: Received %d/%d octet(s) of message length field",
9779 res
, (int) (4 - conn
->msg_len_octets
));
9780 conn
->msg_len_octets
+= res
;
9782 if (conn
->msg_len_octets
< 4) {
9783 wpa_printf(MSG_DEBUG
,
9784 "DPP: Need %d more octets of message length field",
9785 (int) (4 - conn
->msg_len_octets
));
9789 msglen
= WPA_GET_BE32(conn
->msg_len
);
9790 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
9791 if (msglen
> 65535) {
9792 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
9793 dpp_connection_remove(conn
);
9797 wpabuf_free(conn
->msg
);
9798 conn
->msg
= wpabuf_alloc(msglen
);
9802 wpa_printf(MSG_DEBUG
,
9803 "DPP: No buffer available for receiving the message");
9804 dpp_connection_remove(conn
);
9808 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
9809 (unsigned int) wpabuf_tailroom(conn
->msg
));
9811 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
9813 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
9814 dpp_connection_remove(conn
);
9818 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
9819 dpp_connection_remove(conn
);
9822 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
9823 wpabuf_put(conn
->msg
, res
);
9825 if (wpabuf_tailroom(conn
->msg
) > 0) {
9826 wpa_printf(MSG_DEBUG
,
9827 "DPP: Need %u more octets of message payload",
9828 (unsigned int) wpabuf_tailroom(conn
->msg
));
9832 conn
->msg_len_octets
= 0;
9833 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
9834 if (wpabuf_len(conn
->msg
) < 1) {
9835 dpp_connection_remove(conn
);
9839 pos
= wpabuf_head(conn
->msg
);
9841 case WLAN_PA_VENDOR_SPECIFIC
:
9842 if (dpp_controller_rx_action(conn
, pos
+ 1,
9843 wpabuf_len(conn
->msg
) - 1) < 0)
9844 dpp_connection_remove(conn
);
9846 case WLAN_PA_GAS_INITIAL_REQ
:
9847 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
9848 wpabuf_len(conn
->msg
) - 1) < 0)
9849 dpp_connection_remove(conn
);
9851 case WLAN_PA_GAS_INITIAL_RESP
:
9852 if (dpp_rx_gas_resp(conn
, pos
+ 1,
9853 wpabuf_len(conn
->msg
) - 1) < 0)
9854 dpp_connection_remove(conn
);
9857 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
9864 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
9866 struct dpp_controller
*ctrl
= eloop_ctx
;
9867 struct sockaddr_in addr
;
9868 socklen_t addr_len
= sizeof(addr
);
9870 struct dpp_connection
*conn
;
9872 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
9874 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
9876 wpa_printf(MSG_DEBUG
,
9877 "DPP: Failed to accept new connection: %s",
9881 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
9882 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
9884 conn
= os_zalloc(sizeof(*conn
));
9888 conn
->global
= ctrl
->global
;
9892 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9893 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9898 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
9899 dpp_controller_rx
, conn
, NULL
) < 0)
9901 conn
->read_eloop
= 1;
9903 /* TODO: eloop timeout to expire connections that do not complete in
9904 * reasonable time */
9905 dl_list_add(&ctrl
->conn
, &conn
->list
);
9914 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
9915 const struct hostapd_ip_addr
*addr
, int port
)
9917 struct dpp_connection
*conn
;
9918 struct sockaddr_storage saddr
;
9920 const u8
*hdr
, *pos
, *end
;
9923 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
9924 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
9925 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
9927 dpp_auth_deinit(auth
);
9931 conn
= os_zalloc(sizeof(*conn
));
9933 dpp_auth_deinit(auth
);
9939 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9943 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9944 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9949 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
9950 if (errno
!= EINPROGRESS
) {
9951 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9957 * Continue connecting in the background; eloop will call us
9958 * once the connection is ready (or failed).
9962 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9963 dpp_conn_tx_ready
, conn
, NULL
) < 0)
9965 conn
->write_eloop
= 1;
9967 hdr
= wpabuf_head(auth
->req_msg
);
9968 end
= hdr
+ wpabuf_len(auth
->req_msg
);
9969 hdr
+= 2; /* skip Category and Actiom */
9970 pos
= hdr
+ DPP_HDR_LEN
;
9971 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
9974 /* Message will be sent in dpp_conn_tx_ready() */
9976 /* TODO: eloop timeout to clear a connection if it does not complete
9978 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
9981 dpp_connection_free(conn
);
9986 int dpp_controller_start(struct dpp_global
*dpp
,
9987 struct dpp_controller_config
*config
)
9989 struct dpp_controller
*ctrl
;
9991 struct sockaddr_in sin
;
9994 if (!dpp
|| dpp
->controller
)
9997 ctrl
= os_zalloc(sizeof(*ctrl
));
10000 ctrl
->global
= dpp
;
10001 if (config
->configurator_params
)
10002 ctrl
->configurator_params
=
10003 os_strdup(config
->configurator_params
);
10004 dl_list_init(&ctrl
->conn
);
10005 /* TODO: configure these somehow */
10006 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
10007 ctrl
->qr_mutual
= 0;
10009 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10010 if (ctrl
->sock
< 0)
10013 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
10014 &on
, sizeof(on
)) < 0) {
10015 wpa_printf(MSG_DEBUG
,
10016 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10018 /* try to continue anyway */
10021 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
10022 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10028 os_memset(&sin
, 0, sizeof(sin
));
10029 sin
.sin_family
= AF_INET
;
10030 sin
.sin_addr
.s_addr
= INADDR_ANY
;
10031 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
10032 sin
.sin_port
= htons(port
);
10033 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
10034 wpa_printf(MSG_INFO
,
10035 "DPP: Failed to bind Controller TCP port: %s",
10039 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
10040 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
10041 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
10042 dpp_controller_tcp_cb
, ctrl
, NULL
))
10045 dpp
->controller
= ctrl
;
10046 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
10049 dpp_controller_free(ctrl
);
10054 void dpp_controller_stop(struct dpp_global
*dpp
)
10057 dpp_controller_free(dpp
->controller
);
10058 dpp
->controller
= NULL
;
10062 #endif /* CONFIG_DPP2 */