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
;
749 int opclass
, channel
, freq
;
751 while (pos
&& *pos
&& *pos
!= ';') {
755 pos
= os_strchr(pos
, '/');
762 while (*pos
>= '0' && *pos
<= '9')
764 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
765 wpa_printf(MSG_DEBUG
,
766 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
767 opclass
, channel
, freq
);
769 wpa_printf(MSG_DEBUG
,
770 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
772 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
773 wpa_printf(MSG_DEBUG
,
774 "DPP: Too many channels in URI channel-list - ignore list");
778 bi
->freq
[bi
->num_freq
++] = freq
;
781 if (*pos
== ';' || *pos
== '\0')
790 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
795 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
800 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
801 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
805 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
811 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
818 end
= os_strchr(info
, ';');
820 end
= info
+ os_strlen(info
);
821 bi
->info
= os_malloc(end
- info
+ 1);
824 os_memcpy(bi
->info
, info
, end
- info
);
825 bi
->info
[end
- info
] = '\0';
826 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
827 if (!dpp_uri_valid_info(bi
->info
)) {
828 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
836 static const struct dpp_curve_params
*
837 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
842 for (i
= 0; dpp_curves
[i
].name
; i
++) {
843 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
844 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
845 return &dpp_curves
[i
];
851 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
857 for (i
= 0; dpp_curves
[i
].name
; i
++) {
858 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
860 return &dpp_curves
[i
];
866 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
872 const unsigned char *p
;
874 X509_PUBKEY
*pub
= NULL
;
876 const unsigned char *pk
;
879 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
880 (defined(LIBRESSL_VERSION_NUMBER) && \
881 LIBRESSL_VERSION_NUMBER < 0x20800000L)
884 const ASN1_OBJECT
*pa_oid
;
888 const ASN1_OBJECT
*poid
;
891 end
= os_strchr(info
, ';');
895 data
= base64_decode((const unsigned char *) info
, end
- info
,
898 wpa_printf(MSG_DEBUG
,
899 "DPP: Invalid base64 encoding on URI public-key");
902 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
905 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
906 bi
->pubkey_hash
) < 0) {
907 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
911 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
912 bi
->pubkey_hash
, SHA256_MAC_LEN
);
914 /* DER encoded ASN.1 SubjectPublicKeyInfo
916 * SubjectPublicKeyInfo ::= SEQUENCE {
917 * algorithm AlgorithmIdentifier,
918 * subjectPublicKey BIT STRING }
920 * AlgorithmIdentifier ::= SEQUENCE {
921 * algorithm OBJECT IDENTIFIER,
922 * parameters ANY DEFINED BY algorithm OPTIONAL }
924 * subjectPublicKey = compressed format public key per ANSI X9.63
925 * algorithm = ecPublicKey (1.2.840.10045.2.1)
926 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
927 * prime256v1 (1.2.840.10045.3.1.7)
931 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
935 wpa_printf(MSG_DEBUG
,
936 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
940 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
941 wpa_printf(MSG_DEBUG
,
942 "DPP: SubjectPublicKeyInfo does not describe an EC key");
947 res
= X509_PUBKEY_set(&pub
, pkey
);
949 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
953 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
955 wpa_printf(MSG_DEBUG
,
956 "DPP: Could not extract SubjectPublicKeyInfo parameters");
959 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
960 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
961 wpa_printf(MSG_DEBUG
,
962 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
965 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
966 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
967 wpa_printf(MSG_DEBUG
,
968 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
972 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
973 if (ptype
!= V_ASN1_OBJECT
) {
974 wpa_printf(MSG_DEBUG
,
975 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
979 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
980 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
981 wpa_printf(MSG_DEBUG
,
982 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
985 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
986 bi
->curve
= dpp_get_curve_oid(poid
);
988 wpa_printf(MSG_DEBUG
,
989 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
994 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
996 X509_PUBKEY_free(pub
);
1000 X509_PUBKEY_free(pub
);
1001 EVP_PKEY_free(pkey
);
1006 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1008 const char *pos
= uri
;
1010 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1011 struct dpp_bootstrap_info
*bi
;
1013 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1015 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1016 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1022 end
= os_strchr(pos
, ';');
1027 /* Handle terminating ";;" and ignore unexpected ";"
1028 * for parsing robustness. */
1033 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1034 chan_list
= pos
+ 2;
1035 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1037 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1039 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1042 wpa_hexdump_ascii(MSG_DEBUG
,
1043 "DPP: Ignore unrecognized URI parameter",
1049 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1053 bi
= os_zalloc(sizeof(*bi
));
1057 if (dpp_clone_uri(bi
, uri
) < 0 ||
1058 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1059 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1060 dpp_parse_uri_info(bi
, info
) < 0 ||
1061 dpp_parse_uri_pk(bi
, pk
) < 0) {
1062 dpp_bootstrap_info_free(bi
);
1070 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1072 struct dpp_bootstrap_info
*bi
;
1074 bi
= dpp_parse_uri(uri
);
1076 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1081 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1088 unsigned char *der
= NULL
;
1090 const EC_GROUP
*group
;
1091 const EC_POINT
*point
;
1093 out
= BIO_new(BIO_s_mem());
1097 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1098 rlen
= BIO_ctrl_pending(out
);
1099 txt
= os_malloc(rlen
+ 1);
1101 res
= BIO_read(out
, txt
, rlen
);
1104 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1110 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1114 group
= EC_KEY_get0_group(eckey
);
1115 point
= EC_KEY_get0_public_key(eckey
);
1117 dpp_debug_print_point(title
, group
, point
);
1119 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1121 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1125 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1127 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1135 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1137 EVP_PKEY_CTX
*kctx
= NULL
;
1138 EC_KEY
*ec_params
= NULL
;
1139 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1142 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1144 nid
= OBJ_txt2nid(curve
->name
);
1145 if (nid
== NID_undef
) {
1146 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1150 ec_params
= EC_KEY_new_by_curve_name(nid
);
1152 wpa_printf(MSG_ERROR
,
1153 "DPP: Failed to generate EC_KEY parameters");
1156 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1157 params
= EVP_PKEY_new();
1158 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1159 wpa_printf(MSG_ERROR
,
1160 "DPP: Failed to generate EVP_PKEY parameters");
1164 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1166 EVP_PKEY_keygen_init(kctx
) != 1 ||
1167 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1168 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1173 if (wpa_debug_show_keys
)
1174 dpp_debug_print_key("Own generated key", key
);
1177 EC_KEY_free(ec_params
);
1178 EVP_PKEY_free(params
);
1179 EVP_PKEY_CTX_free(kctx
);
1184 static const struct dpp_curve_params
*
1185 dpp_get_curve_name(const char *name
)
1189 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1190 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1191 (dpp_curves
[i
].jwk_crv
&&
1192 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1193 return &dpp_curves
[i
];
1199 static const struct dpp_curve_params
*
1200 dpp_get_curve_jwk_crv(const char *name
)
1204 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1205 if (dpp_curves
[i
].jwk_crv
&&
1206 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1207 return &dpp_curves
[i
];
1213 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1214 const u8
*privkey
, size_t privkey_len
)
1218 const EC_GROUP
*group
;
1221 pkey
= EVP_PKEY_new();
1224 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1226 wpa_printf(MSG_INFO
,
1227 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1228 ERR_error_string(ERR_get_error(), NULL
));
1229 EVP_PKEY_free(pkey
);
1232 group
= EC_KEY_get0_group(eckey
);
1235 EVP_PKEY_free(pkey
);
1238 nid
= EC_GROUP_get_curve_name(group
);
1239 *curve
= dpp_get_curve_nid(nid
);
1241 wpa_printf(MSG_INFO
,
1242 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1245 EVP_PKEY_free(pkey
);
1249 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1251 EVP_PKEY_free(pkey
);
1259 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1260 * as an OID identifying the curve */
1262 /* Compressed format public key per ANSI X9.63 */
1263 ASN1_BIT_STRING
*pub_key
;
1264 } DPP_BOOTSTRAPPING_KEY
;
1266 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1267 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1268 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1269 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1271 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1274 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1276 unsigned char *der
= NULL
;
1279 struct wpabuf
*ret
= NULL
;
1281 const EC_GROUP
*group
;
1282 const EC_POINT
*point
;
1284 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1288 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1292 group
= EC_KEY_get0_group(eckey
);
1293 point
= EC_KEY_get0_public_key(eckey
);
1294 if (!group
|| !point
)
1296 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1297 nid
= EC_GROUP_get_curve_name(group
);
1299 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1301 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1302 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1305 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1310 der
= OPENSSL_malloc(len
);
1313 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1316 OPENSSL_free(bootstrap
->pub_key
->data
);
1317 bootstrap
->pub_key
->data
= der
;
1319 bootstrap
->pub_key
->length
= len
;
1320 /* No unused bits */
1321 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1322 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1324 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1326 wpa_printf(MSG_ERROR
,
1327 "DDP: Failed to build DER encoded public key");
1331 ret
= wpabuf_alloc_copy(der
, der_len
);
1333 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1341 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1348 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1351 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1354 addr
[0] = wpabuf_head(der
);
1355 len
[0] = wpabuf_len(der
);
1356 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1358 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1360 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1367 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1368 const u8
*privkey
, size_t privkey_len
)
1370 unsigned char *base64
= NULL
;
1373 struct wpabuf
*der
= NULL
;
1378 bi
->curve
= &dpp_curves
[0];
1380 bi
->curve
= dpp_get_curve_name(curve
);
1382 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1388 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1390 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1395 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1398 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1401 addr
[0] = wpabuf_head(der
);
1402 len
= wpabuf_len(der
);
1403 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1405 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1408 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1411 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1416 pos
= (char *) base64
;
1419 pos
= os_strchr(pos
, '\n');
1422 os_memmove(pos
, pos
+ 1, end
- pos
);
1424 return (char *) base64
;
1432 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1433 unsigned int hash_len
)
1435 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1436 const char *info
= "first intermediate key";
1439 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1441 /* HKDF-Extract(<>, M.x) */
1442 os_memset(salt
, 0, hash_len
);
1443 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1445 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1448 /* HKDF-Expand(PRK, info, L) */
1449 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1450 os_memset(prk
, 0, hash_len
);
1454 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1460 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1461 unsigned int hash_len
)
1463 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1464 const char *info
= "second intermediate key";
1467 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1469 /* HKDF-Extract(<>, N.x) */
1470 os_memset(salt
, 0, hash_len
);
1471 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1474 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1477 /* HKDF-Expand(PRK, info, L) */
1478 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1479 os_memset(prk
, 0, hash_len
);
1483 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1489 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1490 unsigned int hash_len
)
1493 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1494 const char *info_ke
= "DPP Key";
1495 u8 prk
[DPP_MAX_HASH_LEN
];
1499 size_t num_elem
= 0;
1501 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1502 wpa_printf(MSG_DEBUG
,
1503 "DPP: Mx/Nx not available - cannot derive ke");
1507 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1509 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1510 nonce_len
= auth
->curve
->nonce_len
;
1511 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1512 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1513 addr
[num_elem
] = auth
->Mx
;
1514 len
[num_elem
] = auth
->Mx_len
;
1516 addr
[num_elem
] = auth
->Nx
;
1517 len
[num_elem
] = auth
->Nx_len
;
1519 if (auth
->peer_bi
&& auth
->own_bi
) {
1520 if (!auth
->Lx_len
) {
1521 wpa_printf(MSG_DEBUG
,
1522 "DPP: Lx not available - cannot derive ke");
1525 addr
[num_elem
] = auth
->Lx
;
1526 len
[num_elem
] = auth
->secret_len
;
1529 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1530 num_elem
, addr
, len
, prk
);
1533 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1536 /* HKDF-Expand(PRK, info, L) */
1537 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1538 os_memset(prk
, 0, hash_len
);
1542 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1548 static void dpp_build_attr_status(struct wpabuf
*msg
,
1549 enum dpp_status_error status
)
1551 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1552 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1553 wpabuf_put_le16(msg
, 1);
1554 wpabuf_put_u8(msg
, status
);
1558 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1562 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1563 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1564 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1565 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1570 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1574 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1575 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1576 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1577 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1582 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1583 const struct wpabuf
*pi
,
1585 const u8
*r_pubkey_hash
,
1586 const u8
*i_pubkey_hash
,
1587 unsigned int neg_freq
)
1590 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1591 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1594 size_t len
[2], siv_len
, attr_len
;
1595 u8
*attr_start
, *attr_end
;
1597 /* Build DPP Authentication Request frame attributes */
1598 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1599 4 + sizeof(wrapped_data
);
1604 #endif /* CONFIG_DPP2 */
1605 #ifdef CONFIG_TESTING_OPTIONS
1606 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1608 #endif /* CONFIG_TESTING_OPTIONS */
1609 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1613 attr_start
= wpabuf_put(msg
, 0);
1615 /* Responder Bootstrapping Key Hash */
1616 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1618 /* Initiator Bootstrapping Key Hash */
1619 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1621 /* Initiator Protocol Key */
1623 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1624 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1625 wpabuf_put_buf(msg
, pi
);
1630 u8 op_class
, channel
;
1632 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1634 NUM_HOSTAPD_MODES
) {
1635 wpa_printf(MSG_INFO
,
1636 "DPP: Unsupported negotiation frequency request: %d",
1641 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1642 wpabuf_put_le16(msg
, 2);
1643 wpabuf_put_u8(msg
, op_class
);
1644 wpabuf_put_u8(msg
, channel
);
1648 /* Protocol Version */
1649 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1650 wpabuf_put_le16(msg
, 1);
1651 wpabuf_put_u8(msg
, 2);
1652 #endif /* CONFIG_DPP2 */
1654 #ifdef CONFIG_TESTING_OPTIONS
1655 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1656 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1657 goto skip_wrapped_data
;
1659 #endif /* CONFIG_TESTING_OPTIONS */
1661 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1664 #ifdef CONFIG_TESTING_OPTIONS
1665 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1666 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1669 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1670 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1671 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1673 WPA_PUT_LE16(pos
, nonce_len
- 1);
1675 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1676 pos
+= nonce_len
- 1;
1679 #endif /* CONFIG_TESTING_OPTIONS */
1682 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1684 WPA_PUT_LE16(pos
, nonce_len
);
1686 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1689 #ifdef CONFIG_TESTING_OPTIONS
1691 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1692 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1695 #endif /* CONFIG_TESTING_OPTIONS */
1697 /* I-capabilities */
1698 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1700 WPA_PUT_LE16(pos
, 1);
1702 auth
->i_capab
= auth
->allowed_roles
;
1703 *pos
++ = auth
->i_capab
;
1704 #ifdef CONFIG_TESTING_OPTIONS
1705 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1706 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1710 #endif /* CONFIG_TESTING_OPTIONS */
1712 attr_end
= wpabuf_put(msg
, 0);
1714 /* OUI, OUI type, Crypto Suite, DPP frame type */
1715 addr
[0] = wpabuf_head_u8(msg
) + 2;
1716 len
[0] = 3 + 1 + 1 + 1;
1717 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1719 /* Attributes before Wrapped Data */
1720 addr
[1] = attr_start
;
1721 len
[1] = attr_end
- attr_start
;
1722 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1724 siv_len
= pos
- clear
;
1725 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1726 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1727 2, addr
, len
, wrapped_data
) < 0) {
1731 siv_len
+= AES_BLOCK_SIZE
;
1732 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1733 wrapped_data
, siv_len
);
1735 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1736 wpabuf_put_le16(msg
, siv_len
);
1737 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1739 #ifdef CONFIG_TESTING_OPTIONS
1740 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1741 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1742 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1745 #endif /* CONFIG_TESTING_OPTIONS */
1747 wpa_hexdump_buf(MSG_DEBUG
,
1748 "DPP: Authentication Request frame attributes", msg
);
1754 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1755 enum dpp_status_error status
,
1756 const struct wpabuf
*pr
,
1758 const u8
*r_pubkey_hash
,
1759 const u8
*i_pubkey_hash
,
1760 const u8
*r_nonce
, const u8
*i_nonce
,
1761 const u8
*wrapped_r_auth
,
1762 size_t wrapped_r_auth_len
,
1766 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1767 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1768 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1769 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1771 size_t len
[2], siv_len
, attr_len
;
1772 u8
*attr_start
, *attr_end
, *pos
;
1774 auth
->waiting_auth_conf
= 1;
1775 auth
->auth_resp_tries
= 0;
1777 /* Build DPP Authentication Response frame attributes */
1778 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1779 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1782 #endif /* CONFIG_DPP2 */
1783 #ifdef CONFIG_TESTING_OPTIONS
1784 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1786 #endif /* CONFIG_TESTING_OPTIONS */
1787 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1791 attr_start
= wpabuf_put(msg
, 0);
1795 dpp_build_attr_status(msg
, status
);
1797 /* Responder Bootstrapping Key Hash */
1798 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1800 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1801 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1803 /* Responder Protocol Key */
1805 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1806 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1807 wpabuf_put_buf(msg
, pr
);
1811 /* Protocol Version */
1812 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1813 wpabuf_put_le16(msg
, 1);
1814 wpabuf_put_u8(msg
, 2);
1815 #endif /* CONFIG_DPP2 */
1817 attr_end
= wpabuf_put(msg
, 0);
1819 #ifdef CONFIG_TESTING_OPTIONS
1820 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1821 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1822 goto skip_wrapped_data
;
1824 #endif /* CONFIG_TESTING_OPTIONS */
1826 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1831 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1833 WPA_PUT_LE16(pos
, nonce_len
);
1835 os_memcpy(pos
, r_nonce
, nonce_len
);
1841 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1843 WPA_PUT_LE16(pos
, nonce_len
);
1845 os_memcpy(pos
, i_nonce
, nonce_len
);
1846 #ifdef CONFIG_TESTING_OPTIONS
1847 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1848 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1849 pos
[nonce_len
/ 2] ^= 0x01;
1851 #endif /* CONFIG_TESTING_OPTIONS */
1855 #ifdef CONFIG_TESTING_OPTIONS
1856 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1857 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1860 #endif /* CONFIG_TESTING_OPTIONS */
1862 /* R-capabilities */
1863 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1865 WPA_PUT_LE16(pos
, 1);
1867 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1869 *pos
++ = auth
->r_capab
;
1870 #ifdef CONFIG_TESTING_OPTIONS
1871 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1872 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1874 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1875 wpa_printf(MSG_INFO
,
1876 "DPP: TESTING - incompatible R-capabilities");
1877 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1878 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1881 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1882 DPP_CAPAB_CONFIGURATOR
;
1885 #endif /* CONFIG_TESTING_OPTIONS */
1887 if (wrapped_r_auth
) {
1889 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
1891 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
1893 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
1894 pos
+= wrapped_r_auth_len
;
1897 /* OUI, OUI type, Crypto Suite, DPP frame type */
1898 addr
[0] = wpabuf_head_u8(msg
) + 2;
1899 len
[0] = 3 + 1 + 1 + 1;
1900 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1902 /* Attributes before Wrapped Data */
1903 addr
[1] = attr_start
;
1904 len
[1] = attr_end
- attr_start
;
1905 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1907 siv_len
= pos
- clear
;
1908 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1909 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
1910 2, addr
, len
, wrapped_data
) < 0) {
1914 siv_len
+= AES_BLOCK_SIZE
;
1915 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1916 wrapped_data
, siv_len
);
1918 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1919 wpabuf_put_le16(msg
, siv_len
);
1920 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1922 #ifdef CONFIG_TESTING_OPTIONS
1923 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
1924 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1925 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1928 #endif /* CONFIG_TESTING_OPTIONS */
1930 wpa_hexdump_buf(MSG_DEBUG
,
1931 "DPP: Authentication Response frame attributes", msg
);
1936 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
1937 u16 num_modes
, unsigned int freq
)
1942 if (!own_modes
|| !num_modes
)
1945 for (m
= 0; m
< num_modes
; m
++) {
1946 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
1947 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
1950 flag
= own_modes
[m
].channels
[c
].flag
;
1951 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
1952 HOSTAPD_CHAN_NO_IR
|
1953 HOSTAPD_CHAN_RADAR
)))
1958 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
1963 static int freq_included(const unsigned int freqs
[], unsigned int num
,
1967 if (freqs
[--num
] == freq
)
1974 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
1979 for (i
= 0; i
< num
; i
++) {
1980 if (freqs
[i
] == freq
)
1983 if (i
== 0 || i
>= num
)
1985 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
1990 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
1991 struct hostapd_hw_modes
*own_modes
,
1994 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
1995 unsigned int i
, freq
;
1997 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
1998 freq
= peer_bi
->freq
[i
];
1999 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2001 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2002 auth
->freq
[auth
->num_freq
++] = freq
;
2004 if (!auth
->num_freq
) {
2005 wpa_printf(MSG_INFO
,
2006 "DPP: No available channels for initiating DPP Authentication");
2009 auth
->curr_freq
= auth
->freq
[0];
2014 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2015 struct hostapd_hw_modes
*own_modes
,
2024 if (!own_modes
|| !num_modes
) {
2025 auth
->freq
[0] = 2412;
2026 auth
->freq
[1] = 2437;
2027 auth
->freq
[2] = 2462;
2032 for (m
= 0; m
< num_modes
; m
++) {
2033 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2034 freq
= own_modes
[m
].channels
[c
].freq
;
2035 flag
= own_modes
[m
].channels
[c
].flag
;
2036 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2037 HOSTAPD_CHAN_NO_IR
|
2038 HOSTAPD_CHAN_RADAR
))
2040 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2042 auth
->freq
[auth
->num_freq
++] = freq
;
2043 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2050 return auth
->num_freq
== 0 ? -1 : 0;
2054 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2055 struct hostapd_hw_modes
*own_modes
,
2059 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2062 if (auth
->peer_bi
->num_freq
> 0)
2063 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2065 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2069 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2070 * likely channels first. */
2071 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2072 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2073 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2076 auth
->curr_freq
= auth
->freq
[0];
2079 end
= pos
+ sizeof(freqs
);
2080 for (i
= 0; i
< auth
->num_freq
; i
++) {
2081 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2082 if (os_snprintf_error(end
- pos
, res
))
2087 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2094 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2096 struct dpp_bootstrap_info
*bi
;
2101 return 0; /* already generated */
2103 bi
= os_zalloc(sizeof(*bi
));
2106 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2107 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2111 len
= 4; /* "DPP:" */
2112 len
+= 4 + os_strlen(pk
);
2113 bi
->uri
= os_malloc(len
+ 1);
2116 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2117 wpa_printf(MSG_DEBUG
,
2118 "DPP: Auto-generated own bootstrapping key info: URI %s",
2121 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2128 dpp_bootstrap_info_free(bi
);
2133 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2134 struct dpp_bootstrap_info
*peer_bi
,
2135 struct dpp_bootstrap_info
*own_bi
,
2136 u8 dpp_allowed_roles
,
2137 unsigned int neg_freq
,
2138 struct hostapd_hw_modes
*own_modes
,
2141 struct dpp_authentication
*auth
;
2143 EVP_PKEY_CTX
*ctx
= NULL
;
2145 struct wpabuf
*pi
= NULL
;
2146 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2147 #ifdef CONFIG_TESTING_OPTIONS
2148 u8 test_hash
[SHA256_MAC_LEN
];
2149 #endif /* CONFIG_TESTING_OPTIONS */
2151 auth
= os_zalloc(sizeof(*auth
));
2154 auth
->msg_ctx
= msg_ctx
;
2155 auth
->initiator
= 1;
2156 auth
->waiting_auth_resp
= 1;
2157 auth
->allowed_roles
= dpp_allowed_roles
;
2158 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2159 auth
->peer_bi
= peer_bi
;
2160 auth
->own_bi
= own_bi
;
2161 auth
->curve
= peer_bi
->curve
;
2163 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2164 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2167 #ifdef CONFIG_TESTING_OPTIONS
2168 if (dpp_nonce_override_len
> 0) {
2169 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2170 nonce_len
= dpp_nonce_override_len
;
2171 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2173 nonce_len
= auth
->curve
->nonce_len
;
2174 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2175 wpa_printf(MSG_ERROR
,
2176 "DPP: Failed to generate I-nonce");
2180 #else /* CONFIG_TESTING_OPTIONS */
2181 nonce_len
= auth
->curve
->nonce_len
;
2182 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2183 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2186 #endif /* CONFIG_TESTING_OPTIONS */
2187 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2189 #ifdef CONFIG_TESTING_OPTIONS
2190 if (dpp_protocol_key_override_len
) {
2191 const struct dpp_curve_params
*tmp_curve
;
2193 wpa_printf(MSG_INFO
,
2194 "DPP: TESTING - override protocol key");
2195 auth
->own_protocol_key
= dpp_set_keypair(
2196 &tmp_curve
, dpp_protocol_key_override
,
2197 dpp_protocol_key_override_len
);
2199 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2201 #else /* CONFIG_TESTING_OPTIONS */
2202 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2203 #endif /* CONFIG_TESTING_OPTIONS */
2204 if (!auth
->own_protocol_key
)
2207 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2211 /* ECDH: M = pI * BR */
2212 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2214 EVP_PKEY_derive_init(ctx
) != 1 ||
2215 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_bi
->pubkey
) != 1 ||
2216 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2217 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2218 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
2219 wpa_printf(MSG_ERROR
,
2220 "DPP: Failed to derive ECDH shared secret: %s",
2221 ERR_error_string(ERR_get_error(), NULL
));
2224 auth
->secret_len
= secret_len
;
2225 EVP_PKEY_CTX_free(ctx
);
2228 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2229 auth
->Mx
, auth
->secret_len
);
2230 auth
->Mx_len
= auth
->secret_len
;
2232 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2233 auth
->curve
->hash_len
) < 0)
2236 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2237 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2239 #ifdef CONFIG_TESTING_OPTIONS
2240 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2241 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2242 r_pubkey_hash
= NULL
;
2243 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2244 wpa_printf(MSG_INFO
,
2245 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2246 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2247 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2248 r_pubkey_hash
= test_hash
;
2249 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2250 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2251 i_pubkey_hash
= NULL
;
2252 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2253 wpa_printf(MSG_INFO
,
2254 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2255 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2256 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2257 i_pubkey_hash
= test_hash
;
2258 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2259 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2262 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2263 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2265 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2266 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2269 #endif /* CONFIG_TESTING_OPTIONS */
2271 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2272 i_pubkey_hash
, neg_freq
);
2278 EVP_PKEY_CTX_free(ctx
);
2281 dpp_auth_deinit(auth
);
2287 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2291 size_t json_len
, clear_len
;
2292 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2296 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2298 nonce_len
= auth
->curve
->nonce_len
;
2299 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2300 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2303 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2304 json_len
= os_strlen(json
);
2305 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configAttr JSON", json
, json_len
);
2307 /* { E-nonce, configAttrib }ke */
2308 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2309 clear
= wpabuf_alloc(clear_len
);
2310 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2311 #ifdef CONFIG_TESTING_OPTIONS
2312 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2314 #endif /* CONFIG_TESTING_OPTIONS */
2315 msg
= wpabuf_alloc(attr_len
);
2319 #ifdef CONFIG_TESTING_OPTIONS
2320 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2321 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2324 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2325 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2326 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2327 wpabuf_put_le16(clear
, nonce_len
- 1);
2328 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2331 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2332 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2333 goto skip_wrapped_data
;
2335 #endif /* CONFIG_TESTING_OPTIONS */
2338 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2339 wpabuf_put_le16(clear
, nonce_len
);
2340 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2342 #ifdef CONFIG_TESTING_OPTIONS
2344 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2345 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2346 goto skip_conf_attr_obj
;
2348 #endif /* CONFIG_TESTING_OPTIONS */
2351 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2352 wpabuf_put_le16(clear
, json_len
);
2353 wpabuf_put_data(clear
, json
, json_len
);
2355 #ifdef CONFIG_TESTING_OPTIONS
2357 #endif /* CONFIG_TESTING_OPTIONS */
2359 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2360 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2361 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2364 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2365 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2366 wpabuf_head(clear
), wpabuf_len(clear
),
2367 0, NULL
, NULL
, wrapped
) < 0)
2369 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2370 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2372 #ifdef CONFIG_TESTING_OPTIONS
2373 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2374 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2375 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2378 #endif /* CONFIG_TESTING_OPTIONS */
2380 wpa_hexdump_buf(MSG_DEBUG
,
2381 "DPP: Configuration Request frame attributes", msg
);
2392 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2394 /* Advertisement Protocol IE */
2395 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2396 wpabuf_put_u8(buf
, 8); /* Length */
2397 wpabuf_put_u8(buf
, 0x7f);
2398 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2399 wpabuf_put_u8(buf
, 5);
2400 wpabuf_put_be24(buf
, OUI_WFA
);
2401 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2402 wpabuf_put_u8(buf
, 0x01);
2406 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2409 wpabuf_put_le16(buf
, wpabuf_len(query
));
2410 wpabuf_put_buf(buf
, query
);
2414 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2417 struct wpabuf
*buf
, *conf_req
;
2419 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2421 wpa_printf(MSG_DEBUG
,
2422 "DPP: No configuration request data available");
2426 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2428 wpabuf_free(conf_req
);
2432 dpp_write_adv_proto(buf
);
2433 dpp_write_gas_query(buf
, conf_req
);
2434 wpabuf_free(conf_req
);
2435 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2441 static void dpp_auth_success(struct dpp_authentication
*auth
)
2443 wpa_printf(MSG_DEBUG
,
2444 "DPP: Authentication success - clear temporary keys");
2445 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2447 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2449 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2451 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2452 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2454 auth
->auth_success
= 1;
2458 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2460 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2463 size_t i
, num_elem
= 0;
2468 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2469 nonce_len
= auth
->curve
->nonce_len
;
2471 if (auth
->initiator
) {
2472 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2473 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2475 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2478 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2480 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2481 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2483 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2486 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2488 if (!pix
|| !prx
|| !brx
)
2491 addr
[num_elem
] = auth
->i_nonce
;
2492 len
[num_elem
] = nonce_len
;
2495 addr
[num_elem
] = auth
->r_nonce
;
2496 len
[num_elem
] = nonce_len
;
2499 addr
[num_elem
] = wpabuf_head(pix
);
2500 len
[num_elem
] = wpabuf_len(pix
) / 2;
2503 addr
[num_elem
] = wpabuf_head(prx
);
2504 len
[num_elem
] = wpabuf_len(prx
) / 2;
2508 addr
[num_elem
] = wpabuf_head(bix
);
2509 len
[num_elem
] = wpabuf_len(bix
) / 2;
2513 addr
[num_elem
] = wpabuf_head(brx
);
2514 len
[num_elem
] = wpabuf_len(brx
) / 2;
2517 addr
[num_elem
] = &zero
;
2521 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2522 for (i
= 0; i
< num_elem
; i
++)
2523 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2524 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2526 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2527 auth
->curve
->hash_len
);
2537 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2539 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2542 size_t i
, num_elem
= 0;
2547 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2548 nonce_len
= auth
->curve
->nonce_len
;
2550 if (auth
->initiator
) {
2551 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2552 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2554 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2559 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2561 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2562 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2564 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2569 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2571 if (!pix
|| !prx
|| !brx
)
2574 addr
[num_elem
] = auth
->r_nonce
;
2575 len
[num_elem
] = nonce_len
;
2578 addr
[num_elem
] = auth
->i_nonce
;
2579 len
[num_elem
] = nonce_len
;
2582 addr
[num_elem
] = wpabuf_head(prx
);
2583 len
[num_elem
] = wpabuf_len(prx
) / 2;
2586 addr
[num_elem
] = wpabuf_head(pix
);
2587 len
[num_elem
] = wpabuf_len(pix
) / 2;
2590 addr
[num_elem
] = wpabuf_head(brx
);
2591 len
[num_elem
] = wpabuf_len(brx
) / 2;
2595 addr
[num_elem
] = wpabuf_head(bix
);
2596 len
[num_elem
] = wpabuf_len(bix
) / 2;
2600 addr
[num_elem
] = &one
;
2604 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2605 for (i
= 0; i
< num_elem
; i
++)
2606 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2607 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2609 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2610 auth
->curve
->hash_len
);
2620 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2622 const EC_GROUP
*group
;
2624 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2625 const EC_POINT
*BI_point
;
2627 BIGNUM
*lx
, *sum
, *q
;
2628 const BIGNUM
*bR_bn
, *pR_bn
;
2631 /* L = ((bR + pR) modulo q) * BI */
2633 bnctx
= BN_CTX_new();
2637 if (!bnctx
|| !sum
|| !q
|| !lx
)
2639 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2642 BI_point
= EC_KEY_get0_public_key(BI
);
2643 group
= EC_KEY_get0_group(BI
);
2647 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2648 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2651 bR_bn
= EC_KEY_get0_private_key(bR
);
2652 pR_bn
= EC_KEY_get0_private_key(pR
);
2653 if (!bR_bn
|| !pR_bn
)
2655 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2656 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2658 l
= EC_POINT_new(group
);
2660 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2661 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2663 wpa_printf(MSG_ERROR
,
2664 "OpenSSL: failed: %s",
2665 ERR_error_string(ERR_get_error(), NULL
));
2669 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2671 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2672 auth
->Lx_len
= auth
->secret_len
;
2675 EC_POINT_clear_free(l
);
2687 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2689 const EC_GROUP
*group
;
2690 EC_POINT
*l
= NULL
, *sum
= NULL
;
2691 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2692 const EC_POINT
*BR_point
, *PR_point
;
2695 const BIGNUM
*bI_bn
;
2698 /* L = bI * (BR + PR) */
2700 bnctx
= BN_CTX_new();
2704 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2705 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2708 BR_point
= EC_KEY_get0_public_key(BR
);
2709 PR_point
= EC_KEY_get0_public_key(PR
);
2711 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2714 group
= EC_KEY_get0_group(bI
);
2715 bI_bn
= EC_KEY_get0_private_key(bI
);
2716 if (!group
|| !bI_bn
)
2718 sum
= EC_POINT_new(group
);
2719 l
= EC_POINT_new(group
);
2721 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2722 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2723 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2725 wpa_printf(MSG_ERROR
,
2726 "OpenSSL: failed: %s",
2727 ERR_error_string(ERR_get_error(), NULL
));
2731 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2733 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2734 auth
->Lx_len
= auth
->secret_len
;
2737 EC_POINT_clear_free(l
);
2738 EC_POINT_clear_free(sum
);
2748 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2751 EVP_PKEY_CTX
*ctx
= NULL
;
2753 struct wpabuf
*msg
, *pr
= NULL
;
2754 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2755 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2756 size_t wrapped_r_auth_len
;
2758 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2759 enum dpp_status_error status
= DPP_STATUS_OK
;
2760 #ifdef CONFIG_TESTING_OPTIONS
2761 u8 test_hash
[SHA256_MAC_LEN
];
2762 #endif /* CONFIG_TESTING_OPTIONS */
2764 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2768 #ifdef CONFIG_TESTING_OPTIONS
2769 if (dpp_nonce_override_len
> 0) {
2770 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2771 nonce_len
= dpp_nonce_override_len
;
2772 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2774 nonce_len
= auth
->curve
->nonce_len
;
2775 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2776 wpa_printf(MSG_ERROR
,
2777 "DPP: Failed to generate R-nonce");
2781 #else /* CONFIG_TESTING_OPTIONS */
2782 nonce_len
= auth
->curve
->nonce_len
;
2783 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2784 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2787 #endif /* CONFIG_TESTING_OPTIONS */
2788 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2790 #ifdef CONFIG_TESTING_OPTIONS
2791 if (dpp_protocol_key_override_len
) {
2792 const struct dpp_curve_params
*tmp_curve
;
2794 wpa_printf(MSG_INFO
,
2795 "DPP: TESTING - override protocol key");
2796 auth
->own_protocol_key
= dpp_set_keypair(
2797 &tmp_curve
, dpp_protocol_key_override
,
2798 dpp_protocol_key_override_len
);
2800 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2802 #else /* CONFIG_TESTING_OPTIONS */
2803 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2804 #endif /* CONFIG_TESTING_OPTIONS */
2805 if (!auth
->own_protocol_key
)
2808 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2812 /* ECDH: N = pR * PI */
2813 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
2815 EVP_PKEY_derive_init(ctx
) != 1 ||
2816 EVP_PKEY_derive_set_peer(ctx
, auth
->peer_protocol_key
) != 1 ||
2817 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
2818 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
2819 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
2820 wpa_printf(MSG_ERROR
,
2821 "DPP: Failed to derive ECDH shared secret: %s",
2822 ERR_error_string(ERR_get_error(), NULL
));
2825 EVP_PKEY_CTX_free(ctx
);
2828 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2829 auth
->Nx
, auth
->secret_len
);
2830 auth
->Nx_len
= auth
->secret_len
;
2832 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2833 auth
->curve
->hash_len
) < 0)
2836 if (auth
->own_bi
&& auth
->peer_bi
) {
2837 /* Mutual authentication */
2838 if (dpp_auth_derive_l_responder(auth
) < 0)
2842 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2845 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2846 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2847 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2848 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2850 #ifdef CONFIG_TESTING_OPTIONS
2851 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
2852 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
2853 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
2855 #endif /* CONFIG_TESTING_OPTIONS */
2856 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2857 r_auth
, 4 + auth
->curve
->hash_len
,
2858 0, NULL
, NULL
, wrapped_r_auth
) < 0)
2860 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
2861 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
2862 wrapped_r_auth
, wrapped_r_auth_len
);
2863 w_r_auth
= wrapped_r_auth
;
2865 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2867 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2869 i_pubkey_hash
= NULL
;
2871 i_nonce
= auth
->i_nonce
;
2872 r_nonce
= auth
->r_nonce
;
2874 #ifdef CONFIG_TESTING_OPTIONS
2875 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2876 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2877 r_pubkey_hash
= NULL
;
2878 } else if (dpp_test
==
2879 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2880 wpa_printf(MSG_INFO
,
2881 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2882 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2883 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2884 r_pubkey_hash
= test_hash
;
2885 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2886 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2887 i_pubkey_hash
= NULL
;
2888 } else if (dpp_test
==
2889 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2890 wpa_printf(MSG_INFO
,
2891 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2893 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2895 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2896 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2897 i_pubkey_hash
= test_hash
;
2898 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
2899 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
2902 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
2903 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
2905 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2906 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
2908 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
2909 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
2911 wrapped_r_auth_len
= 0;
2912 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2913 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2915 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
2916 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
2918 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
2919 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
2921 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2922 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2925 #endif /* CONFIG_TESTING_OPTIONS */
2927 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
2928 r_pubkey_hash
, i_pubkey_hash
,
2930 w_r_auth
, wrapped_r_auth_len
,
2934 wpabuf_free(auth
->resp_msg
);
2935 auth
->resp_msg
= msg
;
2943 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
2944 enum dpp_status_error status
)
2947 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
2948 #ifdef CONFIG_TESTING_OPTIONS
2949 u8 test_hash
[SHA256_MAC_LEN
];
2950 #endif /* CONFIG_TESTING_OPTIONS */
2954 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2956 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2958 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2960 i_pubkey_hash
= NULL
;
2962 i_nonce
= auth
->i_nonce
;
2964 #ifdef CONFIG_TESTING_OPTIONS
2965 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2966 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2967 r_pubkey_hash
= NULL
;
2968 } else if (dpp_test
==
2969 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2970 wpa_printf(MSG_INFO
,
2971 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2972 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2973 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2974 r_pubkey_hash
= test_hash
;
2975 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2976 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2977 i_pubkey_hash
= NULL
;
2978 } else if (dpp_test
==
2979 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
2980 wpa_printf(MSG_INFO
,
2981 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2983 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2985 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
2986 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2987 i_pubkey_hash
= test_hash
;
2988 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
2989 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
2991 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
2992 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
2995 #endif /* CONFIG_TESTING_OPTIONS */
2997 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
2998 r_pubkey_hash
, i_pubkey_hash
,
2999 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3002 wpabuf_free(auth
->resp_msg
);
3003 auth
->resp_msg
= msg
;
3008 struct dpp_authentication
*
3009 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3010 struct dpp_bootstrap_info
*peer_bi
,
3011 struct dpp_bootstrap_info
*own_bi
,
3012 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3015 EVP_PKEY
*pi
= NULL
;
3016 EVP_PKEY_CTX
*ctx
= NULL
;
3020 u8
*unwrapped
= NULL
;
3021 size_t unwrapped_len
= 0;
3022 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3024 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3025 i_bootstrap_len
, channel_len
;
3026 struct dpp_authentication
*auth
= NULL
;
3030 #endif /* CONFIG_DPP2 */
3032 #ifdef CONFIG_TESTING_OPTIONS
3033 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3034 wpa_printf(MSG_INFO
,
3035 "DPP: TESTING - stop at Authentication Request");
3038 #endif /* CONFIG_TESTING_OPTIONS */
3040 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3042 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3043 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3044 "Missing or invalid required Wrapped Data attribute");
3047 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3048 wrapped_data
, wrapped_data_len
);
3049 attr_len
= wrapped_data
- 4 - attr_start
;
3051 auth
= os_zalloc(sizeof(*auth
));
3054 auth
->msg_ctx
= msg_ctx
;
3055 auth
->peer_bi
= peer_bi
;
3056 auth
->own_bi
= own_bi
;
3057 auth
->curve
= own_bi
->curve
;
3058 auth
->curr_freq
= freq
;
3060 auth
->peer_version
= 1; /* default to the first version */
3062 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3065 if (version_len
< 1 || version
[0] == 0) {
3067 "Invalid Protocol Version attribute");
3070 auth
->peer_version
= version
[0];
3071 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3072 auth
->peer_version
);
3074 #endif /* CONFIG_DPP2 */
3076 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3081 if (channel_len
< 2) {
3082 dpp_auth_fail(auth
, "Too short Channel attribute");
3086 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3087 wpa_printf(MSG_DEBUG
,
3088 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3089 channel
[0], channel
[1], neg_freq
);
3092 "Unsupported Channel attribute value");
3096 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3097 wpa_printf(MSG_DEBUG
,
3098 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3100 auth
->curr_freq
= neg_freq
;
3104 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3108 "Missing required Initiator Protocol Key attribute");
3111 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3112 i_proto
, i_proto_len
);
3115 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3117 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3120 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3122 ctx
= EVP_PKEY_CTX_new(own_bi
->pubkey
, NULL
);
3124 EVP_PKEY_derive_init(ctx
) != 1 ||
3125 EVP_PKEY_derive_set_peer(ctx
, pi
) != 1 ||
3126 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3127 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3128 EVP_PKEY_derive(ctx
, auth
->Mx
, &secret_len
) != 1) {
3129 wpa_printf(MSG_ERROR
,
3130 "DPP: Failed to derive ECDH shared secret: %s",
3131 ERR_error_string(ERR_get_error(), NULL
));
3132 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3135 auth
->secret_len
= secret_len
;
3136 EVP_PKEY_CTX_free(ctx
);
3139 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3140 auth
->Mx
, auth
->secret_len
);
3141 auth
->Mx_len
= auth
->secret_len
;
3143 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3144 auth
->curve
->hash_len
) < 0)
3148 len
[0] = DPP_HDR_LEN
;
3149 addr
[1] = attr_start
;
3151 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3152 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3153 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3154 wrapped_data
, wrapped_data_len
);
3155 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3156 unwrapped
= os_malloc(unwrapped_len
);
3159 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3160 wrapped_data
, wrapped_data_len
,
3161 2, addr
, len
, unwrapped
) < 0) {
3162 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3165 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3166 unwrapped
, unwrapped_len
);
3168 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3169 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3173 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3175 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3176 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3179 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3180 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3182 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3183 DPP_ATTR_I_CAPABILITIES
,
3185 if (!i_capab
|| i_capab_len
< 1) {
3186 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3189 auth
->i_capab
= i_capab
[0];
3190 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3192 bin_clear_free(unwrapped
, unwrapped_len
);
3195 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3196 case DPP_CAPAB_ENROLLEE
:
3197 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3198 wpa_printf(MSG_DEBUG
,
3199 "DPP: Local policy does not allow Configurator role");
3200 goto not_compatible
;
3202 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3203 auth
->configurator
= 1;
3205 case DPP_CAPAB_CONFIGURATOR
:
3206 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3207 wpa_printf(MSG_DEBUG
,
3208 "DPP: Local policy does not allow Enrollee role");
3209 goto not_compatible
;
3211 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3212 auth
->configurator
= 0;
3214 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3215 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3216 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3217 auth
->configurator
= 0;
3218 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3219 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3220 auth
->configurator
= 1;
3222 wpa_printf(MSG_DEBUG
,
3223 "DPP: Local policy does not allow Configurator/Enrollee role");
3224 goto not_compatible
;
3228 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3229 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3230 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3231 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3235 auth
->peer_protocol_key
= pi
;
3237 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3238 char hex
[SHA256_MAC_LEN
* 2 + 1];
3240 wpa_printf(MSG_DEBUG
,
3241 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3242 if (dpp_auth_build_resp_status(auth
,
3243 DPP_STATUS_RESPONSE_PENDING
) < 0)
3245 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3246 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3248 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3249 auth
->response_pending
= 1;
3250 os_memcpy(auth
->waiting_pubkey_hash
,
3251 i_bootstrap
, i_bootstrap_len
);
3252 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3258 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3262 if (dpp_auth_build_resp_ok(auth
) < 0)
3268 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3269 "i-capab=0x%02x", auth
->i_capab
);
3270 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3271 auth
->configurator
= 1;
3273 auth
->configurator
= 0;
3274 auth
->peer_protocol_key
= pi
;
3276 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3279 auth
->remove_on_tx_status
= 1;
3282 bin_clear_free(unwrapped
, unwrapped_len
);
3284 EVP_PKEY_CTX_free(ctx
);
3285 dpp_auth_deinit(auth
);
3290 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3291 struct dpp_bootstrap_info
*peer_bi
)
3293 if (!auth
|| !auth
->response_pending
||
3294 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3295 SHA256_MAC_LEN
) != 0)
3298 wpa_printf(MSG_DEBUG
,
3299 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3300 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3301 auth
->peer_bi
= peer_bi
;
3303 if (dpp_auth_build_resp_ok(auth
) < 0)
3310 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3311 enum dpp_status_error status
)
3314 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3316 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3319 size_t len
[2], attr_len
;
3321 u8
*wrapped_r_nonce
;
3322 u8
*attr_start
, *attr_end
;
3323 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3324 #ifdef CONFIG_TESTING_OPTIONS
3325 u8 test_hash
[SHA256_MAC_LEN
];
3326 #endif /* CONFIG_TESTING_OPTIONS */
3328 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3330 i_auth_len
= 4 + auth
->curve
->hash_len
;
3331 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3332 /* Build DPP Authentication Confirmation frame attributes */
3333 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3334 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3335 #ifdef CONFIG_TESTING_OPTIONS
3336 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3338 #endif /* CONFIG_TESTING_OPTIONS */
3339 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3343 attr_start
= wpabuf_put(msg
, 0);
3345 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3347 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3349 i_pubkey_hash
= NULL
;
3351 #ifdef CONFIG_TESTING_OPTIONS
3352 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3353 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3355 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3356 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3359 #endif /* CONFIG_TESTING_OPTIONS */
3362 dpp_build_attr_status(msg
, status
);
3364 #ifdef CONFIG_TESTING_OPTIONS
3366 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3367 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3368 r_pubkey_hash
= NULL
;
3369 } else if (dpp_test
==
3370 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3371 wpa_printf(MSG_INFO
,
3372 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3373 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3374 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3375 r_pubkey_hash
= test_hash
;
3376 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3377 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3378 i_pubkey_hash
= NULL
;
3379 } else if (dpp_test
==
3380 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3381 wpa_printf(MSG_INFO
,
3382 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3384 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3386 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3387 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3388 i_pubkey_hash
= test_hash
;
3390 #endif /* CONFIG_TESTING_OPTIONS */
3392 /* Responder Bootstrapping Key Hash */
3393 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3395 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3396 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3398 #ifdef CONFIG_TESTING_OPTIONS
3399 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3400 goto skip_wrapped_data
;
3401 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3403 #endif /* CONFIG_TESTING_OPTIONS */
3405 attr_end
= wpabuf_put(msg
, 0);
3407 /* OUI, OUI type, Crypto Suite, DPP frame type */
3408 addr
[0] = wpabuf_head_u8(msg
) + 2;
3409 len
[0] = 3 + 1 + 1 + 1;
3410 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3412 /* Attributes before Wrapped Data */
3413 addr
[1] = attr_start
;
3414 len
[1] = attr_end
- attr_start
;
3415 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3417 if (status
== DPP_STATUS_OK
) {
3418 /* I-auth wrapped with ke */
3419 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3420 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3421 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3423 #ifdef CONFIG_TESTING_OPTIONS
3424 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3426 #endif /* CONFIG_TESTING_OPTIONS */
3428 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3430 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3431 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3432 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3435 #ifdef CONFIG_TESTING_OPTIONS
3436 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3437 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3438 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3441 #endif /* CONFIG_TESTING_OPTIONS */
3442 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3444 2, addr
, len
, wrapped_i_auth
) < 0)
3446 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3447 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3449 /* R-nonce wrapped with k2 */
3450 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3451 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3452 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3454 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3455 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3456 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3458 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3459 r_nonce
, r_nonce_len
,
3460 2, addr
, len
, wrapped_r_nonce
) < 0)
3462 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3463 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3466 #ifdef CONFIG_TESTING_OPTIONS
3467 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3468 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3469 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3472 #endif /* CONFIG_TESTING_OPTIONS */
3474 wpa_hexdump_buf(MSG_DEBUG
,
3475 "DPP: Authentication Confirmation frame attributes",
3477 if (status
== DPP_STATUS_OK
)
3478 dpp_auth_success(auth
);
3489 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3490 const u8
*attr_start
, size_t attr_len
,
3491 const u8
*wrapped_data
, u16 wrapped_data_len
,
3492 enum dpp_status_error status
)
3496 u8
*unwrapped
= NULL
;
3497 size_t unwrapped_len
= 0;
3498 const u8
*i_nonce
, *r_capab
;
3499 u16 i_nonce_len
, r_capab_len
;
3501 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3502 wpa_printf(MSG_DEBUG
,
3503 "DPP: Responder reported incompatible roles");
3504 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3505 wpa_printf(MSG_DEBUG
,
3506 "DPP: Responder reported more time needed");
3508 wpa_printf(MSG_DEBUG
,
3509 "DPP: Responder reported failure (status %d)",
3511 dpp_auth_fail(auth
, "Responder reported failure");
3516 len
[0] = DPP_HDR_LEN
;
3517 addr
[1] = attr_start
;
3519 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3520 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3521 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3522 wrapped_data
, wrapped_data_len
);
3523 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3524 unwrapped
= os_malloc(unwrapped_len
);
3527 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3528 wrapped_data
, wrapped_data_len
,
3529 2, addr
, len
, unwrapped
) < 0) {
3530 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3533 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3534 unwrapped
, unwrapped_len
);
3536 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3537 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3541 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3543 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3544 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3547 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3548 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3549 dpp_auth_fail(auth
, "I-nonce mismatch");
3553 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3554 DPP_ATTR_R_CAPABILITIES
,
3556 if (!r_capab
|| r_capab_len
< 1) {
3557 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3560 auth
->r_capab
= r_capab
[0];
3561 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3562 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3563 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3564 "r-capab=0x%02x", auth
->r_capab
);
3565 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3566 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3568 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3569 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3570 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3571 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3574 wpa_printf(MSG_DEBUG
,
3575 "DPP: Continue waiting for full DPP Authentication Response");
3576 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3577 DPP_EVENT_RESPONSE_PENDING
"%s",
3578 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3582 bin_clear_free(unwrapped
, unwrapped_len
);
3587 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3588 const u8
*attr_start
, size_t attr_len
)
3591 EVP_PKEY_CTX
*ctx
= NULL
;
3595 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3596 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3597 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3598 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3599 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3600 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3601 wrapped2_len
, r_auth_len
;
3602 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3607 #endif /* CONFIG_DPP2 */
3609 #ifdef CONFIG_TESTING_OPTIONS
3610 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3611 wpa_printf(MSG_INFO
,
3612 "DPP: TESTING - stop at Authentication Response");
3615 #endif /* CONFIG_TESTING_OPTIONS */
3617 if (!auth
->initiator
|| !auth
->peer_bi
) {
3618 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3622 auth
->waiting_auth_resp
= 0;
3624 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3626 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3628 "Missing or invalid required Wrapped Data attribute");
3631 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3632 wrapped_data
, wrapped_data_len
);
3634 attr_len
= wrapped_data
- 4 - attr_start
;
3636 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3637 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3639 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3641 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3644 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3645 r_bootstrap
, r_bootstrap_len
);
3646 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3647 SHA256_MAC_LEN
) != 0) {
3649 "Unexpected Responder Bootstrapping Key Hash value");
3650 wpa_hexdump(MSG_DEBUG
,
3651 "DPP: Expected Responder Bootstrapping Key Hash",
3652 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3656 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3657 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3660 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3662 "Invalid Initiator Bootstrapping Key Hash attribute");
3665 wpa_hexdump(MSG_MSGDUMP
,
3666 "DPP: Initiator Bootstrapping Key Hash",
3667 i_bootstrap
, i_bootstrap_len
);
3668 if (!auth
->own_bi
||
3669 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3670 SHA256_MAC_LEN
) != 0) {
3672 "Initiator Bootstrapping Key Hash attribute did not match");
3675 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3676 /* PKEX bootstrapping mandates use of mutual authentication */
3678 "Missing Initiator Bootstrapping Key Hash attribute");
3682 auth
->peer_version
= 1; /* default to the first version */
3684 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3687 if (version_len
< 1 || version
[0] == 0) {
3689 "Invalid Protocol Version attribute");
3692 auth
->peer_version
= version
[0];
3693 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3694 auth
->peer_version
);
3696 #endif /* CONFIG_DPP2 */
3698 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3700 if (!status
|| status_len
< 1) {
3702 "Missing or invalid required DPP Status attribute");
3705 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3706 auth
->auth_resp_status
= status
[0];
3707 if (status
[0] != DPP_STATUS_OK
) {
3708 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3709 attr_len
, wrapped_data
,
3710 wrapped_data_len
, status
[0]);
3714 if (!i_bootstrap
&& auth
->own_bi
) {
3715 wpa_printf(MSG_DEBUG
,
3716 "DPP: Responder decided not to use mutual authentication");
3717 auth
->own_bi
= NULL
;
3720 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3721 auth
->own_bi
!= NULL
);
3723 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3727 "Missing required Responder Protocol Key attribute");
3730 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3731 r_proto
, r_proto_len
);
3734 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3736 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3739 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3741 ctx
= EVP_PKEY_CTX_new(auth
->own_protocol_key
, NULL
);
3743 EVP_PKEY_derive_init(ctx
) != 1 ||
3744 EVP_PKEY_derive_set_peer(ctx
, pr
) != 1 ||
3745 EVP_PKEY_derive(ctx
, NULL
, &secret_len
) != 1 ||
3746 secret_len
> DPP_MAX_SHARED_SECRET_LEN
||
3747 EVP_PKEY_derive(ctx
, auth
->Nx
, &secret_len
) != 1) {
3748 wpa_printf(MSG_ERROR
,
3749 "DPP: Failed to derive ECDH shared secret: %s",
3750 ERR_error_string(ERR_get_error(), NULL
));
3751 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3754 EVP_PKEY_CTX_free(ctx
);
3756 auth
->peer_protocol_key
= pr
;
3759 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3760 auth
->Nx
, auth
->secret_len
);
3761 auth
->Nx_len
= auth
->secret_len
;
3763 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3764 auth
->curve
->hash_len
) < 0)
3768 len
[0] = DPP_HDR_LEN
;
3769 addr
[1] = attr_start
;
3771 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3772 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3773 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3774 wrapped_data
, wrapped_data_len
);
3775 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3776 unwrapped
= os_malloc(unwrapped_len
);
3779 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3780 wrapped_data
, wrapped_data_len
,
3781 2, addr
, len
, unwrapped
) < 0) {
3782 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3785 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3786 unwrapped
, unwrapped_len
);
3788 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3789 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3793 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3795 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3796 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3799 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3800 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3802 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3804 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3805 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3808 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3809 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3810 dpp_auth_fail(auth
, "I-nonce mismatch");
3815 /* Mutual authentication */
3816 if (dpp_auth_derive_l_initiator(auth
) < 0)
3820 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3821 DPP_ATTR_R_CAPABILITIES
,
3823 if (!r_capab
|| r_capab_len
< 1) {
3824 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3827 auth
->r_capab
= r_capab
[0];
3828 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3829 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3830 if ((auth
->allowed_roles
==
3831 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3832 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3833 /* Peer selected its role, so move from "either role" to the
3834 * role that is compatible with peer's selection. */
3835 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3836 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3837 auth
->configurator
? "Configurator" : "Enrollee");
3838 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3839 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3840 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3841 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3842 "Unexpected role in R-capabilities 0x%02x",
3844 if (role
!= DPP_CAPAB_ENROLLEE
&&
3845 role
!= DPP_CAPAB_CONFIGURATOR
)
3847 bin_clear_free(unwrapped
, unwrapped_len
);
3848 auth
->remove_on_tx_status
= 1;
3849 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3852 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3853 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3854 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3856 "Missing or invalid Secondary Wrapped Data");
3860 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3861 wrapped2
, wrapped2_len
);
3863 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3866 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3867 unwrapped2
= os_malloc(unwrapped2_len
);
3870 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3871 wrapped2
, wrapped2_len
,
3872 0, NULL
, NULL
, unwrapped2
) < 0) {
3873 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3876 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3877 unwrapped2
, unwrapped2_len
);
3879 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
3881 "Invalid attribute in secondary unwrapped data");
3885 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
3887 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
3889 "Missing or invalid Responder Authenticating Tag");
3892 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
3893 r_auth
, r_auth_len
);
3894 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3895 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
3897 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
3898 r_auth2
, r_auth_len
);
3899 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
3900 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
3901 bin_clear_free(unwrapped
, unwrapped_len
);
3902 bin_clear_free(unwrapped2
, unwrapped2_len
);
3903 auth
->remove_on_tx_status
= 1;
3904 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
3907 bin_clear_free(unwrapped
, unwrapped_len
);
3908 bin_clear_free(unwrapped2
, unwrapped2_len
);
3910 #ifdef CONFIG_TESTING_OPTIONS
3911 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
3912 wpa_printf(MSG_INFO
,
3913 "DPP: TESTING - Authentication Response in place of Confirm");
3914 if (dpp_auth_build_resp_ok(auth
) < 0)
3916 return wpabuf_dup(auth
->resp_msg
);
3918 #endif /* CONFIG_TESTING_OPTIONS */
3920 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
3923 bin_clear_free(unwrapped
, unwrapped_len
);
3924 bin_clear_free(unwrapped2
, unwrapped2_len
);
3926 EVP_PKEY_CTX_free(ctx
);
3931 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
3933 const u8
*attr_start
, size_t attr_len
,
3934 const u8
*wrapped_data
,
3935 u16 wrapped_data_len
,
3936 enum dpp_status_error status
)
3940 u8
*unwrapped
= NULL
;
3941 size_t unwrapped_len
= 0;
3945 /* Authentication Confirm failure cases are expected to include
3946 * {R-nonce}k2 in the Wrapped Data attribute. */
3949 len
[0] = DPP_HDR_LEN
;
3950 addr
[1] = attr_start
;
3952 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3953 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3954 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3955 wrapped_data
, wrapped_data_len
);
3956 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3957 unwrapped
= os_malloc(unwrapped_len
);
3959 dpp_auth_fail(auth
, "Authentication failed");
3962 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3963 wrapped_data
, wrapped_data_len
,
3964 2, addr
, len
, unwrapped
) < 0) {
3965 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3968 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3969 unwrapped
, unwrapped_len
);
3971 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3972 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3976 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3978 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3979 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3982 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
3983 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
3984 r_nonce
, r_nonce_len
);
3985 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
3986 auth
->r_nonce
, r_nonce_len
);
3987 dpp_auth_fail(auth
, "R-nonce mismatch");
3991 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
3992 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
3993 else if (status
== DPP_STATUS_AUTH_FAILURE
)
3994 dpp_auth_fail(auth
, "Peer reported authentication failure)");
3997 bin_clear_free(unwrapped
, unwrapped_len
);
4002 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4003 const u8
*attr_start
, size_t attr_len
)
4005 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4006 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4010 u8
*unwrapped
= NULL
;
4011 size_t unwrapped_len
= 0;
4012 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4014 #ifdef CONFIG_TESTING_OPTIONS
4015 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4016 wpa_printf(MSG_INFO
,
4017 "DPP: TESTING - stop at Authentication Confirm");
4020 #endif /* CONFIG_TESTING_OPTIONS */
4022 if (auth
->initiator
|| !auth
->own_bi
) {
4023 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4027 auth
->waiting_auth_conf
= 0;
4029 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4031 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4033 "Missing or invalid required Wrapped Data attribute");
4036 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4037 wrapped_data
, wrapped_data_len
);
4039 attr_len
= wrapped_data
- 4 - attr_start
;
4041 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4042 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4044 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4046 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4049 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4050 r_bootstrap
, r_bootstrap_len
);
4051 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4052 SHA256_MAC_LEN
) != 0) {
4053 wpa_hexdump(MSG_DEBUG
,
4054 "DPP: Expected Responder Bootstrapping Key Hash",
4055 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4057 "Responder Bootstrapping Key Hash mismatch");
4061 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4062 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4065 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4067 "Invalid Initiator Bootstrapping Key Hash attribute");
4070 wpa_hexdump(MSG_MSGDUMP
,
4071 "DPP: Initiator Bootstrapping Key Hash",
4072 i_bootstrap
, i_bootstrap_len
);
4073 if (!auth
->peer_bi
||
4074 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4075 SHA256_MAC_LEN
) != 0) {
4077 "Initiator Bootstrapping Key Hash mismatch");
4080 } else if (auth
->peer_bi
) {
4081 /* Mutual authentication and peer did not include its
4082 * Bootstrapping Key Hash attribute. */
4084 "Missing Initiator Bootstrapping Key Hash attribute");
4088 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4090 if (!status
|| status_len
< 1) {
4092 "Missing or invalid required DPP Status attribute");
4095 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4096 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4097 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4098 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4099 attr_len
, wrapped_data
,
4100 wrapped_data_len
, status
[0]);
4102 if (status
[0] != DPP_STATUS_OK
) {
4103 dpp_auth_fail(auth
, "Authentication failed");
4108 len
[0] = DPP_HDR_LEN
;
4109 addr
[1] = attr_start
;
4111 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4112 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4113 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4114 wrapped_data
, wrapped_data_len
);
4115 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4116 unwrapped
= os_malloc(unwrapped_len
);
4119 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4120 wrapped_data
, wrapped_data_len
,
4121 2, addr
, len
, unwrapped
) < 0) {
4122 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4125 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4126 unwrapped
, unwrapped_len
);
4128 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4129 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4133 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4135 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4137 "Missing or invalid Initiator Authenticating Tag");
4140 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4141 i_auth
, i_auth_len
);
4142 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4143 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4145 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4146 i_auth2
, i_auth_len
);
4147 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4148 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4152 bin_clear_free(unwrapped
, unwrapped_len
);
4153 dpp_auth_success(auth
);
4156 bin_clear_free(unwrapped
, unwrapped_len
);
4161 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4163 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4167 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4169 struct dpp_configuration
*conf
;
4173 conf
= os_zalloc(sizeof(*conf
));
4177 end
= os_strchr(type
, ' ');
4181 len
= os_strlen(type
);
4183 if (bin_str_eq(type
, len
, "psk"))
4184 conf
->akm
= DPP_AKM_PSK
;
4185 else if (bin_str_eq(type
, len
, "sae"))
4186 conf
->akm
= DPP_AKM_SAE
;
4187 else if (bin_str_eq(type
, len
, "psk-sae") ||
4188 bin_str_eq(type
, len
, "psk+sae"))
4189 conf
->akm
= DPP_AKM_PSK_SAE
;
4190 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4191 bin_str_eq(type
, len
, "dpp+sae"))
4192 conf
->akm
= DPP_AKM_SAE_DPP
;
4193 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4194 bin_str_eq(type
, len
, "dpp+psk+sae"))
4195 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4196 else if (bin_str_eq(type
, len
, "dpp"))
4197 conf
->akm
= DPP_AKM_DPP
;
4203 dpp_configuration_free(conf
);
4208 int dpp_akm_psk(enum dpp_akm akm
)
4210 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4211 akm
== DPP_AKM_PSK_SAE_DPP
;
4215 int dpp_akm_sae(enum dpp_akm akm
)
4217 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4218 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4222 int dpp_akm_legacy(enum dpp_akm akm
)
4224 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4229 int dpp_akm_dpp(enum dpp_akm akm
)
4231 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4232 akm
== DPP_AKM_PSK_SAE_DPP
;
4236 int dpp_akm_ver2(enum dpp_akm akm
)
4238 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4242 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4244 if (conf
->ssid_len
== 0)
4246 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4248 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4254 void dpp_configuration_free(struct dpp_configuration
*conf
)
4258 str_clear_free(conf
->passphrase
);
4259 os_free(conf
->group_id
);
4260 bin_clear_free(conf
, sizeof(*conf
));
4264 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4267 const char *pos
, *end
;
4268 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4269 struct dpp_configuration
*conf
= NULL
;
4271 pos
= os_strstr(cmd
, " conf=sta-");
4273 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4279 pos
= os_strstr(cmd
, " conf=ap-");
4281 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4290 pos
= os_strstr(cmd
, " ssid=");
4293 end
= os_strchr(pos
, ' ');
4294 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4295 conf
->ssid_len
/= 2;
4296 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4297 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4300 #ifdef CONFIG_TESTING_OPTIONS
4301 /* use a default SSID for legacy testing reasons */
4302 os_memcpy(conf
->ssid
, "test", 4);
4304 #else /* CONFIG_TESTING_OPTIONS */
4306 #endif /* CONFIG_TESTING_OPTIONS */
4309 pos
= os_strstr(cmd
, " pass=");
4314 end
= os_strchr(pos
, ' ');
4315 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4317 if (pass_len
> 63 || pass_len
< 8)
4319 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4320 if (!conf
->passphrase
||
4321 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4325 pos
= os_strstr(cmd
, " psk=");
4328 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4333 pos
= os_strstr(cmd
, " group_id=");
4335 size_t group_id_len
;
4338 end
= os_strchr(pos
, ' ');
4339 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4340 conf
->group_id
= os_malloc(group_id_len
+ 1);
4341 if (!conf
->group_id
)
4343 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4344 conf
->group_id
[group_id_len
] = '\0';
4347 pos
= os_strstr(cmd
, " expiry=");
4352 val
= strtol(pos
, NULL
, 0);
4355 conf
->netaccesskey_expiry
= val
;
4358 if (!dpp_configuration_valid(conf
))
4361 auth
->conf_sta
= conf_sta
;
4362 auth
->conf_ap
= conf_ap
;
4366 dpp_configuration_free(conf_sta
);
4367 dpp_configuration_free(conf_ap
);
4372 static struct dpp_configurator
*
4373 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4375 struct dpp_configurator
*conf
;
4380 dl_list_for_each(conf
, &dpp
->configurator
,
4381 struct dpp_configurator
, list
) {
4389 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4390 struct dpp_authentication
*auth
,
4398 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4400 pos
= os_strstr(cmd
, " configurator=");
4403 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4405 wpa_printf(MSG_INFO
,
4406 "DPP: Could not find the specified configurator");
4411 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4412 wpa_msg(msg_ctx
, MSG_INFO
,
4413 "DPP: Failed to set configurator parameters");
4420 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4424 dpp_configuration_free(auth
->conf_ap
);
4425 dpp_configuration_free(auth
->conf_sta
);
4426 EVP_PKEY_free(auth
->own_protocol_key
);
4427 EVP_PKEY_free(auth
->peer_protocol_key
);
4428 wpabuf_free(auth
->req_msg
);
4429 wpabuf_free(auth
->resp_msg
);
4430 wpabuf_free(auth
->conf_req
);
4431 os_free(auth
->connector
);
4432 wpabuf_free(auth
->net_access_key
);
4433 wpabuf_free(auth
->c_sign_key
);
4434 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4435 #ifdef CONFIG_TESTING_OPTIONS
4436 os_free(auth
->config_obj_override
);
4437 os_free(auth
->discovery_override
);
4438 os_free(auth
->groups_override
);
4439 #endif /* CONFIG_TESTING_OPTIONS */
4440 bin_clear_free(auth
, sizeof(*auth
));
4444 static struct wpabuf
*
4445 dpp_build_conf_start(struct dpp_authentication
*auth
,
4446 struct dpp_configuration
*conf
, size_t tailroom
)
4449 char ssid
[6 * sizeof(conf
->ssid
) + 1];
4451 #ifdef CONFIG_TESTING_OPTIONS
4452 if (auth
->discovery_override
)
4453 tailroom
+= os_strlen(auth
->discovery_override
);
4454 #endif /* CONFIG_TESTING_OPTIONS */
4456 buf
= wpabuf_alloc(200 + tailroom
);
4459 wpabuf_put_str(buf
, "{\"wi-fi_tech\":\"infra\",\"discovery\":");
4460 #ifdef CONFIG_TESTING_OPTIONS
4461 if (auth
->discovery_override
) {
4462 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4463 auth
->discovery_override
);
4464 wpabuf_put_str(buf
, auth
->discovery_override
);
4465 wpabuf_put_u8(buf
, ',');
4468 #endif /* CONFIG_TESTING_OPTIONS */
4469 wpabuf_put_str(buf
, "{\"ssid\":\"");
4470 json_escape_string(ssid
, sizeof(ssid
),
4471 (const char *) conf
->ssid
, conf
->ssid_len
);
4472 wpabuf_put_str(buf
, ssid
);
4473 wpabuf_put_str(buf
, "\"},");
4479 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4480 const char *kid
, const struct dpp_curve_params
*curve
)
4484 char *x
= NULL
, *y
= NULL
;
4487 pub
= dpp_get_pubkey_point(key
, 0);
4490 pos
= wpabuf_head(pub
);
4491 x
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4492 pos
+= curve
->prime_len
;
4493 y
= (char *) base64_url_encode(pos
, curve
->prime_len
, NULL
, 0);
4497 wpabuf_put_str(buf
, "\"");
4498 wpabuf_put_str(buf
, name
);
4499 wpabuf_put_str(buf
, "\":{\"kty\":\"EC\",\"crv\":\"");
4500 wpabuf_put_str(buf
, curve
->jwk_crv
);
4501 wpabuf_put_str(buf
, "\",\"x\":\"");
4502 wpabuf_put_str(buf
, x
);
4503 wpabuf_put_str(buf
, "\",\"y\":\"");
4504 wpabuf_put_str(buf
, y
);
4506 wpabuf_put_str(buf
, "\",\"kid\":\"");
4507 wpabuf_put_str(buf
, kid
);
4509 wpabuf_put_str(buf
, "\"}");
4519 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4520 struct dpp_configuration
*conf
)
4522 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4523 char pass
[63 * 6 + 1];
4525 json_escape_string(pass
, sizeof(pass
), conf
->passphrase
,
4526 os_strlen(conf
->passphrase
));
4527 wpabuf_put_str(buf
, "\"pass\":\"");
4528 wpabuf_put_str(buf
, pass
);
4529 wpabuf_put_str(buf
, "\"");
4530 os_memset(pass
, 0, sizeof(pass
));
4531 } else if (conf
->psk_set
) {
4532 char psk
[2 * sizeof(conf
->psk
) + 1];
4534 wpa_snprintf_hex(psk
, sizeof(psk
),
4535 conf
->psk
, sizeof(conf
->psk
));
4536 wpabuf_put_str(buf
, "\"psk_hex\":\"");
4537 wpabuf_put_str(buf
, psk
);
4538 wpabuf_put_str(buf
, "\"");
4539 os_memset(psk
, 0, sizeof(psk
));
4544 static struct wpabuf
*
4545 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
, int ap
,
4546 struct dpp_configuration
*conf
)
4548 struct wpabuf
*buf
= NULL
;
4549 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4551 const struct dpp_curve_params
*curve
;
4552 char jws_prot_hdr
[100];
4553 size_t signed1_len
, signed2_len
, signed3_len
;
4554 struct wpabuf
*dppcon
= NULL
;
4555 unsigned char *signature
= NULL
;
4556 const unsigned char *p
;
4557 size_t signature_len
;
4558 EVP_MD_CTX
*md_ctx
= NULL
;
4559 ECDSA_SIG
*sig
= NULL
;
4561 const EVP_MD
*sign_md
;
4562 const BIGNUM
*r
, *s
;
4563 size_t extra_len
= 1000;
4568 wpa_printf(MSG_INFO
,
4569 "DPP: No configurator specified - cannot generate DPP config object");
4572 curve
= auth
->conf
->curve
;
4573 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4574 sign_md
= EVP_sha256();
4575 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4576 sign_md
= EVP_sha384();
4577 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4578 sign_md
= EVP_sha512();
4580 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4585 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4586 wpa_printf(MSG_DEBUG
,
4587 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4591 #ifdef CONFIG_TESTING_OPTIONS
4592 if (auth
->groups_override
)
4593 extra_len
+= os_strlen(auth
->groups_override
);
4594 #endif /* CONFIG_TESTING_OPTIONS */
4597 extra_len
+= os_strlen(conf
->group_id
);
4599 /* Connector (JSON dppCon object) */
4600 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4603 #ifdef CONFIG_TESTING_OPTIONS
4604 if (auth
->groups_override
) {
4605 wpabuf_put_u8(dppcon
, '{');
4606 if (auth
->groups_override
) {
4607 wpa_printf(MSG_DEBUG
,
4608 "DPP: TESTING - groups override: '%s'",
4609 auth
->groups_override
);
4610 wpabuf_put_str(dppcon
, "\"groups\":");
4611 wpabuf_put_str(dppcon
, auth
->groups_override
);
4612 wpabuf_put_u8(dppcon
, ',');
4616 #endif /* CONFIG_TESTING_OPTIONS */
4617 wpabuf_printf(dppcon
, "{\"groups\":[{\"groupId\":\"%s\",",
4618 conf
->group_id
? conf
->group_id
: "*");
4619 wpabuf_printf(dppcon
, "\"netRole\":\"%s\"}],", ap
? "ap" : "sta");
4620 #ifdef CONFIG_TESTING_OPTIONS
4622 #endif /* CONFIG_TESTING_OPTIONS */
4623 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4625 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4628 if (conf
->netaccesskey_expiry
) {
4631 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4632 wpa_printf(MSG_DEBUG
,
4633 "DPP: Failed to generate expiry string");
4636 wpabuf_printf(dppcon
,
4637 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"",
4638 tm
.year
, tm
.month
, tm
.day
,
4639 tm
.hour
, tm
.min
, tm
.sec
);
4641 wpabuf_put_u8(dppcon
, '}');
4642 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4643 (const char *) wpabuf_head(dppcon
));
4645 os_snprintf(jws_prot_hdr
, sizeof(jws_prot_hdr
),
4646 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}",
4647 auth
->conf
->kid
, curve
->jws_alg
);
4648 signed1
= (char *) base64_url_encode((unsigned char *) jws_prot_hdr
,
4649 os_strlen(jws_prot_hdr
),
4651 signed2
= (char *) base64_url_encode(wpabuf_head(dppcon
),
4654 if (!signed1
|| !signed2
)
4657 md_ctx
= EVP_MD_CTX_create();
4662 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4663 auth
->conf
->csign
) != 1) {
4664 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4665 ERR_error_string(ERR_get_error(), NULL
));
4668 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4669 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4670 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4671 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4672 ERR_error_string(ERR_get_error(), NULL
));
4675 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4676 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4677 ERR_error_string(ERR_get_error(), NULL
));
4680 signature
= os_malloc(signature_len
);
4683 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4684 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4685 ERR_error_string(ERR_get_error(), NULL
));
4688 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4689 signature
, signature_len
);
4690 /* Convert to raw coordinates r,s */
4692 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4695 ECDSA_SIG_get0(sig
, &r
, &s
);
4696 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4697 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4698 curve
->prime_len
) < 0)
4700 signature_len
= 2 * curve
->prime_len
;
4701 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4702 signature
, signature_len
);
4703 signed3
= (char *) base64_url_encode(signature
, signature_len
,
4708 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
4710 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4711 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4714 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4718 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm
));
4720 dpp_build_legacy_cred_params(buf
, conf
);
4721 wpabuf_put_str(buf
, ",");
4723 wpabuf_put_str(buf
, "\"signedConnector\":\"");
4724 wpabuf_put_str(buf
, signed1
);
4725 wpabuf_put_u8(buf
, '.');
4726 wpabuf_put_str(buf
, signed2
);
4727 wpabuf_put_u8(buf
, '.');
4728 wpabuf_put_str(buf
, signed3
);
4729 wpabuf_put_str(buf
, "\",");
4730 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4732 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4736 wpabuf_put_str(buf
, "}}");
4738 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4739 wpabuf_head(buf
), wpabuf_len(buf
));
4742 EVP_MD_CTX_destroy(md_ctx
);
4743 ECDSA_SIG_free(sig
);
4748 wpabuf_free(dppcon
);
4751 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4758 static struct wpabuf
*
4759 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
, int ap
,
4760 struct dpp_configuration
*conf
)
4764 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4768 wpabuf_printf(buf
, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf
->akm
));
4769 dpp_build_legacy_cred_params(buf
, conf
);
4770 wpabuf_put_str(buf
, "}}");
4772 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4773 wpabuf_head(buf
), wpabuf_len(buf
));
4779 static struct wpabuf
*
4780 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
)
4782 struct dpp_configuration
*conf
;
4784 #ifdef CONFIG_TESTING_OPTIONS
4785 if (auth
->config_obj_override
) {
4786 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
4787 return wpabuf_alloc_copy(auth
->config_obj_override
,
4788 os_strlen(auth
->config_obj_override
));
4790 #endif /* CONFIG_TESTING_OPTIONS */
4792 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
4794 wpa_printf(MSG_DEBUG
,
4795 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
4800 if (dpp_akm_dpp(conf
->akm
))
4801 return dpp_build_conf_obj_dpp(auth
, ap
, conf
);
4802 return dpp_build_conf_obj_legacy(auth
, ap
, conf
);
4806 static struct wpabuf
*
4807 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
4808 u16 e_nonce_len
, int ap
)
4810 struct wpabuf
*conf
;
4811 size_t clear_len
, attr_len
;
4812 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
4816 enum dpp_status_error status
;
4818 conf
= dpp_build_conf_obj(auth
, ap
);
4820 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
4821 wpabuf_head(conf
), wpabuf_len(conf
));
4823 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
4824 auth
->conf_resp_status
= status
;
4826 /* { E-nonce, configurationObject}ke */
4827 clear_len
= 4 + e_nonce_len
;
4829 clear_len
+= 4 + wpabuf_len(conf
);
4830 clear
= wpabuf_alloc(clear_len
);
4831 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
4832 #ifdef CONFIG_TESTING_OPTIONS
4833 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
4835 #endif /* CONFIG_TESTING_OPTIONS */
4836 msg
= wpabuf_alloc(attr_len
);
4840 #ifdef CONFIG_TESTING_OPTIONS
4841 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
4842 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
4845 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
4846 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
4847 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4848 wpabuf_put_le16(clear
, e_nonce_len
);
4849 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
4850 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
4853 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
4854 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
4855 goto skip_wrapped_data
;
4857 #endif /* CONFIG_TESTING_OPTIONS */
4860 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
4861 wpabuf_put_le16(clear
, e_nonce_len
);
4862 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
4864 #ifdef CONFIG_TESTING_OPTIONS
4866 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
4867 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
4868 goto skip_config_obj
;
4870 #endif /* CONFIG_TESTING_OPTIONS */
4873 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
4874 wpabuf_put_le16(clear
, wpabuf_len(conf
));
4875 wpabuf_put_buf(clear
, conf
);
4878 #ifdef CONFIG_TESTING_OPTIONS
4880 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
4881 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
4884 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
4885 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
4888 #endif /* CONFIG_TESTING_OPTIONS */
4891 dpp_build_attr_status(msg
, status
);
4893 #ifdef CONFIG_TESTING_OPTIONS
4895 #endif /* CONFIG_TESTING_OPTIONS */
4897 addr
[0] = wpabuf_head(msg
);
4898 len
[0] = wpabuf_len(msg
);
4899 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
4901 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
4902 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4903 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4905 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
4906 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
4907 wpabuf_head(clear
), wpabuf_len(clear
),
4908 1, addr
, len
, wrapped
) < 0)
4910 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4911 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
4913 #ifdef CONFIG_TESTING_OPTIONS
4914 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
4915 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
4916 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
4919 #endif /* CONFIG_TESTING_OPTIONS */
4921 wpa_hexdump_buf(MSG_DEBUG
,
4922 "DPP: Configuration Response attributes", msg
);
4936 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
4939 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
4940 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
4941 u8
*unwrapped
= NULL
;
4942 size_t unwrapped_len
= 0;
4943 struct wpabuf
*resp
= NULL
;
4944 struct json_token
*root
= NULL
, *token
;
4947 #ifdef CONFIG_TESTING_OPTIONS
4948 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
4949 wpa_printf(MSG_INFO
,
4950 "DPP: TESTING - stop at Config Request");
4953 #endif /* CONFIG_TESTING_OPTIONS */
4955 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
4956 dpp_auth_fail(auth
, "Invalid attribute in config request");
4960 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4962 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4964 "Missing or invalid required Wrapped Data attribute");
4968 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4969 wrapped_data
, wrapped_data_len
);
4970 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4971 unwrapped
= os_malloc(unwrapped_len
);
4974 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4975 wrapped_data
, wrapped_data_len
,
4976 0, NULL
, NULL
, unwrapped
) < 0) {
4977 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4980 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4981 unwrapped
, unwrapped_len
);
4983 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4984 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4988 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
4989 DPP_ATTR_ENROLLEE_NONCE
,
4991 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
4993 "Missing or invalid Enrollee Nonce attribute");
4996 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
4997 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
4999 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5000 DPP_ATTR_CONFIG_ATTR_OBJ
,
5004 "Missing or invalid Config Attributes attribute");
5007 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5008 config_attr
, config_attr_len
);
5010 root
= json_parse((const char *) config_attr
, config_attr_len
);
5012 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5016 token
= json_get_member(root
, "name");
5017 if (!token
|| token
->type
!= JSON_STRING
) {
5018 dpp_auth_fail(auth
, "No Config Attributes - name");
5021 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5023 token
= json_get_member(root
, "wi-fi_tech");
5024 if (!token
|| token
->type
!= JSON_STRING
) {
5025 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5028 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5029 if (os_strcmp(token
->string
, "infra") != 0) {
5030 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5032 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5036 token
= json_get_member(root
, "netRole");
5037 if (!token
|| token
->type
!= JSON_STRING
) {
5038 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5041 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5042 if (os_strcmp(token
->string
, "sta") == 0) {
5044 } else if (os_strcmp(token
->string
, "ap") == 0) {
5047 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5049 dpp_auth_fail(auth
, "Unsupported netRole");
5053 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
5062 static struct wpabuf
*
5063 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
5064 const u8
*prot_hdr
, u16 prot_hdr_len
,
5065 const EVP_MD
**ret_md
)
5067 struct json_token
*root
, *token
;
5068 struct wpabuf
*kid
= NULL
;
5070 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
5072 wpa_printf(MSG_DEBUG
,
5073 "DPP: JSON parsing failed for JWS Protected Header");
5077 if (root
->type
!= JSON_OBJECT
) {
5078 wpa_printf(MSG_DEBUG
,
5079 "DPP: JWS Protected Header root is not an object");
5083 token
= json_get_member(root
, "typ");
5084 if (!token
|| token
->type
!= JSON_STRING
) {
5085 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
5088 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
5090 if (os_strcmp(token
->string
, "dppCon") != 0) {
5091 wpa_printf(MSG_DEBUG
,
5092 "DPP: Unsupported JWS Protected Header typ=%s",
5097 token
= json_get_member(root
, "alg");
5098 if (!token
|| token
->type
!= JSON_STRING
) {
5099 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
5102 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
5104 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5105 wpa_printf(MSG_DEBUG
,
5106 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5107 token
->string
, curve
->jws_alg
);
5110 if (os_strcmp(token
->string
, "ES256") == 0 ||
5111 os_strcmp(token
->string
, "BS256") == 0)
5112 *ret_md
= EVP_sha256();
5113 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5114 os_strcmp(token
->string
, "BS384") == 0)
5115 *ret_md
= EVP_sha384();
5116 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5117 os_strcmp(token
->string
, "BS512") == 0)
5118 *ret_md
= EVP_sha512();
5122 wpa_printf(MSG_DEBUG
,
5123 "DPP: Unsupported JWS Protected Header alg=%s",
5128 kid
= json_get_member_base64url(root
, "kid");
5130 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5133 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5142 static int dpp_parse_cred_legacy(struct dpp_authentication
*auth
,
5143 struct json_token
*cred
)
5145 struct json_token
*pass
, *psk_hex
;
5147 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5149 pass
= json_get_member(cred
, "pass");
5150 psk_hex
= json_get_member(cred
, "psk_hex");
5152 if (pass
&& pass
->type
== JSON_STRING
) {
5153 size_t len
= os_strlen(pass
->string
);
5155 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5157 if (len
< 8 || len
> 63)
5159 os_strlcpy(auth
->passphrase
, pass
->string
,
5160 sizeof(auth
->passphrase
));
5161 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5162 if (dpp_akm_sae(auth
->akm
) && !dpp_akm_psk(auth
->akm
)) {
5163 wpa_printf(MSG_DEBUG
,
5164 "DPP: Unexpected psk_hex with akm=sae");
5167 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5168 hexstr2bin(psk_hex
->string
, auth
->psk
, PMK_LEN
) < 0) {
5169 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5172 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5173 auth
->psk
, PMK_LEN
);
5176 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5180 if (dpp_akm_sae(auth
->akm
) && !auth
->passphrase
[0]) {
5181 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5189 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5190 const struct dpp_curve_params
**key_curve
)
5192 struct json_token
*token
;
5193 const struct dpp_curve_params
*curve
;
5194 struct wpabuf
*x
= NULL
, *y
= NULL
;
5196 EVP_PKEY
*pkey
= NULL
;
5198 token
= json_get_member(jwk
, "kty");
5199 if (!token
|| token
->type
!= JSON_STRING
) {
5200 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5203 if (os_strcmp(token
->string
, "EC") != 0) {
5204 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5209 token
= json_get_member(jwk
, "crv");
5210 if (!token
|| token
->type
!= JSON_STRING
) {
5211 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5214 curve
= dpp_get_curve_jwk_crv(token
->string
);
5216 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5221 x
= json_get_member_base64url(jwk
, "x");
5223 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5226 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5227 if (wpabuf_len(x
) != curve
->prime_len
) {
5228 wpa_printf(MSG_DEBUG
,
5229 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5230 (unsigned int) wpabuf_len(x
),
5231 (unsigned int) curve
->prime_len
, curve
->name
);
5235 y
= json_get_member_base64url(jwk
, "y");
5237 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5240 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5241 if (wpabuf_len(y
) != curve
->prime_len
) {
5242 wpa_printf(MSG_DEBUG
,
5243 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5244 (unsigned int) wpabuf_len(y
),
5245 (unsigned int) curve
->prime_len
, curve
->name
);
5249 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5251 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5255 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5257 EC_GROUP_free(group
);
5268 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5271 unsigned int year
, month
, day
, hour
, min
, sec
;
5275 /* ISO 8601 date and time:
5277 * YYYY-MM-DDTHH:MM:SSZ
5278 * YYYY-MM-DDTHH:MM:SS+03:00
5280 if (os_strlen(timestamp
) < 19) {
5281 wpa_printf(MSG_DEBUG
,
5282 "DPP: Too short timestamp - assume expired key");
5285 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5286 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5287 wpa_printf(MSG_DEBUG
,
5288 "DPP: Failed to parse expiration day - assume expired key");
5292 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5293 wpa_printf(MSG_DEBUG
,
5294 "DPP: Invalid date/time information - assume expired key");
5298 pos
= timestamp
+ 19;
5299 if (*pos
== 'Z' || *pos
== '\0') {
5300 /* In UTC - no need to adjust */
5301 } else if (*pos
== '-' || *pos
== '+') {
5304 /* Adjust local time to UTC */
5305 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5307 wpa_printf(MSG_DEBUG
,
5308 "DPP: Invalid time zone designator (%s) - assume expired key",
5313 utime
+= 3600 * hour
;
5315 utime
-= 3600 * hour
;
5323 wpa_printf(MSG_DEBUG
,
5324 "DPP: Invalid time zone designator (%s) - assume expired key",
5331 if (os_get_time(&now
) < 0) {
5332 wpa_printf(MSG_DEBUG
,
5333 "DPP: Cannot get current time - assume expired key");
5337 if (now
.sec
> utime
) {
5338 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5347 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5348 const unsigned char *payload
,
5351 struct json_token
*root
, *groups
, *netkey
, *token
;
5353 EVP_PKEY
*key
= NULL
;
5354 const struct dpp_curve_params
*curve
;
5355 unsigned int rules
= 0;
5357 root
= json_parse((const char *) payload
, payload_len
);
5359 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5363 groups
= json_get_member(root
, "groups");
5364 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5365 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5368 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5369 struct json_token
*id
, *role
;
5371 id
= json_get_member(token
, "groupId");
5372 if (!id
|| id
->type
!= JSON_STRING
) {
5373 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5377 role
= json_get_member(token
, "netRole");
5378 if (!role
|| role
->type
!= JSON_STRING
) {
5379 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5382 wpa_printf(MSG_DEBUG
,
5383 "DPP: connector group: groupId='%s' netRole='%s'",
5384 id
->string
, role
->string
);
5390 wpa_printf(MSG_DEBUG
,
5391 "DPP: Connector includes no groups");
5395 token
= json_get_member(root
, "expiry");
5396 if (!token
|| token
->type
!= JSON_STRING
) {
5397 wpa_printf(MSG_DEBUG
,
5398 "DPP: No expiry string found - connector does not expire");
5400 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5401 if (dpp_key_expired(token
->string
,
5402 &auth
->net_access_key_expiry
)) {
5403 wpa_printf(MSG_DEBUG
,
5404 "DPP: Connector (netAccessKey) has expired");
5409 netkey
= json_get_member(root
, "netAccessKey");
5410 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5411 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5415 key
= dpp_parse_jwk(netkey
, &curve
);
5418 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5420 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5421 wpa_printf(MSG_DEBUG
,
5422 "DPP: netAccessKey in connector does not match own protocol key");
5423 #ifdef CONFIG_TESTING_OPTIONS
5424 if (auth
->ignore_netaccesskey_mismatch
) {
5425 wpa_printf(MSG_DEBUG
,
5426 "DPP: TESTING - skip netAccessKey mismatch");
5430 #else /* CONFIG_TESTING_OPTIONS */
5432 #endif /* CONFIG_TESTING_OPTIONS */
5443 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5445 struct wpabuf
*uncomp
;
5447 u8 hash
[SHA256_MAC_LEN
];
5451 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5453 uncomp
= dpp_get_pubkey_point(pub
, 1);
5456 addr
[0] = wpabuf_head(uncomp
);
5457 len
[0] = wpabuf_len(uncomp
);
5458 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5460 res
= sha256_vector(1, addr
, len
, hash
);
5461 wpabuf_free(uncomp
);
5464 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5465 wpa_printf(MSG_DEBUG
,
5466 "DPP: Received hash value does not match calculated public key hash value");
5467 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5468 hash
, SHA256_MAC_LEN
);
5475 static void dpp_copy_csign(struct dpp_authentication
*auth
, EVP_PKEY
*csign
)
5477 unsigned char *der
= NULL
;
5480 der_len
= i2d_PUBKEY(csign
, &der
);
5483 wpabuf_free(auth
->c_sign_key
);
5484 auth
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5489 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
)
5491 unsigned char *der
= NULL
;
5495 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5499 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5504 wpabuf_free(auth
->net_access_key
);
5505 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5511 struct dpp_signed_connector_info
{
5512 unsigned char *payload
;
5516 static enum dpp_status_error
5517 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5518 EVP_PKEY
*csign_pub
, const char *connector
)
5520 enum dpp_status_error ret
= 255;
5521 const char *pos
, *end
, *signed_start
, *signed_end
;
5522 struct wpabuf
*kid
= NULL
;
5523 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5524 size_t prot_hdr_len
= 0, signature_len
= 0;
5525 const EVP_MD
*sign_md
= NULL
;
5526 unsigned char *der
= NULL
;
5529 EVP_MD_CTX
*md_ctx
= NULL
;
5530 ECDSA_SIG
*sig
= NULL
;
5531 BIGNUM
*r
= NULL
, *s
= NULL
;
5532 const struct dpp_curve_params
*curve
;
5534 const EC_GROUP
*group
;
5537 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5540 group
= EC_KEY_get0_group(eckey
);
5543 nid
= EC_GROUP_get_curve_name(group
);
5544 curve
= dpp_get_curve_nid(nid
);
5547 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5548 os_memset(info
, 0, sizeof(*info
));
5550 signed_start
= pos
= connector
;
5551 end
= os_strchr(pos
, '.');
5553 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5554 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5557 prot_hdr
= base64_url_decode((const unsigned char *) pos
,
5558 end
- pos
, &prot_hdr_len
);
5560 wpa_printf(MSG_DEBUG
,
5561 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5562 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5565 wpa_hexdump_ascii(MSG_DEBUG
,
5566 "DPP: signedConnector - JWS Protected Header",
5567 prot_hdr
, prot_hdr_len
);
5568 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5570 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5573 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5574 wpa_printf(MSG_DEBUG
,
5575 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5576 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5577 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5582 end
= os_strchr(pos
, '.');
5584 wpa_printf(MSG_DEBUG
,
5585 "DPP: Missing dot(2) in signedConnector");
5586 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5589 signed_end
= end
- 1;
5590 info
->payload
= base64_url_decode((const unsigned char *) pos
,
5591 end
- pos
, &info
->payload_len
);
5592 if (!info
->payload
) {
5593 wpa_printf(MSG_DEBUG
,
5594 "DPP: Failed to base64url decode signedConnector JWS Payload");
5595 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5598 wpa_hexdump_ascii(MSG_DEBUG
,
5599 "DPP: signedConnector - JWS Payload",
5600 info
->payload
, info
->payload_len
);
5602 signature
= base64_url_decode((const unsigned char *) pos
,
5603 os_strlen(pos
), &signature_len
);
5605 wpa_printf(MSG_DEBUG
,
5606 "DPP: Failed to base64url decode signedConnector signature");
5607 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5610 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5611 signature
, signature_len
);
5613 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5614 ret
= DPP_STATUS_NO_MATCH
;
5618 if (signature_len
& 0x01) {
5619 wpa_printf(MSG_DEBUG
,
5620 "DPP: Unexpected signedConnector signature length (%d)",
5621 (int) signature_len
);
5622 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5626 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5627 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5628 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5629 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5630 sig
= ECDSA_SIG_new();
5631 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5636 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5638 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5641 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5642 md_ctx
= EVP_MD_CTX_create();
5647 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5648 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5649 ERR_error_string(ERR_get_error(), NULL
));
5652 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5653 signed_end
- signed_start
+ 1) != 1) {
5654 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5655 ERR_error_string(ERR_get_error(), NULL
));
5658 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5660 wpa_printf(MSG_DEBUG
,
5661 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5662 res
, ERR_error_string(ERR_get_error(), NULL
));
5663 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5667 ret
= DPP_STATUS_OK
;
5670 EVP_MD_CTX_destroy(md_ctx
);
5674 ECDSA_SIG_free(sig
);
5682 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5683 struct json_token
*cred
)
5685 struct dpp_signed_connector_info info
;
5686 struct json_token
*token
, *csign
;
5688 EVP_PKEY
*csign_pub
= NULL
;
5689 const struct dpp_curve_params
*key_curve
= NULL
;
5690 const char *signed_connector
;
5692 os_memset(&info
, 0, sizeof(info
));
5694 if (dpp_akm_psk(auth
->akm
) || dpp_akm_sae(auth
->akm
)) {
5695 wpa_printf(MSG_DEBUG
,
5696 "DPP: Legacy credential included in Connector credential");
5697 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5701 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5703 csign
= json_get_member(cred
, "csign");
5704 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5705 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5709 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5711 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5714 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5716 token
= json_get_member(cred
, "signedConnector");
5717 if (!token
|| token
->type
!= JSON_STRING
) {
5718 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5721 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5722 token
->string
, os_strlen(token
->string
));
5723 signed_connector
= token
->string
;
5725 if (os_strchr(signed_connector
, '"') ||
5726 os_strchr(signed_connector
, '\n')) {
5727 wpa_printf(MSG_DEBUG
,
5728 "DPP: Unexpected character in signedConnector");
5732 if (dpp_process_signed_connector(&info
, csign_pub
,
5733 signed_connector
) != DPP_STATUS_OK
)
5736 if (dpp_parse_connector(auth
, info
.payload
, info
.payload_len
) < 0) {
5737 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
5741 os_free(auth
->connector
);
5742 auth
->connector
= os_strdup(signed_connector
);
5744 dpp_copy_csign(auth
, csign_pub
);
5745 dpp_copy_netaccesskey(auth
);
5749 EVP_PKEY_free(csign_pub
);
5750 os_free(info
.payload
);
5755 const char * dpp_akm_str(enum dpp_akm akm
)
5764 case DPP_AKM_PSK_SAE
:
5766 case DPP_AKM_SAE_DPP
:
5768 case DPP_AKM_PSK_SAE_DPP
:
5769 return "dpp+psk+sae";
5776 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
5778 if (os_strcmp(akm
, "psk") == 0)
5780 if (os_strcmp(akm
, "sae") == 0)
5782 if (os_strcmp(akm
, "psk+sae") == 0)
5783 return DPP_AKM_PSK_SAE
;
5784 if (os_strcmp(akm
, "dpp") == 0)
5786 if (os_strcmp(akm
, "dpp+sae") == 0)
5787 return DPP_AKM_SAE_DPP
;
5788 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
5789 return DPP_AKM_PSK_SAE_DPP
;
5790 return DPP_AKM_UNKNOWN
;
5794 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
5795 const u8
*conf_obj
, u16 conf_obj_len
)
5798 struct json_token
*root
, *token
, *discovery
, *cred
;
5800 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
5803 if (root
->type
!= JSON_OBJECT
) {
5804 dpp_auth_fail(auth
, "JSON root is not an object");
5808 token
= json_get_member(root
, "wi-fi_tech");
5809 if (!token
|| token
->type
!= JSON_STRING
) {
5810 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
5813 if (os_strcmp(token
->string
, "infra") != 0) {
5814 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
5816 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
5820 discovery
= json_get_member(root
, "discovery");
5821 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
5822 dpp_auth_fail(auth
, "No discovery object in JSON");
5826 token
= json_get_member(discovery
, "ssid");
5827 if (!token
|| token
->type
!= JSON_STRING
) {
5828 dpp_auth_fail(auth
, "No discovery::ssid string value found");
5831 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
5832 token
->string
, os_strlen(token
->string
));
5833 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
5834 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
5837 auth
->ssid_len
= os_strlen(token
->string
);
5838 os_memcpy(auth
->ssid
, token
->string
, auth
->ssid_len
);
5840 cred
= json_get_member(root
, "cred");
5841 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
5842 dpp_auth_fail(auth
, "No cred object in JSON");
5846 token
= json_get_member(cred
, "akm");
5847 if (!token
|| token
->type
!= JSON_STRING
) {
5848 dpp_auth_fail(auth
, "No cred::akm string value found");
5851 auth
->akm
= dpp_akm_from_str(token
->string
);
5853 if (dpp_akm_legacy(auth
->akm
)) {
5854 if (dpp_parse_cred_legacy(auth
, cred
) < 0)
5856 } else if (dpp_akm_dpp(auth
->akm
)) {
5857 if (dpp_parse_cred_dpp(auth
, cred
) < 0)
5860 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
5862 dpp_auth_fail(auth
, "Unsupported akm");
5866 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
5874 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
5875 const struct wpabuf
*resp
)
5877 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
5878 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
5881 u8
*unwrapped
= NULL
;
5882 size_t unwrapped_len
= 0;
5885 auth
->conf_resp_status
= 255;
5887 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
5888 dpp_auth_fail(auth
, "Invalid attribute in config response");
5892 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5893 DPP_ATTR_WRAPPED_DATA
,
5895 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5897 "Missing or invalid required Wrapped Data attribute");
5901 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5902 wrapped_data
, wrapped_data_len
);
5903 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5904 unwrapped
= os_malloc(unwrapped_len
);
5908 addr
[0] = wpabuf_head(resp
);
5909 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
5910 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5912 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5913 wrapped_data
, wrapped_data_len
,
5914 1, addr
, len
, unwrapped
) < 0) {
5915 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5918 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5919 unwrapped
, unwrapped_len
);
5921 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5922 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5926 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5927 DPP_ATTR_ENROLLEE_NONCE
,
5929 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5931 "Missing or invalid Enrollee Nonce attribute");
5934 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5935 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
5936 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
5940 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
5941 DPP_ATTR_STATUS
, &status_len
);
5942 if (!status
|| status_len
< 1) {
5944 "Missing or invalid required DPP Status attribute");
5947 auth
->conf_resp_status
= status
[0];
5948 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
5949 if (status
[0] != DPP_STATUS_OK
) {
5950 dpp_auth_fail(auth
, "Configurator rejected configuration");
5954 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
,
5955 DPP_ATTR_CONFIG_OBJ
, &conf_obj_len
);
5958 "Missing required Configuration Object attribute");
5961 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5962 conf_obj
, conf_obj_len
);
5963 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
5975 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
5977 const u8
*attr_start
, size_t attr_len
)
5979 const u8
*wrapped_data
, *status
, *e_nonce
;
5980 u16 wrapped_data_len
, status_len
, e_nonce_len
;
5983 u8
*unwrapped
= NULL
;
5984 size_t unwrapped_len
= 0;
5985 enum dpp_status_error ret
= 256;
5987 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5989 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5991 "Missing or invalid required Wrapped Data attribute");
5994 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
5995 wrapped_data
, wrapped_data_len
);
5997 attr_len
= wrapped_data
- 4 - attr_start
;
6000 len
[0] = DPP_HDR_LEN
;
6001 addr
[1] = attr_start
;
6003 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6004 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6005 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6006 wrapped_data
, wrapped_data_len
);
6007 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6008 unwrapped
= os_malloc(unwrapped_len
);
6011 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6012 wrapped_data
, wrapped_data_len
,
6013 2, addr
, len
, unwrapped
) < 0) {
6014 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6017 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6018 unwrapped
, unwrapped_len
);
6020 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6021 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6025 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6026 DPP_ATTR_ENROLLEE_NONCE
,
6028 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6030 "Missing or invalid Enrollee Nonce attribute");
6033 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6034 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6035 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6036 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
6037 auth
->e_nonce
, e_nonce_len
);
6041 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
6043 if (!status
|| status_len
< 1) {
6045 "Missing or invalid required DPP Status attribute");
6048 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
6052 bin_clear_free(unwrapped
, unwrapped_len
);
6055 #endif /* CONFIG_DPP2 */
6058 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
6059 enum dpp_status_error status
)
6061 struct wpabuf
*msg
, *clear
;
6062 size_t nonce_len
, clear_len
, attr_len
;
6067 nonce_len
= auth
->curve
->nonce_len
;
6068 clear_len
= 5 + 4 + nonce_len
;
6069 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6070 clear
= wpabuf_alloc(clear_len
);
6071 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
6076 dpp_build_attr_status(clear
, status
);
6079 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
6080 wpabuf_put_le16(clear
, nonce_len
);
6081 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
6083 /* OUI, OUI type, Crypto Suite, DPP frame type */
6084 addr
[0] = wpabuf_head_u8(msg
) + 2;
6085 len
[0] = 3 + 1 + 1 + 1;
6086 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6088 /* Attributes before Wrapped Data (none) */
6089 addr
[1] = wpabuf_put(msg
, 0);
6091 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6094 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6095 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6096 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6098 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6099 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
6100 wpabuf_head(clear
), wpabuf_len(clear
),
6101 2, addr
, len
, wrapped
) < 0)
6104 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
6114 void dpp_configurator_free(struct dpp_configurator
*conf
)
6118 EVP_PKEY_free(conf
->csign
);
6124 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
6128 int key_len
, ret
= -1;
6129 unsigned char *key
= NULL
;
6134 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
6138 key_len
= i2d_ECPrivateKey(eckey
, &key
);
6140 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
6148 struct dpp_configurator
*
6149 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
6152 struct dpp_configurator
*conf
;
6153 struct wpabuf
*csign_pub
= NULL
;
6154 u8 kid_hash
[SHA256_MAC_LEN
];
6158 conf
= os_zalloc(sizeof(*conf
));
6163 conf
->curve
= &dpp_curves
[0];
6165 conf
->curve
= dpp_get_curve_name(curve
);
6167 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6174 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
6177 conf
->csign
= dpp_gen_keypair(conf
->curve
);
6182 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
6184 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
6188 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6189 addr
[0] = wpabuf_head(csign_pub
);
6190 len
[0] = wpabuf_len(csign_pub
);
6191 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
6192 wpa_printf(MSG_DEBUG
,
6193 "DPP: Failed to derive kid for C-sign-key");
6197 conf
->kid
= (char *) base64_url_encode(kid_hash
, sizeof(kid_hash
),
6202 wpabuf_free(csign_pub
);
6205 dpp_configurator_free(conf
);
6211 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
6212 const char *curve
, int ap
)
6214 struct wpabuf
*conf_obj
;
6218 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
6223 auth
->curve
= &dpp_curves
[0];
6225 auth
->curve
= dpp_get_curve_name(curve
);
6227 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6232 wpa_printf(MSG_DEBUG
,
6233 "DPP: Building own configuration/connector with curve %s",
6236 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
6237 if (!auth
->own_protocol_key
)
6239 dpp_copy_netaccesskey(auth
);
6240 auth
->peer_protocol_key
= auth
->own_protocol_key
;
6241 dpp_copy_csign(auth
, auth
->conf
->csign
);
6243 conf_obj
= dpp_build_conf_obj(auth
, ap
);
6246 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
6247 wpabuf_len(conf_obj
));
6249 wpabuf_free(conf_obj
);
6250 auth
->peer_protocol_key
= NULL
;
6255 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
6257 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
6258 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
6262 static int dpp_connector_compatible_group(struct json_token
*root
,
6263 const char *group_id
,
6264 const char *net_role
)
6266 struct json_token
*groups
, *token
;
6268 groups
= json_get_member(root
, "groups");
6269 if (!groups
|| groups
->type
!= JSON_ARRAY
)
6272 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6273 struct json_token
*id
, *role
;
6275 id
= json_get_member(token
, "groupId");
6276 if (!id
|| id
->type
!= JSON_STRING
)
6279 role
= json_get_member(token
, "netRole");
6280 if (!role
|| role
->type
!= JSON_STRING
)
6283 if (os_strcmp(id
->string
, "*") != 0 &&
6284 os_strcmp(group_id
, "*") != 0 &&
6285 os_strcmp(id
->string
, group_id
) != 0)
6288 if (dpp_compatible_netrole(role
->string
, net_role
))
6296 static int dpp_connector_match_groups(struct json_token
*own_root
,
6297 struct json_token
*peer_root
)
6299 struct json_token
*groups
, *token
;
6301 groups
= json_get_member(peer_root
, "groups");
6302 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6303 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
6307 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6308 struct json_token
*id
, *role
;
6310 id
= json_get_member(token
, "groupId");
6311 if (!id
|| id
->type
!= JSON_STRING
) {
6312 wpa_printf(MSG_DEBUG
,
6313 "DPP: Missing peer groupId string");
6317 role
= json_get_member(token
, "netRole");
6318 if (!role
|| role
->type
!= JSON_STRING
) {
6319 wpa_printf(MSG_DEBUG
,
6320 "DPP: Missing peer groups::netRole string");
6323 wpa_printf(MSG_DEBUG
,
6324 "DPP: peer connector group: groupId='%s' netRole='%s'",
6325 id
->string
, role
->string
);
6326 if (dpp_connector_compatible_group(own_root
, id
->string
,
6328 wpa_printf(MSG_DEBUG
,
6329 "DPP: Compatible group/netRole in own connector");
6338 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
6339 unsigned int hash_len
)
6341 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6342 const char *info
= "DPP PMK";
6345 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6347 /* HKDF-Extract(<>, N.x) */
6348 os_memset(salt
, 0, hash_len
);
6349 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
6351 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6354 /* HKDF-Expand(PRK, info, L) */
6355 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
6356 os_memset(prk
, 0, hash_len
);
6360 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6366 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
6367 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
6369 struct wpabuf
*nkx
, *pkx
;
6373 u8 hash
[SHA256_MAC_LEN
];
6375 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6376 nkx
= dpp_get_pubkey_point(own_key
, 0);
6377 pkx
= dpp_get_pubkey_point(peer_key
, 0);
6380 addr
[0] = wpabuf_head(nkx
);
6381 len
[0] = wpabuf_len(nkx
) / 2;
6382 addr
[1] = wpabuf_head(pkx
);
6383 len
[1] = wpabuf_len(pkx
) / 2;
6384 if (len
[0] != len
[1])
6386 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
6387 addr
[0] = wpabuf_head(pkx
);
6388 addr
[1] = wpabuf_head(nkx
);
6390 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
6391 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
6392 res
= sha256_vector(2, addr
, len
, hash
);
6395 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
6396 os_memcpy(pmkid
, hash
, PMKID_LEN
);
6397 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
6406 enum dpp_status_error
6407 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
6408 const u8
*net_access_key
, size_t net_access_key_len
,
6409 const u8
*csign_key
, size_t csign_key_len
,
6410 const u8
*peer_connector
, size_t peer_connector_len
,
6413 struct json_token
*root
= NULL
, *netkey
, *token
;
6414 struct json_token
*own_root
= NULL
;
6415 enum dpp_status_error ret
= 255, res
;
6416 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
6417 struct wpabuf
*own_key_pub
= NULL
;
6418 const struct dpp_curve_params
*curve
, *own_curve
;
6419 struct dpp_signed_connector_info info
;
6420 const unsigned char *p
;
6421 EVP_PKEY
*csign
= NULL
;
6422 char *signed_connector
= NULL
;
6423 const char *pos
, *end
;
6424 unsigned char *own_conn
= NULL
;
6425 size_t own_conn_len
;
6426 EVP_PKEY_CTX
*ctx
= NULL
;
6428 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
6430 os_memset(intro
, 0, sizeof(*intro
));
6431 os_memset(&info
, 0, sizeof(info
));
6436 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
6438 wpa_printf(MSG_ERROR
,
6439 "DPP: Failed to parse local C-sign-key information");
6443 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
6444 net_access_key_len
);
6446 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
6450 pos
= os_strchr(own_connector
, '.');
6452 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
6456 end
= os_strchr(pos
, '.');
6458 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
6461 own_conn
= base64_url_decode((const unsigned char *) pos
,
6462 end
- pos
, &own_conn_len
);
6464 wpa_printf(MSG_DEBUG
,
6465 "DPP: Failed to base64url decode own signedConnector JWS Payload");
6469 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
6471 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
6475 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
6476 peer_connector
, peer_connector_len
);
6477 signed_connector
= os_malloc(peer_connector_len
+ 1);
6478 if (!signed_connector
)
6480 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
6481 signed_connector
[peer_connector_len
] = '\0';
6483 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
6484 if (res
!= DPP_STATUS_OK
) {
6489 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
6491 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6492 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6496 if (!dpp_connector_match_groups(own_root
, root
)) {
6497 wpa_printf(MSG_DEBUG
,
6498 "DPP: Peer connector does not include compatible group netrole with own connector");
6499 ret
= DPP_STATUS_NO_MATCH
;
6503 token
= json_get_member(root
, "expiry");
6504 if (!token
|| token
->type
!= JSON_STRING
) {
6505 wpa_printf(MSG_DEBUG
,
6506 "DPP: No expiry string found - connector does not expire");
6508 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6509 if (dpp_key_expired(token
->string
, expiry
)) {
6510 wpa_printf(MSG_DEBUG
,
6511 "DPP: Connector (netAccessKey) has expired");
6512 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6517 netkey
= json_get_member(root
, "netAccessKey");
6518 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6519 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6520 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6524 peer_key
= dpp_parse_jwk(netkey
, &curve
);
6526 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6529 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
6531 if (own_curve
!= curve
) {
6532 wpa_printf(MSG_DEBUG
,
6533 "DPP: Mismatching netAccessKey curves (%s != %s)",
6534 own_curve
->name
, curve
->name
);
6535 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6539 /* ECDH: N = nk * PK */
6540 ctx
= EVP_PKEY_CTX_new(own_key
, NULL
);
6542 EVP_PKEY_derive_init(ctx
) != 1 ||
6543 EVP_PKEY_derive_set_peer(ctx
, peer_key
) != 1 ||
6544 EVP_PKEY_derive(ctx
, NULL
, &Nx_len
) != 1 ||
6545 Nx_len
> DPP_MAX_SHARED_SECRET_LEN
||
6546 EVP_PKEY_derive(ctx
, Nx
, &Nx_len
) != 1) {
6547 wpa_printf(MSG_ERROR
,
6548 "DPP: Failed to derive ECDH shared secret: %s",
6549 ERR_error_string(ERR_get_error(), NULL
));
6553 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
6556 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6557 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
6558 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
6561 intro
->pmk_len
= curve
->hash_len
;
6563 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6564 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
6565 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
6569 ret
= DPP_STATUS_OK
;
6571 if (ret
!= DPP_STATUS_OK
)
6572 os_memset(intro
, 0, sizeof(*intro
));
6573 os_memset(Nx
, 0, sizeof(Nx
));
6574 EVP_PKEY_CTX_free(ctx
);
6576 os_free(signed_connector
);
6577 os_free(info
.payload
);
6578 EVP_PKEY_free(own_key
);
6579 wpabuf_free(own_key_pub
);
6580 EVP_PKEY_free(peer_key
);
6581 EVP_PKEY_free(csign
);
6583 json_free(own_root
);
6588 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
6592 size_t len
= curve
->prime_len
;
6596 switch (curve
->ike_group
) {
6598 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
6599 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
6602 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
6603 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
6606 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
6607 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
6610 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
6611 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
6614 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
6615 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
6618 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
6619 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
6625 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6628 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
6629 EC_GROUP_free(group
);
6634 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
6635 const u8
*mac_init
, const char *code
,
6636 const char *identifier
, BN_CTX
*bnctx
,
6637 EC_GROUP
**ret_group
)
6639 u8 hash
[DPP_MAX_HASH_LEN
];
6642 unsigned int num_elem
= 0;
6643 EC_POINT
*Qi
= NULL
;
6644 EVP_PKEY
*Pi
= NULL
;
6645 EC_KEY
*Pi_ec
= NULL
;
6646 const EC_POINT
*Pi_point
;
6647 BIGNUM
*hash_bn
= NULL
;
6648 const EC_GROUP
*group
= NULL
;
6649 EC_GROUP
*group2
= NULL
;
6651 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6653 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
6654 addr
[num_elem
] = mac_init
;
6655 len
[num_elem
] = ETH_ALEN
;
6658 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6660 addr
[num_elem
] = (const u8
*) identifier
;
6661 len
[num_elem
] = os_strlen(identifier
);
6664 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6665 addr
[num_elem
] = (const u8
*) code
;
6666 len
[num_elem
] = os_strlen(code
);
6668 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6670 wpa_hexdump_key(MSG_DEBUG
,
6671 "DPP: H(MAC-Initiator | [identifier |] code)",
6672 hash
, curve
->hash_len
);
6673 Pi
= dpp_pkex_get_role_elem(curve
, 1);
6676 dpp_debug_print_key("DPP: Pi", Pi
);
6677 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
6680 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
6682 group
= EC_KEY_get0_group(Pi_ec
);
6685 group2
= EC_GROUP_dup(group
);
6688 Qi
= EC_POINT_new(group2
);
6690 EC_GROUP_free(group2
);
6693 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6695 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
6697 if (EC_POINT_is_at_infinity(group
, Qi
)) {
6698 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
6701 dpp_debug_print_point("DPP: Qi", group
, Qi
);
6705 BN_clear_free(hash_bn
);
6706 if (ret_group
&& Qi
)
6707 *ret_group
= group2
;
6709 EC_GROUP_free(group2
);
6718 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
6719 const u8
*mac_resp
, const char *code
,
6720 const char *identifier
, BN_CTX
*bnctx
,
6721 EC_GROUP
**ret_group
)
6723 u8 hash
[DPP_MAX_HASH_LEN
];
6726 unsigned int num_elem
= 0;
6727 EC_POINT
*Qr
= NULL
;
6728 EVP_PKEY
*Pr
= NULL
;
6729 EC_KEY
*Pr_ec
= NULL
;
6730 const EC_POINT
*Pr_point
;
6731 BIGNUM
*hash_bn
= NULL
;
6732 const EC_GROUP
*group
= NULL
;
6733 EC_GROUP
*group2
= NULL
;
6735 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
6737 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
6738 addr
[num_elem
] = mac_resp
;
6739 len
[num_elem
] = ETH_ALEN
;
6742 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
6744 addr
[num_elem
] = (const u8
*) identifier
;
6745 len
[num_elem
] = os_strlen(identifier
);
6748 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
6749 addr
[num_elem
] = (const u8
*) code
;
6750 len
[num_elem
] = os_strlen(code
);
6752 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
6754 wpa_hexdump_key(MSG_DEBUG
,
6755 "DPP: H(MAC-Responder | [identifier |] code)",
6756 hash
, curve
->hash_len
);
6757 Pr
= dpp_pkex_get_role_elem(curve
, 0);
6760 dpp_debug_print_key("DPP: Pr", Pr
);
6761 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
6764 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
6766 group
= EC_KEY_get0_group(Pr_ec
);
6769 group2
= EC_GROUP_dup(group
);
6772 Qr
= EC_POINT_new(group2
);
6774 EC_GROUP_free(group2
);
6777 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
6779 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
6781 if (EC_POINT_is_at_infinity(group
, Qr
)) {
6782 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
6785 dpp_debug_print_point("DPP: Qr", group
, Qr
);
6789 BN_clear_free(hash_bn
);
6790 if (ret_group
&& Qr
)
6791 *ret_group
= group2
;
6793 EC_GROUP_free(group2
);
6802 #ifdef CONFIG_TESTING_OPTIONS
6803 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
6804 const struct dpp_curve_params
*curve
)
6812 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6817 point
= EC_POINT_new(group
);
6820 if (!ctx
|| !point
|| !x
|| !y
)
6823 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
6826 /* Generate a random y coordinate that results in a point that is not
6829 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
6832 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
6834 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
6835 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
6836 * return an error from EC_POINT_set_affine_coordinates_GFp()
6837 * when the point is not on the curve. */
6839 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
6841 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
6844 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
6848 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
6849 curve
->prime_len
) < 0 ||
6850 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
6851 curve
->prime_len
) < 0)
6857 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
6860 EC_POINT_free(point
);
6862 EC_GROUP_free(group
);
6866 #endif /* CONFIG_TESTING_OPTIONS */
6869 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
6871 EC_KEY
*X_ec
= NULL
;
6872 const EC_POINT
*X_point
;
6873 BN_CTX
*bnctx
= NULL
;
6874 EC_GROUP
*group
= NULL
;
6875 EC_POINT
*Qi
= NULL
, *M
= NULL
;
6876 struct wpabuf
*M_buf
= NULL
;
6877 BIGNUM
*Mx
= NULL
, *My
= NULL
;
6878 struct wpabuf
*msg
= NULL
;
6880 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
6882 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
6884 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
6885 bnctx
= BN_CTX_new();
6888 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
6889 pkex
->identifier
, bnctx
, &group
);
6893 /* Generate a random ephemeral keypair x/X */
6894 #ifdef CONFIG_TESTING_OPTIONS
6895 if (dpp_pkex_ephemeral_key_override_len
) {
6896 const struct dpp_curve_params
*tmp_curve
;
6898 wpa_printf(MSG_INFO
,
6899 "DPP: TESTING - override ephemeral key x/X");
6900 pkex
->x
= dpp_set_keypair(&tmp_curve
,
6901 dpp_pkex_ephemeral_key_override
,
6902 dpp_pkex_ephemeral_key_override_len
);
6904 pkex
->x
= dpp_gen_keypair(curve
);
6906 #else /* CONFIG_TESTING_OPTIONS */
6907 pkex
->x
= dpp_gen_keypair(curve
);
6908 #endif /* CONFIG_TESTING_OPTIONS */
6913 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
6916 X_point
= EC_KEY_get0_public_key(X_ec
);
6919 dpp_debug_print_point("DPP: X", group
, X_point
);
6920 M
= EC_POINT_new(group
);
6923 if (!M
|| !Mx
|| !My
||
6924 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
6925 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
6927 dpp_debug_print_point("DPP: M", group
, M
);
6929 /* Initiator -> Responder: group, [identifier,] M */
6931 if (pkex
->identifier
)
6932 attr_len
+= 4 + os_strlen(pkex
->identifier
);
6933 attr_len
+= 4 + 2 * curve
->prime_len
;
6934 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
6938 #ifdef CONFIG_TESTING_OPTIONS
6939 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
6940 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
6941 goto skip_finite_cyclic_group
;
6943 #endif /* CONFIG_TESTING_OPTIONS */
6945 /* Finite Cyclic Group attribute */
6946 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
6947 wpabuf_put_le16(msg
, 2);
6948 wpabuf_put_le16(msg
, curve
->ike_group
);
6950 #ifdef CONFIG_TESTING_OPTIONS
6951 skip_finite_cyclic_group
:
6952 #endif /* CONFIG_TESTING_OPTIONS */
6954 /* Code Identifier attribute */
6955 if (pkex
->identifier
) {
6956 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
6957 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
6958 wpabuf_put_str(msg
, pkex
->identifier
);
6961 #ifdef CONFIG_TESTING_OPTIONS
6962 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6963 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
6966 #endif /* CONFIG_TESTING_OPTIONS */
6968 /* M in Encrypted Key attribute */
6969 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
6970 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
6972 #ifdef CONFIG_TESTING_OPTIONS
6973 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
6974 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
6975 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
6979 #endif /* CONFIG_TESTING_OPTIONS */
6981 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
6982 curve
->prime_len
) < 0 ||
6983 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
6984 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
6985 curve
->prime_len
) < 0)
6996 EC_GROUP_free(group
);
6999 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
7006 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
7008 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
7012 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
7014 const char *identifier
,
7017 struct dpp_pkex
*pkex
;
7019 #ifdef CONFIG_TESTING_OPTIONS
7020 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7021 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7022 MAC2STR(dpp_pkex_own_mac_override
));
7023 own_mac
= dpp_pkex_own_mac_override
;
7025 #endif /* CONFIG_TESTING_OPTIONS */
7027 pkex
= os_zalloc(sizeof(*pkex
));
7030 pkex
->msg_ctx
= msg_ctx
;
7031 pkex
->initiator
= 1;
7033 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7035 pkex
->identifier
= os_strdup(identifier
);
7036 if (!pkex
->identifier
)
7039 pkex
->code
= os_strdup(code
);
7042 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
7043 if (!pkex
->exchange_req
)
7047 dpp_pkex_free(pkex
);
7052 static struct wpabuf
*
7053 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
7054 enum dpp_status_error status
,
7055 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
7057 struct wpabuf
*msg
= NULL
;
7059 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7061 /* Initiator -> Responder: DPP Status, [identifier,] N */
7063 if (pkex
->identifier
)
7064 attr_len
+= 4 + os_strlen(pkex
->identifier
);
7065 attr_len
+= 4 + 2 * curve
->prime_len
;
7066 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
7070 #ifdef CONFIG_TESTING_OPTIONS
7071 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
7072 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
7076 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
7077 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
7080 #endif /* CONFIG_TESTING_OPTIONS */
7083 dpp_build_attr_status(msg
, status
);
7085 #ifdef CONFIG_TESTING_OPTIONS
7087 #endif /* CONFIG_TESTING_OPTIONS */
7089 /* Code Identifier attribute */
7090 if (pkex
->identifier
) {
7091 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
7092 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
7093 wpabuf_put_str(msg
, pkex
->identifier
);
7096 if (status
!= DPP_STATUS_OK
)
7097 goto skip_encrypted_key
;
7099 #ifdef CONFIG_TESTING_OPTIONS
7100 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7101 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
7102 goto skip_encrypted_key
;
7104 #endif /* CONFIG_TESTING_OPTIONS */
7106 /* N in Encrypted Key attribute */
7107 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
7108 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7110 #ifdef CONFIG_TESTING_OPTIONS
7111 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7112 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7113 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7115 goto skip_encrypted_key
;
7117 #endif /* CONFIG_TESTING_OPTIONS */
7119 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
7120 curve
->prime_len
) < 0 ||
7121 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
7122 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
7123 curve
->prime_len
) < 0)
7127 if (status
== DPP_STATUS_BAD_GROUP
) {
7128 /* Finite Cyclic Group attribute */
7129 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7130 wpabuf_put_le16(msg
, 2);
7131 wpabuf_put_le16(msg
, curve
->ike_group
);
7141 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
7142 const u8
*Mx
, size_t Mx_len
,
7143 const u8
*Nx
, size_t Nx_len
,
7145 const u8
*Kx
, size_t Kx_len
,
7146 u8
*z
, unsigned int hash_len
)
7148 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7153 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7156 /* HKDF-Extract(<>, IKM=K.x) */
7157 os_memset(salt
, 0, hash_len
);
7158 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
7160 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
7162 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
7163 info
= os_malloc(info_len
);
7167 os_memcpy(pos
, mac_init
, ETH_ALEN
);
7169 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
7171 os_memcpy(pos
, Mx
, Mx_len
);
7173 os_memcpy(pos
, Nx
, Nx_len
);
7175 os_memcpy(pos
, code
, os_strlen(code
));
7177 /* HKDF-Expand(PRK, info, L) */
7179 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7181 else if (hash_len
== 48)
7182 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7184 else if (hash_len
== 64)
7185 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7190 os_memset(prk
, 0, hash_len
);
7194 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
7200 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
7201 const char *identifier
)
7203 if (!attr_id
&& identifier
) {
7204 wpa_printf(MSG_DEBUG
,
7205 "DPP: No PKEX code identifier received, but expected one");
7209 if (attr_id
&& !identifier
) {
7210 wpa_printf(MSG_DEBUG
,
7211 "DPP: PKEX code identifier received, but not expecting one");
7215 if (attr_id
&& identifier
&&
7216 (os_strlen(identifier
) != attr_id_len
||
7217 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
7218 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
7226 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
7227 struct dpp_bootstrap_info
*bi
,
7230 const char *identifier
,
7232 const u8
*buf
, size_t len
)
7234 const u8
*attr_group
, *attr_id
, *attr_key
;
7235 u16 attr_group_len
, attr_id_len
, attr_key_len
;
7236 const struct dpp_curve_params
*curve
= bi
->curve
;
7238 struct dpp_pkex
*pkex
= NULL
;
7239 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
7240 BN_CTX
*bnctx
= NULL
;
7241 EC_GROUP
*group
= NULL
;
7242 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7243 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
7244 const EC_POINT
*Y_point
;
7245 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7246 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7249 EVP_PKEY_CTX
*ctx
= NULL
;
7251 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
7252 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7253 "PKEX counter t limit reached - ignore message");
7257 #ifdef CONFIG_TESTING_OPTIONS
7258 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7259 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7260 MAC2STR(dpp_pkex_peer_mac_override
));
7261 peer_mac
= dpp_pkex_peer_mac_override
;
7263 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7264 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7265 MAC2STR(dpp_pkex_own_mac_override
));
7266 own_mac
= dpp_pkex_own_mac_override
;
7268 #endif /* CONFIG_TESTING_OPTIONS */
7271 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
7273 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
7276 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
7278 if (!attr_group
|| attr_group_len
!= 2) {
7279 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7280 "Missing or invalid Finite Cyclic Group attribute");
7283 ike_group
= WPA_GET_LE16(attr_group
);
7284 if (ike_group
!= curve
->ike_group
) {
7285 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7286 "Mismatching PKEX curve: peer=%u own=%u",
7287 ike_group
, curve
->ike_group
);
7288 pkex
= os_zalloc(sizeof(*pkex
));
7293 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
7294 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
7295 if (!pkex
->exchange_resp
)
7300 /* M in Encrypted Key attribute */
7301 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
7303 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
7304 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
7305 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7306 "Missing Encrypted Key attribute");
7310 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7311 bnctx
= BN_CTX_new();
7314 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
7320 X
= EC_POINT_new(group
);
7321 M
= EC_POINT_new(group
);
7322 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7323 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7324 if (!X
|| !M
|| !Mx
|| !My
||
7325 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
7326 EC_POINT_is_at_infinity(group
, M
) ||
7327 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
7328 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
7329 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
7330 EC_POINT_is_at_infinity(group
, X
) ||
7331 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
7332 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7333 "Invalid Encrypted Key value");
7337 dpp_debug_print_point("DPP: M", group
, M
);
7338 dpp_debug_print_point("DPP: X'", group
, X
);
7340 pkex
= os_zalloc(sizeof(*pkex
));
7343 pkex
->t
= bi
->pkex_t
;
7344 pkex
->msg_ctx
= msg_ctx
;
7346 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7347 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7349 pkex
->identifier
= os_strdup(identifier
);
7350 if (!pkex
->identifier
)
7353 pkex
->code
= os_strdup(code
);
7357 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
7359 X_ec
= EC_KEY_new();
7361 EC_KEY_set_group(X_ec
, group
) != 1 ||
7362 EC_KEY_set_public_key(X_ec
, X
) != 1)
7364 pkex
->x
= EVP_PKEY_new();
7366 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
7369 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7370 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
7374 /* Generate a random ephemeral keypair y/Y */
7375 #ifdef CONFIG_TESTING_OPTIONS
7376 if (dpp_pkex_ephemeral_key_override_len
) {
7377 const struct dpp_curve_params
*tmp_curve
;
7379 wpa_printf(MSG_INFO
,
7380 "DPP: TESTING - override ephemeral key y/Y");
7381 pkex
->y
= dpp_set_keypair(&tmp_curve
,
7382 dpp_pkex_ephemeral_key_override
,
7383 dpp_pkex_ephemeral_key_override_len
);
7385 pkex
->y
= dpp_gen_keypair(curve
);
7387 #else /* CONFIG_TESTING_OPTIONS */
7388 pkex
->y
= dpp_gen_keypair(curve
);
7389 #endif /* CONFIG_TESTING_OPTIONS */
7394 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
7397 Y_point
= EC_KEY_get0_public_key(Y_ec
);
7400 dpp_debug_print_point("DPP: Y", group
, Y_point
);
7401 N
= EC_POINT_new(group
);
7404 if (!N
|| !Nx
|| !Ny
||
7405 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
7406 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
7408 dpp_debug_print_point("DPP: N", group
, N
);
7410 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
7412 if (!pkex
->exchange_resp
)
7416 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7418 EVP_PKEY_derive_init(ctx
) != 1 ||
7419 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
7420 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7421 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7422 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7423 wpa_printf(MSG_ERROR
,
7424 "DPP: Failed to derive ECDH shared secret: %s",
7425 ERR_error_string(ERR_get_error(), NULL
));
7429 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7432 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7434 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
7435 pkex
->Mx
, curve
->prime_len
,
7436 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
7437 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
7438 os_memset(Kx
, 0, Kx_len
);
7442 pkex
->exchange_done
= 1;
7445 EVP_PKEY_CTX_free(ctx
);
7458 EC_GROUP_free(group
);
7461 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
7462 dpp_pkex_free(pkex
);
7468 static struct wpabuf
*
7469 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
7470 const struct wpabuf
*A_pub
, const u8
*u
)
7472 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7473 struct wpabuf
*msg
= NULL
;
7474 size_t clear_len
, attr_len
;
7475 struct wpabuf
*clear
= NULL
;
7481 /* {A, u, [bootstrapping info]}z */
7482 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7483 clear
= wpabuf_alloc(clear_len
);
7484 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7485 #ifdef CONFIG_TESTING_OPTIONS
7486 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
7488 #endif /* CONFIG_TESTING_OPTIONS */
7489 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
7493 #ifdef CONFIG_TESTING_OPTIONS
7494 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7495 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7496 goto skip_bootstrap_key
;
7498 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
7499 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7500 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7501 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7502 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7504 goto skip_bootstrap_key
;
7506 #endif /* CONFIG_TESTING_OPTIONS */
7508 /* A in Bootstrap Key attribute */
7509 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7510 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
7511 wpabuf_put_buf(clear
, A_pub
);
7513 #ifdef CONFIG_TESTING_OPTIONS
7515 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
7516 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
7517 goto skip_i_auth_tag
;
7519 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
7520 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
7521 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7522 wpabuf_put_le16(clear
, curve
->hash_len
);
7523 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
7524 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
7525 goto skip_i_auth_tag
;
7527 #endif /* CONFIG_TESTING_OPTIONS */
7529 /* u in I-Auth tag attribute */
7530 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
7531 wpabuf_put_le16(clear
, curve
->hash_len
);
7532 wpabuf_put_data(clear
, u
, curve
->hash_len
);
7534 #ifdef CONFIG_TESTING_OPTIONS
7536 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
7537 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7538 goto skip_wrapped_data
;
7540 #endif /* CONFIG_TESTING_OPTIONS */
7542 addr
[0] = wpabuf_head_u8(msg
) + 2;
7543 len
[0] = DPP_HDR_LEN
;
7546 len
[1] = sizeof(octet
);
7547 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7548 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7550 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7551 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7552 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7554 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7555 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7556 wpabuf_head(clear
), wpabuf_len(clear
),
7557 2, addr
, len
, wrapped
) < 0)
7559 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7560 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7562 #ifdef CONFIG_TESTING_OPTIONS
7563 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
7564 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7565 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7568 #endif /* CONFIG_TESTING_OPTIONS */
7581 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
7583 const u8
*buf
, size_t buflen
)
7585 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
7586 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
7587 EC_GROUP
*group
= NULL
;
7588 BN_CTX
*bnctx
= NULL
;
7589 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7590 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7591 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
7592 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7593 EVP_PKEY_CTX
*ctx
= NULL
;
7594 EC_KEY
*Y_ec
= NULL
;
7595 size_t Jx_len
, Kx_len
;
7596 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7599 u8 u
[DPP_MAX_HASH_LEN
];
7602 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
7605 #ifdef CONFIG_TESTING_OPTIONS
7606 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
7607 wpa_printf(MSG_INFO
,
7608 "DPP: TESTING - stop at PKEX Exchange Response");
7613 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7614 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7615 MAC2STR(dpp_pkex_peer_mac_override
));
7616 peer_mac
= dpp_pkex_peer_mac_override
;
7618 #endif /* CONFIG_TESTING_OPTIONS */
7620 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7622 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
7624 if (!attr_status
|| attr_status_len
!= 1) {
7625 dpp_pkex_fail(pkex
, "No DPP Status attribute");
7628 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
7630 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
7631 attr_group
= dpp_get_attr(buf
, buflen
,
7632 DPP_ATTR_FINITE_CYCLIC_GROUP
,
7634 if (attr_group
&& attr_group_len
== 2) {
7635 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7636 "Peer indicated mismatching PKEX group - proposed %u",
7637 WPA_GET_LE16(attr_group
));
7642 if (attr_status
[0] != DPP_STATUS_OK
) {
7643 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
7648 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
7650 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
7651 pkex
->identifier
)) {
7652 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
7656 /* N in Encrypted Key attribute */
7657 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
7659 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
7660 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
7664 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
7665 bnctx
= BN_CTX_new();
7668 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
7669 pkex
->identifier
, bnctx
, &group
);
7674 Y
= EC_POINT_new(group
);
7675 N
= EC_POINT_new(group
);
7676 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7677 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7678 if (!Y
|| !N
|| !Nx
|| !Ny
||
7679 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
7680 EC_POINT_is_at_infinity(group
, N
) ||
7681 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
7682 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
7683 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
7684 EC_POINT_is_at_infinity(group
, Y
) ||
7685 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
7686 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
7690 dpp_debug_print_point("DPP: N", group
, N
);
7691 dpp_debug_print_point("DPP: Y'", group
, Y
);
7693 pkex
->exchange_done
= 1;
7695 /* ECDH: J = a * Y’ */
7696 Y_ec
= EC_KEY_new();
7698 EC_KEY_set_group(Y_ec
, group
) != 1 ||
7699 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
7701 pkex
->y
= EVP_PKEY_new();
7703 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
7705 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
7707 EVP_PKEY_derive_init(ctx
) != 1 ||
7708 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7709 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7710 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7711 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
7712 wpa_printf(MSG_ERROR
,
7713 "DPP: Failed to derive ECDH shared secret: %s",
7714 ERR_error_string(ERR_get_error(), NULL
));
7718 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
7721 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
7722 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
7723 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
7724 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
7725 if (!A_pub
|| !Y_pub
|| !X_pub
)
7727 addr
[0] = pkex
->own_mac
;
7729 addr
[1] = wpabuf_head(A_pub
);
7730 len
[1] = wpabuf_len(A_pub
) / 2;
7731 addr
[2] = wpabuf_head(Y_pub
);
7732 len
[2] = wpabuf_len(Y_pub
) / 2;
7733 addr
[3] = wpabuf_head(X_pub
);
7734 len
[3] = wpabuf_len(X_pub
) / 2;
7735 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
7737 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
7740 EVP_PKEY_CTX_free(ctx
);
7741 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
7743 EVP_PKEY_derive_init(ctx
) != 1 ||
7744 EVP_PKEY_derive_set_peer(ctx
, pkex
->y
) != 1 ||
7745 EVP_PKEY_derive(ctx
, NULL
, &Kx_len
) != 1 ||
7746 Kx_len
> DPP_MAX_SHARED_SECRET_LEN
||
7747 EVP_PKEY_derive(ctx
, Kx
, &Kx_len
) != 1) {
7748 wpa_printf(MSG_ERROR
,
7749 "DPP: Failed to derive ECDH shared secret: %s",
7750 ERR_error_string(ERR_get_error(), NULL
));
7754 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7757 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7759 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
7760 pkex
->Mx
, curve
->prime_len
,
7761 attr_key
/* N.x */, attr_key_len
/ 2,
7762 pkex
->code
, Kx
, Kx_len
,
7763 pkex
->z
, curve
->hash_len
);
7764 os_memset(Kx
, 0, Kx_len
);
7768 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
7782 EVP_PKEY_CTX_free(ctx
);
7784 EC_GROUP_free(group
);
7787 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
7792 static struct wpabuf
*
7793 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
7794 const struct wpabuf
*B_pub
, const u8
*v
)
7796 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7797 struct wpabuf
*msg
= NULL
;
7802 struct wpabuf
*clear
= NULL
;
7803 size_t clear_len
, attr_len
;
7805 /* {B, v [bootstrapping info]}z */
7806 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
7807 clear
= wpabuf_alloc(clear_len
);
7808 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7809 #ifdef CONFIG_TESTING_OPTIONS
7810 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
7812 #endif /* CONFIG_TESTING_OPTIONS */
7813 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
7817 #ifdef CONFIG_TESTING_OPTIONS
7818 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7819 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
7820 goto skip_bootstrap_key
;
7822 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
7823 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
7824 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7825 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
7826 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
7828 goto skip_bootstrap_key
;
7830 #endif /* CONFIG_TESTING_OPTIONS */
7832 /* B in Bootstrap Key attribute */
7833 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
7834 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
7835 wpabuf_put_buf(clear
, B_pub
);
7837 #ifdef CONFIG_TESTING_OPTIONS
7839 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
7840 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
7841 goto skip_r_auth_tag
;
7843 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
7844 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
7845 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7846 wpabuf_put_le16(clear
, curve
->hash_len
);
7847 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
7848 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
7849 goto skip_r_auth_tag
;
7851 #endif /* CONFIG_TESTING_OPTIONS */
7853 /* v in R-Auth tag attribute */
7854 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
7855 wpabuf_put_le16(clear
, curve
->hash_len
);
7856 wpabuf_put_data(clear
, v
, curve
->hash_len
);
7858 #ifdef CONFIG_TESTING_OPTIONS
7860 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
7861 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
7862 goto skip_wrapped_data
;
7864 #endif /* CONFIG_TESTING_OPTIONS */
7866 addr
[0] = wpabuf_head_u8(msg
) + 2;
7867 len
[0] = DPP_HDR_LEN
;
7870 len
[1] = sizeof(octet
);
7871 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7872 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7874 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7875 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7876 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7878 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7879 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
7880 wpabuf_head(clear
), wpabuf_len(clear
),
7881 2, addr
, len
, wrapped
) < 0)
7883 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7884 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7886 #ifdef CONFIG_TESTING_OPTIONS
7887 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
7888 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
7889 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
7892 #endif /* CONFIG_TESTING_OPTIONS */
7905 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
7907 const u8
*buf
, size_t buflen
)
7909 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7910 EVP_PKEY_CTX
*ctx
= NULL
;
7911 size_t Jx_len
, Lx_len
;
7912 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
7913 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
7914 const u8
*wrapped_data
, *b_key
, *peer_u
;
7915 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
7919 u8
*unwrapped
= NULL
;
7920 size_t unwrapped_len
= 0;
7921 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
7922 struct wpabuf
*B_pub
= NULL
;
7923 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
7925 #ifdef CONFIG_TESTING_OPTIONS
7926 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
7927 wpa_printf(MSG_INFO
,
7928 "DPP: TESTING - stop at PKEX CR Request");
7932 #endif /* CONFIG_TESTING_OPTIONS */
7934 if (!pkex
->exchange_done
|| pkex
->failed
||
7935 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
7938 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
7940 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7942 "Missing or invalid required Wrapped Data attribute");
7946 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7947 wrapped_data
, wrapped_data_len
);
7948 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7949 unwrapped
= os_malloc(unwrapped_len
);
7954 len
[0] = DPP_HDR_LEN
;
7957 len
[1] = sizeof(octet
);
7958 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7959 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7961 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
7962 wrapped_data
, wrapped_data_len
,
7963 2, addr
, len
, unwrapped
) < 0) {
7965 "AES-SIV decryption failed - possible PKEX code mismatch");
7970 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7971 unwrapped
, unwrapped_len
);
7973 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7974 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
7978 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
7980 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
7981 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
7984 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
7986 if (!pkex
->peer_bootstrap_key
) {
7987 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
7990 dpp_debug_print_key("DPP: Peer bootstrap public key",
7991 pkex
->peer_bootstrap_key
);
7993 /* ECDH: J' = y * A' */
7994 ctx
= EVP_PKEY_CTX_new(pkex
->y
, NULL
);
7996 EVP_PKEY_derive_init(ctx
) != 1 ||
7997 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
7998 EVP_PKEY_derive(ctx
, NULL
, &Jx_len
) != 1 ||
7999 Jx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8000 EVP_PKEY_derive(ctx
, Jx
, &Jx_len
) != 1) {
8001 wpa_printf(MSG_ERROR
,
8002 "DPP: Failed to derive ECDH shared secret: %s",
8003 ERR_error_string(ERR_get_error(), NULL
));
8007 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
8010 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
8011 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8012 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8013 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8014 if (!A_pub
|| !Y_pub
|| !X_pub
)
8016 addr
[0] = pkex
->peer_mac
;
8018 addr
[1] = wpabuf_head(A_pub
);
8019 len
[1] = wpabuf_len(A_pub
) / 2;
8020 addr
[2] = wpabuf_head(Y_pub
);
8021 len
[2] = wpabuf_len(Y_pub
) / 2;
8022 addr
[3] = wpabuf_head(X_pub
);
8023 len
[3] = wpabuf_len(X_pub
) / 2;
8024 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
8027 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
8029 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
8030 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
8031 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
8032 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
8033 u
, curve
->hash_len
);
8034 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
8038 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
8040 /* ECDH: L = b * X' */
8041 EVP_PKEY_CTX_free(ctx
);
8042 ctx
= EVP_PKEY_CTX_new(pkex
->own_bi
->pubkey
, NULL
);
8044 EVP_PKEY_derive_init(ctx
) != 1 ||
8045 EVP_PKEY_derive_set_peer(ctx
, pkex
->x
) != 1 ||
8046 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
8047 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8048 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
8049 wpa_printf(MSG_ERROR
,
8050 "DPP: Failed to derive ECDH shared secret: %s",
8051 ERR_error_string(ERR_get_error(), NULL
));
8055 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8058 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8059 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
8062 addr
[0] = pkex
->own_mac
;
8064 addr
[1] = wpabuf_head(B_pub
);
8065 len
[1] = wpabuf_len(B_pub
) / 2;
8066 addr
[2] = wpabuf_head(X_pub
);
8067 len
[2] = wpabuf_len(X_pub
) / 2;
8068 addr
[3] = wpabuf_head(Y_pub
);
8069 len
[3] = wpabuf_len(Y_pub
) / 2;
8070 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8072 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
8074 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
8079 EVP_PKEY_CTX_free(ctx
);
8087 wpa_printf(MSG_DEBUG
,
8088 "DPP: PKEX Commit-Reveal Request processing failed");
8093 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
8094 const u8
*buf
, size_t buflen
)
8096 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8097 const u8
*wrapped_data
, *b_key
, *peer_v
;
8098 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
8102 u8
*unwrapped
= NULL
;
8103 size_t unwrapped_len
= 0;
8105 u8 v
[DPP_MAX_HASH_LEN
];
8107 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
8108 EVP_PKEY_CTX
*ctx
= NULL
;
8109 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8111 #ifdef CONFIG_TESTING_OPTIONS
8112 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
8113 wpa_printf(MSG_INFO
,
8114 "DPP: TESTING - stop at PKEX CR Response");
8118 #endif /* CONFIG_TESTING_OPTIONS */
8120 if (!pkex
->exchange_done
|| pkex
->failed
||
8121 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8124 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8126 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8128 "Missing or invalid required Wrapped Data attribute");
8132 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8133 wrapped_data
, wrapped_data_len
);
8134 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8135 unwrapped
= os_malloc(unwrapped_len
);
8140 len
[0] = DPP_HDR_LEN
;
8143 len
[1] = sizeof(octet
);
8144 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8145 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8147 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8148 wrapped_data
, wrapped_data_len
,
8149 2, addr
, len
, unwrapped
) < 0) {
8151 "AES-SIV decryption failed - possible PKEX code mismatch");
8155 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8156 unwrapped
, unwrapped_len
);
8158 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8159 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8163 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8165 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8166 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8169 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8171 if (!pkex
->peer_bootstrap_key
) {
8172 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8175 dpp_debug_print_key("DPP: Peer bootstrap public key",
8176 pkex
->peer_bootstrap_key
);
8178 /* ECDH: L' = x * B' */
8179 ctx
= EVP_PKEY_CTX_new(pkex
->x
, NULL
);
8181 EVP_PKEY_derive_init(ctx
) != 1 ||
8182 EVP_PKEY_derive_set_peer(ctx
, pkex
->peer_bootstrap_key
) != 1 ||
8183 EVP_PKEY_derive(ctx
, NULL
, &Lx_len
) != 1 ||
8184 Lx_len
> DPP_MAX_SHARED_SECRET_LEN
||
8185 EVP_PKEY_derive(ctx
, Lx
, &Lx_len
) != 1) {
8186 wpa_printf(MSG_ERROR
,
8187 "DPP: Failed to derive ECDH shared secret: %s",
8188 ERR_error_string(ERR_get_error(), NULL
));
8192 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8195 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8196 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8197 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8198 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8199 if (!B_pub
|| !X_pub
|| !Y_pub
)
8201 addr
[0] = pkex
->peer_mac
;
8203 addr
[1] = wpabuf_head(B_pub
);
8204 len
[1] = wpabuf_len(B_pub
) / 2;
8205 addr
[2] = wpabuf_head(X_pub
);
8206 len
[2] = wpabuf_len(X_pub
) / 2;
8207 addr
[3] = wpabuf_head(Y_pub
);
8208 len
[3] = wpabuf_len(Y_pub
) / 2;
8209 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8212 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
8214 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
8215 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
8216 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
8217 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
8218 v
, curve
->hash_len
);
8219 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
8223 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
8230 EVP_PKEY_CTX_free(ctx
);
8238 void dpp_pkex_free(struct dpp_pkex
*pkex
)
8243 os_free(pkex
->identifier
);
8244 os_free(pkex
->code
);
8245 EVP_PKEY_free(pkex
->x
);
8246 EVP_PKEY_free(pkex
->y
);
8247 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
8248 wpabuf_free(pkex
->exchange_req
);
8249 wpabuf_free(pkex
->exchange_resp
);
8254 #ifdef CONFIG_TESTING_OPTIONS
8255 char * dpp_corrupt_connector_signature(const char *connector
)
8257 char *tmp
, *pos
, *signed3
= NULL
;
8258 unsigned char *signature
= NULL
;
8259 size_t signature_len
= 0, signed3_len
;
8261 tmp
= os_zalloc(os_strlen(connector
) + 5);
8264 os_memcpy(tmp
, connector
, os_strlen(connector
));
8266 pos
= os_strchr(tmp
, '.');
8270 pos
= os_strchr(pos
+ 1, '.');
8275 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
8277 signature
= base64_url_decode((const unsigned char *) pos
,
8278 os_strlen(pos
), &signature_len
);
8279 if (!signature
|| signature_len
== 0)
8281 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
8282 signature
, signature_len
);
8283 signature
[signature_len
- 1] ^= 0x01;
8284 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
8285 signature
, signature_len
);
8286 signed3
= (char *) base64_url_encode(signature
, signature_len
,
8290 os_memcpy(pos
, signed3
, signed3_len
);
8291 pos
[signed3_len
] = '\0';
8292 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
8304 #endif /* CONFIG_TESTING_OPTIONS */
8309 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
8310 size_t net_access_key_len
)
8312 struct wpabuf
*pub
= NULL
;
8314 struct dpp_pfs
*pfs
;
8316 pfs
= os_zalloc(sizeof(*pfs
));
8320 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
8321 net_access_key_len
);
8323 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8326 EVP_PKEY_free(own_key
);
8328 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
8332 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
8333 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
8337 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
8340 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
8341 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
8342 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
8343 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
8344 wpabuf_put_buf(pfs
->ie
, pub
);
8346 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
8357 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
8359 if (peer_ie_len
< 2)
8361 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
8362 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
8366 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
8368 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
8370 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
8373 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
8378 void dpp_pfs_free(struct dpp_pfs
*pfs
)
8382 crypto_ecdh_deinit(pfs
->ecdh
);
8383 wpabuf_free(pfs
->ie
);
8384 wpabuf_clear_free(pfs
->secret
);
8388 #endif /* CONFIG_DPP2 */
8391 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
8393 struct dpp_bootstrap_info
*bi
;
8394 unsigned int max_id
= 0;
8396 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8397 if (bi
->id
> max_id
)
8404 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
8406 struct dpp_bootstrap_info
*bi
, *tmp
;
8412 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
8413 struct dpp_bootstrap_info
, list
) {
8414 if (id
&& bi
->id
!= id
)
8417 dl_list_del(&bi
->list
);
8418 dpp_bootstrap_info_free(bi
);
8422 return 0; /* flush succeeds regardless of entries found */
8423 return found
? 0 : -1;
8427 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
8430 struct dpp_bootstrap_info
*bi
;
8435 bi
= dpp_parse_qr_code(uri
);
8439 bi
->id
= dpp_next_id(dpp
);
8440 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8445 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
8447 char *chan
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
, *curve
= NULL
;
8450 size_t privkey_len
= 0;
8453 struct dpp_bootstrap_info
*bi
;
8458 bi
= os_zalloc(sizeof(*bi
));
8462 if (os_strstr(cmd
, "type=qrcode"))
8463 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
8464 else if (os_strstr(cmd
, "type=pkex"))
8465 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8469 chan
= get_param(cmd
, " chan=");
8470 mac
= get_param(cmd
, " mac=");
8471 info
= get_param(cmd
, " info=");
8472 curve
= get_param(cmd
, " curve=");
8473 key
= get_param(cmd
, " key=");
8476 privkey_len
= os_strlen(key
) / 2;
8477 privkey
= os_malloc(privkey_len
);
8479 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8483 pk
= dpp_keygen(bi
, curve
, privkey
, privkey_len
);
8487 len
= 4; /* "DPP:" */
8489 if (dpp_parse_uri_chan_list(bi
, chan
) < 0)
8491 len
+= 3 + os_strlen(chan
); /* C:...; */
8494 if (dpp_parse_uri_mac(bi
, mac
) < 0)
8496 len
+= 3 + os_strlen(mac
); /* M:...; */
8499 if (dpp_parse_uri_info(bi
, info
) < 0)
8501 len
+= 3 + os_strlen(info
); /* I:...; */
8503 len
+= 4 + os_strlen(pk
);
8504 bi
->uri
= os_malloc(len
+ 1);
8507 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8508 chan
? "C:" : "", chan
? chan
: "", chan
? ";" : "",
8509 mac
? "M:" : "", mac
? mac
: "", mac
? ";" : "",
8510 info
? "I:" : "", info
? info
: "", info
? ";" : "",
8512 bi
->id
= dpp_next_id(dpp
);
8513 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8522 str_clear_free(key
);
8523 bin_clear_free(privkey
, privkey_len
);
8524 dpp_bootstrap_info_free(bi
);
8529 struct dpp_bootstrap_info
*
8530 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
8532 struct dpp_bootstrap_info
*bi
;
8537 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8545 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
8547 unsigned int id_val
;
8549 if (os_strcmp(id
, "*") == 0) {
8557 return dpp_bootstrap_del(dpp
, id_val
);
8561 struct dpp_bootstrap_info
*
8562 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
8565 struct dpp_bootstrap_info
*bi
;
8567 bi
= os_zalloc(sizeof(*bi
));
8570 bi
->id
= dpp_next_id(dpp
);
8571 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8572 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
8575 bi
->curve
= pkex
->own_bi
->curve
;
8576 bi
->pubkey
= pkex
->peer_bootstrap_key
;
8577 pkex
->peer_bootstrap_key
= NULL
;
8578 if (dpp_bootstrap_key_hash(bi
) < 0) {
8579 dpp_bootstrap_info_free(bi
);
8582 dpp_pkex_free(pkex
);
8583 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8588 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
8590 struct dpp_bootstrap_info
*bi
;
8592 bi
= dpp_bootstrap_get_id(dpp
, id
);
8599 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
8600 char *reply
, int reply_size
)
8602 struct dpp_bootstrap_info
*bi
;
8603 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
8605 bi
= dpp_bootstrap_get_id(dpp
, id
);
8608 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
8610 return os_snprintf(reply
, reply_size
, "type=%s\n"
8611 "mac_addr=" MACSTR
"\n"
8616 dpp_bootstrap_type_txt(bi
->type
),
8617 MAC2STR(bi
->mac_addr
),
8618 bi
->info
? bi
->info
: "",
8625 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
8626 const u8
*r_bootstrap
,
8627 struct dpp_bootstrap_info
**own_bi
,
8628 struct dpp_bootstrap_info
**peer_bi
)
8630 struct dpp_bootstrap_info
*bi
;
8637 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8638 if (!*own_bi
&& bi
->own
&&
8639 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
8640 SHA256_MAC_LEN
) == 0) {
8641 wpa_printf(MSG_DEBUG
,
8642 "DPP: Found matching own bootstrapping information");
8646 if (!*peer_bi
&& !bi
->own
&&
8647 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
8648 SHA256_MAC_LEN
) == 0) {
8649 wpa_printf(MSG_DEBUG
,
8650 "DPP: Found matching peer bootstrapping information");
8654 if (*own_bi
&& *peer_bi
)
8661 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
8663 struct dpp_configurator
*conf
;
8664 unsigned int max_id
= 0;
8666 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
8668 if (conf
->id
> max_id
)
8675 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
8680 size_t privkey_len
= 0;
8682 struct dpp_configurator
*conf
= NULL
;
8684 curve
= get_param(cmd
, " curve=");
8685 key
= get_param(cmd
, " key=");
8688 privkey_len
= os_strlen(key
) / 2;
8689 privkey
= os_malloc(privkey_len
);
8691 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8695 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
8699 conf
->id
= dpp_next_configurator_id(dpp
);
8700 dl_list_add(&dpp
->configurator
, &conf
->list
);
8705 str_clear_free(key
);
8706 bin_clear_free(privkey
, privkey_len
);
8707 dpp_configurator_free(conf
);
8712 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
8714 struct dpp_configurator
*conf
, *tmp
;
8720 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
8721 struct dpp_configurator
, list
) {
8722 if (id
&& conf
->id
!= id
)
8725 dl_list_del(&conf
->list
);
8726 dpp_configurator_free(conf
);
8730 return 0; /* flush succeeds regardless of entries found */
8731 return found
? 0 : -1;
8735 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
8737 unsigned int id_val
;
8739 if (os_strcmp(id
, "*") == 0) {
8747 return dpp_configurator_del(dpp
, id_val
);
8751 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
8752 char *buf
, size_t buflen
)
8754 struct dpp_configurator
*conf
;
8756 conf
= dpp_configurator_get_id(dpp
, id
);
8760 return dpp_configurator_get_key(conf
, buf
, buflen
);
8766 static void dpp_connection_free(struct dpp_connection
*conn
)
8768 if (conn
->sock
>= 0) {
8769 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
8771 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
8772 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8775 wpabuf_free(conn
->msg
);
8776 wpabuf_free(conn
->msg_out
);
8777 dpp_auth_deinit(conn
->auth
);
8782 static void dpp_connection_remove(struct dpp_connection
*conn
)
8784 dl_list_del(&conn
->list
);
8785 dpp_connection_free(conn
);
8789 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
8791 struct dpp_connection
*conn
, *tmp
;
8793 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
8795 dpp_connection_remove(conn
);
8799 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
8801 struct dpp_connection
*conn
, *tmp
;
8803 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
8805 dpp_connection_remove(conn
);
8810 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
8812 struct dpp_relay_controller
*ctrl
, *tmp
;
8817 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
8818 struct dpp_relay_controller
, list
) {
8819 dl_list_del(&ctrl
->list
);
8820 dpp_relay_controller_free(ctrl
);
8824 #endif /* CONFIG_DPP2 */
8827 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
8829 struct dpp_global
*dpp
;
8831 dpp
= os_zalloc(sizeof(*dpp
));
8834 dpp
->msg_ctx
= config
->msg_ctx
;
8836 dpp
->cb_ctx
= config
->cb_ctx
;
8837 dpp
->process_conf_obj
= config
->process_conf_obj
;
8838 #endif /* CONFIG_DPP2 */
8840 dl_list_init(&dpp
->bootstrap
);
8841 dl_list_init(&dpp
->configurator
);
8843 dl_list_init(&dpp
->controllers
);
8844 dl_list_init(&dpp
->tcp_init
);
8845 #endif /* CONFIG_DPP2 */
8851 void dpp_global_clear(struct dpp_global
*dpp
)
8856 dpp_bootstrap_del(dpp
, 0);
8857 dpp_configurator_del(dpp
, 0);
8859 dpp_tcp_init_flush(dpp
);
8860 dpp_relay_flush_controllers(dpp
);
8861 dpp_controller_stop(dpp
);
8862 #endif /* CONFIG_DPP2 */
8866 void dpp_global_deinit(struct dpp_global
*dpp
)
8868 dpp_global_clear(dpp
);
8875 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
8876 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
8877 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
8881 int dpp_relay_add_controller(struct dpp_global
*dpp
,
8882 struct dpp_relay_config
*config
)
8884 struct dpp_relay_controller
*ctrl
;
8889 ctrl
= os_zalloc(sizeof(*ctrl
));
8892 dl_list_init(&ctrl
->conn
);
8894 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
8895 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
8896 ctrl
->cb_ctx
= config
->cb_ctx
;
8897 ctrl
->tx
= config
->tx
;
8898 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
8899 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
8904 static struct dpp_relay_controller
*
8905 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
8907 struct dpp_relay_controller
*ctrl
;
8912 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
8914 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
8922 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
8924 struct dpp_authentication
*auth
= conn
->auth
;
8926 if (auth
->peer_version
>= 2 &&
8927 auth
->conf_resp_status
== DPP_STATUS_OK
) {
8928 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
8929 auth
->waiting_conf_result
= 1;
8933 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
8934 dpp_connection_remove(conn
);
8938 static int dpp_tcp_send(struct dpp_connection
*conn
)
8942 if (!conn
->msg_out
) {
8943 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8944 conn
->write_eloop
= 0;
8947 res
= send(conn
->sock
,
8948 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
8949 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
8951 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
8953 dpp_connection_remove(conn
);
8957 conn
->msg_out_pos
+= res
;
8958 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
8959 wpa_printf(MSG_DEBUG
,
8960 "DPP: %u/%u bytes of message sent to Controller",
8961 (unsigned int) conn
->msg_out_pos
,
8962 (unsigned int) wpabuf_len(conn
->msg_out
));
8963 if (!conn
->write_eloop
&&
8964 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
8965 dpp_conn_tx_ready
, conn
, NULL
) == 0)
8966 conn
->write_eloop
= 1;
8970 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
8971 wpabuf_free(conn
->msg_out
);
8972 conn
->msg_out
= NULL
;
8973 conn
->msg_out_pos
= 0;
8974 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
8975 conn
->write_eloop
= 0;
8976 if (!conn
->read_eloop
&&
8977 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
8978 dpp_controller_rx
, conn
, NULL
) == 0)
8979 conn
->read_eloop
= 1;
8980 if (conn
->on_tcp_tx_complete_remove
) {
8981 dpp_connection_remove(conn
);
8982 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
8984 dpp_controller_gas_done(conn
);
8985 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
8986 conn
->on_tcp_tx_complete_auth_ok
= 0;
8987 dpp_controller_auth_success(conn
, 1);
8994 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
8996 struct dpp_authentication
*auth
= conn
->auth
;
8999 int netrole_ap
= 0; /* TODO: make this configurable */
9001 os_snprintf(json
, sizeof(json
),
9002 "{\"name\":\"Test\","
9003 "\"wi-fi_tech\":\"infra\","
9004 "\"netRole\":\"%s\"}",
9005 netrole_ap
? "ap" : "sta");
9006 #ifdef CONFIG_TESTING_OPTIONS
9007 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
9008 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
9009 json
[29] = 'k'; /* replace "infra" with "knfra" */
9011 #endif /* CONFIG_TESTING_OPTIONS */
9012 wpa_printf(MSG_DEBUG
, "DPP: GAS Config Attributes: %s", json
);
9014 buf
= dpp_build_conf_req(auth
, json
);
9016 wpa_printf(MSG_DEBUG
,
9017 "DPP: No configuration request data available");
9021 wpabuf_free(conn
->msg_out
);
9022 conn
->msg_out_pos
= 0;
9023 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
9024 if (!conn
->msg_out
) {
9028 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
9029 wpabuf_put_data(conn
->msg_out
, wpabuf_head(buf
) + 1,
9030 wpabuf_len(buf
) - 1);
9033 if (dpp_tcp_send(conn
) == 1) {
9034 if (!conn
->write_eloop
) {
9035 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9039 conn
->write_eloop
= 1;
9045 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
9048 struct dpp_authentication
*auth
= conn
->auth
;
9053 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
9054 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
9055 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
9056 #ifdef CONFIG_TESTING_OPTIONS
9057 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
9058 wpa_printf(MSG_INFO
,
9059 "DPP: TESTING - stop at Authentication Confirm");
9060 if (auth
->configurator
) {
9061 /* Prevent GAS response */
9062 auth
->auth_success
= 0;
9066 #endif /* CONFIG_TESTING_OPTIONS */
9068 if (!auth
->configurator
)
9069 dpp_controller_start_gas_client(conn
);
9073 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
9075 struct dpp_connection
*conn
= eloop_ctx
;
9077 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
9082 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
9083 const struct hostapd_ip_addr
*ipaddr
,
9086 struct sockaddr_in
*dst
;
9088 struct sockaddr_in6
*dst6
;
9089 #endif /* CONFIG_IPV6 */
9091 switch (ipaddr
->af
) {
9093 dst
= (struct sockaddr_in
*) addr
;
9094 os_memset(dst
, 0, sizeof(*dst
));
9095 dst
->sin_family
= AF_INET
;
9096 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
9097 dst
->sin_port
= htons(port
);
9098 *addrlen
= sizeof(*dst
);
9102 dst6
= (struct sockaddr_in6
*) addr
;
9103 os_memset(dst6
, 0, sizeof(*dst6
));
9104 dst6
->sin6_family
= AF_INET6
;
9105 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
9106 sizeof(struct in6_addr
));
9107 dst6
->sin6_port
= htons(port
);
9108 *addrlen
= sizeof(*dst6
);
9110 #endif /* CONFIG_IPV6 */
9119 static struct dpp_connection
*
9120 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
9123 struct dpp_connection
*conn
;
9124 struct sockaddr_storage addr
;
9128 if (dl_list_len(&ctrl
->conn
) >= 15) {
9129 wpa_printf(MSG_DEBUG
,
9130 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9134 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
9135 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
9138 conn
= os_zalloc(sizeof(*conn
));
9142 conn
->global
= ctrl
->global
;
9144 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
9147 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9150 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
9151 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
9153 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9154 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9159 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
9160 if (errno
!= EINPROGRESS
) {
9161 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9167 * Continue connecting in the background; eloop will call us
9168 * once the connection is ready (or failed).
9172 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9173 dpp_conn_tx_ready
, conn
, NULL
) < 0)
9175 conn
->write_eloop
= 1;
9177 /* TODO: eloop timeout to clear a connection if it does not complete
9180 dl_list_add(&ctrl
->conn
, &conn
->list
);
9183 dpp_connection_free(conn
);
9188 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
9192 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
9195 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
9196 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
9197 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
9198 wpabuf_put_data(msg
, buf
, len
);
9199 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9204 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
9205 const u8
*buf
, size_t len
)
9207 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9209 wpa_printf(MSG_DEBUG
,
9210 "DPP: Continue already established Relay/Controller connection for this session");
9211 wpabuf_free(conn
->msg_out
);
9212 conn
->msg_out_pos
= 0;
9213 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9214 if (!conn
->msg_out
) {
9215 dpp_connection_remove(conn
);
9219 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9221 if (type
== DPP_PA_CONFIGURATION_RESULT
)
9222 conn
->on_tcp_tx_complete_remove
= 1;
9228 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
9229 const u8
*buf
, size_t len
, unsigned int freq
,
9230 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
9232 struct dpp_relay_controller
*ctrl
;
9233 struct dpp_connection
*conn
;
9234 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9236 /* Check if there is an already started session for this peer and if so,
9237 * continue that session (send this over TCP) and return 0.
9239 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
9240 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
9241 dl_list_for_each(ctrl
, &dpp
->controllers
,
9242 struct dpp_relay_controller
, list
) {
9243 dl_list_for_each(conn
, &ctrl
->conn
,
9244 struct dpp_connection
, list
) {
9245 if (os_memcmp(src
, conn
->mac_addr
,
9247 return dpp_relay_tx(conn
, hdr
, buf
, len
);
9255 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
9259 wpa_printf(MSG_DEBUG
,
9260 "DPP: Authentication Request for a configured Controller");
9261 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
9265 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9266 if (!conn
->msg_out
) {
9267 dpp_connection_remove(conn
);
9270 /* Message will be sent in dpp_conn_tx_ready() */
9276 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
9279 struct dpp_relay_controller
*ctrl
;
9280 struct dpp_connection
*conn
, *found
= NULL
;
9283 /* Check if there is a successfully completed authentication for this
9284 * and if so, continue that session (send this over TCP) and return 0.
9286 dl_list_for_each(ctrl
, &dpp
->controllers
,
9287 struct dpp_relay_controller
, list
) {
9290 dl_list_for_each(conn
, &ctrl
->conn
,
9291 struct dpp_connection
, list
) {
9292 if (os_memcmp(src
, conn
->mac_addr
,
9303 msg
= wpabuf_alloc(4 + 1 + data_len
);
9306 wpabuf_put_be32(msg
, 1 + data_len
);
9307 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
9308 wpabuf_put_data(msg
, data
, data_len
);
9309 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9311 wpabuf_free(conn
->msg_out
);
9312 conn
->msg_out_pos
= 0;
9313 conn
->msg_out
= msg
;
9319 static void dpp_controller_free(struct dpp_controller
*ctrl
)
9321 struct dpp_connection
*conn
, *tmp
;
9326 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
9328 dpp_connection_remove(conn
);
9330 if (ctrl
->sock
>= 0) {
9332 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
9334 os_free(ctrl
->configurator_params
);
9339 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
9340 const u8
*hdr
, const u8
*buf
, size_t len
)
9342 const u8
*r_bootstrap
, *i_bootstrap
;
9343 u16 r_bootstrap_len
, i_bootstrap_len
;
9344 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
9349 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
9351 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
9353 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
9354 wpa_printf(MSG_INFO
,
9355 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9358 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
9359 r_bootstrap
, r_bootstrap_len
);
9361 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
9363 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
9364 wpa_printf(MSG_INFO
,
9365 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9368 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
9369 i_bootstrap
, i_bootstrap_len
);
9371 /* Try to find own and peer bootstrapping key matches based on the
9372 * received hash values */
9373 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
9376 wpa_printf(MSG_INFO
,
9377 "No matching own bootstrapping key found - ignore message");
9382 wpa_printf(MSG_INFO
,
9383 "Already in DPP authentication exchange - ignore new one");
9387 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
9388 conn
->ctrl
->allowed_roles
,
9389 conn
->ctrl
->qr_mutual
,
9390 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
9392 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
9396 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
9398 conn
->ctrl
->configurator_params
) < 0) {
9399 dpp_connection_remove(conn
);
9403 wpabuf_free(conn
->msg_out
);
9404 conn
->msg_out_pos
= 0;
9405 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
9408 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
9409 wpabuf_put_data(conn
->msg_out
, wpabuf_head(conn
->auth
->resp_msg
) + 1,
9410 wpabuf_len(conn
->auth
->resp_msg
) - 1);
9412 if (dpp_tcp_send(conn
) == 1) {
9413 if (!conn
->write_eloop
) {
9414 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9418 conn
->write_eloop
= 1;
9426 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
9427 const u8
*hdr
, const u8
*buf
, size_t len
)
9429 struct dpp_authentication
*auth
= conn
->auth
;
9435 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
9437 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
9439 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
9440 wpa_printf(MSG_DEBUG
,
9441 "DPP: Start wait for full response");
9444 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
9445 dpp_connection_remove(conn
);
9449 wpabuf_free(conn
->msg_out
);
9450 conn
->msg_out_pos
= 0;
9451 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9452 if (!conn
->msg_out
) {
9456 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
9457 wpabuf_put_data(conn
->msg_out
, wpabuf_head(msg
) + 1,
9458 wpabuf_len(msg
) - 1);
9461 conn
->on_tcp_tx_complete_auth_ok
= 1;
9462 if (dpp_tcp_send(conn
) == 1) {
9463 if (!conn
->write_eloop
) {
9464 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9468 conn
->write_eloop
= 1;
9476 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
9477 const u8
*hdr
, const u8
*buf
, size_t len
)
9479 struct dpp_authentication
*auth
= conn
->auth
;
9481 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
9484 wpa_printf(MSG_DEBUG
,
9485 "DPP: No DPP Authentication in progress - drop");
9489 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
9490 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
9494 dpp_controller_auth_success(conn
, 0);
9499 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
9500 const u8
*hdr
, const u8
*buf
,
9503 struct dpp_authentication
*auth
= conn
->auth
;
9504 enum dpp_status_error status
;
9509 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
9511 if (!auth
|| !auth
->waiting_conf_result
) {
9512 wpa_printf(MSG_DEBUG
,
9513 "DPP: No DPP Configuration waiting for result - drop");
9517 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
9518 if (status
== DPP_STATUS_OK
)
9519 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9520 DPP_EVENT_CONF_SENT
);
9522 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9523 DPP_EVENT_CONF_FAILED
);
9524 return -1; /* to remove the completed connection */
9528 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
9531 const u8
*pos
, *end
;
9534 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
9538 if (end
- pos
< DPP_HDR_LEN
||
9539 WPA_GET_BE24(pos
) != OUI_WFA
||
9540 pos
[3] != DPP_OUI_TYPE
) {
9541 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
9546 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
9551 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
9554 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
9556 if (dpp_check_attrs(pos
, end
- pos
) < 0)
9560 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9561 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9562 conn
->freq
, msg
, len
);
9567 case DPP_PA_AUTHENTICATION_REQ
:
9568 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
9569 case DPP_PA_AUTHENTICATION_RESP
:
9570 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
9571 case DPP_PA_AUTHENTICATION_CONF
:
9572 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
9573 case DPP_PA_CONFIGURATION_RESULT
:
9574 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
9576 /* TODO: missing messages types */
9577 wpa_printf(MSG_DEBUG
,
9578 "DPP: Unsupported frame subtype %d", type
);
9584 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
9587 const u8
*pos
, *end
, *next
;
9589 const u8
*adv_proto
;
9591 struct wpabuf
*resp
, *buf
;
9592 struct dpp_authentication
*auth
= conn
->auth
;
9597 wpa_printf(MSG_DEBUG
,
9598 "DPP: Received DPP Configuration Request over TCP");
9600 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
9601 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9608 dialog_token
= *pos
++;
9611 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9612 slen
> end
- pos
|| slen
< 2)
9616 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9618 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9619 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9620 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9627 slen
= WPA_GET_LE16(pos
);
9629 if (slen
> end
- pos
)
9632 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
9636 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
9642 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
9644 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
9645 wpabuf_put_u8(buf
, dialog_token
);
9646 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
9647 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
9649 dpp_write_adv_proto(buf
);
9650 dpp_write_gas_query(buf
, resp
);
9653 /* Send Config Response over TCP; GAS fragmentation is taken care of by
9655 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
9656 wpabuf_free(conn
->msg_out
);
9657 conn
->msg_out_pos
= 0;
9658 conn
->msg_out
= buf
;
9659 conn
->on_tcp_tx_complete_gas_done
= 1;
9665 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
9667 struct dpp_authentication
*auth
= conn
->auth
;
9669 struct wpabuf
*msg
, *encaps
;
9670 enum dpp_status_error status
;
9672 wpa_printf(MSG_DEBUG
,
9673 "DPP: Configuration Response for local stack from TCP");
9675 res
= dpp_conf_resp_rx(auth
, resp
);
9678 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
9682 if (conn
->global
->process_conf_obj
)
9683 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
9688 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
9691 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
9692 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
9693 msg
= dpp_build_conf_result(auth
, status
);
9697 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9702 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
9703 wpabuf_put_data(encaps
, wpabuf_head(msg
) + 1, wpabuf_len(msg
) - 1);
9705 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
9707 wpabuf_free(conn
->msg_out
);
9708 conn
->msg_out_pos
= 0;
9709 conn
->msg_out
= encaps
;
9710 conn
->on_tcp_tx_complete_remove
= 1;
9713 /* This exchange will be terminated in the TX status handler */
9719 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
9724 const u8
*pos
, *end
, *next
, *adv_proto
;
9730 wpa_printf(MSG_DEBUG
,
9731 "DPP: Received DPP Configuration Response over TCP");
9736 dialog_token
= *pos
++;
9737 status
= WPA_GET_LE16(pos
);
9738 if (status
!= WLAN_STATUS_SUCCESS
) {
9739 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
9743 pos
+= 2; /* ignore GAS Comeback Delay */
9747 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
9748 slen
> end
- pos
|| slen
< 2)
9752 pos
++; /* skip QueryRespLenLimit and PAME-BI */
9754 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
9755 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
9756 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
9760 /* Query Response */
9763 slen
= WPA_GET_LE16(pos
);
9765 if (slen
> end
- pos
)
9768 buf
= wpabuf_alloc(slen
);
9771 wpabuf_put_data(buf
, pos
, slen
);
9773 if (!conn
->relay
&& !conn
->ctrl
)
9774 return dpp_tcp_rx_gas_resp(conn
, buf
);
9777 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
9781 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
9782 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
9783 dialog_token
, 0, buf
);
9789 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
9791 struct dpp_connection
*conn
= eloop_ctx
;
9795 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
9798 if (conn
->msg_len_octets
< 4) {
9801 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
9802 4 - conn
->msg_len_octets
, 0);
9804 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
9806 dpp_connection_remove(conn
);
9810 wpa_printf(MSG_DEBUG
,
9811 "DPP: No more data available over TCP");
9812 dpp_connection_remove(conn
);
9815 wpa_printf(MSG_DEBUG
,
9816 "DPP: Received %d/%d octet(s) of message length field",
9817 res
, (int) (4 - conn
->msg_len_octets
));
9818 conn
->msg_len_octets
+= res
;
9820 if (conn
->msg_len_octets
< 4) {
9821 wpa_printf(MSG_DEBUG
,
9822 "DPP: Need %d more octets of message length field",
9823 (int) (4 - conn
->msg_len_octets
));
9827 msglen
= WPA_GET_BE32(conn
->msg_len
);
9828 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
9829 if (msglen
> 65535) {
9830 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
9831 dpp_connection_remove(conn
);
9835 wpabuf_free(conn
->msg
);
9836 conn
->msg
= wpabuf_alloc(msglen
);
9840 wpa_printf(MSG_DEBUG
,
9841 "DPP: No buffer available for receiving the message");
9842 dpp_connection_remove(conn
);
9846 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
9847 (unsigned int) wpabuf_tailroom(conn
->msg
));
9849 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
9851 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
9852 dpp_connection_remove(conn
);
9856 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
9857 dpp_connection_remove(conn
);
9860 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
9861 wpabuf_put(conn
->msg
, res
);
9863 if (wpabuf_tailroom(conn
->msg
) > 0) {
9864 wpa_printf(MSG_DEBUG
,
9865 "DPP: Need %u more octets of message payload",
9866 (unsigned int) wpabuf_tailroom(conn
->msg
));
9870 conn
->msg_len_octets
= 0;
9871 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
9872 if (wpabuf_len(conn
->msg
) < 1) {
9873 dpp_connection_remove(conn
);
9877 pos
= wpabuf_head(conn
->msg
);
9879 case WLAN_PA_VENDOR_SPECIFIC
:
9880 if (dpp_controller_rx_action(conn
, pos
+ 1,
9881 wpabuf_len(conn
->msg
) - 1) < 0)
9882 dpp_connection_remove(conn
);
9884 case WLAN_PA_GAS_INITIAL_REQ
:
9885 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
9886 wpabuf_len(conn
->msg
) - 1) < 0)
9887 dpp_connection_remove(conn
);
9889 case WLAN_PA_GAS_INITIAL_RESP
:
9890 if (dpp_rx_gas_resp(conn
, pos
+ 1,
9891 wpabuf_len(conn
->msg
) - 1) < 0)
9892 dpp_connection_remove(conn
);
9895 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
9902 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
9904 struct dpp_controller
*ctrl
= eloop_ctx
;
9905 struct sockaddr_in addr
;
9906 socklen_t addr_len
= sizeof(addr
);
9908 struct dpp_connection
*conn
;
9910 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
9912 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
9914 wpa_printf(MSG_DEBUG
,
9915 "DPP: Failed to accept new connection: %s",
9919 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
9920 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
9922 conn
= os_zalloc(sizeof(*conn
));
9926 conn
->global
= ctrl
->global
;
9930 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9931 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9936 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
9937 dpp_controller_rx
, conn
, NULL
) < 0)
9939 conn
->read_eloop
= 1;
9941 /* TODO: eloop timeout to expire connections that do not complete in
9942 * reasonable time */
9943 dl_list_add(&ctrl
->conn
, &conn
->list
);
9952 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
9953 const struct hostapd_ip_addr
*addr
, int port
)
9955 struct dpp_connection
*conn
;
9956 struct sockaddr_storage saddr
;
9958 const u8
*hdr
, *pos
, *end
;
9961 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
9962 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
9963 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
9965 dpp_auth_deinit(auth
);
9969 conn
= os_zalloc(sizeof(*conn
));
9971 dpp_auth_deinit(auth
);
9977 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9981 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9982 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9987 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
9988 if (errno
!= EINPROGRESS
) {
9989 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9995 * Continue connecting in the background; eloop will call us
9996 * once the connection is ready (or failed).
10000 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10001 dpp_conn_tx_ready
, conn
, NULL
) < 0)
10003 conn
->write_eloop
= 1;
10005 hdr
= wpabuf_head(auth
->req_msg
);
10006 end
= hdr
+ wpabuf_len(auth
->req_msg
);
10007 hdr
+= 2; /* skip Category and Actiom */
10008 pos
= hdr
+ DPP_HDR_LEN
;
10009 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
10010 if (!conn
->msg_out
)
10012 /* Message will be sent in dpp_conn_tx_ready() */
10014 /* TODO: eloop timeout to clear a connection if it does not complete
10016 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
10019 dpp_connection_free(conn
);
10024 int dpp_controller_start(struct dpp_global
*dpp
,
10025 struct dpp_controller_config
*config
)
10027 struct dpp_controller
*ctrl
;
10029 struct sockaddr_in sin
;
10032 if (!dpp
|| dpp
->controller
)
10035 ctrl
= os_zalloc(sizeof(*ctrl
));
10038 ctrl
->global
= dpp
;
10039 if (config
->configurator_params
)
10040 ctrl
->configurator_params
=
10041 os_strdup(config
->configurator_params
);
10042 dl_list_init(&ctrl
->conn
);
10043 /* TODO: configure these somehow */
10044 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
10045 ctrl
->qr_mutual
= 0;
10047 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10048 if (ctrl
->sock
< 0)
10051 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
10052 &on
, sizeof(on
)) < 0) {
10053 wpa_printf(MSG_DEBUG
,
10054 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10056 /* try to continue anyway */
10059 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
10060 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10066 os_memset(&sin
, 0, sizeof(sin
));
10067 sin
.sin_family
= AF_INET
;
10068 sin
.sin_addr
.s_addr
= INADDR_ANY
;
10069 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
10070 sin
.sin_port
= htons(port
);
10071 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
10072 wpa_printf(MSG_INFO
,
10073 "DPP: Failed to bind Controller TCP port: %s",
10077 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
10078 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
10079 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
10080 dpp_controller_tcp_cb
, ctrl
, NULL
))
10083 dpp
->controller
= ctrl
;
10084 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
10087 dpp_controller_free(ctrl
);
10092 void dpp_controller_stop(struct dpp_global
*dpp
)
10095 dpp_controller_free(dpp
->controller
);
10096 dpp
->controller
= NULL
;
10100 #endif /* CONFIG_DPP2 */