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 void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
615 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
619 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
624 msg
= wpabuf_alloc(8 + len
);
627 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
628 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
629 wpabuf_put_be24(msg
, OUI_WFA
);
630 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
631 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
632 wpabuf_put_u8(msg
, type
);
637 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
640 const u8
*pos
= buf
, *end
= buf
+ len
;
642 while (end
- pos
>= 4) {
643 id
= WPA_GET_LE16(pos
);
645 alen
= WPA_GET_LE16(pos
);
647 if (alen
> end
- pos
)
660 int dpp_check_attrs(const u8
*buf
, size_t len
)
663 int wrapped_data
= 0;
667 while (end
- pos
>= 4) {
670 id
= WPA_GET_LE16(pos
);
672 alen
= WPA_GET_LE16(pos
);
674 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
676 if (alen
> end
- pos
) {
677 wpa_printf(MSG_DEBUG
,
678 "DPP: Truncated message - not enough room for the attribute - dropped");
682 wpa_printf(MSG_DEBUG
,
683 "DPP: An unexpected attribute included after the Wrapped Data attribute");
686 if (id
== DPP_ATTR_WRAPPED_DATA
)
692 wpa_printf(MSG_DEBUG
,
693 "DPP: Unexpected octets (%d) after the last attribute",
702 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
708 EVP_PKEY_free(info
->pubkey
);
713 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
716 case DPP_BOOTSTRAP_QR_CODE
:
718 case DPP_BOOTSTRAP_PKEX
:
725 static int dpp_uri_valid_info(const char *info
)
728 unsigned char val
= *info
++;
730 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
738 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
740 bi
->uri
= os_strdup(uri
);
741 return bi
->uri
? 0 : -1;
745 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
746 const char *chan_list
)
748 const char *pos
= chan_list
, *pos2
;
749 int opclass
= -1, channel
, freq
;
751 while (pos
&& *pos
&& *pos
!= ';') {
753 while (*pos2
>= '0' && *pos2
<= '9')
764 while (*pos
>= '0' && *pos
<= '9')
766 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
767 wpa_printf(MSG_DEBUG
,
768 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
769 opclass
, channel
, freq
);
771 wpa_printf(MSG_DEBUG
,
772 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
774 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
775 wpa_printf(MSG_DEBUG
,
776 "DPP: Too many channels in URI channel-list - ignore list");
780 bi
->freq
[bi
->num_freq
++] = freq
;
783 if (*pos
== ';' || *pos
== '\0')
792 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
797 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
802 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
803 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
807 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
813 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
820 end
= os_strchr(info
, ';');
822 end
= info
+ os_strlen(info
);
823 bi
->info
= os_malloc(end
- info
+ 1);
826 os_memcpy(bi
->info
, info
, end
- info
);
827 bi
->info
[end
- info
] = '\0';
828 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
829 if (!dpp_uri_valid_info(bi
->info
)) {
830 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
838 static const struct dpp_curve_params
*
839 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
844 for (i
= 0; dpp_curves
[i
].name
; i
++) {
845 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
846 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
847 return &dpp_curves
[i
];
853 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
859 for (i
= 0; dpp_curves
[i
].name
; i
++) {
860 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
862 return &dpp_curves
[i
];
868 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
874 const unsigned char *p
;
876 X509_PUBKEY
*pub
= NULL
;
878 const unsigned char *pk
;
881 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
882 (defined(LIBRESSL_VERSION_NUMBER) && \
883 LIBRESSL_VERSION_NUMBER < 0x20800000L)
886 const ASN1_OBJECT
*pa_oid
;
890 const ASN1_OBJECT
*poid
;
893 end
= os_strchr(info
, ';');
897 data
= base64_decode((const unsigned char *) info
, end
- info
,
900 wpa_printf(MSG_DEBUG
,
901 "DPP: Invalid base64 encoding on URI public-key");
904 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
907 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
908 bi
->pubkey_hash
) < 0) {
909 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
913 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
914 bi
->pubkey_hash
, SHA256_MAC_LEN
);
916 /* DER encoded ASN.1 SubjectPublicKeyInfo
918 * SubjectPublicKeyInfo ::= SEQUENCE {
919 * algorithm AlgorithmIdentifier,
920 * subjectPublicKey BIT STRING }
922 * AlgorithmIdentifier ::= SEQUENCE {
923 * algorithm OBJECT IDENTIFIER,
924 * parameters ANY DEFINED BY algorithm OPTIONAL }
926 * subjectPublicKey = compressed format public key per ANSI X9.63
927 * algorithm = ecPublicKey (1.2.840.10045.2.1)
928 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
929 * prime256v1 (1.2.840.10045.3.1.7)
933 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
937 wpa_printf(MSG_DEBUG
,
938 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
942 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
943 wpa_printf(MSG_DEBUG
,
944 "DPP: SubjectPublicKeyInfo does not describe an EC key");
949 res
= X509_PUBKEY_set(&pub
, pkey
);
951 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
955 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
957 wpa_printf(MSG_DEBUG
,
958 "DPP: Could not extract SubjectPublicKeyInfo parameters");
961 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
962 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
963 wpa_printf(MSG_DEBUG
,
964 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
967 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
968 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
969 wpa_printf(MSG_DEBUG
,
970 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
974 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
975 if (ptype
!= V_ASN1_OBJECT
) {
976 wpa_printf(MSG_DEBUG
,
977 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
981 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
982 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
983 wpa_printf(MSG_DEBUG
,
984 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
987 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
988 bi
->curve
= dpp_get_curve_oid(poid
);
990 wpa_printf(MSG_DEBUG
,
991 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
996 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
998 X509_PUBKEY_free(pub
);
1002 X509_PUBKEY_free(pub
);
1003 EVP_PKEY_free(pkey
);
1008 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1010 const char *pos
= uri
;
1012 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1013 struct dpp_bootstrap_info
*bi
;
1015 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1017 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1018 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1024 end
= os_strchr(pos
, ';');
1029 /* Handle terminating ";;" and ignore unexpected ";"
1030 * for parsing robustness. */
1035 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1036 chan_list
= pos
+ 2;
1037 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1039 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1041 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1044 wpa_hexdump_ascii(MSG_DEBUG
,
1045 "DPP: Ignore unrecognized URI parameter",
1051 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1055 bi
= os_zalloc(sizeof(*bi
));
1059 if (dpp_clone_uri(bi
, uri
) < 0 ||
1060 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1061 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1062 dpp_parse_uri_info(bi
, info
) < 0 ||
1063 dpp_parse_uri_pk(bi
, pk
) < 0) {
1064 dpp_bootstrap_info_free(bi
);
1072 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1074 struct dpp_bootstrap_info
*bi
;
1076 bi
= dpp_parse_uri(uri
);
1078 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1083 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1090 unsigned char *der
= NULL
;
1092 const EC_GROUP
*group
;
1093 const EC_POINT
*point
;
1095 out
= BIO_new(BIO_s_mem());
1099 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1100 rlen
= BIO_ctrl_pending(out
);
1101 txt
= os_malloc(rlen
+ 1);
1103 res
= BIO_read(out
, txt
, rlen
);
1106 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1112 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1116 group
= EC_KEY_get0_group(eckey
);
1117 point
= EC_KEY_get0_public_key(eckey
);
1119 dpp_debug_print_point(title
, group
, point
);
1121 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1123 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1127 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1129 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1137 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1139 EVP_PKEY_CTX
*kctx
= NULL
;
1140 EC_KEY
*ec_params
= NULL
;
1141 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1144 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1146 nid
= OBJ_txt2nid(curve
->name
);
1147 if (nid
== NID_undef
) {
1148 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1152 ec_params
= EC_KEY_new_by_curve_name(nid
);
1154 wpa_printf(MSG_ERROR
,
1155 "DPP: Failed to generate EC_KEY parameters");
1158 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1159 params
= EVP_PKEY_new();
1160 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1161 wpa_printf(MSG_ERROR
,
1162 "DPP: Failed to generate EVP_PKEY parameters");
1166 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1168 EVP_PKEY_keygen_init(kctx
) != 1 ||
1169 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1170 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1175 if (wpa_debug_show_keys
)
1176 dpp_debug_print_key("Own generated key", key
);
1179 EC_KEY_free(ec_params
);
1180 EVP_PKEY_free(params
);
1181 EVP_PKEY_CTX_free(kctx
);
1186 static const struct dpp_curve_params
*
1187 dpp_get_curve_name(const char *name
)
1191 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1192 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1193 (dpp_curves
[i
].jwk_crv
&&
1194 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1195 return &dpp_curves
[i
];
1201 static const struct dpp_curve_params
*
1202 dpp_get_curve_jwk_crv(const char *name
)
1206 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1207 if (dpp_curves
[i
].jwk_crv
&&
1208 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1209 return &dpp_curves
[i
];
1215 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1216 const u8
*privkey
, size_t privkey_len
)
1220 const EC_GROUP
*group
;
1223 pkey
= EVP_PKEY_new();
1226 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1228 wpa_printf(MSG_INFO
,
1229 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1230 ERR_error_string(ERR_get_error(), NULL
));
1231 EVP_PKEY_free(pkey
);
1234 group
= EC_KEY_get0_group(eckey
);
1237 EVP_PKEY_free(pkey
);
1240 nid
= EC_GROUP_get_curve_name(group
);
1241 *curve
= dpp_get_curve_nid(nid
);
1243 wpa_printf(MSG_INFO
,
1244 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1247 EVP_PKEY_free(pkey
);
1251 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1253 EVP_PKEY_free(pkey
);
1261 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1262 * as an OID identifying the curve */
1264 /* Compressed format public key per ANSI X9.63 */
1265 ASN1_BIT_STRING
*pub_key
;
1266 } DPP_BOOTSTRAPPING_KEY
;
1268 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1269 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1270 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1271 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1273 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1276 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1278 unsigned char *der
= NULL
;
1281 struct wpabuf
*ret
= NULL
;
1283 const EC_GROUP
*group
;
1284 const EC_POINT
*point
;
1286 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1290 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1294 group
= EC_KEY_get0_group(eckey
);
1295 point
= EC_KEY_get0_public_key(eckey
);
1296 if (!group
|| !point
)
1298 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1299 nid
= EC_GROUP_get_curve_name(group
);
1301 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1303 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1304 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1307 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1312 der
= OPENSSL_malloc(len
);
1315 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1318 OPENSSL_free(bootstrap
->pub_key
->data
);
1319 bootstrap
->pub_key
->data
= der
;
1321 bootstrap
->pub_key
->length
= len
;
1322 /* No unused bits */
1323 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1324 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1326 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1328 wpa_printf(MSG_ERROR
,
1329 "DDP: Failed to build DER encoded public key");
1333 ret
= wpabuf_alloc_copy(der
, der_len
);
1335 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1343 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1350 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1353 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1356 addr
[0] = wpabuf_head(der
);
1357 len
[0] = wpabuf_len(der
);
1358 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1360 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1362 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1369 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1370 const u8
*privkey
, size_t privkey_len
)
1372 unsigned char *base64
= NULL
;
1375 struct wpabuf
*der
= NULL
;
1380 bi
->curve
= &dpp_curves
[0];
1382 bi
->curve
= dpp_get_curve_name(curve
);
1384 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1390 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1392 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1397 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1400 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1403 addr
[0] = wpabuf_head(der
);
1404 len
= wpabuf_len(der
);
1405 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1407 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1410 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1413 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1418 pos
= (char *) base64
;
1421 pos
= os_strchr(pos
, '\n');
1424 os_memmove(pos
, pos
+ 1, end
- pos
);
1426 return (char *) base64
;
1434 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1435 unsigned int hash_len
)
1437 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1438 const char *info
= "first intermediate key";
1441 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1443 /* HKDF-Extract(<>, M.x) */
1444 os_memset(salt
, 0, hash_len
);
1445 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1447 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1450 /* HKDF-Expand(PRK, info, L) */
1451 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1452 os_memset(prk
, 0, hash_len
);
1456 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1462 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1463 unsigned int hash_len
)
1465 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1466 const char *info
= "second intermediate key";
1469 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1471 /* HKDF-Extract(<>, N.x) */
1472 os_memset(salt
, 0, hash_len
);
1473 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1476 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1479 /* HKDF-Expand(PRK, info, L) */
1480 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1481 os_memset(prk
, 0, hash_len
);
1485 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1491 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1492 unsigned int hash_len
)
1495 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1496 const char *info_ke
= "DPP Key";
1497 u8 prk
[DPP_MAX_HASH_LEN
];
1501 size_t num_elem
= 0;
1503 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1504 wpa_printf(MSG_DEBUG
,
1505 "DPP: Mx/Nx not available - cannot derive ke");
1509 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1511 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1512 nonce_len
= auth
->curve
->nonce_len
;
1513 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1514 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1515 addr
[num_elem
] = auth
->Mx
;
1516 len
[num_elem
] = auth
->Mx_len
;
1518 addr
[num_elem
] = auth
->Nx
;
1519 len
[num_elem
] = auth
->Nx_len
;
1521 if (auth
->peer_bi
&& auth
->own_bi
) {
1522 if (!auth
->Lx_len
) {
1523 wpa_printf(MSG_DEBUG
,
1524 "DPP: Lx not available - cannot derive ke");
1527 addr
[num_elem
] = auth
->Lx
;
1528 len
[num_elem
] = auth
->secret_len
;
1531 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1532 num_elem
, addr
, len
, prk
);
1535 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1538 /* HKDF-Expand(PRK, info, L) */
1539 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1540 os_memset(prk
, 0, hash_len
);
1544 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1550 static void dpp_build_attr_status(struct wpabuf
*msg
,
1551 enum dpp_status_error status
)
1553 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1554 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1555 wpabuf_put_le16(msg
, 1);
1556 wpabuf_put_u8(msg
, status
);
1560 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1564 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1565 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1566 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1567 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1572 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1576 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1577 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1578 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1579 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1584 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1585 const struct wpabuf
*pi
,
1587 const u8
*r_pubkey_hash
,
1588 const u8
*i_pubkey_hash
,
1589 unsigned int neg_freq
)
1592 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1593 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1596 size_t len
[2], siv_len
, attr_len
;
1597 u8
*attr_start
, *attr_end
;
1599 /* Build DPP Authentication Request frame attributes */
1600 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1601 4 + sizeof(wrapped_data
);
1606 #endif /* CONFIG_DPP2 */
1607 #ifdef CONFIG_TESTING_OPTIONS
1608 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1610 #endif /* CONFIG_TESTING_OPTIONS */
1611 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1615 attr_start
= wpabuf_put(msg
, 0);
1617 /* Responder Bootstrapping Key Hash */
1618 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1620 /* Initiator Bootstrapping Key Hash */
1621 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1623 /* Initiator Protocol Key */
1625 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1626 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1627 wpabuf_put_buf(msg
, pi
);
1632 u8 op_class
, channel
;
1634 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1636 NUM_HOSTAPD_MODES
) {
1637 wpa_printf(MSG_INFO
,
1638 "DPP: Unsupported negotiation frequency request: %d",
1643 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1644 wpabuf_put_le16(msg
, 2);
1645 wpabuf_put_u8(msg
, op_class
);
1646 wpabuf_put_u8(msg
, channel
);
1650 /* Protocol Version */
1651 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1652 wpabuf_put_le16(msg
, 1);
1653 wpabuf_put_u8(msg
, 2);
1654 #endif /* CONFIG_DPP2 */
1656 #ifdef CONFIG_TESTING_OPTIONS
1657 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1658 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1659 goto skip_wrapped_data
;
1661 #endif /* CONFIG_TESTING_OPTIONS */
1663 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1666 #ifdef CONFIG_TESTING_OPTIONS
1667 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1668 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1671 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1672 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1673 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1675 WPA_PUT_LE16(pos
, nonce_len
- 1);
1677 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1678 pos
+= nonce_len
- 1;
1681 #endif /* CONFIG_TESTING_OPTIONS */
1684 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1686 WPA_PUT_LE16(pos
, nonce_len
);
1688 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1691 #ifdef CONFIG_TESTING_OPTIONS
1693 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1694 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1697 #endif /* CONFIG_TESTING_OPTIONS */
1699 /* I-capabilities */
1700 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1702 WPA_PUT_LE16(pos
, 1);
1704 auth
->i_capab
= auth
->allowed_roles
;
1705 *pos
++ = auth
->i_capab
;
1706 #ifdef CONFIG_TESTING_OPTIONS
1707 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1708 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1712 #endif /* CONFIG_TESTING_OPTIONS */
1714 attr_end
= wpabuf_put(msg
, 0);
1716 /* OUI, OUI type, Crypto Suite, DPP frame type */
1717 addr
[0] = wpabuf_head_u8(msg
) + 2;
1718 len
[0] = 3 + 1 + 1 + 1;
1719 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1721 /* Attributes before Wrapped Data */
1722 addr
[1] = attr_start
;
1723 len
[1] = attr_end
- attr_start
;
1724 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1726 siv_len
= pos
- clear
;
1727 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1728 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1729 2, addr
, len
, wrapped_data
) < 0) {
1733 siv_len
+= AES_BLOCK_SIZE
;
1734 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1735 wrapped_data
, siv_len
);
1737 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1738 wpabuf_put_le16(msg
, siv_len
);
1739 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1741 #ifdef CONFIG_TESTING_OPTIONS
1742 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1743 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1744 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1747 #endif /* CONFIG_TESTING_OPTIONS */
1749 wpa_hexdump_buf(MSG_DEBUG
,
1750 "DPP: Authentication Request frame attributes", msg
);
1756 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1757 enum dpp_status_error status
,
1758 const struct wpabuf
*pr
,
1760 const u8
*r_pubkey_hash
,
1761 const u8
*i_pubkey_hash
,
1762 const u8
*r_nonce
, const u8
*i_nonce
,
1763 const u8
*wrapped_r_auth
,
1764 size_t wrapped_r_auth_len
,
1768 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1769 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1770 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1771 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1773 size_t len
[2], siv_len
, attr_len
;
1774 u8
*attr_start
, *attr_end
, *pos
;
1776 auth
->waiting_auth_conf
= 1;
1777 auth
->auth_resp_tries
= 0;
1779 /* Build DPP Authentication Response frame attributes */
1780 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1781 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1784 #endif /* CONFIG_DPP2 */
1785 #ifdef CONFIG_TESTING_OPTIONS
1786 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1788 #endif /* CONFIG_TESTING_OPTIONS */
1789 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1793 attr_start
= wpabuf_put(msg
, 0);
1797 dpp_build_attr_status(msg
, status
);
1799 /* Responder Bootstrapping Key Hash */
1800 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1802 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1803 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1805 /* Responder Protocol Key */
1807 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1808 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1809 wpabuf_put_buf(msg
, pr
);
1813 /* Protocol Version */
1814 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1815 wpabuf_put_le16(msg
, 1);
1816 wpabuf_put_u8(msg
, 2);
1817 #endif /* CONFIG_DPP2 */
1819 attr_end
= wpabuf_put(msg
, 0);
1821 #ifdef CONFIG_TESTING_OPTIONS
1822 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1823 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1824 goto skip_wrapped_data
;
1826 #endif /* CONFIG_TESTING_OPTIONS */
1828 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1833 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1835 WPA_PUT_LE16(pos
, nonce_len
);
1837 os_memcpy(pos
, r_nonce
, nonce_len
);
1843 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1845 WPA_PUT_LE16(pos
, nonce_len
);
1847 os_memcpy(pos
, i_nonce
, nonce_len
);
1848 #ifdef CONFIG_TESTING_OPTIONS
1849 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1850 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1851 pos
[nonce_len
/ 2] ^= 0x01;
1853 #endif /* CONFIG_TESTING_OPTIONS */
1857 #ifdef CONFIG_TESTING_OPTIONS
1858 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1859 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1862 #endif /* CONFIG_TESTING_OPTIONS */
1864 /* R-capabilities */
1865 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1867 WPA_PUT_LE16(pos
, 1);
1869 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1871 *pos
++ = auth
->r_capab
;
1872 #ifdef CONFIG_TESTING_OPTIONS
1873 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1874 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1876 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1877 wpa_printf(MSG_INFO
,
1878 "DPP: TESTING - incompatible R-capabilities");
1879 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1880 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1883 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1884 DPP_CAPAB_CONFIGURATOR
;
1887 #endif /* CONFIG_TESTING_OPTIONS */
1889 if (wrapped_r_auth
) {
1891 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1893 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1895 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1896 pos
+= wrapped_r_auth_len
;
1899 /* OUI, OUI type, Crypto Suite, DPP frame type */
1900 addr
[0] = wpabuf_head_u8(msg
) + 2;
1901 len
[0] = 3 + 1 + 1 + 1;
1902 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1904 /* Attributes before Wrapped Data */
1905 addr
[1] = attr_start
;
1906 len
[1] = attr_end
- attr_start
;
1907 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1909 siv_len
= pos
- clear
;
1910 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1911 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1912 2, addr
, len
, wrapped_data
) < 0) {
1916 siv_len
+= AES_BLOCK_SIZE
;
1917 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1918 wrapped_data
, siv_len
);
1920 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1921 wpabuf_put_le16(msg
, siv_len
);
1922 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1924 #ifdef CONFIG_TESTING_OPTIONS
1925 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1926 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1927 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1930 #endif /* CONFIG_TESTING_OPTIONS */
1932 wpa_hexdump_buf(MSG_DEBUG
,
1933 "DPP: Authentication Response frame attributes", msg
);
1938 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1939 u16 num_modes
, unsigned int freq
)
1944 if (!own_modes
|| !num_modes
)
1947 for (m
= 0; m
< num_modes
; m
++) {
1948 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1949 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1952 flag
= own_modes
[m
].channels
[c
].flag
;
1953 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1954 HOSTAPD_CHAN_NO_IR
|
1955 HOSTAPD_CHAN_RADAR
)))
1960 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1965 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1969 if (freqs
[--num
] == freq
)
1976 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1981 for (i
= 0; i
< num
; i
++) {
1982 if (freqs
[i
] == freq
)
1985 if (i
== 0 || i
>= num
)
1987 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1992 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1993 struct hostapd_hw_modes
*own_modes
,
1996 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1997 unsigned int i
, freq
;
1999 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2000 freq
= peer_bi
->freq
[i
];
2001 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2003 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2004 auth
->freq
[auth
->num_freq
++] = freq
;
2006 if (!auth
->num_freq
) {
2007 wpa_printf(MSG_INFO
,
2008 "DPP: No available channels for initiating DPP Authentication");
2011 auth
->curr_freq
= auth
->freq
[0];
2016 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2017 struct hostapd_hw_modes
*own_modes
,
2026 if (!own_modes
|| !num_modes
) {
2027 auth
->freq
[0] = 2412;
2028 auth
->freq
[1] = 2437;
2029 auth
->freq
[2] = 2462;
2034 for (m
= 0; m
< num_modes
; m
++) {
2035 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2036 freq
= 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
))
2042 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2044 auth
->freq
[auth
->num_freq
++] = freq
;
2045 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2052 return auth
->num_freq
== 0 ? -1 : 0;
2056 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2057 struct hostapd_hw_modes
*own_modes
,
2061 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2064 if (auth
->peer_bi
->num_freq
> 0)
2065 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2067 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2071 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2072 * likely channels first. */
2073 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2074 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2075 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2078 auth
->curr_freq
= auth
->freq
[0];
2081 end
= pos
+ sizeof(freqs
);
2082 for (i
= 0; i
< auth
->num_freq
; i
++) {
2083 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2084 if (os_snprintf_error(end
- pos
, res
))
2089 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2096 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2098 struct dpp_bootstrap_info
*bi
;
2103 return 0; /* already generated */
2105 bi
= os_zalloc(sizeof(*bi
));
2108 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2109 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2113 len
= 4; /* "DPP:" */
2114 len
+= 4 + os_strlen(pk
);
2115 bi
->uri
= os_malloc(len
+ 1);
2118 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2119 wpa_printf(MSG_DEBUG
,
2120 "DPP: Auto-generated own bootstrapping key info: URI %s",
2123 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2130 dpp_bootstrap_info_free(bi
);
2135 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2136 struct dpp_bootstrap_info
*peer_bi
,
2137 struct dpp_bootstrap_info
*own_bi
,
2138 u8 dpp_allowed_roles
,
2139 unsigned int neg_freq
,
2140 struct hostapd_hw_modes
*own_modes
,
2143 struct dpp_authentication
*auth
;
2145 EVP_PKEY_CTX
*ctx
= NULL
;
2147 struct wpabuf
*pi
= NULL
;
2148 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2149 #ifdef CONFIG_TESTING_OPTIONS
2150 u8 test_hash
[SHA256_MAC_LEN
];
2151 #endif /* CONFIG_TESTING_OPTIONS */
2153 auth
= os_zalloc(sizeof(*auth
));
2156 auth
->msg_ctx
= msg_ctx
;
2157 auth
->initiator
= 1;
2158 auth
->waiting_auth_resp
= 1;
2159 auth
->allowed_roles
= dpp_allowed_roles
;
2160 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2161 auth
->peer_bi
= peer_bi
;
2162 auth
->own_bi
= own_bi
;
2163 auth
->curve
= peer_bi
->curve
;
2165 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2166 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2169 #ifdef CONFIG_TESTING_OPTIONS
2170 if (dpp_nonce_override_len
> 0) {
2171 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2172 nonce_len
= dpp_nonce_override_len
;
2173 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2175 nonce_len
= auth
->curve
->nonce_len
;
2176 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2177 wpa_printf(MSG_ERROR
,
2178 "DPP: Failed to generate I-nonce");
2182 #else /* CONFIG_TESTING_OPTIONS */
2183 nonce_len
= auth
->curve
->nonce_len
;
2184 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2185 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2188 #endif /* CONFIG_TESTING_OPTIONS */
2189 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2191 #ifdef CONFIG_TESTING_OPTIONS
2192 if (dpp_protocol_key_override_len
) {
2193 const struct dpp_curve_params
*tmp_curve
;
2195 wpa_printf(MSG_INFO
,
2196 "DPP: TESTING - override protocol key");
2197 auth
->own_protocol_key
= dpp_set_keypair(
2198 &tmp_curve
, dpp_protocol_key_override
,
2199 dpp_protocol_key_override_len
);
2201 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2203 #else /* CONFIG_TESTING_OPTIONS */
2204 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2205 #endif /* CONFIG_TESTING_OPTIONS */
2206 if (!auth
->own_protocol_key
)
2209 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2213 /* ECDH: M = pI * BR */
2214 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2216 EVP_PKEY_derive_init(ctx
) != 1 ||
2217 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2218 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2219 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2220 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2221 wpa_printf(MSG_ERROR
,
2222 "DPP: Failed to derive ECDH shared secret: %s",
2223 ERR_error_string(ERR_get_error(), NULL
));
2226 auth
->secret_len
= secret_len
;
2227 EVP_PKEY_CTX_free(ctx
);
2230 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2231 auth
->Mx
, auth
->secret_len
);
2232 auth
->Mx_len
= auth
->secret_len
;
2234 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2235 auth
->curve
->hash_len
) < 0)
2238 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2239 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2241 #ifdef CONFIG_TESTING_OPTIONS
2242 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2243 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2244 r_pubkey_hash
= NULL
;
2245 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2246 wpa_printf(MSG_INFO
,
2247 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2248 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2249 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2250 r_pubkey_hash
= test_hash
;
2251 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2252 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2253 i_pubkey_hash
= NULL
;
2254 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2255 wpa_printf(MSG_INFO
,
2256 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2257 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2258 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2259 i_pubkey_hash
= test_hash
;
2260 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2261 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2264 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2265 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2267 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2268 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2271 #endif /* CONFIG_TESTING_OPTIONS */
2273 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2274 i_pubkey_hash
, neg_freq
);
2280 EVP_PKEY_CTX_free(ctx
);
2283 dpp_auth_deinit(auth
);
2289 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2293 size_t json_len
, clear_len
;
2294 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2298 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2300 nonce_len
= auth
->curve
->nonce_len
;
2301 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2302 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2305 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2306 json_len
= os_strlen(json
);
2307 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2309 /* { E-nonce, configAttrib }ke */
2310 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2311 clear
= wpabuf_alloc(clear_len
);
2312 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2313 #ifdef CONFIG_TESTING_OPTIONS
2314 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2316 #endif /* CONFIG_TESTING_OPTIONS */
2317 msg
= wpabuf_alloc(attr_len
);
2321 #ifdef CONFIG_TESTING_OPTIONS
2322 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2323 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2326 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2327 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2328 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2329 wpabuf_put_le16(clear
, nonce_len
- 1);
2330 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2333 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2334 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2335 goto skip_wrapped_data
;
2337 #endif /* CONFIG_TESTING_OPTIONS */
2340 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2341 wpabuf_put_le16(clear
, nonce_len
);
2342 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2344 #ifdef CONFIG_TESTING_OPTIONS
2346 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2347 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2348 goto skip_conf_attr_obj
;
2350 #endif /* CONFIG_TESTING_OPTIONS */
2353 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2354 wpabuf_put_le16(clear
, json_len
);
2355 wpabuf_put_data(clear
, json
, json_len
);
2357 #ifdef CONFIG_TESTING_OPTIONS
2359 #endif /* CONFIG_TESTING_OPTIONS */
2361 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2362 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2363 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2366 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2367 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2368 wpabuf_head(clear
), wpabuf_len(clear
),
2369 0, NULL
, NULL
, wrapped
) < 0)
2371 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2372 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2374 #ifdef CONFIG_TESTING_OPTIONS
2375 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2376 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2377 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2380 #endif /* CONFIG_TESTING_OPTIONS */
2382 wpa_hexdump_buf(MSG_DEBUG
,
2383 "DPP: Configuration Request frame attributes", msg
);
2394 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2396 /* Advertisement Protocol IE */
2397 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2398 wpabuf_put_u8(buf
, 8); /* Length */
2399 wpabuf_put_u8(buf
, 0x7f);
2400 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2401 wpabuf_put_u8(buf
, 5);
2402 wpabuf_put_be24(buf
, OUI_WFA
);
2403 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2404 wpabuf_put_u8(buf
, 0x01);
2408 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2411 wpabuf_put_le16(buf
, wpabuf_len(query
));
2412 wpabuf_put_buf(buf
, query
);
2416 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2419 struct wpabuf
*buf
, *conf_req
;
2421 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2423 wpa_printf(MSG_DEBUG
,
2424 "DPP: No configuration request data available");
2428 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2430 wpabuf_free(conf_req
);
2434 dpp_write_adv_proto(buf
);
2435 dpp_write_gas_query(buf
, conf_req
);
2436 wpabuf_free(conf_req
);
2437 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2443 static void dpp_auth_success(struct dpp_authentication
*auth
)
2445 wpa_printf(MSG_DEBUG
,
2446 "DPP: Authentication success - clear temporary keys");
2447 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2449 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2451 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2453 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2454 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2456 auth
->auth_success
= 1;
2460 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2462 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2465 size_t i
, num_elem
= 0;
2470 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2471 nonce_len
= auth
->curve
->nonce_len
;
2473 if (auth
->initiator
) {
2474 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2475 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2477 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2480 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2482 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2483 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2485 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2488 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2490 if (!pix
|| !prx
|| !brx
)
2493 addr
[num_elem
] = auth
->i_nonce
;
2494 len
[num_elem
] = nonce_len
;
2497 addr
[num_elem
] = auth
->r_nonce
;
2498 len
[num_elem
] = nonce_len
;
2501 addr
[num_elem
] = wpabuf_head(pix
);
2502 len
[num_elem
] = wpabuf_len(pix
) / 2;
2505 addr
[num_elem
] = wpabuf_head(prx
);
2506 len
[num_elem
] = wpabuf_len(prx
) / 2;
2510 addr
[num_elem
] = wpabuf_head(bix
);
2511 len
[num_elem
] = wpabuf_len(bix
) / 2;
2515 addr
[num_elem
] = wpabuf_head(brx
);
2516 len
[num_elem
] = wpabuf_len(brx
) / 2;
2519 addr
[num_elem
] = &zero
;
2523 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2524 for (i
= 0; i
< num_elem
; i
++)
2525 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2526 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2528 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2529 auth
->curve
->hash_len
);
2539 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2541 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2544 size_t i
, num_elem
= 0;
2549 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2550 nonce_len
= auth
->curve
->nonce_len
;
2552 if (auth
->initiator
) {
2553 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2554 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2556 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2561 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2563 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2564 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2566 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2571 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2573 if (!pix
|| !prx
|| !brx
)
2576 addr
[num_elem
] = auth
->r_nonce
;
2577 len
[num_elem
] = nonce_len
;
2580 addr
[num_elem
] = auth
->i_nonce
;
2581 len
[num_elem
] = nonce_len
;
2584 addr
[num_elem
] = wpabuf_head(prx
);
2585 len
[num_elem
] = wpabuf_len(prx
) / 2;
2588 addr
[num_elem
] = wpabuf_head(pix
);
2589 len
[num_elem
] = wpabuf_len(pix
) / 2;
2592 addr
[num_elem
] = wpabuf_head(brx
);
2593 len
[num_elem
] = wpabuf_len(brx
) / 2;
2597 addr
[num_elem
] = wpabuf_head(bix
);
2598 len
[num_elem
] = wpabuf_len(bix
) / 2;
2602 addr
[num_elem
] = &one
;
2606 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2607 for (i
= 0; i
< num_elem
; i
++)
2608 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2609 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2611 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2612 auth
->curve
->hash_len
);
2622 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2624 const EC_GROUP
*group
;
2626 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2627 const EC_POINT
*BI_point
;
2629 BIGNUM
*lx
, *sum
, *q
;
2630 const BIGNUM
*bR_bn
, *pR_bn
;
2633 /* L = ((bR + pR) modulo q) * BI */
2635 bnctx
= BN_CTX_new();
2639 if (!bnctx
|| !sum
|| !q
|| !lx
)
2641 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2644 BI_point
= EC_KEY_get0_public_key(BI
);
2645 group
= EC_KEY_get0_group(BI
);
2649 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2650 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2653 bR_bn
= EC_KEY_get0_private_key(bR
);
2654 pR_bn
= EC_KEY_get0_private_key(pR
);
2655 if (!bR_bn
|| !pR_bn
)
2657 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2658 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2660 l
= EC_POINT_new(group
);
2662 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2663 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2665 wpa_printf(MSG_ERROR
,
2666 "OpenSSL: failed: %s",
2667 ERR_error_string(ERR_get_error(), NULL
));
2671 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2673 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2674 auth
->Lx_len
= auth
->secret_len
;
2677 EC_POINT_clear_free(l
);
2689 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2691 const EC_GROUP
*group
;
2692 EC_POINT
*l
= NULL
, *sum
= NULL
;
2693 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2694 const EC_POINT
*BR_point
, *PR_point
;
2697 const BIGNUM
*bI_bn
;
2700 /* L = bI * (BR + PR) */
2702 bnctx
= BN_CTX_new();
2706 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2707 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2710 BR_point
= EC_KEY_get0_public_key(BR
);
2711 PR_point
= EC_KEY_get0_public_key(PR
);
2713 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2716 group
= EC_KEY_get0_group(bI
);
2717 bI_bn
= EC_KEY_get0_private_key(bI
);
2718 if (!group
|| !bI_bn
)
2720 sum
= EC_POINT_new(group
);
2721 l
= EC_POINT_new(group
);
2723 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2724 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2725 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2727 wpa_printf(MSG_ERROR
,
2728 "OpenSSL: failed: %s",
2729 ERR_error_string(ERR_get_error(), NULL
));
2733 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2735 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2736 auth
->Lx_len
= auth
->secret_len
;
2739 EC_POINT_clear_free(l
);
2740 EC_POINT_clear_free(sum
);
2750 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2753 EVP_PKEY_CTX
*ctx
= NULL
;
2755 struct wpabuf
*msg
, *pr
= NULL
;
2756 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2757 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2758 size_t wrapped_r_auth_len
;
2760 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2761 enum dpp_status_error status
= DPP_STATUS_OK
;
2762 #ifdef CONFIG_TESTING_OPTIONS
2763 u8 test_hash
[SHA256_MAC_LEN
];
2764 #endif /* CONFIG_TESTING_OPTIONS */
2766 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2770 #ifdef CONFIG_TESTING_OPTIONS
2771 if (dpp_nonce_override_len
> 0) {
2772 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2773 nonce_len
= dpp_nonce_override_len
;
2774 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2776 nonce_len
= auth
->curve
->nonce_len
;
2777 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2778 wpa_printf(MSG_ERROR
,
2779 "DPP: Failed to generate R-nonce");
2783 #else /* CONFIG_TESTING_OPTIONS */
2784 nonce_len
= auth
->curve
->nonce_len
;
2785 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2786 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2789 #endif /* CONFIG_TESTING_OPTIONS */
2790 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2792 EVP_PKEY_free(auth
->own_protocol_key
);
2793 #ifdef CONFIG_TESTING_OPTIONS
2794 if (dpp_protocol_key_override_len
) {
2795 const struct dpp_curve_params
*tmp_curve
;
2797 wpa_printf(MSG_INFO
,
2798 "DPP: TESTING - override protocol key");
2799 auth
->own_protocol_key
= dpp_set_keypair(
2800 &tmp_curve
, dpp_protocol_key_override
,
2801 dpp_protocol_key_override_len
);
2803 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2805 #else /* CONFIG_TESTING_OPTIONS */
2806 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2807 #endif /* CONFIG_TESTING_OPTIONS */
2808 if (!auth
->own_protocol_key
)
2811 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2815 /* ECDH: N = pR * PI */
2816 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2818 EVP_PKEY_derive_init(ctx
) != 1 ||
2819 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2820 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2821 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2822 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2823 wpa_printf(MSG_ERROR
,
2824 "DPP: Failed to derive ECDH shared secret: %s",
2825 ERR_error_string(ERR_get_error(), NULL
));
2828 EVP_PKEY_CTX_free(ctx
);
2831 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2832 auth
->Nx
, auth
->secret_len
);
2833 auth
->Nx_len
= auth
->secret_len
;
2835 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2836 auth
->curve
->hash_len
) < 0)
2839 if (auth
->own_bi
&& auth
->peer_bi
) {
2840 /* Mutual authentication */
2841 if (dpp_auth_derive_l_responder(auth
) < 0)
2845 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2848 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2849 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2850 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2851 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2853 #ifdef CONFIG_TESTING_OPTIONS
2854 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2855 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2856 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2858 #endif /* CONFIG_TESTING_OPTIONS */
2859 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2860 r_auth
, 4 + auth
->curve
->hash_len
,
2861 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2863 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2864 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2865 wrapped_r_auth
, wrapped_r_auth_len
);
2866 w_r_auth
= wrapped_r_auth
;
2868 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2870 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2872 i_pubkey_hash
= NULL
;
2874 i_nonce
= auth
->i_nonce
;
2875 r_nonce
= auth
->r_nonce
;
2877 #ifdef CONFIG_TESTING_OPTIONS
2878 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2879 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2880 r_pubkey_hash
= NULL
;
2881 } else if (dpp_test
==
2882 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2883 wpa_printf(MSG_INFO
,
2884 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2885 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2886 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2887 r_pubkey_hash
= test_hash
;
2888 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2889 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2890 i_pubkey_hash
= NULL
;
2891 } else if (dpp_test
==
2892 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2893 wpa_printf(MSG_INFO
,
2894 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2896 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2898 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2899 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2900 i_pubkey_hash
= test_hash
;
2901 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2902 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2905 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2906 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2908 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2909 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2911 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2912 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2914 wrapped_r_auth_len
= 0;
2915 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2916 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2918 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2919 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2921 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2922 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2924 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2925 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2928 #endif /* CONFIG_TESTING_OPTIONS */
2930 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2931 r_pubkey_hash
, i_pubkey_hash
,
2933 w_r_auth
, wrapped_r_auth_len
,
2937 wpabuf_free(auth
->resp_msg
);
2938 auth
->resp_msg
= msg
;
2946 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2947 enum dpp_status_error status
)
2950 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2951 #ifdef CONFIG_TESTING_OPTIONS
2952 u8 test_hash
[SHA256_MAC_LEN
];
2953 #endif /* CONFIG_TESTING_OPTIONS */
2957 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2959 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2961 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2963 i_pubkey_hash
= NULL
;
2965 i_nonce
= auth
->i_nonce
;
2967 #ifdef CONFIG_TESTING_OPTIONS
2968 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2969 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2970 r_pubkey_hash
= NULL
;
2971 } else if (dpp_test
==
2972 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2973 wpa_printf(MSG_INFO
,
2974 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2975 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2976 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2977 r_pubkey_hash
= test_hash
;
2978 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2979 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2980 i_pubkey_hash
= NULL
;
2981 } else if (dpp_test
==
2982 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2983 wpa_printf(MSG_INFO
,
2984 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2986 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2988 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2989 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2990 i_pubkey_hash
= test_hash
;
2991 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2992 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2994 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2995 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2998 #endif /* CONFIG_TESTING_OPTIONS */
3000 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3001 r_pubkey_hash
, i_pubkey_hash
,
3002 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3005 wpabuf_free(auth
->resp_msg
);
3006 auth
->resp_msg
= msg
;
3011 struct dpp_authentication
*
3012 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3013 struct dpp_bootstrap_info
*peer_bi
,
3014 struct dpp_bootstrap_info
*own_bi
,
3015 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3018 EVP_PKEY
*pi
= NULL
;
3019 EVP_PKEY_CTX
*ctx
= NULL
;
3023 u8
*unwrapped
= NULL
;
3024 size_t unwrapped_len
= 0;
3025 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3027 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3028 i_bootstrap_len
, channel_len
;
3029 struct dpp_authentication
*auth
= NULL
;
3033 #endif /* CONFIG_DPP2 */
3035 #ifdef CONFIG_TESTING_OPTIONS
3036 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3037 wpa_printf(MSG_INFO
,
3038 "DPP: TESTING - stop at Authentication Request");
3041 #endif /* CONFIG_TESTING_OPTIONS */
3043 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3045 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3046 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3047 "Missing or invalid required Wrapped Data attribute");
3050 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3051 wrapped_data
, wrapped_data_len
);
3052 attr_len
= wrapped_data
- 4 - attr_start
;
3054 auth
= os_zalloc(sizeof(*auth
));
3057 auth
->msg_ctx
= msg_ctx
;
3058 auth
->peer_bi
= peer_bi
;
3059 auth
->own_bi
= own_bi
;
3060 auth
->curve
= own_bi
->curve
;
3061 auth
->curr_freq
= freq
;
3063 auth
->peer_version
= 1; /* default to the first version */
3065 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3068 if (version_len
< 1 || version
[0] == 0) {
3070 "Invalid Protocol Version attribute");
3073 auth
->peer_version
= version
[0];
3074 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3075 auth
->peer_version
);
3077 #endif /* CONFIG_DPP2 */
3079 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3084 if (channel_len
< 2) {
3085 dpp_auth_fail(auth
, "Too short Channel attribute");
3089 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3090 wpa_printf(MSG_DEBUG
,
3091 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3092 channel
[0], channel
[1], neg_freq
);
3095 "Unsupported Channel attribute value");
3099 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3100 wpa_printf(MSG_DEBUG
,
3101 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3103 auth
->curr_freq
= neg_freq
;
3107 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3111 "Missing required Initiator Protocol Key attribute");
3114 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3115 i_proto
, i_proto_len
);
3118 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3120 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3123 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3125 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
3127 EVP_PKEY_derive_init(ctx
) != 1 ||
3128 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
3129 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3130 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3131 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
3132 wpa_printf(MSG_ERROR
,
3133 "DPP: Failed to derive ECDH shared secret: %s",
3134 ERR_error_string(ERR_get_error(), NULL
));
3135 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3138 auth
->secret_len
= secret_len
;
3139 EVP_PKEY_CTX_free(ctx
);
3142 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3143 auth
->Mx
, auth
->secret_len
);
3144 auth
->Mx_len
= auth
->secret_len
;
3146 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3147 auth
->curve
->hash_len
) < 0)
3151 len
[0] = DPP_HDR_LEN
;
3152 addr
[1] = attr_start
;
3154 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3155 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3156 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3157 wrapped_data
, wrapped_data_len
);
3158 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3159 unwrapped
= os_malloc(unwrapped_len
);
3162 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3163 wrapped_data
, wrapped_data_len
,
3164 2, addr
, len
, unwrapped
) < 0) {
3165 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3168 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3169 unwrapped
, unwrapped_len
);
3171 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3172 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3176 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3178 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3179 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3182 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3183 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3185 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3186 DPP_ATTR_I_CAPABILITIES
,
3188 if (!i_capab
|| i_capab_len
< 1) {
3189 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3192 auth
->i_capab
= i_capab
[0];
3193 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3195 bin_clear_free(unwrapped
, unwrapped_len
);
3198 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3199 case DPP_CAPAB_ENROLLEE
:
3200 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3201 wpa_printf(MSG_DEBUG
,
3202 "DPP: Local policy does not allow Configurator role");
3203 goto not_compatible
;
3205 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3206 auth
->configurator
= 1;
3208 case DPP_CAPAB_CONFIGURATOR
:
3209 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3210 wpa_printf(MSG_DEBUG
,
3211 "DPP: Local policy does not allow Enrollee role");
3212 goto not_compatible
;
3214 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3215 auth
->configurator
= 0;
3217 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3218 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3219 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3220 auth
->configurator
= 0;
3221 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3222 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3223 auth
->configurator
= 1;
3225 wpa_printf(MSG_DEBUG
,
3226 "DPP: Local policy does not allow Configurator/Enrollee role");
3227 goto not_compatible
;
3231 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3232 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3233 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3234 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3238 auth
->peer_protocol_key
= pi
;
3240 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3241 char hex
[SHA256_MAC_LEN
* 2 + 1];
3243 wpa_printf(MSG_DEBUG
,
3244 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3245 if (dpp_auth_build_resp_status(auth
,
3246 DPP_STATUS_RESPONSE_PENDING
) < 0)
3248 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3249 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3251 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3252 auth
->response_pending
= 1;
3253 os_memcpy(auth
->waiting_pubkey_hash
,
3254 i_bootstrap
, i_bootstrap_len
);
3255 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3261 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3265 if (dpp_auth_build_resp_ok(auth
) < 0)
3271 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3272 "i-capab=0x%02x", auth
->i_capab
);
3273 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3274 auth
->configurator
= 1;
3276 auth
->configurator
= 0;
3277 auth
->peer_protocol_key
= pi
;
3279 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3282 auth
->remove_on_tx_status
= 1;
3285 bin_clear_free(unwrapped
, unwrapped_len
);
3287 EVP_PKEY_CTX_free(ctx
);
3288 dpp_auth_deinit(auth
);
3293 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3294 struct dpp_bootstrap_info
*peer_bi
)
3296 if (!auth
|| !auth
->response_pending
||
3297 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3298 SHA256_MAC_LEN
) != 0)
3301 wpa_printf(MSG_DEBUG
,
3302 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3303 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3304 auth
->peer_bi
= peer_bi
;
3306 if (dpp_auth_build_resp_ok(auth
) < 0)
3313 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3314 enum dpp_status_error status
)
3317 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3319 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3322 size_t len
[2], attr_len
;
3324 u8
*wrapped_r_nonce
;
3325 u8
*attr_start
, *attr_end
;
3326 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3327 #ifdef CONFIG_TESTING_OPTIONS
3328 u8 test_hash
[SHA256_MAC_LEN
];
3329 #endif /* CONFIG_TESTING_OPTIONS */
3331 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3333 i_auth_len
= 4 + auth
->curve
->hash_len
;
3334 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3335 /* Build DPP Authentication Confirmation frame attributes */
3336 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3337 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3338 #ifdef CONFIG_TESTING_OPTIONS
3339 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3341 #endif /* CONFIG_TESTING_OPTIONS */
3342 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3346 attr_start
= wpabuf_put(msg
, 0);
3348 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3350 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3352 i_pubkey_hash
= NULL
;
3354 #ifdef CONFIG_TESTING_OPTIONS
3355 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3356 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3358 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3359 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3362 #endif /* CONFIG_TESTING_OPTIONS */
3365 dpp_build_attr_status(msg
, status
);
3367 #ifdef CONFIG_TESTING_OPTIONS
3369 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3370 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3371 r_pubkey_hash
= NULL
;
3372 } else if (dpp_test
==
3373 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3374 wpa_printf(MSG_INFO
,
3375 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3376 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3377 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3378 r_pubkey_hash
= test_hash
;
3379 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3380 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3381 i_pubkey_hash
= NULL
;
3382 } else if (dpp_test
==
3383 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3384 wpa_printf(MSG_INFO
,
3385 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3387 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3389 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3390 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3391 i_pubkey_hash
= test_hash
;
3393 #endif /* CONFIG_TESTING_OPTIONS */
3395 /* Responder Bootstrapping Key Hash */
3396 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3398 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3399 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3401 #ifdef CONFIG_TESTING_OPTIONS
3402 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3403 goto skip_wrapped_data
;
3404 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3406 #endif /* CONFIG_TESTING_OPTIONS */
3408 attr_end
= wpabuf_put(msg
, 0);
3410 /* OUI, OUI type, Crypto Suite, DPP frame type */
3411 addr
[0] = wpabuf_head_u8(msg
) + 2;
3412 len
[0] = 3 + 1 + 1 + 1;
3413 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3415 /* Attributes before Wrapped Data */
3416 addr
[1] = attr_start
;
3417 len
[1] = attr_end
- attr_start
;
3418 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3420 if (status
== DPP_STATUS_OK
) {
3421 /* I-auth wrapped with ke */
3422 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3423 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3424 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3426 #ifdef CONFIG_TESTING_OPTIONS
3427 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3429 #endif /* CONFIG_TESTING_OPTIONS */
3431 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3433 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3434 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3435 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3438 #ifdef CONFIG_TESTING_OPTIONS
3439 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3440 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3441 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3444 #endif /* CONFIG_TESTING_OPTIONS */
3445 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3447 2, addr
, len
, wrapped_i_auth
) < 0)
3449 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3450 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3452 /* R-nonce wrapped with k2 */
3453 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3454 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3455 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3457 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3458 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3459 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3461 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3462 r_nonce
, r_nonce_len
,
3463 2, addr
, len
, wrapped_r_nonce
) < 0)
3465 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3466 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3469 #ifdef CONFIG_TESTING_OPTIONS
3470 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3471 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3472 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3475 #endif /* CONFIG_TESTING_OPTIONS */
3477 wpa_hexdump_buf(MSG_DEBUG
,
3478 "DPP: Authentication Confirmation frame attributes",
3480 if (status
== DPP_STATUS_OK
)
3481 dpp_auth_success(auth
);
3492 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3493 const u8
*attr_start
, size_t attr_len
,
3494 const u8
*wrapped_data
, u16 wrapped_data_len
,
3495 enum dpp_status_error status
)
3499 u8
*unwrapped
= NULL
;
3500 size_t unwrapped_len
= 0;
3501 const u8
*i_nonce
, *r_capab
;
3502 u16 i_nonce_len
, r_capab_len
;
3504 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3505 wpa_printf(MSG_DEBUG
,
3506 "DPP: Responder reported incompatible roles");
3507 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3508 wpa_printf(MSG_DEBUG
,
3509 "DPP: Responder reported more time needed");
3511 wpa_printf(MSG_DEBUG
,
3512 "DPP: Responder reported failure (status %d)",
3514 dpp_auth_fail(auth
, "Responder reported failure");
3519 len
[0] = DPP_HDR_LEN
;
3520 addr
[1] = attr_start
;
3522 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3523 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3524 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3525 wrapped_data
, wrapped_data_len
);
3526 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3527 unwrapped
= os_malloc(unwrapped_len
);
3530 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3531 wrapped_data
, wrapped_data_len
,
3532 2, addr
, len
, unwrapped
) < 0) {
3533 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3536 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3537 unwrapped
, unwrapped_len
);
3539 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3540 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3544 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3546 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3547 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3550 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3551 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3552 dpp_auth_fail(auth
, "I-nonce mismatch");
3556 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3557 DPP_ATTR_R_CAPABILITIES
,
3559 if (!r_capab
|| r_capab_len
< 1) {
3560 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3563 auth
->r_capab
= r_capab
[0];
3564 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3565 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3566 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3567 "r-capab=0x%02x", auth
->r_capab
);
3568 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3569 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3571 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3572 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3573 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3574 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3577 wpa_printf(MSG_DEBUG
,
3578 "DPP: Continue waiting for full DPP Authentication Response");
3579 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3580 DPP_EVENT_RESPONSE_PENDING
"%s",
3581 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3585 bin_clear_free(unwrapped
, unwrapped_len
);
3590 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3591 const u8
*attr_start
, size_t attr_len
)
3594 EVP_PKEY_CTX
*ctx
= NULL
;
3598 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3599 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3600 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3601 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3602 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3603 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3604 wrapped2_len
, r_auth_len
;
3605 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3610 #endif /* CONFIG_DPP2 */
3612 #ifdef CONFIG_TESTING_OPTIONS
3613 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3614 wpa_printf(MSG_INFO
,
3615 "DPP: TESTING - stop at Authentication Response");
3618 #endif /* CONFIG_TESTING_OPTIONS */
3620 if (!auth
->initiator
|| !auth
->peer_bi
) {
3621 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3625 auth
->waiting_auth_resp
= 0;
3627 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3629 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3631 "Missing or invalid required Wrapped Data attribute");
3634 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3635 wrapped_data
, wrapped_data_len
);
3637 attr_len
= wrapped_data
- 4 - attr_start
;
3639 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3640 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3642 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3644 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3647 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3648 r_bootstrap
, r_bootstrap_len
);
3649 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3650 SHA256_MAC_LEN
) != 0) {
3652 "Unexpected Responder Bootstrapping Key Hash value");
3653 wpa_hexdump(MSG_DEBUG
,
3654 "DPP: Expected Responder Bootstrapping Key Hash",
3655 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3659 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3660 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3663 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3665 "Invalid Initiator Bootstrapping Key Hash attribute");
3668 wpa_hexdump(MSG_MSGDUMP
,
3669 "DPP: Initiator Bootstrapping Key Hash",
3670 i_bootstrap
, i_bootstrap_len
);
3671 if (!auth
->own_bi
||
3672 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3673 SHA256_MAC_LEN
) != 0) {
3675 "Initiator Bootstrapping Key Hash attribute did not match");
3678 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3679 /* PKEX bootstrapping mandates use of mutual authentication */
3681 "Missing Initiator Bootstrapping Key Hash attribute");
3685 auth
->peer_version
= 1; /* default to the first version */
3687 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3690 if (version_len
< 1 || version
[0] == 0) {
3692 "Invalid Protocol Version attribute");
3695 auth
->peer_version
= version
[0];
3696 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3697 auth
->peer_version
);
3699 #endif /* CONFIG_DPP2 */
3701 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3703 if (!status
|| status_len
< 1) {
3705 "Missing or invalid required DPP Status attribute");
3708 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3709 auth
->auth_resp_status
= status
[0];
3710 if (status
[0] != DPP_STATUS_OK
) {
3711 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3712 attr_len
, wrapped_data
,
3713 wrapped_data_len
, status
[0]);
3717 if (!i_bootstrap
&& auth
->own_bi
) {
3718 wpa_printf(MSG_DEBUG
,
3719 "DPP: Responder decided not to use mutual authentication");
3720 auth
->own_bi
= NULL
;
3723 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3724 auth
->own_bi
!= NULL
);
3726 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3730 "Missing required Responder Protocol Key attribute");
3733 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3734 r_proto
, r_proto_len
);
3737 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3739 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3742 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3744 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3746 EVP_PKEY_derive_init(ctx
) != 1 ||
3747 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3748 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3749 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3750 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3751 wpa_printf(MSG_ERROR
,
3752 "DPP: Failed to derive ECDH shared secret: %s",
3753 ERR_error_string(ERR_get_error(), NULL
));
3754 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3757 EVP_PKEY_CTX_free(ctx
);
3759 EVP_PKEY_free(auth
->peer_protocol_key
);
3760 auth
->peer_protocol_key
= pr
;
3763 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3764 auth
->Nx
, auth
->secret_len
);
3765 auth
->Nx_len
= auth
->secret_len
;
3767 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3768 auth
->curve
->hash_len
) < 0)
3772 len
[0] = DPP_HDR_LEN
;
3773 addr
[1] = attr_start
;
3775 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3776 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3777 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3778 wrapped_data
, wrapped_data_len
);
3779 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3780 unwrapped
= os_malloc(unwrapped_len
);
3783 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3784 wrapped_data
, wrapped_data_len
,
3785 2, addr
, len
, unwrapped
) < 0) {
3786 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3789 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3790 unwrapped
, unwrapped_len
);
3792 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3793 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3797 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3799 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3800 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3803 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3804 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3806 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3808 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3809 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3812 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3813 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3814 dpp_auth_fail(auth
, "I-nonce mismatch");
3819 /* Mutual authentication */
3820 if (dpp_auth_derive_l_initiator(auth
) < 0)
3824 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3825 DPP_ATTR_R_CAPABILITIES
,
3827 if (!r_capab
|| r_capab_len
< 1) {
3828 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3831 auth
->r_capab
= r_capab
[0];
3832 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3833 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3834 if ((auth
->allowed_roles
==
3835 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3836 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3837 /* Peer selected its role, so move from "either role" to the
3838 * role that is compatible with peer's selection. */
3839 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3840 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3841 auth
->configurator
? "Configurator" : "Enrollee");
3842 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3843 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3844 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3845 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3846 "Unexpected role in R-capabilities 0x%02x",
3848 if (role
!= DPP_CAPAB_ENROLLEE
&&
3849 role
!= DPP_CAPAB_CONFIGURATOR
)
3851 bin_clear_free(unwrapped
, unwrapped_len
);
3852 auth
->remove_on_tx_status
= 1;
3853 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3856 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3857 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3858 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3860 "Missing or invalid Secondary Wrapped Data");
3864 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3865 wrapped2
, wrapped2_len
);
3867 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3870 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3871 unwrapped2
= os_malloc(unwrapped2_len
);
3874 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3875 wrapped2
, wrapped2_len
,
3876 0, NULL
, NULL
, unwrapped2
) < 0) {
3877 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3880 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3881 unwrapped2
, unwrapped2_len
);
3883 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3885 "Invalid attribute in secondary unwrapped data");
3889 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3891 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3893 "Missing or invalid Responder Authenticating Tag");
3896 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3897 r_auth
, r_auth_len
);
3898 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3899 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3901 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3902 r_auth2
, r_auth_len
);
3903 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3904 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3905 bin_clear_free(unwrapped
, unwrapped_len
);
3906 bin_clear_free(unwrapped2
, unwrapped2_len
);
3907 auth
->remove_on_tx_status
= 1;
3908 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3911 bin_clear_free(unwrapped
, unwrapped_len
);
3912 bin_clear_free(unwrapped2
, unwrapped2_len
);
3914 #ifdef CONFIG_TESTING_OPTIONS
3915 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3916 wpa_printf(MSG_INFO
,
3917 "DPP: TESTING - Authentication Response in place of Confirm");
3918 if (dpp_auth_build_resp_ok(auth
) < 0)
3920 return wpabuf_dup(auth
->resp_msg
);
3922 #endif /* CONFIG_TESTING_OPTIONS */
3924 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3927 bin_clear_free(unwrapped
, unwrapped_len
);
3928 bin_clear_free(unwrapped2
, unwrapped2_len
);
3930 EVP_PKEY_CTX_free(ctx
);
3935 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3937 const u8
*attr_start
, size_t attr_len
,
3938 const u8
*wrapped_data
,
3939 u16 wrapped_data_len
,
3940 enum dpp_status_error status
)
3944 u8
*unwrapped
= NULL
;
3945 size_t unwrapped_len
= 0;
3949 /* Authentication Confirm failure cases are expected to include
3950 * {R-nonce}k2 in the Wrapped Data attribute. */
3953 len
[0] = DPP_HDR_LEN
;
3954 addr
[1] = attr_start
;
3956 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3957 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3958 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3959 wrapped_data
, wrapped_data_len
);
3960 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3961 unwrapped
= os_malloc(unwrapped_len
);
3963 dpp_auth_fail(auth
, "Authentication failed");
3966 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3967 wrapped_data
, wrapped_data_len
,
3968 2, addr
, len
, unwrapped
) < 0) {
3969 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3972 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3973 unwrapped
, unwrapped_len
);
3975 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3976 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3980 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3982 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3983 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3986 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3987 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3988 r_nonce
, r_nonce_len
);
3989 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3990 auth
->r_nonce
, r_nonce_len
);
3991 dpp_auth_fail(auth
, "R-nonce mismatch");
3995 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3996 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3997 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3998 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4001 bin_clear_free(unwrapped
, unwrapped_len
);
4006 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4007 const u8
*attr_start
, size_t attr_len
)
4009 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4010 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4014 u8
*unwrapped
= NULL
;
4015 size_t unwrapped_len
= 0;
4016 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4018 #ifdef CONFIG_TESTING_OPTIONS
4019 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4020 wpa_printf(MSG_INFO
,
4021 "DPP: TESTING - stop at Authentication Confirm");
4024 #endif /* CONFIG_TESTING_OPTIONS */
4026 if (auth
->initiator
|| !auth
->own_bi
) {
4027 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4031 auth
->waiting_auth_conf
= 0;
4033 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4035 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4037 "Missing or invalid required Wrapped Data attribute");
4040 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4041 wrapped_data
, wrapped_data_len
);
4043 attr_len
= wrapped_data
- 4 - attr_start
;
4045 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4046 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4048 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4050 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4053 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4054 r_bootstrap
, r_bootstrap_len
);
4055 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4056 SHA256_MAC_LEN
) != 0) {
4057 wpa_hexdump(MSG_DEBUG
,
4058 "DPP: Expected Responder Bootstrapping Key Hash",
4059 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4061 "Responder Bootstrapping Key Hash mismatch");
4065 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4066 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4069 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4071 "Invalid Initiator Bootstrapping Key Hash attribute");
4074 wpa_hexdump(MSG_MSGDUMP
,
4075 "DPP: Initiator Bootstrapping Key Hash",
4076 i_bootstrap
, i_bootstrap_len
);
4077 if (!auth
->peer_bi
||
4078 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4079 SHA256_MAC_LEN
) != 0) {
4081 "Initiator Bootstrapping Key Hash mismatch");
4084 } else if (auth
->peer_bi
) {
4085 /* Mutual authentication and peer did not include its
4086 * Bootstrapping Key Hash attribute. */
4088 "Missing Initiator Bootstrapping Key Hash attribute");
4092 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4094 if (!status
|| status_len
< 1) {
4096 "Missing or invalid required DPP Status attribute");
4099 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4100 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4101 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4102 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4103 attr_len
, wrapped_data
,
4104 wrapped_data_len
, status
[0]);
4106 if (status
[0] != DPP_STATUS_OK
) {
4107 dpp_auth_fail(auth
, "Authentication failed");
4112 len
[0] = DPP_HDR_LEN
;
4113 addr
[1] = attr_start
;
4115 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4116 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4117 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4118 wrapped_data
, wrapped_data_len
);
4119 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4120 unwrapped
= os_malloc(unwrapped_len
);
4123 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4124 wrapped_data
, wrapped_data_len
,
4125 2, addr
, len
, unwrapped
) < 0) {
4126 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4129 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4130 unwrapped
, unwrapped_len
);
4132 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4133 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4137 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4139 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4141 "Missing or invalid Initiator Authenticating Tag");
4144 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4145 i_auth
, i_auth_len
);
4146 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4147 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4149 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4150 i_auth2
, i_auth_len
);
4151 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4152 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4156 bin_clear_free(unwrapped
, unwrapped_len
);
4157 dpp_auth_success(auth
);
4160 bin_clear_free(unwrapped
, unwrapped_len
);
4165 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4167 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4171 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4173 struct dpp_configuration
*conf
;
4177 conf
= os_zalloc(sizeof(*conf
));
4181 end
= os_strchr(type
, ' ');
4185 len
= os_strlen(type
);
4187 if (bin_str_eq(type
, len
, "psk"))
4188 conf
->akm
= DPP_AKM_PSK
;
4189 else if (bin_str_eq(type
, len
, "sae"))
4190 conf
->akm
= DPP_AKM_SAE
;
4191 else if (bin_str_eq(type
, len
, "psk-sae") ||
4192 bin_str_eq(type
, len
, "psk+sae"))
4193 conf
->akm
= DPP_AKM_PSK_SAE
;
4194 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4195 bin_str_eq(type
, len
, "dpp+sae"))
4196 conf
->akm
= DPP_AKM_SAE_DPP
;
4197 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4198 bin_str_eq(type
, len
, "dpp+psk+sae"))
4199 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4200 else if (bin_str_eq(type
, len
, "dpp"))
4201 conf
->akm
= DPP_AKM_DPP
;
4207 dpp_configuration_free(conf
);
4212 int dpp_akm_psk(enum dpp_akm akm
)
4214 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4215 akm
== DPP_AKM_PSK_SAE_DPP
;
4219 int dpp_akm_sae(enum dpp_akm akm
)
4221 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4222 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4226 int dpp_akm_legacy(enum dpp_akm akm
)
4228 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4233 int dpp_akm_dpp(enum dpp_akm akm
)
4235 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4236 akm
== DPP_AKM_PSK_SAE_DPP
;
4240 int dpp_akm_ver2(enum dpp_akm akm
)
4242 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4246 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4248 if (conf
->ssid_len
== 0)
4250 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4252 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4258 void dpp_configuration_free(struct dpp_configuration
*conf
)
4262 str_clear_free(conf
->passphrase
);
4263 os_free(conf
->group_id
);
4264 bin_clear_free(conf
, sizeof(*conf
));
4268 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4271 const char *pos
, *end
;
4272 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4273 struct dpp_configuration
*conf
= NULL
;
4275 pos
= os_strstr(cmd
, " conf=sta-");
4277 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4283 pos
= os_strstr(cmd
, " conf=ap-");
4285 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4294 pos
= os_strstr(cmd
, " ssid=");
4297 end
= os_strchr(pos
, ' ');
4298 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4299 conf
->ssid_len
/= 2;
4300 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4301 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4304 #ifdef CONFIG_TESTING_OPTIONS
4305 /* use a default SSID for legacy testing reasons */
4306 os_memcpy(conf
->ssid
, "test", 4);
4308 #else /* CONFIG_TESTING_OPTIONS */
4310 #endif /* CONFIG_TESTING_OPTIONS */
4313 pos
= os_strstr(cmd
, " pass=");
4318 end
= os_strchr(pos
, ' ');
4319 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4321 if (pass_len
> 63 || pass_len
< 8)
4323 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4324 if (!conf
->passphrase
||
4325 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4329 pos
= os_strstr(cmd
, " psk=");
4332 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4337 pos
= os_strstr(cmd
, " group_id=");
4339 size_t group_id_len
;
4342 end
= os_strchr(pos
, ' ');
4343 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4344 conf
->group_id
= os_malloc(group_id_len
+ 1);
4345 if (!conf
->group_id
)
4347 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4348 conf
->group_id
[group_id_len
] = '\0';
4351 pos
= os_strstr(cmd
, " expiry=");
4356 val
= strtol(pos
, NULL
, 0);
4359 conf
->netaccesskey_expiry
= val
;
4362 if (!dpp_configuration_valid(conf
))
4365 auth
->conf_sta
= conf_sta
;
4366 auth
->conf_ap
= conf_ap
;
4370 dpp_configuration_free(conf_sta
);
4371 dpp_configuration_free(conf_ap
);
4376 static struct dpp_configurator
*
4377 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4379 struct dpp_configurator
*conf
;
4384 dl_list_for_each(conf
, &dpp
->configurator
,
4385 struct dpp_configurator
, list
) {
4393 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4394 struct dpp_authentication
*auth
,
4402 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4404 pos
= os_strstr(cmd
, " configurator=");
4407 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4409 wpa_printf(MSG_INFO
,
4410 "DPP: Could not find the specified configurator");
4415 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4416 wpa_msg(msg_ctx
, MSG_INFO
,
4417 "DPP: Failed to set configurator parameters");
4424 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4428 dpp_configuration_free(auth
->conf_ap
);
4429 dpp_configuration_free(auth
->conf_sta
);
4430 EVP_PKEY_free(auth
->own_protocol_key
);
4431 EVP_PKEY_free(auth
->peer_protocol_key
);
4432 wpabuf_free(auth
->req_msg
);
4433 wpabuf_free(auth
->resp_msg
);
4434 wpabuf_free(auth
->conf_req
);
4435 os_free(auth
->connector
);
4436 wpabuf_free(auth
->net_access_key
);
4437 wpabuf_free(auth
->c_sign_key
);
4438 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4439 #ifdef CONFIG_TESTING_OPTIONS
4440 os_free(auth
->config_obj_override
);
4441 os_free(auth
->discovery_override
);
4442 os_free(auth
->groups_override
);
4443 #endif /* CONFIG_TESTING_OPTIONS */
4444 bin_clear_free(auth
, sizeof(*auth
));
4448 static struct wpabuf
*
4449 dpp_build_conf_start(struct dpp_authentication
*auth
,
4450 struct dpp_configuration
*conf
, size_t tailroom
)
4453 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4455 #ifdef CONFIG_TESTING_OPTIONS
4456 if (auth
->discovery_override
)
4457 tailroom
+= os_strlen(auth
->discovery_override
);
4458 #endif /* CONFIG_TESTING_OPTIONS */
4460 buf
= wpabuf_alloc(200 + tailroom
);
4463 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4464 #ifdef CONFIG_TESTING_OPTIONS
4465 if (auth
->discovery_override
) {
4466 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4467 auth
->discovery_override
);
4468 wpabuf_put_str(buf
, auth
->discovery_override
);
4469 wpabuf_put_u8(buf
, ',');
4472 #endif /* CONFIG_TESTING_OPTIONS */
4473 wpabuf_put_str(buf
, "{\"ssid\":\"");
4474 json_escape_string(ssid
, sizeof(ssid
),
4475 (const char *) conf
->ssid
, conf
->ssid_len
);
4476 wpabuf_put_str(buf
, ssid
);
4477 wpabuf_put_str(buf
, "\"},");
4483 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4484 const char *kid
, const struct dpp_curve_params
*curve
)
4488 char *x
= NULL
, *y
= NULL
;
4491 pub
= dpp_get_pubkey_point(key
, 0);
4494 pos
= wpabuf_head(pub
);
4495 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4496 pos
+= curve
->prime_len
;
4497 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4501 wpabuf_put_str(buf
, "\"");
4502 wpabuf_put_str(buf
, name
);
4503 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4504 wpabuf_put_str(buf
, curve
->jwk_crv
);
4505 wpabuf_put_str(buf
, "\",\"x\":\"");
4506 wpabuf_put_str(buf
, x
);
4507 wpabuf_put_str(buf
, "\",\"y\":\"");
4508 wpabuf_put_str(buf
, y
);
4510 wpabuf_put_str(buf
, "\",\"kid\":\"");
4511 wpabuf_put_str(buf
, kid
);
4513 wpabuf_put_str(buf
, "\"}");
4523 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4524 struct dpp_configuration
*conf
)
4526 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4527 char pass
[63 * 6 + 1];
4529 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4530 os_strlen(conf
->passphrase
));
4531 wpabuf_put_str(buf
, "\"pass\":\"");
4532 wpabuf_put_str(buf
, pass
);
4533 wpabuf_put_str(buf
, "\"");
4534 os_memset(pass
, 0, sizeof(pass
));
4535 } else if (conf
->psk_set
) {
4536 char psk
[2 * sizeof(conf
->psk
) + 1];
4538 wpa_snprintf_hex(psk
, sizeof(psk
),
4539 conf
->psk
, sizeof(conf
->psk
));
4540 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4541 wpabuf_put_str(buf
, psk
);
4542 wpabuf_put_str(buf
, "\"");
4543 os_memset(psk
, 0, sizeof(psk
));
4548 static struct wpabuf
*
4549 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4550 struct dpp_configuration
*conf
)
4552 struct wpabuf
*buf
= NULL
;
4553 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4555 const struct dpp_curve_params
*curve
;
4556 char jws_prot_hdr
[100];
4557 size_t signed1_len
, signed2_len
, signed3_len
;
4558 struct wpabuf
*dppcon
= NULL
;
4559 unsigned char *signature
= NULL
;
4560 const unsigned char *p
;
4561 size_t signature_len
;
4562 EVP_MD_CTX
*md_ctx
= NULL
;
4563 ECDSA_SIG
*sig
= NULL
;
4565 const EVP_MD
*sign_md
;
4566 const BIGNUM
*r
, *s
;
4567 size_t extra_len
= 1000;
4572 wpa_printf(MSG_INFO
,
4573 "DPP: No configurator specified - cannot generate DPP config object");
4576 curve
= auth
->conf
->curve
;
4577 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4578 sign_md
= EVP_sha256();
4579 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4580 sign_md
= EVP_sha384();
4581 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4582 sign_md
= EVP_sha512();
4584 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4589 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4590 wpa_printf(MSG_DEBUG
,
4591 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4595 #ifdef CONFIG_TESTING_OPTIONS
4596 if (auth
->groups_override
)
4597 extra_len
+= os_strlen(auth
->groups_override
);
4598 #endif /* CONFIG_TESTING_OPTIONS */
4601 extra_len
+= os_strlen(conf
->group_id
);
4603 /* Connector (JSON dppCon object) */
4604 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4607 #ifdef CONFIG_TESTING_OPTIONS
4608 if (auth
->groups_override
) {
4609 wpabuf_put_u8(dppcon
, '{');
4610 if (auth
->groups_override
) {
4611 wpa_printf(MSG_DEBUG
,
4612 "DPP: TESTING - groups override: '%s'",
4613 auth
->groups_override
);
4614 wpabuf_put_str(dppcon
, "\"groups\":");
4615 wpabuf_put_str(dppcon
, auth
->groups_override
);
4616 wpabuf_put_u8(dppcon
, ',');
4620 #endif /* CONFIG_TESTING_OPTIONS */
4621 wpabuf_printf(dppcon
, "{\"groups\":[{\"groupId\":\"%s\",",
4622 conf
->group_id
? conf
->group_id
: "*");
4623 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4624 #ifdef CONFIG_TESTING_OPTIONS
4626 #endif /* CONFIG_TESTING_OPTIONS */
4627 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4629 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4632 if (conf
->netaccesskey_expiry
) {
4635 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4636 wpa_printf(MSG_DEBUG
,
4637 "DPP: Failed to generate expiry string");
4640 wpabuf_printf(dppcon
,
4641 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4642 tm
.year
, tm
.month
, tm
.day
,
4643 tm
.hour
, tm
.min
, tm
.sec
);
4645 wpabuf_put_u8(dppcon
, '}');
4646 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4647 (const char *) wpabuf_head(dppcon
));
4649 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4650 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4651 auth
->conf
->kid
, curve
->jws_alg
);
4652 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4653 os_strlen(jws_prot_hdr
),
4655 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4658 if (!signed1
|| !signed2
)
4661 md_ctx
= EVP_MD_CTX_create();
4666 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4667 auth
->conf
->csign
) != 1) {
4668 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4669 ERR_error_string(ERR_get_error(), NULL
));
4672 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4673 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4674 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4675 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4676 ERR_error_string(ERR_get_error(), NULL
));
4679 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4680 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4681 ERR_error_string(ERR_get_error(), NULL
));
4684 signature
= os_malloc(signature_len
);
4687 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4688 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4689 ERR_error_string(ERR_get_error(), NULL
));
4692 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4693 signature
, signature_len
);
4694 /* Convert to raw coordinates r,s */
4696 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4699 ECDSA_SIG_get0(sig
, &r
, &s
);
4700 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4701 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4702 curve
->prime_len
) < 0)
4704 signature_len
= 2 * curve
->prime_len
;
4705 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4706 signature
, signature_len
);
4707 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4712 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
4714 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4715 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4718 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4722 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm
));
4724 dpp_build_legacy_cred_params(buf
, conf
);
4725 wpabuf_put_str(buf
, ",");
4727 wpabuf_put_str(buf
, "\"signedConnector\":\"");
4728 wpabuf_put_str(buf
, signed1
);
4729 wpabuf_put_u8(buf
, '.');
4730 wpabuf_put_str(buf
, signed2
);
4731 wpabuf_put_u8(buf
, '.');
4732 wpabuf_put_str(buf
, signed3
);
4733 wpabuf_put_str(buf
, "\",");
4734 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4736 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4740 wpabuf_put_str(buf
, "}}");
4742 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4743 wpabuf_head(buf
), wpabuf_len(buf
));
4746 EVP_MD_CTX_destroy(md_ctx
);
4747 ECDSA_SIG_free(sig
);
4752 wpabuf_free(dppcon
);
4755 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4762 static struct wpabuf
*
4763 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4764 struct dpp_configuration
*conf
)
4768 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4772 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4773 dpp_build_legacy_cred_params(buf
, conf
);
4774 wpabuf_put_str(buf
, "}}");
4776 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4777 wpabuf_head(buf
), wpabuf_len(buf
));
4783 static struct wpabuf
*
4784 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4786 struct dpp_configuration
*conf
;
4788 #ifdef CONFIG_TESTING_OPTIONS
4789 if (auth
->config_obj_override
) {
4790 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4791 return wpabuf_alloc_copy(auth
->config_obj_override
,
4792 os_strlen(auth
->config_obj_override
));
4794 #endif /* CONFIG_TESTING_OPTIONS */
4796 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4798 wpa_printf(MSG_DEBUG
,
4799 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4804 if (dpp_akm_dpp(conf
->akm
))
4805 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4806 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4810 static struct wpabuf
*
4811 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4812 u16 e_nonce_len
, int ap
)
4814 struct wpabuf
*conf
;
4815 size_t clear_len
, attr_len
;
4816 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4820 enum dpp_status_error status
;
4822 conf
= dpp_build_conf_obj(auth
, ap
);
4824 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4825 wpabuf_head(conf
), wpabuf_len(conf
));
4827 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4828 auth
->conf_resp_status
= status
;
4830 /* { E-nonce, configurationObject}ke */
4831 clear_len
= 4 + e_nonce_len
;
4833 clear_len
+= 4 + wpabuf_len(conf
);
4834 clear
= wpabuf_alloc(clear_len
);
4835 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4836 #ifdef CONFIG_TESTING_OPTIONS
4837 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4839 #endif /* CONFIG_TESTING_OPTIONS */
4840 msg
= wpabuf_alloc(attr_len
);
4844 #ifdef CONFIG_TESTING_OPTIONS
4845 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4846 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4849 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4850 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4851 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4852 wpabuf_put_le16(clear
, e_nonce_len
);
4853 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4854 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4857 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4858 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4859 goto skip_wrapped_data
;
4861 #endif /* CONFIG_TESTING_OPTIONS */
4864 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4865 wpabuf_put_le16(clear
, e_nonce_len
);
4866 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4868 #ifdef CONFIG_TESTING_OPTIONS
4870 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4871 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4872 goto skip_config_obj
;
4874 #endif /* CONFIG_TESTING_OPTIONS */
4877 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4878 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4879 wpabuf_put_buf(clear
, conf
);
4882 #ifdef CONFIG_TESTING_OPTIONS
4884 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4885 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4888 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4889 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4892 #endif /* CONFIG_TESTING_OPTIONS */
4895 dpp_build_attr_status(msg
, status
);
4897 #ifdef CONFIG_TESTING_OPTIONS
4899 #endif /* CONFIG_TESTING_OPTIONS */
4901 addr
[0] = wpabuf_head(msg
);
4902 len
[0] = wpabuf_len(msg
);
4903 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4905 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4906 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4907 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4909 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4910 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4911 wpabuf_head(clear
), wpabuf_len(clear
),
4912 1, addr
, len
, wrapped
) < 0)
4914 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4915 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4917 #ifdef CONFIG_TESTING_OPTIONS
4918 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4919 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4920 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4923 #endif /* CONFIG_TESTING_OPTIONS */
4925 wpa_hexdump_buf(MSG_DEBUG
,
4926 "DPP: Configuration Response attributes", msg
);
4940 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4943 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4944 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4945 u8
*unwrapped
= NULL
;
4946 size_t unwrapped_len
= 0;
4947 struct wpabuf
*resp
= NULL
;
4948 struct json_token
*root
= NULL
, *token
;
4951 #ifdef CONFIG_TESTING_OPTIONS
4952 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4953 wpa_printf(MSG_INFO
,
4954 "DPP: TESTING - stop at Config Request");
4957 #endif /* CONFIG_TESTING_OPTIONS */
4959 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4960 dpp_auth_fail(auth
, "Invalid attribute in config request");
4964 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4966 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4968 "Missing or invalid required Wrapped Data attribute");
4972 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4973 wrapped_data
, wrapped_data_len
);
4974 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4975 unwrapped
= os_malloc(unwrapped_len
);
4978 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4979 wrapped_data
, wrapped_data_len
,
4980 0, NULL
, NULL
, unwrapped
) < 0) {
4981 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4984 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4985 unwrapped
, unwrapped_len
);
4987 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4988 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4992 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4993 DPP_ATTR_ENROLLEE_NONCE
,
4995 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4997 "Missing or invalid Enrollee Nonce attribute");
5000 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5001 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5003 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5004 DPP_ATTR_CONFIG_ATTR_OBJ
,
5008 "Missing or invalid Config Attributes attribute");
5011 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5012 config_attr
, config_attr_len
);
5014 root
= json_parse((const char *) config_attr
, config_attr_len
);
5016 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5020 token
= json_get_member(root
, "name");
5021 if (!token
|| token
->type
!= JSON_STRING
) {
5022 dpp_auth_fail(auth
, "No Config Attributes - name");
5025 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5027 token
= json_get_member(root
, "wi-fi_tech");
5028 if (!token
|| token
->type
!= JSON_STRING
) {
5029 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5032 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5033 if (os_strcmp(token
->string
, "infra") != 0) {
5034 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5036 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5040 token
= json_get_member(root
, "netRole");
5041 if (!token
|| token
->type
!= JSON_STRING
) {
5042 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5045 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5046 if (os_strcmp(token
->string
, "sta") == 0) {
5048 } else if (os_strcmp(token
->string
, "ap") == 0) {
5051 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5053 dpp_auth_fail(auth
, "Unsupported netRole");
5057 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
5066 static struct wpabuf
*
5067 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
5068 const u8
*prot_hdr
, u16 prot_hdr_len
,
5069 const EVP_MD
**ret_md
)
5071 struct json_token
*root
, *token
;
5072 struct wpabuf
*kid
= NULL
;
5074 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
5076 wpa_printf(MSG_DEBUG
,
5077 "DPP: JSON parsing failed for JWS Protected Header");
5081 if (root
->type
!= JSON_OBJECT
) {
5082 wpa_printf(MSG_DEBUG
,
5083 "DPP: JWS Protected Header root is not an object");
5087 token
= json_get_member(root
, "typ");
5088 if (!token
|| token
->type
!= JSON_STRING
) {
5089 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
5092 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
5094 if (os_strcmp(token
->string
, "dppCon") != 0) {
5095 wpa_printf(MSG_DEBUG
,
5096 "DPP: Unsupported JWS Protected Header typ=%s",
5101 token
= json_get_member(root
, "alg");
5102 if (!token
|| token
->type
!= JSON_STRING
) {
5103 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
5106 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
5108 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5109 wpa_printf(MSG_DEBUG
,
5110 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5111 token
->string
, curve
->jws_alg
);
5114 if (os_strcmp(token
->string
, "ES256") == 0 ||
5115 os_strcmp(token
->string
, "BS256") == 0)
5116 *ret_md
= EVP_sha256();
5117 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5118 os_strcmp(token
->string
, "BS384") == 0)
5119 *ret_md
= EVP_sha384();
5120 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5121 os_strcmp(token
->string
, "BS512") == 0)
5122 *ret_md
= EVP_sha512();
5126 wpa_printf(MSG_DEBUG
,
5127 "DPP: Unsupported JWS Protected Header alg=%s",
5132 kid
= json_get_member_base64url(root
, "kid");
5134 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5137 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5146 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
5147 struct json_token
*cred
)
5149 struct json_token
*pass
, *psk_hex
;
5151 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5153 pass
= json_get_member(cred
, "pass");
5154 psk_hex
= json_get_member(cred
, "psk_hex");
5156 if (pass
&& pass
->type
== JSON_STRING
) {
5157 size_t len
= os_strlen(pass
->string
);
5159 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5161 if (len
< 8 || len
> 63)
5163 os_strlcpy(auth
->passphrase
, pass
->string
,
5164 sizeof(auth
->passphrase
));
5165 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5166 if (dpp_akm_sae(auth
->akm
) && !dpp_akm_psk(auth
->akm
)) {
5167 wpa_printf(MSG_DEBUG
,
5168 "DPP: Unexpected psk_hex with akm=sae");
5171 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5172 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
5173 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5176 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5177 auth
->psk
, PMK_LEN
);
5180 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5184 if (dpp_akm_sae(auth
->akm
) && !auth
->passphrase
[0]) {
5185 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5193 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5194 const struct dpp_curve_params
**key_curve
)
5196 struct json_token
*token
;
5197 const struct dpp_curve_params
*curve
;
5198 struct wpabuf
*x
= NULL
, *y
= NULL
;
5200 EVP_PKEY
*pkey
= NULL
;
5202 token
= json_get_member(jwk
, "kty");
5203 if (!token
|| token
->type
!= JSON_STRING
) {
5204 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5207 if (os_strcmp(token
->string
, "EC") != 0) {
5208 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5213 token
= json_get_member(jwk
, "crv");
5214 if (!token
|| token
->type
!= JSON_STRING
) {
5215 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5218 curve
= dpp_get_curve_jwk_crv(token
->string
);
5220 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5225 x
= json_get_member_base64url(jwk
, "x");
5227 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5230 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5231 if (wpabuf_len(x
) != curve
->prime_len
) {
5232 wpa_printf(MSG_DEBUG
,
5233 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5234 (unsigned int) wpabuf_len(x
),
5235 (unsigned int) curve
->prime_len
, curve
->name
);
5239 y
= json_get_member_base64url(jwk
, "y");
5241 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5244 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5245 if (wpabuf_len(y
) != curve
->prime_len
) {
5246 wpa_printf(MSG_DEBUG
,
5247 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5248 (unsigned int) wpabuf_len(y
),
5249 (unsigned int) curve
->prime_len
, curve
->name
);
5253 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5255 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5259 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5261 EC_GROUP_free(group
);
5272 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5275 unsigned int year
, month
, day
, hour
, min
, sec
;
5279 /* ISO 8601 date and time:
5281 * YYYY-MM-DDTHH:MM:SSZ
5282 * YYYY-MM-DDTHH:MM:SS+03:00
5284 if (os_strlen(timestamp
) < 19) {
5285 wpa_printf(MSG_DEBUG
,
5286 "DPP: Too short timestamp - assume expired key");
5289 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5290 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5291 wpa_printf(MSG_DEBUG
,
5292 "DPP: Failed to parse expiration day - assume expired key");
5296 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5297 wpa_printf(MSG_DEBUG
,
5298 "DPP: Invalid date/time information - assume expired key");
5302 pos
= timestamp
+ 19;
5303 if (*pos
== 'Z' || *pos
== '\0') {
5304 /* In UTC - no need to adjust */
5305 } else if (*pos
== '-' || *pos
== '+') {
5308 /* Adjust local time to UTC */
5309 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5311 wpa_printf(MSG_DEBUG
,
5312 "DPP: Invalid time zone designator (%s) - assume expired key",
5317 utime
+= 3600 * hour
;
5319 utime
-= 3600 * hour
;
5327 wpa_printf(MSG_DEBUG
,
5328 "DPP: Invalid time zone designator (%s) - assume expired key",
5335 if (os_get_time(&now
) < 0) {
5336 wpa_printf(MSG_DEBUG
,
5337 "DPP: Cannot get current time - assume expired key");
5341 if (now
.sec
> utime
) {
5342 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5351 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5352 const unsigned char *payload
,
5355 struct json_token
*root
, *groups
, *netkey
, *token
;
5357 EVP_PKEY
*key
= NULL
;
5358 const struct dpp_curve_params
*curve
;
5359 unsigned int rules
= 0;
5361 root
= json_parse((const char *) payload
, payload_len
);
5363 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5367 groups
= json_get_member(root
, "groups");
5368 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5369 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5372 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5373 struct json_token
*id
, *role
;
5375 id
= json_get_member(token
, "groupId");
5376 if (!id
|| id
->type
!= JSON_STRING
) {
5377 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5381 role
= json_get_member(token
, "netRole");
5382 if (!role
|| role
->type
!= JSON_STRING
) {
5383 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5386 wpa_printf(MSG_DEBUG
,
5387 "DPP: connector group: groupId='%s' netRole='%s'",
5388 id
->string
, role
->string
);
5394 wpa_printf(MSG_DEBUG
,
5395 "DPP: Connector includes no groups");
5399 token
= json_get_member(root
, "expiry");
5400 if (!token
|| token
->type
!= JSON_STRING
) {
5401 wpa_printf(MSG_DEBUG
,
5402 "DPP: No expiry string found - connector does not expire");
5404 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5405 if (dpp_key_expired(token
->string
,
5406 &auth
->net_access_key_expiry
)) {
5407 wpa_printf(MSG_DEBUG
,
5408 "DPP: Connector (netAccessKey) has expired");
5413 netkey
= json_get_member(root
, "netAccessKey");
5414 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5415 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5419 key
= dpp_parse_jwk(netkey
, &curve
);
5422 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5424 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5425 wpa_printf(MSG_DEBUG
,
5426 "DPP: netAccessKey in connector does not match own protocol key");
5427 #ifdef CONFIG_TESTING_OPTIONS
5428 if (auth
->ignore_netaccesskey_mismatch
) {
5429 wpa_printf(MSG_DEBUG
,
5430 "DPP: TESTING - skip netAccessKey mismatch");
5434 #else /* CONFIG_TESTING_OPTIONS */
5436 #endif /* CONFIG_TESTING_OPTIONS */
5447 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5449 struct wpabuf
*uncomp
;
5451 u8 hash
[SHA256_MAC_LEN
];
5455 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5457 uncomp
= dpp_get_pubkey_point(pub
, 1);
5460 addr
[0] = wpabuf_head(uncomp
);
5461 len
[0] = wpabuf_len(uncomp
);
5462 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5464 res
= sha256_vector(1, addr
, len
, hash
);
5465 wpabuf_free(uncomp
);
5468 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5469 wpa_printf(MSG_DEBUG
,
5470 "DPP: Received hash value does not match calculated public key hash value");
5471 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5472 hash
, SHA256_MAC_LEN
);
5479 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5481 unsigned char *der
= NULL
;
5484 der_len
= i2d_PUBKEY(csign
, &der
);
5487 wpabuf_free(auth
->c_sign_key
);
5488 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5493 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5495 unsigned char *der
= NULL
;
5499 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5503 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5508 wpabuf_free(auth
->net_access_key
);
5509 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5515 struct dpp_signed_connector_info
{
5516 unsigned char *payload
;
5520 static enum dpp_status_error
5521 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5522 EVP_PKEY
*csign_pub
, const char *connector
)
5524 enum dpp_status_error ret
= 255;
5525 const char *pos
, *end
, *signed_start
, *signed_end
;
5526 struct wpabuf
*kid
= NULL
;
5527 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5528 size_t prot_hdr_len
= 0, signature_len
= 0;
5529 const EVP_MD
*sign_md
= NULL
;
5530 unsigned char *der
= NULL
;
5533 EVP_MD_CTX
*md_ctx
= NULL
;
5534 ECDSA_SIG
*sig
= NULL
;
5535 BIGNUM
*r
= NULL
, *s
= NULL
;
5536 const struct dpp_curve_params
*curve
;
5538 const EC_GROUP
*group
;
5541 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5544 group
= EC_KEY_get0_group(eckey
);
5547 nid
= EC_GROUP_get_curve_name(group
);
5548 curve
= dpp_get_curve_nid(nid
);
5551 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5552 os_memset(info
, 0, sizeof(*info
));
5554 signed_start
= pos
= connector
;
5555 end
= os_strchr(pos
, '.');
5557 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5558 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5561 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5562 end
- pos
, &prot_hdr_len
);
5564 wpa_printf(MSG_DEBUG
,
5565 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5566 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5569 wpa_hexdump_ascii(MSG_DEBUG
,
5570 "DPP: signedConnector - JWS Protected Header",
5571 prot_hdr
, prot_hdr_len
);
5572 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5574 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5577 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5578 wpa_printf(MSG_DEBUG
,
5579 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5580 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5581 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5586 end
= os_strchr(pos
, '.');
5588 wpa_printf(MSG_DEBUG
,
5589 "DPP: Missing dot(2) in signedConnector");
5590 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5593 signed_end
= end
- 1;
5594 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5595 end
- pos
, &info
->payload_len
);
5596 if (!info
->payload
) {
5597 wpa_printf(MSG_DEBUG
,
5598 "DPP: Failed to base64url decode signedConnector JWS Payload");
5599 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5602 wpa_hexdump_ascii(MSG_DEBUG
,
5603 "DPP: signedConnector - JWS Payload",
5604 info
->payload
, info
->payload_len
);
5606 signature
= base64_url_decode((const unsigned char *) pos
,
5607 os_strlen(pos
), &signature_len
);
5609 wpa_printf(MSG_DEBUG
,
5610 "DPP: Failed to base64url decode signedConnector signature");
5611 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5614 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5615 signature
, signature_len
);
5617 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5618 ret
= DPP_STATUS_NO_MATCH
;
5622 if (signature_len
& 0x01) {
5623 wpa_printf(MSG_DEBUG
,
5624 "DPP: Unexpected signedConnector signature length (%d)",
5625 (int) signature_len
);
5626 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5630 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5631 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5632 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5633 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5634 sig
= ECDSA_SIG_new();
5635 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5640 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5642 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5645 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5646 md_ctx
= EVP_MD_CTX_create();
5651 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5652 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5653 ERR_error_string(ERR_get_error(), NULL
));
5656 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5657 signed_end
- signed_start
+ 1) != 1) {
5658 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5659 ERR_error_string(ERR_get_error(), NULL
));
5662 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5664 wpa_printf(MSG_DEBUG
,
5665 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5666 res
, ERR_error_string(ERR_get_error(), NULL
));
5667 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5671 ret
= DPP_STATUS_OK
;
5674 EVP_MD_CTX_destroy(md_ctx
);
5678 ECDSA_SIG_free(sig
);
5686 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5687 struct json_token
*cred
)
5689 struct dpp_signed_connector_info info
;
5690 struct json_token
*token
, *csign
;
5692 EVP_PKEY
*csign_pub
= NULL
;
5693 const struct dpp_curve_params
*key_curve
= NULL
;
5694 const char *signed_connector
;
5696 os_memset(&info
, 0, sizeof(info
));
5698 if (dpp_akm_psk(auth
->akm
) || dpp_akm_sae(auth
->akm
)) {
5699 wpa_printf(MSG_DEBUG
,
5700 "DPP: Legacy credential included in Connector credential");
5701 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5705 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5707 csign
= json_get_member(cred
, "csign");
5708 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5709 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5713 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5715 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5718 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5720 token
= json_get_member(cred
, "signedConnector");
5721 if (!token
|| token
->type
!= JSON_STRING
) {
5722 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5725 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5726 token
->string
, os_strlen(token
->string
));
5727 signed_connector
= token
->string
;
5729 if (os_strchr(signed_connector
, '"') ||
5730 os_strchr(signed_connector
, '\n')) {
5731 wpa_printf(MSG_DEBUG
,
5732 "DPP: Unexpected character in signedConnector");
5736 if (dpp_process_signed_connector(&info
, csign_pub
,
5737 signed_connector
) != DPP_STATUS_OK
)
5740 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5741 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5745 os_free(auth
->connector
);
5746 auth
->connector
= os_strdup(signed_connector
);
5748 dpp_copy_csign(auth
, csign_pub
);
5749 dpp_copy_netaccesskey(auth
);
5753 EVP_PKEY_free(csign_pub
);
5754 os_free(info
.payload
);
5759 const char * dpp_akm_str(enum dpp_akm akm
)
5768 case DPP_AKM_PSK_SAE
:
5770 case DPP_AKM_SAE_DPP
:
5772 case DPP_AKM_PSK_SAE_DPP
:
5773 return "dpp+psk+sae";
5780 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5782 if (os_strcmp(akm
, "psk") == 0)
5784 if (os_strcmp(akm
, "sae") == 0)
5786 if (os_strcmp(akm
, "psk+sae") == 0)
5787 return DPP_AKM_PSK_SAE
;
5788 if (os_strcmp(akm
, "dpp") == 0)
5790 if (os_strcmp(akm
, "dpp+sae") == 0)
5791 return DPP_AKM_SAE_DPP
;
5792 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
5793 return DPP_AKM_PSK_SAE_DPP
;
5794 return DPP_AKM_UNKNOWN
;
5798 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5799 const u8
*conf_obj
, u16 conf_obj_len
)
5802 struct json_token
*root
, *token
, *discovery
, *cred
;
5804 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5807 if (root
->type
!= JSON_OBJECT
) {
5808 dpp_auth_fail(auth
, "JSON root is not an object");
5812 token
= json_get_member(root
, "wi-fi_tech");
5813 if (!token
|| token
->type
!= JSON_STRING
) {
5814 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5817 if (os_strcmp(token
->string
, "infra") != 0) {
5818 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5820 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5824 discovery
= json_get_member(root
, "discovery");
5825 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5826 dpp_auth_fail(auth
, "No discovery object in JSON");
5830 token
= json_get_member(discovery
, "ssid");
5831 if (!token
|| token
->type
!= JSON_STRING
) {
5832 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5835 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5836 token
->string
, os_strlen(token
->string
));
5837 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5838 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5841 auth
->ssid_len
= os_strlen(token
->string
);
5842 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5844 cred
= json_get_member(root
, "cred");
5845 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5846 dpp_auth_fail(auth
, "No cred object in JSON");
5850 token
= json_get_member(cred
, "akm");
5851 if (!token
|| token
->type
!= JSON_STRING
) {
5852 dpp_auth_fail(auth
, "No cred::akm string value found");
5855 auth
->akm
= dpp_akm_from_str(token
->string
);
5857 if (dpp_akm_legacy(auth
->akm
)) {
5858 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5860 } else if (dpp_akm_dpp(auth
->akm
)) {
5861 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5864 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5866 dpp_auth_fail(auth
, "Unsupported akm");
5870 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5878 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5879 const struct wpabuf
*resp
)
5881 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5882 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5885 u8
*unwrapped
= NULL
;
5886 size_t unwrapped_len
= 0;
5889 auth
->conf_resp_status
= 255;
5891 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5892 dpp_auth_fail(auth
, "Invalid attribute in config response");
5896 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5897 DPP_ATTR_WRAPPED_DATA
,
5899 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5901 "Missing or invalid required Wrapped Data attribute");
5905 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5906 wrapped_data
, wrapped_data_len
);
5907 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5908 unwrapped
= os_malloc(unwrapped_len
);
5912 addr
[0] = wpabuf_head(resp
);
5913 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5914 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5916 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5917 wrapped_data
, wrapped_data_len
,
5918 1, addr
, len
, unwrapped
) < 0) {
5919 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5922 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5923 unwrapped
, unwrapped_len
);
5925 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5926 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5930 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5931 DPP_ATTR_ENROLLEE_NONCE
,
5933 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5935 "Missing or invalid Enrollee Nonce attribute");
5938 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5939 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5940 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5944 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5945 DPP_ATTR_STATUS
, &status_len
);
5946 if (!status
|| status_len
< 1) {
5948 "Missing or invalid required DPP Status attribute");
5951 auth
->conf_resp_status
= status
[0];
5952 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5953 if (status
[0] != DPP_STATUS_OK
) {
5954 dpp_auth_fail(auth
, "Configurator rejected configuration");
5958 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5959 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5962 "Missing required Configuration Object attribute");
5965 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5966 conf_obj
, conf_obj_len
);
5967 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5979 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
5981 const u8
*attr_start
, size_t attr_len
)
5983 const u8
*wrapped_data
, *status
, *e_nonce
;
5984 u16 wrapped_data_len
, status_len
, e_nonce_len
;
5987 u8
*unwrapped
= NULL
;
5988 size_t unwrapped_len
= 0;
5989 enum dpp_status_error ret
= 256;
5991 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5993 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5995 "Missing or invalid required Wrapped Data attribute");
5998 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
5999 wrapped_data
, wrapped_data_len
);
6001 attr_len
= wrapped_data
- 4 - attr_start
;
6004 len
[0] = DPP_HDR_LEN
;
6005 addr
[1] = attr_start
;
6007 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6008 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6009 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6010 wrapped_data
, wrapped_data_len
);
6011 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6012 unwrapped
= os_malloc(unwrapped_len
);
6015 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6016 wrapped_data
, wrapped_data_len
,
6017 2, addr
, len
, unwrapped
) < 0) {
6018 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6021 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6022 unwrapped
, unwrapped_len
);
6024 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6025 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6029 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6030 DPP_ATTR_ENROLLEE_NONCE
,
6032 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6034 "Missing or invalid Enrollee Nonce attribute");
6037 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6038 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6039 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6040 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
6041 auth
->e_nonce
, e_nonce_len
);
6045 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
6047 if (!status
|| status_len
< 1) {
6049 "Missing or invalid required DPP Status attribute");
6052 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
6056 bin_clear_free(unwrapped
, unwrapped_len
);
6059 #endif /* CONFIG_DPP2 */
6062 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
6063 enum dpp_status_error status
)
6065 struct wpabuf
*msg
, *clear
;
6066 size_t nonce_len
, clear_len
, attr_len
;
6071 nonce_len
= auth
->curve
->nonce_len
;
6072 clear_len
= 5 + 4 + nonce_len
;
6073 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6074 clear
= wpabuf_alloc(clear_len
);
6075 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
6080 dpp_build_attr_status(clear
, status
);
6083 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
6084 wpabuf_put_le16(clear
, nonce_len
);
6085 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
6087 /* OUI, OUI type, Crypto Suite, DPP frame type */
6088 addr
[0] = wpabuf_head_u8(msg
) + 2;
6089 len
[0] = 3 + 1 + 1 + 1;
6090 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6092 /* Attributes before Wrapped Data (none) */
6093 addr
[1] = wpabuf_put(msg
, 0);
6095 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6098 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6099 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6100 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6102 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6103 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
6104 wpabuf_head(clear
), wpabuf_len(clear
),
6105 2, addr
, len
, wrapped
) < 0)
6108 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
6118 void dpp_configurator_free(struct dpp_configurator
*conf
)
6122 EVP_PKEY_free(conf
->csign
);
6128 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
6132 int key_len
, ret
= -1;
6133 unsigned char *key
= NULL
;
6138 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
6142 key_len
= i2d_ECPrivateKey(eckey
, &key
);
6144 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
6152 struct dpp_configurator
*
6153 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
6156 struct dpp_configurator
*conf
;
6157 struct wpabuf
*csign_pub
= NULL
;
6158 u8 kid_hash
[SHA256_MAC_LEN
];
6162 conf
= os_zalloc(sizeof(*conf
));
6167 conf
->curve
= &dpp_curves
[0];
6169 conf
->curve
= dpp_get_curve_name(curve
);
6171 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6178 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
6181 conf
->csign
= dpp_gen_keypair(conf
->curve
);
6186 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
6188 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
6192 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6193 addr
[0] = wpabuf_head(csign_pub
);
6194 len
[0] = wpabuf_len(csign_pub
);
6195 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
6196 wpa_printf(MSG_DEBUG
,
6197 "DPP: Failed to derive kid for C-sign-key");
6201 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
6206 wpabuf_free(csign_pub
);
6209 dpp_configurator_free(conf
);
6215 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
6216 const char *curve
, int ap
)
6218 struct wpabuf
*conf_obj
;
6222 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
6227 auth
->curve
= &dpp_curves
[0];
6229 auth
->curve
= dpp_get_curve_name(curve
);
6231 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6236 wpa_printf(MSG_DEBUG
,
6237 "DPP: Building own configuration/connector with curve %s",
6240 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
6241 if (!auth
->own_protocol_key
)
6243 dpp_copy_netaccesskey(auth
);
6244 auth
->peer_protocol_key
= auth
->own_protocol_key
;
6245 dpp_copy_csign(auth
, auth
->conf
->csign
);
6247 conf_obj
= dpp_build_conf_obj(auth
, ap
);
6250 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
6251 wpabuf_len(conf_obj
));
6253 wpabuf_free(conf_obj
);
6254 auth
->peer_protocol_key
= NULL
;
6259 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
6261 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
6262 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
6266 static int dpp_connector_compatible_group(struct json_token
*root
,
6267 const char *group_id
,
6268 const char *net_role
)
6270 struct json_token
*groups
, *token
;
6272 groups
= json_get_member(root
, "groups");
6273 if (!groups
|| groups
->type
!= JSON_ARRAY
)
6276 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6277 struct json_token
*id
, *role
;
6279 id
= json_get_member(token
, "groupId");
6280 if (!id
|| id
->type
!= JSON_STRING
)
6283 role
= json_get_member(token
, "netRole");
6284 if (!role
|| role
->type
!= JSON_STRING
)
6287 if (os_strcmp(id
->string
, "*") != 0 &&
6288 os_strcmp(group_id
, "*") != 0 &&
6289 os_strcmp(id
->string
, group_id
) != 0)
6292 if (dpp_compatible_netrole(role
->string
, net_role
))
6300 static int dpp_connector_match_groups(struct json_token
*own_root
,
6301 struct json_token
*peer_root
)
6303 struct json_token
*groups
, *token
;
6305 groups
= json_get_member(peer_root
, "groups");
6306 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6307 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
6311 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6312 struct json_token
*id
, *role
;
6314 id
= json_get_member(token
, "groupId");
6315 if (!id
|| id
->type
!= JSON_STRING
) {
6316 wpa_printf(MSG_DEBUG
,
6317 "DPP: Missing peer groupId string");
6321 role
= json_get_member(token
, "netRole");
6322 if (!role
|| role
->type
!= JSON_STRING
) {
6323 wpa_printf(MSG_DEBUG
,
6324 "DPP: Missing peer groups::netRole string");
6327 wpa_printf(MSG_DEBUG
,
6328 "DPP: peer connector group: groupId='%s' netRole='%s'",
6329 id
->string
, role
->string
);
6330 if (dpp_connector_compatible_group(own_root
, id
->string
,
6332 wpa_printf(MSG_DEBUG
,
6333 "DPP: Compatible group/netRole in own connector");
6342 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
6343 unsigned int hash_len
)
6345 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6346 const char *info
= "DPP PMK";
6349 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6351 /* HKDF-Extract(<>, N.x) */
6352 os_memset(salt
, 0, hash_len
);
6353 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
6355 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6358 /* HKDF-Expand(PRK, info, L) */
6359 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
6360 os_memset(prk
, 0, hash_len
);
6364 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6370 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
6371 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
6373 struct wpabuf
*nkx
, *pkx
;
6377 u8 hash
[SHA256_MAC_LEN
];
6379 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6380 nkx
= dpp_get_pubkey_point(own_key
, 0);
6381 pkx
= dpp_get_pubkey_point(peer_key
, 0);
6384 addr
[0] = wpabuf_head(nkx
);
6385 len
[0] = wpabuf_len(nkx
) / 2;
6386 addr
[1] = wpabuf_head(pkx
);
6387 len
[1] = wpabuf_len(pkx
) / 2;
6388 if (len
[0] != len
[1])
6390 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
6391 addr
[0] = wpabuf_head(pkx
);
6392 addr
[1] = wpabuf_head(nkx
);
6394 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
6395 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
6396 res
= sha256_vector(2, addr
, len
, hash
);
6399 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
6400 os_memcpy(pmkid
, hash
, PMKID_LEN
);
6401 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
6410 enum dpp_status_error
6411 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
6412 const u8
*net_access_key
, size_t net_access_key_len
,
6413 const u8
*csign_key
, size_t csign_key_len
,
6414 const u8
*peer_connector
, size_t peer_connector_len
,
6417 struct json_token
*root
= NULL
, *netkey
, *token
;
6418 struct json_token
*own_root
= NULL
;
6419 enum dpp_status_error ret
= 255, res
;
6420 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
6421 struct wpabuf
*own_key_pub
= NULL
;
6422 const struct dpp_curve_params
*curve
, *own_curve
;
6423 struct dpp_signed_connector_info info
;
6424 const unsigned char *p
;
6425 EVP_PKEY
*csign
= NULL
;
6426 char *signed_connector
= NULL
;
6427 const char *pos
, *end
;
6428 unsigned char *own_conn
= NULL
;
6429 size_t own_conn_len
;
6430 EVP_PKEY_CTX
*ctx
= NULL
;
6432 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
6434 os_memset(intro
, 0, sizeof(*intro
));
6435 os_memset(&info
, 0, sizeof(info
));
6440 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
6442 wpa_printf(MSG_ERROR
,
6443 "DPP: Failed to parse local C-sign-key information");
6447 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
6448 net_access_key_len
);
6450 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
6454 pos
= os_strchr(own_connector
, '.');
6456 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
6460 end
= os_strchr(pos
, '.');
6462 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
6465 own_conn
= base64_url_decode((const unsigned char *) pos
,
6466 end
- pos
, &own_conn_len
);
6468 wpa_printf(MSG_DEBUG
,
6469 "DPP: Failed to base64url decode own signedConnector JWS Payload");
6473 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
6475 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
6479 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
6480 peer_connector
, peer_connector_len
);
6481 signed_connector
= os_malloc(peer_connector_len
+ 1);
6482 if (!signed_connector
)
6484 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
6485 signed_connector
[peer_connector_len
] = '\0';
6487 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
6488 if (res
!= DPP_STATUS_OK
) {
6493 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
6495 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6496 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6500 if (!dpp_connector_match_groups(own_root
, root
)) {
6501 wpa_printf(MSG_DEBUG
,
6502 "DPP: Peer connector does not include compatible group netrole with own connector");
6503 ret
= DPP_STATUS_NO_MATCH
;
6507 token
= json_get_member(root
, "expiry");
6508 if (!token
|| token
->type
!= JSON_STRING
) {
6509 wpa_printf(MSG_DEBUG
,
6510 "DPP: No expiry string found - connector does not expire");
6512 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6513 if (dpp_key_expired(token
->string
, expiry
)) {
6514 wpa_printf(MSG_DEBUG
,
6515 "DPP: Connector (netAccessKey) has expired");
6516 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6521 netkey
= json_get_member(root
, "netAccessKey");
6522 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6523 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6524 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6528 peer_key
= dpp_parse_jwk(netkey
, &curve
);
6530 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6533 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
6535 if (own_curve
!= curve
) {
6536 wpa_printf(MSG_DEBUG
,
6537 "DPP: Mismatching netAccessKey curves (%s != %s)",
6538 own_curve
->name
, curve
->name
);
6539 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6543 /* ECDH: N = nk * PK */
6544 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
6546 EVP_PKEY_derive_init(ctx
) != 1 ||
6547 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
6548 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
6549 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6550 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
6551 wpa_printf(MSG_ERROR
,
6552 "DPP: Failed to derive ECDH shared secret: %s",
6553 ERR_error_string(ERR_get_error(), NULL
));
6557 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
6560 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6561 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
6562 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
6565 intro
->pmk_len
= curve
->hash_len
;
6567 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6568 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
6569 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
6573 ret
= DPP_STATUS_OK
;
6575 if (ret
!= DPP_STATUS_OK
)
6576 os_memset(intro
, 0, sizeof(*intro
));
6577 os_memset(Nx
, 0, sizeof(Nx
));
6578 EVP_PKEY_CTX_free(ctx
);
6580 os_free(signed_connector
);
6581 os_free(info
.payload
);
6582 EVP_PKEY_free(own_key
);
6583 wpabuf_free(own_key_pub
);
6584 EVP_PKEY_free(peer_key
);
6585 EVP_PKEY_free(csign
);
6587 json_free(own_root
);
6592 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
6596 size_t len
= curve
->prime_len
;
6600 switch (curve
->ike_group
) {
6602 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
6603 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
6606 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
6607 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
6610 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
6611 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
6614 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
6615 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6618 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6619 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6622 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6623 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6629 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6632 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
6633 EC_GROUP_free(group
);
6638 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6639 const u8
*mac_init
, const char *code
,
6640 const char *identifier
, BN_CTX
*bnctx
,
6641 EC_GROUP
**ret_group
)
6643 u8 hash
[DPP_MAX_HASH_LEN
];
6646 unsigned int num_elem
= 0;
6647 EC_POINT
*Qi
= NULL
;
6648 EVP_PKEY
*Pi
= NULL
;
6649 EC_KEY
*Pi_ec
= NULL
;
6650 const EC_POINT
*Pi_point
;
6651 BIGNUM
*hash_bn
= NULL
;
6652 const EC_GROUP
*group
= NULL
;
6653 EC_GROUP
*group2
= NULL
;
6655 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6657 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6658 addr
[num_elem
] = mac_init
;
6659 len
[num_elem
] = ETH_ALEN
;
6662 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6664 addr
[num_elem
] = (const u8
*) identifier
;
6665 len
[num_elem
] = os_strlen(identifier
);
6668 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6669 addr
[num_elem
] = (const u8
*) code
;
6670 len
[num_elem
] = os_strlen(code
);
6672 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6674 wpa_hexdump_key(MSG_DEBUG
,
6675 "DPP: H(MAC-Initiator | [identifier |] code)",
6676 hash
, curve
->hash_len
);
6677 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6680 dpp_debug_print_key("DPP: Pi", Pi
);
6681 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6684 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6686 group
= EC_KEY_get0_group(Pi_ec
);
6689 group2
= EC_GROUP_dup(group
);
6692 Qi
= EC_POINT_new(group2
);
6694 EC_GROUP_free(group2
);
6697 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6699 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6701 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6702 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6705 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6709 BN_clear_free(hash_bn
);
6710 if (ret_group
&& Qi
)
6711 *ret_group
= group2
;
6713 EC_GROUP_free(group2
);
6722 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6723 const u8
*mac_resp
, const char *code
,
6724 const char *identifier
, BN_CTX
*bnctx
,
6725 EC_GROUP
**ret_group
)
6727 u8 hash
[DPP_MAX_HASH_LEN
];
6730 unsigned int num_elem
= 0;
6731 EC_POINT
*Qr
= NULL
;
6732 EVP_PKEY
*Pr
= NULL
;
6733 EC_KEY
*Pr_ec
= NULL
;
6734 const EC_POINT
*Pr_point
;
6735 BIGNUM
*hash_bn
= NULL
;
6736 const EC_GROUP
*group
= NULL
;
6737 EC_GROUP
*group2
= NULL
;
6739 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6741 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6742 addr
[num_elem
] = mac_resp
;
6743 len
[num_elem
] = ETH_ALEN
;
6746 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6748 addr
[num_elem
] = (const u8
*) identifier
;
6749 len
[num_elem
] = os_strlen(identifier
);
6752 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6753 addr
[num_elem
] = (const u8
*) code
;
6754 len
[num_elem
] = os_strlen(code
);
6756 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6758 wpa_hexdump_key(MSG_DEBUG
,
6759 "DPP: H(MAC-Responder | [identifier |] code)",
6760 hash
, curve
->hash_len
);
6761 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6764 dpp_debug_print_key("DPP: Pr", Pr
);
6765 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6768 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6770 group
= EC_KEY_get0_group(Pr_ec
);
6773 group2
= EC_GROUP_dup(group
);
6776 Qr
= EC_POINT_new(group2
);
6778 EC_GROUP_free(group2
);
6781 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6783 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6785 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6786 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6789 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6793 BN_clear_free(hash_bn
);
6794 if (ret_group
&& Qr
)
6795 *ret_group
= group2
;
6797 EC_GROUP_free(group2
);
6806 #ifdef CONFIG_TESTING_OPTIONS
6807 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6808 const struct dpp_curve_params
*curve
)
6816 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6821 point
= EC_POINT_new(group
);
6824 if (!ctx
|| !point
|| !x
|| !y
)
6827 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6830 /* Generate a random y coordinate that results in a point that is not
6833 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6836 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6838 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6839 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6840 * return an error from EC_POINT_set_affine_coordinates_GFp()
6841 * when the point is not on the curve. */
6843 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6845 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6848 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6852 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6853 curve
->prime_len
) < 0 ||
6854 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6855 curve
->prime_len
) < 0)
6861 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6864 EC_POINT_free(point
);
6866 EC_GROUP_free(group
);
6870 #endif /* CONFIG_TESTING_OPTIONS */
6873 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6875 EC_KEY
*X_ec
= NULL
;
6876 const EC_POINT
*X_point
;
6877 BN_CTX
*bnctx
= NULL
;
6878 EC_GROUP
*group
= NULL
;
6879 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6880 struct wpabuf
*M_buf
= NULL
;
6881 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6882 struct wpabuf
*msg
= NULL
;
6884 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6886 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6888 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6889 bnctx
= BN_CTX_new();
6892 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6893 pkex
->identifier
, bnctx
, &group
);
6897 /* Generate a random ephemeral keypair x/X */
6898 #ifdef CONFIG_TESTING_OPTIONS
6899 if (dpp_pkex_ephemeral_key_override_len
) {
6900 const struct dpp_curve_params
*tmp_curve
;
6902 wpa_printf(MSG_INFO
,
6903 "DPP: TESTING - override ephemeral key x/X");
6904 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6905 dpp_pkex_ephemeral_key_override
,
6906 dpp_pkex_ephemeral_key_override_len
);
6908 pkex
->x
= dpp_gen_keypair(curve
);
6910 #else /* CONFIG_TESTING_OPTIONS */
6911 pkex
->x
= dpp_gen_keypair(curve
);
6912 #endif /* CONFIG_TESTING_OPTIONS */
6917 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6920 X_point
= EC_KEY_get0_public_key(X_ec
);
6923 dpp_debug_print_point("DPP: X", group
, X_point
);
6924 M
= EC_POINT_new(group
);
6927 if (!M
|| !Mx
|| !My
||
6928 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6929 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6931 dpp_debug_print_point("DPP: M", group
, M
);
6933 /* Initiator -> Responder: group, [identifier,] M */
6935 if (pkex
->identifier
)
6936 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6937 attr_len
+= 4 + 2 * curve
->prime_len
;
6938 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6942 #ifdef CONFIG_TESTING_OPTIONS
6943 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6944 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6945 goto skip_finite_cyclic_group
;
6947 #endif /* CONFIG_TESTING_OPTIONS */
6949 /* Finite Cyclic Group attribute */
6950 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6951 wpabuf_put_le16(msg
, 2);
6952 wpabuf_put_le16(msg
, curve
->ike_group
);
6954 #ifdef CONFIG_TESTING_OPTIONS
6955 skip_finite_cyclic_group
:
6956 #endif /* CONFIG_TESTING_OPTIONS */
6958 /* Code Identifier attribute */
6959 if (pkex
->identifier
) {
6960 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6961 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6962 wpabuf_put_str(msg
, pkex
->identifier
);
6965 #ifdef CONFIG_TESTING_OPTIONS
6966 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6967 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6970 #endif /* CONFIG_TESTING_OPTIONS */
6972 /* M in Encrypted Key attribute */
6973 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6974 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6976 #ifdef CONFIG_TESTING_OPTIONS
6977 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6978 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6979 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6983 #endif /* CONFIG_TESTING_OPTIONS */
6985 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6986 curve
->prime_len
) < 0 ||
6987 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6988 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6989 curve
->prime_len
) < 0)
7000 EC_GROUP_free(group
);
7003 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
7010 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
7012 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
7016 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
7018 const char *identifier
,
7021 struct dpp_pkex
*pkex
;
7023 #ifdef CONFIG_TESTING_OPTIONS
7024 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7025 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7026 MAC2STR(dpp_pkex_own_mac_override
));
7027 own_mac
= dpp_pkex_own_mac_override
;
7029 #endif /* CONFIG_TESTING_OPTIONS */
7031 pkex
= os_zalloc(sizeof(*pkex
));
7034 pkex
->msg_ctx
= msg_ctx
;
7035 pkex
->initiator
= 1;
7037 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7039 pkex
->identifier
= os_strdup(identifier
);
7040 if (!pkex
->identifier
)
7043 pkex
->code
= os_strdup(code
);
7046 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
7047 if (!pkex
->exchange_req
)
7051 dpp_pkex_free(pkex
);
7056 static struct wpabuf
*
7057 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
7058 enum dpp_status_error status
,
7059 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
7061 struct wpabuf
*msg
= NULL
;
7063 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7065 /* Initiator -> Responder: DPP Status, [identifier,] N */
7067 if (pkex
->identifier
)
7068 attr_len
+= 4 + os_strlen(pkex
->identifier
);
7069 attr_len
+= 4 + 2 * curve
->prime_len
;
7070 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
7074 #ifdef CONFIG_TESTING_OPTIONS
7075 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
7076 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
7080 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
7081 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
7084 #endif /* CONFIG_TESTING_OPTIONS */
7087 dpp_build_attr_status(msg
, status
);
7089 #ifdef CONFIG_TESTING_OPTIONS
7091 #endif /* CONFIG_TESTING_OPTIONS */
7093 /* Code Identifier attribute */
7094 if (pkex
->identifier
) {
7095 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
7096 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
7097 wpabuf_put_str(msg
, pkex
->identifier
);
7100 if (status
!= DPP_STATUS_OK
)
7101 goto skip_encrypted_key
;
7103 #ifdef CONFIG_TESTING_OPTIONS
7104 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7105 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
7106 goto skip_encrypted_key
;
7108 #endif /* CONFIG_TESTING_OPTIONS */
7110 /* N in Encrypted Key attribute */
7111 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
7112 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7114 #ifdef CONFIG_TESTING_OPTIONS
7115 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7116 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7117 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7119 goto skip_encrypted_key
;
7121 #endif /* CONFIG_TESTING_OPTIONS */
7123 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
7124 curve
->prime_len
) < 0 ||
7125 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
7126 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
7127 curve
->prime_len
) < 0)
7131 if (status
== DPP_STATUS_BAD_GROUP
) {
7132 /* Finite Cyclic Group attribute */
7133 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7134 wpabuf_put_le16(msg
, 2);
7135 wpabuf_put_le16(msg
, curve
->ike_group
);
7145 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
7146 const u8
*Mx
, size_t Mx_len
,
7147 const u8
*Nx
, size_t Nx_len
,
7149 const u8
*Kx
, size_t Kx_len
,
7150 u8
*z
, unsigned int hash_len
)
7152 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7157 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7160 /* HKDF-Extract(<>, IKM=K.x) */
7161 os_memset(salt
, 0, hash_len
);
7162 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
7164 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
7166 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
7167 info
= os_malloc(info_len
);
7171 os_memcpy(pos
, mac_init
, ETH_ALEN
);
7173 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
7175 os_memcpy(pos
, Mx
, Mx_len
);
7177 os_memcpy(pos
, Nx
, Nx_len
);
7179 os_memcpy(pos
, code
, os_strlen(code
));
7181 /* HKDF-Expand(PRK, info, L) */
7183 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7185 else if (hash_len
== 48)
7186 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7188 else if (hash_len
== 64)
7189 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7194 os_memset(prk
, 0, hash_len
);
7198 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
7204 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
7205 const char *identifier
)
7207 if (!attr_id
&& identifier
) {
7208 wpa_printf(MSG_DEBUG
,
7209 "DPP: No PKEX code identifier received, but expected one");
7213 if (attr_id
&& !identifier
) {
7214 wpa_printf(MSG_DEBUG
,
7215 "DPP: PKEX code identifier received, but not expecting one");
7219 if (attr_id
&& identifier
&&
7220 (os_strlen(identifier
) != attr_id_len
||
7221 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
7222 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
7230 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
7231 struct dpp_bootstrap_info
*bi
,
7234 const char *identifier
,
7236 const u8
*buf
, size_t len
)
7238 const u8
*attr_group
, *attr_id
, *attr_key
;
7239 u16 attr_group_len
, attr_id_len
, attr_key_len
;
7240 const struct dpp_curve_params
*curve
= bi
->curve
;
7242 struct dpp_pkex
*pkex
= NULL
;
7243 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
7244 BN_CTX
*bnctx
= NULL
;
7245 EC_GROUP
*group
= NULL
;
7246 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7247 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
7248 const EC_POINT
*Y_point
;
7249 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7250 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7253 EVP_PKEY_CTX
*ctx
= NULL
;
7255 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
7256 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7257 "PKEX counter t limit reached - ignore message");
7261 #ifdef CONFIG_TESTING_OPTIONS
7262 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7263 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7264 MAC2STR(dpp_pkex_peer_mac_override
));
7265 peer_mac
= dpp_pkex_peer_mac_override
;
7267 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7268 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7269 MAC2STR(dpp_pkex_own_mac_override
));
7270 own_mac
= dpp_pkex_own_mac_override
;
7272 #endif /* CONFIG_TESTING_OPTIONS */
7275 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
7277 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
7280 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
7282 if (!attr_group
|| attr_group_len
!= 2) {
7283 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7284 "Missing or invalid Finite Cyclic Group attribute");
7287 ike_group
= WPA_GET_LE16(attr_group
);
7288 if (ike_group
!= curve
->ike_group
) {
7289 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7290 "Mismatching PKEX curve: peer=%u own=%u",
7291 ike_group
, curve
->ike_group
);
7292 pkex
= os_zalloc(sizeof(*pkex
));
7297 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
7298 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
7299 if (!pkex
->exchange_resp
)
7304 /* M in Encrypted Key attribute */
7305 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
7307 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
7308 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
7309 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7310 "Missing Encrypted Key attribute");
7314 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7315 bnctx
= BN_CTX_new();
7318 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
7324 X
= EC_POINT_new(group
);
7325 M
= EC_POINT_new(group
);
7326 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7327 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7328 if (!X
|| !M
|| !Mx
|| !My
||
7329 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
7330 EC_POINT_is_at_infinity(group
, M
) ||
7331 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
7332 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
7333 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
7334 EC_POINT_is_at_infinity(group
, X
) ||
7335 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
7336 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7337 "Invalid Encrypted Key value");
7341 dpp_debug_print_point("DPP: M", group
, M
);
7342 dpp_debug_print_point("DPP: X'", group
, X
);
7344 pkex
= os_zalloc(sizeof(*pkex
));
7347 pkex
->t
= bi
->pkex_t
;
7348 pkex
->msg_ctx
= msg_ctx
;
7350 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7351 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7353 pkex
->identifier
= os_strdup(identifier
);
7354 if (!pkex
->identifier
)
7357 pkex
->code
= os_strdup(code
);
7361 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
7363 X_ec
= EC_KEY_new();
7365 EC_KEY_set_group(X_ec
, group
) != 1 ||
7366 EC_KEY_set_public_key(X_ec
, X
) != 1)
7368 pkex
->x
= EVP_PKEY_new();
7370 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
7373 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7374 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
7378 /* Generate a random ephemeral keypair y/Y */
7379 #ifdef CONFIG_TESTING_OPTIONS
7380 if (dpp_pkex_ephemeral_key_override_len
) {
7381 const struct dpp_curve_params
*tmp_curve
;
7383 wpa_printf(MSG_INFO
,
7384 "DPP: TESTING - override ephemeral key y/Y");
7385 pkex
->y
= dpp_set_keypair(&tmp_curve
,
7386 dpp_pkex_ephemeral_key_override
,
7387 dpp_pkex_ephemeral_key_override_len
);
7389 pkex
->y
= dpp_gen_keypair(curve
);
7391 #else /* CONFIG_TESTING_OPTIONS */
7392 pkex
->y
= dpp_gen_keypair(curve
);
7393 #endif /* CONFIG_TESTING_OPTIONS */
7398 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
7401 Y_point
= EC_KEY_get0_public_key(Y_ec
);
7404 dpp_debug_print_point("DPP: Y", group
, Y_point
);
7405 N
= EC_POINT_new(group
);
7408 if (!N
|| !Nx
|| !Ny
||
7409 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
7410 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
7412 dpp_debug_print_point("DPP: N", group
, N
);
7414 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
7416 if (!pkex
->exchange_resp
)
7420 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7422 EVP_PKEY_derive_init(ctx
) != 1 ||
7423 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7424 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7425 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7426 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7427 wpa_printf(MSG_ERROR
,
7428 "DPP: Failed to derive ECDH shared secret: %s",
7429 ERR_error_string(ERR_get_error(), NULL
));
7433 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7436 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7438 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
7439 pkex
->Mx
, curve
->prime_len
,
7440 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
7441 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
7442 os_memset(Kx
, 0, Kx_len
);
7446 pkex
->exchange_done
= 1;
7449 EVP_PKEY_CTX_free(ctx
);
7462 EC_GROUP_free(group
);
7465 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
7466 dpp_pkex_free(pkex
);
7472 static struct wpabuf
*
7473 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
7474 const struct wpabuf
*A_pub
, const u8
*u
)
7476 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7477 struct wpabuf
*msg
= NULL
;
7478 size_t clear_len
, attr_len
;
7479 struct wpabuf
*clear
= NULL
;
7485 /* {A, u, [bootstrapping info]}z */
7486 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7487 clear
= wpabuf_alloc(clear_len
);
7488 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7489 #ifdef CONFIG_TESTING_OPTIONS
7490 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
7492 #endif /* CONFIG_TESTING_OPTIONS */
7493 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
7497 #ifdef CONFIG_TESTING_OPTIONS
7498 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7499 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7500 goto skip_bootstrap_key
;
7502 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7503 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7504 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7505 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7506 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7508 goto skip_bootstrap_key
;
7510 #endif /* CONFIG_TESTING_OPTIONS */
7512 /* A in Bootstrap Key attribute */
7513 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7514 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
7515 wpabuf_put_buf(clear
, A_pub
);
7517 #ifdef CONFIG_TESTING_OPTIONS
7519 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
7520 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
7521 goto skip_i_auth_tag
;
7523 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
7524 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
7525 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7526 wpabuf_put_le16(clear
, curve
->hash_len
);
7527 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
7528 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
7529 goto skip_i_auth_tag
;
7531 #endif /* CONFIG_TESTING_OPTIONS */
7533 /* u in I-Auth tag attribute */
7534 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7535 wpabuf_put_le16(clear
, curve
->hash_len
);
7536 wpabuf_put_data(clear
, u
, curve
->hash_len
);
7538 #ifdef CONFIG_TESTING_OPTIONS
7540 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
7541 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7542 goto skip_wrapped_data
;
7544 #endif /* CONFIG_TESTING_OPTIONS */
7546 addr
[0] = wpabuf_head_u8(msg
) + 2;
7547 len
[0] = DPP_HDR_LEN
;
7550 len
[1] = sizeof(octet
);
7551 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7552 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7554 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7555 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7556 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7558 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7559 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7560 wpabuf_head(clear
), wpabuf_len(clear
),
7561 2, addr
, len
, wrapped
) < 0)
7563 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7564 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7566 #ifdef CONFIG_TESTING_OPTIONS
7567 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
7568 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7569 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7572 #endif /* CONFIG_TESTING_OPTIONS */
7585 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
7587 const u8
*buf
, size_t buflen
)
7589 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
7590 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
7591 EC_GROUP
*group
= NULL
;
7592 BN_CTX
*bnctx
= NULL
;
7593 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7594 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7595 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
7596 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7597 EVP_PKEY_CTX
*ctx
= NULL
;
7598 EC_KEY
*Y_ec
= NULL
;
7599 size_t Jx_len
, Kx_len
;
7600 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7603 u8 u
[DPP_MAX_HASH_LEN
];
7606 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7609 #ifdef CONFIG_TESTING_OPTIONS
7610 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
7611 wpa_printf(MSG_INFO
,
7612 "DPP: TESTING - stop at PKEX Exchange Response");
7617 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7618 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7619 MAC2STR(dpp_pkex_peer_mac_override
));
7620 peer_mac
= dpp_pkex_peer_mac_override
;
7622 #endif /* CONFIG_TESTING_OPTIONS */
7624 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7626 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
7628 if (!attr_status
|| attr_status_len
!= 1) {
7629 dpp_pkex_fail(pkex
, "No DPP Status attribute");
7632 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
7634 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
7635 attr_group
= dpp_get_attr(buf
, buflen
,
7636 DPP_ATTR_FINITE_CYCLIC_GROUP
,
7638 if (attr_group
&& attr_group_len
== 2) {
7639 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7640 "Peer indicated mismatching PKEX group - proposed %u",
7641 WPA_GET_LE16(attr_group
));
7646 if (attr_status
[0] != DPP_STATUS_OK
) {
7647 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7652 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7654 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
7655 pkex
->identifier
)) {
7656 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7660 /* N in Encrypted Key attribute */
7661 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7663 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7664 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7668 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7669 bnctx
= BN_CTX_new();
7672 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7673 pkex
->identifier
, bnctx
, &group
);
7678 Y
= EC_POINT_new(group
);
7679 N
= EC_POINT_new(group
);
7680 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7681 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7682 if (!Y
|| !N
|| !Nx
|| !Ny
||
7683 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7684 EC_POINT_is_at_infinity(group
, N
) ||
7685 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7686 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7687 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7688 EC_POINT_is_at_infinity(group
, Y
) ||
7689 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7690 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7694 dpp_debug_print_point("DPP: N", group
, N
);
7695 dpp_debug_print_point("DPP: Y'", group
, Y
);
7697 pkex
->exchange_done
= 1;
7699 /* ECDH: J = a * Y’ */
7700 Y_ec
= EC_KEY_new();
7702 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7703 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7705 pkex
->y
= EVP_PKEY_new();
7707 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7709 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7711 EVP_PKEY_derive_init(ctx
) != 1 ||
7712 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7713 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7714 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7715 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7716 wpa_printf(MSG_ERROR
,
7717 "DPP: Failed to derive ECDH shared secret: %s",
7718 ERR_error_string(ERR_get_error(), NULL
));
7722 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7725 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7726 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7727 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7728 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7729 if (!A_pub
|| !Y_pub
|| !X_pub
)
7731 addr
[0] = pkex
->own_mac
;
7733 addr
[1] = wpabuf_head(A_pub
);
7734 len
[1] = wpabuf_len(A_pub
) / 2;
7735 addr
[2] = wpabuf_head(Y_pub
);
7736 len
[2] = wpabuf_len(Y_pub
) / 2;
7737 addr
[3] = wpabuf_head(X_pub
);
7738 len
[3] = wpabuf_len(X_pub
) / 2;
7739 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7741 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7744 EVP_PKEY_CTX_free(ctx
);
7745 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7747 EVP_PKEY_derive_init(ctx
) != 1 ||
7748 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7749 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7750 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7751 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7752 wpa_printf(MSG_ERROR
,
7753 "DPP: Failed to derive ECDH shared secret: %s",
7754 ERR_error_string(ERR_get_error(), NULL
));
7758 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7761 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7763 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7764 pkex
->Mx
, curve
->prime_len
,
7765 attr_key
/* N.x */, attr_key_len
/ 2,
7766 pkex
->code
, Kx
, Kx_len
,
7767 pkex
->z
, curve
->hash_len
);
7768 os_memset(Kx
, 0, Kx_len
);
7772 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7786 EVP_PKEY_CTX_free(ctx
);
7788 EC_GROUP_free(group
);
7791 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7796 static struct wpabuf
*
7797 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7798 const struct wpabuf
*B_pub
, const u8
*v
)
7800 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7801 struct wpabuf
*msg
= NULL
;
7806 struct wpabuf
*clear
= NULL
;
7807 size_t clear_len
, attr_len
;
7809 /* {B, v [bootstrapping info]}z */
7810 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7811 clear
= wpabuf_alloc(clear_len
);
7812 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7813 #ifdef CONFIG_TESTING_OPTIONS
7814 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7816 #endif /* CONFIG_TESTING_OPTIONS */
7817 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7821 #ifdef CONFIG_TESTING_OPTIONS
7822 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7823 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7824 goto skip_bootstrap_key
;
7826 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7827 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7828 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7829 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7830 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7832 goto skip_bootstrap_key
;
7834 #endif /* CONFIG_TESTING_OPTIONS */
7836 /* B in Bootstrap Key attribute */
7837 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7838 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7839 wpabuf_put_buf(clear
, B_pub
);
7841 #ifdef CONFIG_TESTING_OPTIONS
7843 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7844 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7845 goto skip_r_auth_tag
;
7847 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7848 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7849 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7850 wpabuf_put_le16(clear
, curve
->hash_len
);
7851 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7852 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7853 goto skip_r_auth_tag
;
7855 #endif /* CONFIG_TESTING_OPTIONS */
7857 /* v in R-Auth tag attribute */
7858 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7859 wpabuf_put_le16(clear
, curve
->hash_len
);
7860 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7862 #ifdef CONFIG_TESTING_OPTIONS
7864 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7865 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7866 goto skip_wrapped_data
;
7868 #endif /* CONFIG_TESTING_OPTIONS */
7870 addr
[0] = wpabuf_head_u8(msg
) + 2;
7871 len
[0] = DPP_HDR_LEN
;
7874 len
[1] = sizeof(octet
);
7875 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7876 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7878 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7879 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7880 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7882 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7883 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7884 wpabuf_head(clear
), wpabuf_len(clear
),
7885 2, addr
, len
, wrapped
) < 0)
7887 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7888 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7890 #ifdef CONFIG_TESTING_OPTIONS
7891 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7892 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7893 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7896 #endif /* CONFIG_TESTING_OPTIONS */
7909 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7911 const u8
*buf
, size_t buflen
)
7913 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7914 EVP_PKEY_CTX
*ctx
= NULL
;
7915 size_t Jx_len
, Lx_len
;
7916 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7917 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7918 const u8
*wrapped_data
, *b_key
, *peer_u
;
7919 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7923 u8
*unwrapped
= NULL
;
7924 size_t unwrapped_len
= 0;
7925 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7926 struct wpabuf
*B_pub
= NULL
;
7927 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7929 #ifdef CONFIG_TESTING_OPTIONS
7930 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7931 wpa_printf(MSG_INFO
,
7932 "DPP: TESTING - stop at PKEX CR Request");
7936 #endif /* CONFIG_TESTING_OPTIONS */
7938 if (!pkex
->exchange_done
|| pkex
->failed
||
7939 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7942 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7944 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7946 "Missing or invalid required Wrapped Data attribute");
7950 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7951 wrapped_data
, wrapped_data_len
);
7952 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7953 unwrapped
= os_malloc(unwrapped_len
);
7958 len
[0] = DPP_HDR_LEN
;
7961 len
[1] = sizeof(octet
);
7962 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7963 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7965 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7966 wrapped_data
, wrapped_data_len
,
7967 2, addr
, len
, unwrapped
) < 0) {
7969 "AES-SIV decryption failed - possible PKEX code mismatch");
7974 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7975 unwrapped
, unwrapped_len
);
7977 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7978 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7982 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7984 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7985 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7988 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7990 if (!pkex
->peer_bootstrap_key
) {
7991 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7994 dpp_debug_print_key("DPP: Peer bootstrap public key",
7995 pkex
->peer_bootstrap_key
);
7997 /* ECDH: J' = y * A' */
7998 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
8000 EVP_PKEY_derive_init(ctx
) != 1 ||
8001 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
8002 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
8003 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8004 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
8005 wpa_printf(MSG_ERROR
,
8006 "DPP: Failed to derive ECDH shared secret: %s",
8007 ERR_error_string(ERR_get_error(), NULL
));
8011 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
8014 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
8015 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8016 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8017 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8018 if (!A_pub
|| !Y_pub
|| !X_pub
)
8020 addr
[0] = pkex
->peer_mac
;
8022 addr
[1] = wpabuf_head(A_pub
);
8023 len
[1] = wpabuf_len(A_pub
) / 2;
8024 addr
[2] = wpabuf_head(Y_pub
);
8025 len
[2] = wpabuf_len(Y_pub
) / 2;
8026 addr
[3] = wpabuf_head(X_pub
);
8027 len
[3] = wpabuf_len(X_pub
) / 2;
8028 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
8031 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
8033 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
8034 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
8035 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
8036 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
8037 u
, curve
->hash_len
);
8038 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
8042 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
8044 /* ECDH: L = b * X' */
8045 EVP_PKEY_CTX_free(ctx
);
8046 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
8048 EVP_PKEY_derive_init(ctx
) != 1 ||
8049 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
8050 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
8051 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8052 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
8053 wpa_printf(MSG_ERROR
,
8054 "DPP: Failed to derive ECDH shared secret: %s",
8055 ERR_error_string(ERR_get_error(), NULL
));
8059 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8062 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8063 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
8066 addr
[0] = pkex
->own_mac
;
8068 addr
[1] = wpabuf_head(B_pub
);
8069 len
[1] = wpabuf_len(B_pub
) / 2;
8070 addr
[2] = wpabuf_head(X_pub
);
8071 len
[2] = wpabuf_len(X_pub
) / 2;
8072 addr
[3] = wpabuf_head(Y_pub
);
8073 len
[3] = wpabuf_len(Y_pub
) / 2;
8074 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8076 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
8078 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
8083 EVP_PKEY_CTX_free(ctx
);
8091 wpa_printf(MSG_DEBUG
,
8092 "DPP: PKEX Commit-Reveal Request processing failed");
8097 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
8098 const u8
*buf
, size_t buflen
)
8100 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8101 const u8
*wrapped_data
, *b_key
, *peer_v
;
8102 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
8106 u8
*unwrapped
= NULL
;
8107 size_t unwrapped_len
= 0;
8109 u8 v
[DPP_MAX_HASH_LEN
];
8111 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
8112 EVP_PKEY_CTX
*ctx
= NULL
;
8113 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8115 #ifdef CONFIG_TESTING_OPTIONS
8116 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
8117 wpa_printf(MSG_INFO
,
8118 "DPP: TESTING - stop at PKEX CR Response");
8122 #endif /* CONFIG_TESTING_OPTIONS */
8124 if (!pkex
->exchange_done
|| pkex
->failed
||
8125 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8128 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8130 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8132 "Missing or invalid required Wrapped Data attribute");
8136 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8137 wrapped_data
, wrapped_data_len
);
8138 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8139 unwrapped
= os_malloc(unwrapped_len
);
8144 len
[0] = DPP_HDR_LEN
;
8147 len
[1] = sizeof(octet
);
8148 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8149 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8151 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8152 wrapped_data
, wrapped_data_len
,
8153 2, addr
, len
, unwrapped
) < 0) {
8155 "AES-SIV decryption failed - possible PKEX code mismatch");
8159 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8160 unwrapped
, unwrapped_len
);
8162 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8163 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8167 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8169 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8170 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8173 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8175 if (!pkex
->peer_bootstrap_key
) {
8176 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8179 dpp_debug_print_key("DPP: Peer bootstrap public key",
8180 pkex
->peer_bootstrap_key
);
8182 /* ECDH: L' = x * B' */
8183 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
8185 EVP_PKEY_derive_init(ctx
) != 1 ||
8186 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
8187 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
8188 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8189 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
8190 wpa_printf(MSG_ERROR
,
8191 "DPP: Failed to derive ECDH shared secret: %s",
8192 ERR_error_string(ERR_get_error(), NULL
));
8196 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8199 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8200 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8201 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8202 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8203 if (!B_pub
|| !X_pub
|| !Y_pub
)
8205 addr
[0] = pkex
->peer_mac
;
8207 addr
[1] = wpabuf_head(B_pub
);
8208 len
[1] = wpabuf_len(B_pub
) / 2;
8209 addr
[2] = wpabuf_head(X_pub
);
8210 len
[2] = wpabuf_len(X_pub
) / 2;
8211 addr
[3] = wpabuf_head(Y_pub
);
8212 len
[3] = wpabuf_len(Y_pub
) / 2;
8213 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8216 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
8218 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
8219 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
8220 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
8221 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
8222 v
, curve
->hash_len
);
8223 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
8227 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
8234 EVP_PKEY_CTX_free(ctx
);
8242 void dpp_pkex_free(struct dpp_pkex
*pkex
)
8247 os_free(pkex
->identifier
);
8248 os_free(pkex
->code
);
8249 EVP_PKEY_free(pkex
->x
);
8250 EVP_PKEY_free(pkex
->y
);
8251 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
8252 wpabuf_free(pkex
->exchange_req
);
8253 wpabuf_free(pkex
->exchange_resp
);
8258 #ifdef CONFIG_TESTING_OPTIONS
8259 char * dpp_corrupt_connector_signature(const char *connector
)
8261 char *tmp
, *pos
, *signed3
= NULL
;
8262 unsigned char *signature
= NULL
;
8263 size_t signature_len
= 0, signed3_len
;
8265 tmp
= os_zalloc(os_strlen(connector
) + 5);
8268 os_memcpy(tmp
, connector
, os_strlen(connector
));
8270 pos
= os_strchr(tmp
, '.');
8274 pos
= os_strchr(pos
+ 1, '.');
8279 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
8281 signature
= base64_url_decode((const unsigned char *) pos
,
8282 os_strlen(pos
), &signature_len
);
8283 if (!signature
|| signature_len
== 0)
8285 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
8286 signature
, signature_len
);
8287 signature
[signature_len
- 1] ^= 0x01;
8288 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
8289 signature
, signature_len
);
8290 signed3
= (char *) base64_url_encode(signature
, signature_len
,
8294 os_memcpy(pos
, signed3
, signed3_len
);
8295 pos
[signed3_len
] = '\0';
8296 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
8308 #endif /* CONFIG_TESTING_OPTIONS */
8313 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
8314 size_t net_access_key_len
)
8316 struct wpabuf
*pub
= NULL
;
8318 struct dpp_pfs
*pfs
;
8320 pfs
= os_zalloc(sizeof(*pfs
));
8324 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
8325 net_access_key_len
);
8327 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8330 EVP_PKEY_free(own_key
);
8332 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
8336 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
8337 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
8341 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
8344 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
8345 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
8346 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
8347 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
8348 wpabuf_put_buf(pfs
->ie
, pub
);
8350 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
8361 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
8363 if (peer_ie_len
< 2)
8365 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
8366 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
8370 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
8372 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
8374 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
8377 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
8382 void dpp_pfs_free(struct dpp_pfs
*pfs
)
8386 crypto_ecdh_deinit(pfs
->ecdh
);
8387 wpabuf_free(pfs
->ie
);
8388 wpabuf_clear_free(pfs
->secret
);
8392 #endif /* CONFIG_DPP2 */
8395 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
8397 struct dpp_bootstrap_info
*bi
;
8398 unsigned int max_id
= 0;
8400 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8401 if (bi
->id
> max_id
)
8408 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
8410 struct dpp_bootstrap_info
*bi
, *tmp
;
8416 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
8417 struct dpp_bootstrap_info
, list
) {
8418 if (id
&& bi
->id
!= id
)
8421 dl_list_del(&bi
->list
);
8422 dpp_bootstrap_info_free(bi
);
8426 return 0; /* flush succeeds regardless of entries found */
8427 return found
? 0 : -1;
8431 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
8434 struct dpp_bootstrap_info
*bi
;
8439 bi
= dpp_parse_qr_code(uri
);
8443 bi
->id
= dpp_next_id(dpp
);
8444 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8449 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
8451 char *chan
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
, *curve
= NULL
;
8454 size_t privkey_len
= 0;
8457 struct dpp_bootstrap_info
*bi
;
8462 bi
= os_zalloc(sizeof(*bi
));
8466 if (os_strstr(cmd
, "type=qrcode"))
8467 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
8468 else if (os_strstr(cmd
, "type=pkex"))
8469 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8473 chan
= get_param(cmd
, " chan=");
8474 mac
= get_param(cmd
, " mac=");
8475 info
= get_param(cmd
, " info=");
8476 curve
= get_param(cmd
, " curve=");
8477 key
= get_param(cmd
, " key=");
8480 privkey_len
= os_strlen(key
) / 2;
8481 privkey
= os_malloc(privkey_len
);
8483 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8487 pk
= dpp_keygen(bi
, curve
, privkey
, privkey_len
);
8491 len
= 4; /* "DPP:" */
8493 if (dpp_parse_uri_chan_list(bi
, chan
) < 0)
8495 len
+= 3 + os_strlen(chan
); /* C:...; */
8498 if (dpp_parse_uri_mac(bi
, mac
) < 0)
8500 len
+= 3 + os_strlen(mac
); /* M:...; */
8503 if (dpp_parse_uri_info(bi
, info
) < 0)
8505 len
+= 3 + os_strlen(info
); /* I:...; */
8507 len
+= 4 + os_strlen(pk
);
8508 bi
->uri
= os_malloc(len
+ 1);
8511 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8512 chan
? "C:" : "", chan
? chan
: "", chan
? ";" : "",
8513 mac
? "M:" : "", mac
? mac
: "", mac
? ";" : "",
8514 info
? "I:" : "", info
? info
: "", info
? ";" : "",
8516 bi
->id
= dpp_next_id(dpp
);
8517 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8526 str_clear_free(key
);
8527 bin_clear_free(privkey
, privkey_len
);
8528 dpp_bootstrap_info_free(bi
);
8533 struct dpp_bootstrap_info
*
8534 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
8536 struct dpp_bootstrap_info
*bi
;
8541 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8549 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
8551 unsigned int id_val
;
8553 if (os_strcmp(id
, "*") == 0) {
8561 return dpp_bootstrap_del(dpp
, id_val
);
8565 struct dpp_bootstrap_info
*
8566 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
8569 struct dpp_bootstrap_info
*bi
;
8571 bi
= os_zalloc(sizeof(*bi
));
8574 bi
->id
= dpp_next_id(dpp
);
8575 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8576 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
8579 bi
->curve
= pkex
->own_bi
->curve
;
8580 bi
->pubkey
= pkex
->peer_bootstrap_key
;
8581 pkex
->peer_bootstrap_key
= NULL
;
8582 if (dpp_bootstrap_key_hash(bi
) < 0) {
8583 dpp_bootstrap_info_free(bi
);
8586 dpp_pkex_free(pkex
);
8587 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8592 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
8594 struct dpp_bootstrap_info
*bi
;
8596 bi
= dpp_bootstrap_get_id(dpp
, id
);
8603 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
8604 char *reply
, int reply_size
)
8606 struct dpp_bootstrap_info
*bi
;
8607 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
8609 bi
= dpp_bootstrap_get_id(dpp
, id
);
8612 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
8614 return os_snprintf(reply
, reply_size
, "type=%s\n"
8615 "mac_addr=" MACSTR
"\n"
8620 dpp_bootstrap_type_txt(bi
->type
),
8621 MAC2STR(bi
->mac_addr
),
8622 bi
->info
? bi
->info
: "",
8629 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
8630 const u8
*r_bootstrap
,
8631 struct dpp_bootstrap_info
**own_bi
,
8632 struct dpp_bootstrap_info
**peer_bi
)
8634 struct dpp_bootstrap_info
*bi
;
8641 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8642 if (!*own_bi
&& bi
->own
&&
8643 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
8644 SHA256_MAC_LEN
) == 0) {
8645 wpa_printf(MSG_DEBUG
,
8646 "DPP: Found matching own bootstrapping information");
8650 if (!*peer_bi
&& !bi
->own
&&
8651 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
8652 SHA256_MAC_LEN
) == 0) {
8653 wpa_printf(MSG_DEBUG
,
8654 "DPP: Found matching peer bootstrapping information");
8658 if (*own_bi
&& *peer_bi
)
8665 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
8667 struct dpp_configurator
*conf
;
8668 unsigned int max_id
= 0;
8670 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
8672 if (conf
->id
> max_id
)
8679 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
8684 size_t privkey_len
= 0;
8686 struct dpp_configurator
*conf
= NULL
;
8688 curve
= get_param(cmd
, " curve=");
8689 key
= get_param(cmd
, " key=");
8692 privkey_len
= os_strlen(key
) / 2;
8693 privkey
= os_malloc(privkey_len
);
8695 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8699 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
8703 conf
->id
= dpp_next_configurator_id(dpp
);
8704 dl_list_add(&dpp
->configurator
, &conf
->list
);
8709 str_clear_free(key
);
8710 bin_clear_free(privkey
, privkey_len
);
8711 dpp_configurator_free(conf
);
8716 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
8718 struct dpp_configurator
*conf
, *tmp
;
8724 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
8725 struct dpp_configurator
, list
) {
8726 if (id
&& conf
->id
!= id
)
8729 dl_list_del(&conf
->list
);
8730 dpp_configurator_free(conf
);
8734 return 0; /* flush succeeds regardless of entries found */
8735 return found
? 0 : -1;
8739 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
8741 unsigned int id_val
;
8743 if (os_strcmp(id
, "*") == 0) {
8751 return dpp_configurator_del(dpp
, id_val
);
8755 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
8756 char *buf
, size_t buflen
)
8758 struct dpp_configurator
*conf
;
8760 conf
= dpp_configurator_get_id(dpp
, id
);
8764 return dpp_configurator_get_key(conf
, buf
, buflen
);
8770 static void dpp_connection_free(struct dpp_connection
*conn
)
8772 if (conn
->sock
>= 0) {
8773 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
8775 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
8776 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8779 wpabuf_free(conn
->msg
);
8780 wpabuf_free(conn
->msg_out
);
8781 dpp_auth_deinit(conn
->auth
);
8786 static void dpp_connection_remove(struct dpp_connection
*conn
)
8788 dl_list_del(&conn
->list
);
8789 dpp_connection_free(conn
);
8793 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
8795 struct dpp_connection
*conn
, *tmp
;
8797 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
8799 dpp_connection_remove(conn
);
8803 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
8805 struct dpp_connection
*conn
, *tmp
;
8807 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
8809 dpp_connection_remove(conn
);
8814 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
8816 struct dpp_relay_controller
*ctrl
, *tmp
;
8821 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
8822 struct dpp_relay_controller
, list
) {
8823 dl_list_del(&ctrl
->list
);
8824 dpp_relay_controller_free(ctrl
);
8828 #endif /* CONFIG_DPP2 */
8831 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
8833 struct dpp_global
*dpp
;
8835 dpp
= os_zalloc(sizeof(*dpp
));
8838 dpp
->msg_ctx
= config
->msg_ctx
;
8840 dpp
->cb_ctx
= config
->cb_ctx
;
8841 dpp
->process_conf_obj
= config
->process_conf_obj
;
8842 #endif /* CONFIG_DPP2 */
8844 dl_list_init(&dpp
->bootstrap
);
8845 dl_list_init(&dpp
->configurator
);
8847 dl_list_init(&dpp
->controllers
);
8848 dl_list_init(&dpp
->tcp_init
);
8849 #endif /* CONFIG_DPP2 */
8855 void dpp_global_clear(struct dpp_global
*dpp
)
8860 dpp_bootstrap_del(dpp
, 0);
8861 dpp_configurator_del(dpp
, 0);
8863 dpp_tcp_init_flush(dpp
);
8864 dpp_relay_flush_controllers(dpp
);
8865 dpp_controller_stop(dpp
);
8866 #endif /* CONFIG_DPP2 */
8870 void dpp_global_deinit(struct dpp_global
*dpp
)
8872 dpp_global_clear(dpp
);
8879 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
8880 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
8881 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
8885 int dpp_relay_add_controller(struct dpp_global
*dpp
,
8886 struct dpp_relay_config
*config
)
8888 struct dpp_relay_controller
*ctrl
;
8893 ctrl
= os_zalloc(sizeof(*ctrl
));
8896 dl_list_init(&ctrl
->conn
);
8898 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
8899 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
8900 ctrl
->cb_ctx
= config
->cb_ctx
;
8901 ctrl
->tx
= config
->tx
;
8902 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
8903 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
8908 static struct dpp_relay_controller
*
8909 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
8911 struct dpp_relay_controller
*ctrl
;
8916 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
8918 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
8926 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
8928 struct dpp_authentication
*auth
= conn
->auth
;
8930 if (auth
->peer_version
>= 2 &&
8931 auth
->conf_resp_status
== DPP_STATUS_OK
) {
8932 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
8933 auth
->waiting_conf_result
= 1;
8937 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
8938 dpp_connection_remove(conn
);
8942 static int dpp_tcp_send(struct dpp_connection
*conn
)
8946 if (!conn
->msg_out
) {
8947 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8948 conn
->write_eloop
= 0;
8951 res
= send(conn
->sock
,
8952 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
8953 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
8955 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
8957 dpp_connection_remove(conn
);
8961 conn
->msg_out_pos
+= res
;
8962 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
8963 wpa_printf(MSG_DEBUG
,
8964 "DPP: %u/%u bytes of message sent to Controller",
8965 (unsigned int) conn
->msg_out_pos
,
8966 (unsigned int) wpabuf_len(conn
->msg_out
));
8967 if (!conn
->write_eloop
&&
8968 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
8969 dpp_conn_tx_ready
, conn
, NULL
) == 0)
8970 conn
->write_eloop
= 1;
8974 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
8975 wpabuf_free(conn
->msg_out
);
8976 conn
->msg_out
= NULL
;
8977 conn
->msg_out_pos
= 0;
8978 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8979 conn
->write_eloop
= 0;
8980 if (!conn
->read_eloop
&&
8981 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
8982 dpp_controller_rx
, conn
, NULL
) == 0)
8983 conn
->read_eloop
= 1;
8984 if (conn
->on_tcp_tx_complete_remove
) {
8985 dpp_connection_remove(conn
);
8986 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
8988 dpp_controller_gas_done(conn
);
8989 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
8990 conn
->on_tcp_tx_complete_auth_ok
= 0;
8991 dpp_controller_auth_success(conn
, 1);
8998 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
9000 struct dpp_authentication
*auth
= conn
->auth
;
9003 int netrole_ap
= 0; /* TODO: make this configurable */
9005 os_snprintf(json
, sizeof(json
),
9006 "{\"name\":\"Test\","
9007 "\"wi-fi_tech\":\"infra\","
9008 "\"netRole\":\"%s\"}",
9009 netrole_ap
? "ap" : "sta");
9010 #ifdef CONFIG_TESTING_OPTIONS
9011 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
9012 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
9013 json
[29] = 'k'; /* replace "infra" with "knfra" */
9015 #endif /* CONFIG_TESTING_OPTIONS */
9016 wpa_printf(MSG_DEBUG
, "DPP: GAS Config Attributes: %s", json
);
9018 buf
= dpp_build_conf_req(auth
, json
);
9020 wpa_printf(MSG_DEBUG
,
9021 "DPP: No configuration request data available");
9025 wpabuf_free(conn
->msg_out
);
9026 conn
->msg_out_pos
= 0;
9027 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
9028 if (!conn
->msg_out
) {
9032 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
9033 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
9034 wpabuf_len(buf
) - 1);
9037 if (dpp_tcp_send(conn
) == 1) {
9038 if (!conn
->write_eloop
) {
9039 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9043 conn
->write_eloop
= 1;
9049 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
9052 struct dpp_authentication
*auth
= conn
->auth
;
9057 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
9058 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
9059 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
9060 #ifdef CONFIG_TESTING_OPTIONS
9061 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
9062 wpa_printf(MSG_INFO
,
9063 "DPP: TESTING - stop at Authentication Confirm");
9064 if (auth
->configurator
) {
9065 /* Prevent GAS response */
9066 auth
->auth_success
= 0;
9070 #endif /* CONFIG_TESTING_OPTIONS */
9072 if (!auth
->configurator
)
9073 dpp_controller_start_gas_client(conn
);
9077 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
9079 struct dpp_connection
*conn
= eloop_ctx
;
9081 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
9086 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
9087 const struct hostapd_ip_addr
*ipaddr
,
9090 struct sockaddr_in
*dst
;
9092 struct sockaddr_in6
*dst6
;
9093 #endif /* CONFIG_IPV6 */
9095 switch (ipaddr
->af
) {
9097 dst
= (struct sockaddr_in
*) addr
;
9098 os_memset(dst
, 0, sizeof(*dst
));
9099 dst
->sin_family
= AF_INET
;
9100 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
9101 dst
->sin_port
= htons(port
);
9102 *addrlen
= sizeof(*dst
);
9106 dst6
= (struct sockaddr_in6
*) addr
;
9107 os_memset(dst6
, 0, sizeof(*dst6
));
9108 dst6
->sin6_family
= AF_INET6
;
9109 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
9110 sizeof(struct in6_addr
));
9111 dst6
->sin6_port
= htons(port
);
9112 *addrlen
= sizeof(*dst6
);
9114 #endif /* CONFIG_IPV6 */
9123 static struct dpp_connection
*
9124 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
9127 struct dpp_connection
*conn
;
9128 struct sockaddr_storage addr
;
9132 if (dl_list_len(&ctrl
->conn
) >= 15) {
9133 wpa_printf(MSG_DEBUG
,
9134 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9138 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
9139 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
9142 conn
= os_zalloc(sizeof(*conn
));
9146 conn
->global
= ctrl
->global
;
9148 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
9151 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9154 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
9155 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
9157 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9158 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9163 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
9164 if (errno
!= EINPROGRESS
) {
9165 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9171 * Continue connecting in the background; eloop will call us
9172 * once the connection is ready (or failed).
9176 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9177 dpp_conn_tx_ready
, conn
, NULL
) < 0)
9179 conn
->write_eloop
= 1;
9181 /* TODO: eloop timeout to clear a connection if it does not complete
9184 dl_list_add(&ctrl
->conn
, &conn
->list
);
9187 dpp_connection_free(conn
);
9192 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
9196 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
9199 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
9200 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
9201 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
9202 wpabuf_put_data(msg
, buf
, len
);
9203 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9208 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
9209 const u8
*buf
, size_t len
)
9211 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9213 wpa_printf(MSG_DEBUG
,
9214 "DPP: Continue already established Relay/Controller connection for this session");
9215 wpabuf_free(conn
->msg_out
);
9216 conn
->msg_out_pos
= 0;
9217 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9218 if (!conn
->msg_out
) {
9219 dpp_connection_remove(conn
);
9223 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9225 if (type
== DPP_PA_CONFIGURATION_RESULT
)
9226 conn
->on_tcp_tx_complete_remove
= 1;
9232 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
9233 const u8
*buf
, size_t len
, unsigned int freq
,
9234 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
9236 struct dpp_relay_controller
*ctrl
;
9237 struct dpp_connection
*conn
;
9238 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9240 /* Check if there is an already started session for this peer and if so,
9241 * continue that session (send this over TCP) and return 0.
9243 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
9244 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
9245 dl_list_for_each(ctrl
, &dpp
->controllers
,
9246 struct dpp_relay_controller
, list
) {
9247 dl_list_for_each(conn
, &ctrl
->conn
,
9248 struct dpp_connection
, list
) {
9249 if (os_memcmp(src
, conn
->mac_addr
,
9251 return dpp_relay_tx(conn
, hdr
, buf
, len
);
9259 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
9263 wpa_printf(MSG_DEBUG
,
9264 "DPP: Authentication Request for a configured Controller");
9265 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
9269 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9270 if (!conn
->msg_out
) {
9271 dpp_connection_remove(conn
);
9274 /* Message will be sent in dpp_conn_tx_ready() */
9280 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
9283 struct dpp_relay_controller
*ctrl
;
9284 struct dpp_connection
*conn
, *found
= NULL
;
9287 /* Check if there is a successfully completed authentication for this
9288 * and if so, continue that session (send this over TCP) and return 0.
9290 dl_list_for_each(ctrl
, &dpp
->controllers
,
9291 struct dpp_relay_controller
, list
) {
9294 dl_list_for_each(conn
, &ctrl
->conn
,
9295 struct dpp_connection
, list
) {
9296 if (os_memcmp(src
, conn
->mac_addr
,
9307 msg
= wpabuf_alloc(4 + 1 + data_len
);
9310 wpabuf_put_be32(msg
, 1 + data_len
);
9311 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
9312 wpabuf_put_data(msg
, data
, data_len
);
9313 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9315 wpabuf_free(conn
->msg_out
);
9316 conn
->msg_out_pos
= 0;
9317 conn
->msg_out
= msg
;
9323 static void dpp_controller_free(struct dpp_controller
*ctrl
)
9325 struct dpp_connection
*conn
, *tmp
;
9330 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
9332 dpp_connection_remove(conn
);
9334 if (ctrl
->sock
>= 0) {
9336 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
9338 os_free(ctrl
->configurator_params
);
9343 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
9344 const u8
*hdr
, const u8
*buf
, size_t len
)
9346 const u8
*r_bootstrap
, *i_bootstrap
;
9347 u16 r_bootstrap_len
, i_bootstrap_len
;
9348 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
9353 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
9355 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
9357 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
9358 wpa_printf(MSG_INFO
,
9359 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9362 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
9363 r_bootstrap
, r_bootstrap_len
);
9365 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
9367 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
9368 wpa_printf(MSG_INFO
,
9369 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9372 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
9373 i_bootstrap
, i_bootstrap_len
);
9375 /* Try to find own and peer bootstrapping key matches based on the
9376 * received hash values */
9377 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
9380 wpa_printf(MSG_INFO
,
9381 "No matching own bootstrapping key found - ignore message");
9386 wpa_printf(MSG_INFO
,
9387 "Already in DPP authentication exchange - ignore new one");
9391 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
9392 conn
->ctrl
->allowed_roles
,
9393 conn
->ctrl
->qr_mutual
,
9394 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
9396 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
9400 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
9402 conn
->ctrl
->configurator_params
) < 0) {
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(conn
->auth
->resp_msg
) - 1);
9412 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
9413 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
9414 wpabuf_len(conn
->auth
->resp_msg
) - 1);
9416 if (dpp_tcp_send(conn
) == 1) {
9417 if (!conn
->write_eloop
) {
9418 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9422 conn
->write_eloop
= 1;
9430 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
9431 const u8
*hdr
, const u8
*buf
, size_t len
)
9433 struct dpp_authentication
*auth
= conn
->auth
;
9439 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
9441 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
9443 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
9444 wpa_printf(MSG_DEBUG
,
9445 "DPP: Start wait for full response");
9448 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
9449 dpp_connection_remove(conn
);
9453 wpabuf_free(conn
->msg_out
);
9454 conn
->msg_out_pos
= 0;
9455 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9456 if (!conn
->msg_out
) {
9460 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
9461 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
9462 wpabuf_len(msg
) - 1);
9465 conn
->on_tcp_tx_complete_auth_ok
= 1;
9466 if (dpp_tcp_send(conn
) == 1) {
9467 if (!conn
->write_eloop
) {
9468 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9472 conn
->write_eloop
= 1;
9480 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
9481 const u8
*hdr
, const u8
*buf
, size_t len
)
9483 struct dpp_authentication
*auth
= conn
->auth
;
9485 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
9488 wpa_printf(MSG_DEBUG
,
9489 "DPP: No DPP Authentication in progress - drop");
9493 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
9494 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
9498 dpp_controller_auth_success(conn
, 0);
9503 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
9504 const u8
*hdr
, const u8
*buf
,
9507 struct dpp_authentication
*auth
= conn
->auth
;
9508 enum dpp_status_error status
;
9513 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
9515 if (!auth
|| !auth
->waiting_conf_result
) {
9516 wpa_printf(MSG_DEBUG
,
9517 "DPP: No DPP Configuration waiting for result - drop");
9521 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
9522 if (status
== DPP_STATUS_OK
)
9523 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9524 DPP_EVENT_CONF_SENT
);
9526 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9527 DPP_EVENT_CONF_FAILED
);
9528 return -1; /* to remove the completed connection */
9532 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
9535 const u8
*pos
, *end
;
9538 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
9542 if (end
- pos
< DPP_HDR_LEN
||
9543 WPA_GET_BE24(pos
) != OUI_WFA
||
9544 pos
[3] != DPP_OUI_TYPE
) {
9545 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
9550 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
9555 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
9558 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
9560 if (dpp_check_attrs(pos
, end
- pos
) < 0)
9564 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9565 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9566 conn
->freq
, msg
, len
);
9571 case DPP_PA_AUTHENTICATION_REQ
:
9572 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
9573 case DPP_PA_AUTHENTICATION_RESP
:
9574 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
9575 case DPP_PA_AUTHENTICATION_CONF
:
9576 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
9577 case DPP_PA_CONFIGURATION_RESULT
:
9578 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
9580 /* TODO: missing messages types */
9581 wpa_printf(MSG_DEBUG
,
9582 "DPP: Unsupported frame subtype %d", type
);
9588 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
9591 const u8
*pos
, *end
, *next
;
9593 const u8
*adv_proto
;
9595 struct wpabuf
*resp
, *buf
;
9596 struct dpp_authentication
*auth
= conn
->auth
;
9601 wpa_printf(MSG_DEBUG
,
9602 "DPP: Received DPP Configuration Request over TCP");
9604 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
9605 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9612 dialog_token
= *pos
++;
9615 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9616 slen
> end
- pos
|| slen
< 2)
9620 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9622 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9623 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9624 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9631 slen
= WPA_GET_LE16(pos
);
9633 if (slen
> end
- pos
)
9636 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
9640 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
9646 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
9648 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
9649 wpabuf_put_u8(buf
, dialog_token
);
9650 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
9651 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
9653 dpp_write_adv_proto(buf
);
9654 dpp_write_gas_query(buf
, resp
);
9657 /* Send Config Response over TCP; GAS fragmentation is taken care of by
9659 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
9660 wpabuf_free(conn
->msg_out
);
9661 conn
->msg_out_pos
= 0;
9662 conn
->msg_out
= buf
;
9663 conn
->on_tcp_tx_complete_gas_done
= 1;
9669 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
9671 struct dpp_authentication
*auth
= conn
->auth
;
9673 struct wpabuf
*msg
, *encaps
;
9674 enum dpp_status_error status
;
9676 wpa_printf(MSG_DEBUG
,
9677 "DPP: Configuration Response for local stack from TCP");
9679 res
= dpp_conf_resp_rx(auth
, resp
);
9682 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
9686 if (conn
->global
->process_conf_obj
)
9687 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
9692 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
9695 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
9696 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
9697 msg
= dpp_build_conf_result(auth
, status
);
9701 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9706 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
9707 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
9709 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
9711 wpabuf_free(conn
->msg_out
);
9712 conn
->msg_out_pos
= 0;
9713 conn
->msg_out
= encaps
;
9714 conn
->on_tcp_tx_complete_remove
= 1;
9717 /* This exchange will be terminated in the TX status handler */
9723 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
9728 const u8
*pos
, *end
, *next
, *adv_proto
;
9734 wpa_printf(MSG_DEBUG
,
9735 "DPP: Received DPP Configuration Response over TCP");
9740 dialog_token
= *pos
++;
9741 status
= WPA_GET_LE16(pos
);
9742 if (status
!= WLAN_STATUS_SUCCESS
) {
9743 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
9747 pos
+= 2; /* ignore GAS Comeback Delay */
9751 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9752 slen
> end
- pos
|| slen
< 2)
9756 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9758 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9759 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9760 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9764 /* Query Response */
9767 slen
= WPA_GET_LE16(pos
);
9769 if (slen
> end
- pos
)
9772 buf
= wpabuf_alloc(slen
);
9775 wpabuf_put_data(buf
, pos
, slen
);
9777 if (!conn
->relay
&& !conn
->ctrl
)
9778 return dpp_tcp_rx_gas_resp(conn
, buf
);
9781 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9785 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9786 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9787 dialog_token
, 0, buf
);
9793 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
9795 struct dpp_connection
*conn
= eloop_ctx
;
9799 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
9802 if (conn
->msg_len_octets
< 4) {
9805 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
9806 4 - conn
->msg_len_octets
, 0);
9808 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
9810 dpp_connection_remove(conn
);
9814 wpa_printf(MSG_DEBUG
,
9815 "DPP: No more data available over TCP");
9816 dpp_connection_remove(conn
);
9819 wpa_printf(MSG_DEBUG
,
9820 "DPP: Received %d/%d octet(s) of message length field",
9821 res
, (int) (4 - conn
->msg_len_octets
));
9822 conn
->msg_len_octets
+= res
;
9824 if (conn
->msg_len_octets
< 4) {
9825 wpa_printf(MSG_DEBUG
,
9826 "DPP: Need %d more octets of message length field",
9827 (int) (4 - conn
->msg_len_octets
));
9831 msglen
= WPA_GET_BE32(conn
->msg_len
);
9832 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
9833 if (msglen
> 65535) {
9834 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
9835 dpp_connection_remove(conn
);
9839 wpabuf_free(conn
->msg
);
9840 conn
->msg
= wpabuf_alloc(msglen
);
9844 wpa_printf(MSG_DEBUG
,
9845 "DPP: No buffer available for receiving the message");
9846 dpp_connection_remove(conn
);
9850 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
9851 (unsigned int) wpabuf_tailroom(conn
->msg
));
9853 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
9855 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
9856 dpp_connection_remove(conn
);
9860 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
9861 dpp_connection_remove(conn
);
9864 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
9865 wpabuf_put(conn
->msg
, res
);
9867 if (wpabuf_tailroom(conn
->msg
) > 0) {
9868 wpa_printf(MSG_DEBUG
,
9869 "DPP: Need %u more octets of message payload",
9870 (unsigned int) wpabuf_tailroom(conn
->msg
));
9874 conn
->msg_len_octets
= 0;
9875 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
9876 if (wpabuf_len(conn
->msg
) < 1) {
9877 dpp_connection_remove(conn
);
9881 pos
= wpabuf_head(conn
->msg
);
9883 case WLAN_PA_VENDOR_SPECIFIC
:
9884 if (dpp_controller_rx_action(conn
, pos
+ 1,
9885 wpabuf_len(conn
->msg
) - 1) < 0)
9886 dpp_connection_remove(conn
);
9888 case WLAN_PA_GAS_INITIAL_REQ
:
9889 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
9890 wpabuf_len(conn
->msg
) - 1) < 0)
9891 dpp_connection_remove(conn
);
9893 case WLAN_PA_GAS_INITIAL_RESP
:
9894 if (dpp_rx_gas_resp(conn
, pos
+ 1,
9895 wpabuf_len(conn
->msg
) - 1) < 0)
9896 dpp_connection_remove(conn
);
9899 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
9906 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
9908 struct dpp_controller
*ctrl
= eloop_ctx
;
9909 struct sockaddr_in addr
;
9910 socklen_t addr_len
= sizeof(addr
);
9912 struct dpp_connection
*conn
;
9914 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
9916 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
9918 wpa_printf(MSG_DEBUG
,
9919 "DPP: Failed to accept new connection: %s",
9923 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
9924 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
9926 conn
= os_zalloc(sizeof(*conn
));
9930 conn
->global
= ctrl
->global
;
9934 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9935 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9940 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
9941 dpp_controller_rx
, conn
, NULL
) < 0)
9943 conn
->read_eloop
= 1;
9945 /* TODO: eloop timeout to expire connections that do not complete in
9946 * reasonable time */
9947 dl_list_add(&ctrl
->conn
, &conn
->list
);
9956 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
9957 const struct hostapd_ip_addr
*addr
, int port
)
9959 struct dpp_connection
*conn
;
9960 struct sockaddr_storage saddr
;
9962 const u8
*hdr
, *pos
, *end
;
9965 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
9966 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
9967 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
9969 dpp_auth_deinit(auth
);
9973 conn
= os_zalloc(sizeof(*conn
));
9975 dpp_auth_deinit(auth
);
9981 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9985 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9986 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9991 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
9992 if (errno
!= EINPROGRESS
) {
9993 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9999 * Continue connecting in the background; eloop will call us
10000 * once the connection is ready (or failed).
10004 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10005 dpp_conn_tx_ready
, conn
, NULL
) < 0)
10007 conn
->write_eloop
= 1;
10009 hdr
= wpabuf_head(auth
->req_msg
);
10010 end
= hdr
+ wpabuf_len(auth
->req_msg
);
10011 hdr
+= 2; /* skip Category and Actiom */
10012 pos
= hdr
+ DPP_HDR_LEN
;
10013 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
10014 if (!conn
->msg_out
)
10016 /* Message will be sent in dpp_conn_tx_ready() */
10018 /* TODO: eloop timeout to clear a connection if it does not complete
10020 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
10023 dpp_connection_free(conn
);
10028 int dpp_controller_start(struct dpp_global
*dpp
,
10029 struct dpp_controller_config
*config
)
10031 struct dpp_controller
*ctrl
;
10033 struct sockaddr_in sin
;
10036 if (!dpp
|| dpp
->controller
)
10039 ctrl
= os_zalloc(sizeof(*ctrl
));
10042 ctrl
->global
= dpp
;
10043 if (config
->configurator_params
)
10044 ctrl
->configurator_params
=
10045 os_strdup(config
->configurator_params
);
10046 dl_list_init(&ctrl
->conn
);
10047 /* TODO: configure these somehow */
10048 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
10049 ctrl
->qr_mutual
= 0;
10051 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10052 if (ctrl
->sock
< 0)
10055 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
10056 &on
, sizeof(on
)) < 0) {
10057 wpa_printf(MSG_DEBUG
,
10058 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10060 /* try to continue anyway */
10063 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
10064 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10070 os_memset(&sin
, 0, sizeof(sin
));
10071 sin
.sin_family
= AF_INET
;
10072 sin
.sin_addr
.s_addr
= INADDR_ANY
;
10073 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
10074 sin
.sin_port
= htons(port
);
10075 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
10076 wpa_printf(MSG_INFO
,
10077 "DPP: Failed to bind Controller TCP port: %s",
10081 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
10082 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
10083 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
10084 dpp_controller_tcp_cb
, ctrl
, NULL
))
10087 dpp
->controller
= ctrl
;
10088 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
10091 dpp_controller_free(ctrl
);
10096 void dpp_controller_stop(struct dpp_global
*dpp
)
10099 dpp_controller_free(dpp
->controller
);
10100 dpp
->controller
= NULL
;
10104 #endif /* CONFIG_DPP2 */