2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2019, The Linux Foundation
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
10 #include "utils/includes.h"
12 #include <openssl/opensslv.h>
13 #include <openssl/err.h>
14 #include <openssl/asn1.h>
15 #include <openssl/asn1t.h>
17 #include "utils/common.h"
18 #include "utils/base64.h"
19 #include "utils/json.h"
20 #include "utils/ip_addr.h"
21 #include "utils/eloop.h"
22 #include "common/ieee802_11_common.h"
23 #include "common/ieee802_11_defs.h"
24 #include "common/wpa_ctrl.h"
25 #include "common/gas.h"
26 #include "crypto/crypto.h"
27 #include "crypto/random.h"
28 #include "crypto/aes.h"
29 #include "crypto/aes_siv.h"
30 #include "crypto/sha384.h"
31 #include "crypto/sha512.h"
32 #include "drivers/driver.h"
36 #ifdef CONFIG_TESTING_OPTIONS
37 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
38 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
39 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
40 u8 dpp_pkex_ephemeral_key_override
[600];
41 size_t dpp_pkex_ephemeral_key_override_len
= 0;
42 u8 dpp_protocol_key_override
[600];
43 size_t dpp_protocol_key_override_len
= 0;
44 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
45 size_t dpp_nonce_override_len
= 0;
47 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
48 const struct dpp_curve_params
*curve
);
49 #endif /* CONFIG_TESTING_OPTIONS */
51 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
52 (defined(LIBRESSL_VERSION_NUMBER) && \
53 LIBRESSL_VERSION_NUMBER < 0x20700000L)
54 /* Compatibility wrappers for older versions. */
56 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
64 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
76 struct dpp_connection
{
78 struct dpp_controller
*ctrl
;
79 struct dpp_relay_controller
*relay
;
80 struct dpp_global
*global
;
81 struct dpp_authentication
*auth
;
83 u8 mac_addr
[ETH_ALEN
];
86 size_t msg_len_octets
;
88 struct wpabuf
*msg_out
;
90 unsigned int read_eloop
:1;
91 unsigned int write_eloop
:1;
92 unsigned int on_tcp_tx_complete_gas_done
:1;
93 unsigned int on_tcp_tx_complete_remove
:1;
94 unsigned int on_tcp_tx_complete_auth_ok
:1;
97 /* Remote Controller */
98 struct dpp_relay_controller
{
100 struct dpp_global
*global
;
101 u8 pkhash
[SHA256_MAC_LEN
];
102 struct hostapd_ip_addr ipaddr
;
104 void (*tx
)(void *ctx
, const u8
*addr
, unsigned int freq
, const u8
*msg
,
106 void (*gas_resp_tx
)(void *ctx
, const u8
*addr
, u8 dialog_token
,
107 int prot
, struct wpabuf
*buf
);
108 struct dl_list conn
; /* struct dpp_connection */
111 /* Local Controller */
112 struct dpp_controller
{
113 struct dpp_global
*global
;
117 struct dl_list conn
; /* struct dpp_connection */
118 char *configurator_params
;
123 struct dl_list bootstrap
; /* struct dpp_bootstrap_info */
124 struct dl_list configurator
; /* struct dpp_configurator */
126 struct dl_list controllers
; /* struct dpp_relay_controller */
127 struct dpp_controller
*controller
;
128 struct dl_list tcp_init
; /* struct dpp_connection */
130 int (*process_conf_obj
)(void *ctx
, struct dpp_authentication
*auth
);
131 #endif /* CONFIG_DPP2 */
134 static const struct dpp_curve_params dpp_curves
[] = {
135 /* The mandatory to support and the default NIST P-256 curve needs to
136 * be the first entry on this list. */
137 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
138 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
139 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
140 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
141 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
142 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
143 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
147 /* Role-specific elements for PKEX */
150 static const u8 pkex_init_x_p256
[32] = {
151 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
152 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
153 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
154 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
156 static const u8 pkex_init_y_p256
[32] = {
157 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
158 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
159 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
160 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
162 static const u8 pkex_resp_x_p256
[32] = {
163 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
164 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
165 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
166 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
168 static const u8 pkex_resp_y_p256
[32] = {
169 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
170 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
171 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
172 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
176 static const u8 pkex_init_x_p384
[48] = {
177 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
178 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
179 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
180 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
181 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
182 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
184 static const u8 pkex_init_y_p384
[48] = {
185 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
186 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
187 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
188 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
189 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
190 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
192 static const u8 pkex_resp_x_p384
[48] = {
193 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
194 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
195 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
196 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
197 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
198 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
200 static const u8 pkex_resp_y_p384
[48] = {
201 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
202 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
203 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
204 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
205 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
206 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
210 static const u8 pkex_init_x_p521
[66] = {
211 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
212 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
213 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
214 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
215 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
216 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
217 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
218 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
221 static const u8 pkex_init_y_p521
[66] = {
222 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
223 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
224 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
225 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
226 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
227 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
228 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
229 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
232 static const u8 pkex_resp_x_p521
[66] = {
233 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
234 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
235 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
236 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
237 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
238 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
239 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
240 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
243 static const u8 pkex_resp_y_p521
[66] = {
244 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
245 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
246 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
247 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
248 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
249 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
250 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
251 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
255 /* Brainpool P-256r1 */
256 static const u8 pkex_init_x_bp_p256r1
[32] = {
257 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
258 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
259 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
260 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
262 static const u8 pkex_init_y_bp_p256r1
[32] = {
263 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
264 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
265 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
266 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
268 static const u8 pkex_resp_x_bp_p256r1
[32] = {
269 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
270 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
271 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
272 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
274 static const u8 pkex_resp_y_bp_p256r1
[32] = {
275 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
276 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
277 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
278 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
281 /* Brainpool P-384r1 */
282 static const u8 pkex_init_x_bp_p384r1
[48] = {
283 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
284 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
285 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
286 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
287 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
288 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
290 static const u8 pkex_init_y_bp_p384r1
[48] = {
291 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
292 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
293 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
294 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
295 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
296 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
298 static const u8 pkex_resp_x_bp_p384r1
[48] = {
299 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
300 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
301 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
302 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
303 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
304 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
306 static const u8 pkex_resp_y_bp_p384r1
[48] = {
307 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
308 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
309 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
310 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
311 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
312 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
315 /* Brainpool P-512r1 */
316 static const u8 pkex_init_x_bp_p512r1
[64] = {
317 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
318 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
319 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
320 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
321 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
322 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
323 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
324 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
326 static const u8 pkex_init_y_bp_p512r1
[64] = {
327 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
328 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
329 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
330 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
331 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
332 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
333 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
334 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
336 static const u8 pkex_resp_x_bp_p512r1
[64] = {
337 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
338 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
339 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
340 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
341 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
342 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
343 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
344 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
346 static const u8 pkex_resp_y_bp_p512r1
[64] = {
347 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
348 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
349 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
350 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
351 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
352 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
353 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
354 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
358 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
359 const EC_POINT
*point
)
363 char *x_str
= NULL
, *y_str
= NULL
;
365 if (!wpa_debug_show_keys
)
371 if (!ctx
|| !x
|| !y
||
372 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
375 x_str
= BN_bn2hex(x
);
376 y_str
= BN_bn2hex(y
);
377 if (!x_str
|| !y_str
)
380 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
391 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
392 size_t num_elem
, const u8
*addr
[], const size_t *len
,
395 if (curve
->hash_len
== 32)
396 return sha256_vector(num_elem
, addr
, len
, mac
);
397 if (curve
->hash_len
== 48)
398 return sha384_vector(num_elem
, addr
, len
, mac
);
399 if (curve
->hash_len
== 64)
400 return sha512_vector(num_elem
, addr
, len
, mac
);
405 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
406 const char *label
, u8
*out
, size_t outlen
)
409 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
410 (const u8
*) label
, os_strlen(label
),
413 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
414 (const u8
*) label
, os_strlen(label
),
417 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
418 (const u8
*) label
, os_strlen(label
),
424 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
425 size_t num_elem
, const u8
*addr
[],
426 const size_t *len
, u8
*mac
)
429 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
432 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
435 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
441 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
442 const u8
*data
, size_t data_len
, u8
*mac
)
445 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
447 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
449 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
454 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
456 int num_bytes
, offset
;
458 num_bytes
= BN_num_bytes(bn
);
459 if ((size_t) num_bytes
> len
)
461 offset
= len
- num_bytes
;
462 os_memset(pos
, 0, offset
);
463 BN_bn2bin(bn
, pos
+ offset
);
468 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
475 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
478 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
479 len
= i2o_ECPublicKey(eckey
, NULL
);
481 wpa_printf(MSG_ERROR
,
482 "DDP: Failed to determine public key encoding length");
487 buf
= wpabuf_alloc(len
);
493 pos
= wpabuf_put(buf
, len
);
494 res
= i2o_ECPublicKey(eckey
, &pos
);
497 wpa_printf(MSG_ERROR
,
498 "DDP: Failed to encode public key (res=%d/%d)",
505 /* Remove 0x04 prefix to match DPP definition */
506 pos
= wpabuf_mhead(buf
);
507 os_memmove(pos
, pos
+ 1, len
- 1);
515 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
516 const u8
*buf_x
, const u8
*buf_y
,
519 EC_KEY
*eckey
= NULL
;
521 EC_POINT
*point
= NULL
;
522 BIGNUM
*x
= NULL
, *y
= NULL
;
523 EVP_PKEY
*pkey
= NULL
;
527 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
531 point
= EC_POINT_new(group
);
532 x
= BN_bin2bn(buf_x
, len
, NULL
);
533 y
= BN_bin2bn(buf_y
, len
, NULL
);
534 if (!point
|| !x
|| !y
) {
535 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
539 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
540 wpa_printf(MSG_ERROR
,
541 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
542 ERR_error_string(ERR_get_error(), NULL
));
546 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
547 EC_POINT_is_at_infinity(group
, point
)) {
548 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
551 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
553 eckey
= EC_KEY_new();
555 EC_KEY_set_group(eckey
, group
) != 1 ||
556 EC_KEY_set_public_key(eckey
, point
) != 1) {
557 wpa_printf(MSG_ERROR
,
558 "DPP: Failed to set EC_KEY: %s",
559 ERR_error_string(ERR_get_error(), NULL
));
562 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
564 pkey
= EVP_PKEY_new();
565 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
566 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
574 EC_POINT_free(point
);
584 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
585 const u8
*buf
, size_t len
)
588 const EC_GROUP
*group
;
589 EVP_PKEY
*pkey
= NULL
;
594 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
596 wpa_printf(MSG_ERROR
,
597 "DPP: Could not get EC_KEY from group_key");
601 group
= EC_KEY_get0_group(eckey
);
603 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
606 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
613 static int dpp_ecdh(EVP_PKEY
*own
, EVP_PKEY
*peer
,
614 u8
*secret
, size_t *secret_len
)
622 ctx
= EVP_PKEY_CTX_new(own
, NULL
);
624 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_CTX_new failed: %s",
625 ERR_error_string(ERR_get_error(), NULL
));
629 if (EVP_PKEY_derive_init(ctx
) != 1) {
630 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive_init failed: %s",
631 ERR_error_string(ERR_get_error(), NULL
));
635 if (EVP_PKEY_derive_set_peer(ctx
, peer
) != 1) {
636 wpa_printf(MSG_ERROR
,
637 "DPP: EVP_PKEY_derive_set_peet failed: %s",
638 ERR_error_string(ERR_get_error(), NULL
));
642 if (EVP_PKEY_derive(ctx
, NULL
, secret_len
) != 1) {
643 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive(NULL) failed: %s",
644 ERR_error_string(ERR_get_error(), NULL
));
648 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
650 int level
= *secret_len
> 200 ? MSG_ERROR
: MSG_DEBUG
;
652 /* It looks like OpenSSL can return unexpectedly large buffer
653 * need for shared secret from EVP_PKEY_derive(NULL) in some
654 * cases. For example, group 19 has shown cases where secret_len
655 * is set to 72 even though the actual length ends up being
656 * updated to 32 when EVP_PKEY_derive() is called with a buffer
657 * for the value. Work around this by trying to fetch the value
658 * and continue if it is within supported range even when the
659 * initial buffer need is claimed to be larger. */
661 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
663 if (*secret_len
> 200)
665 if (EVP_PKEY_derive(ctx
, buf
, secret_len
) != 1) {
666 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
667 ERR_error_string(ERR_get_error(), NULL
));
670 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
671 wpa_printf(MSG_ERROR
,
672 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
676 wpa_hexdump_key(MSG_DEBUG
, "DPP: Unexpected secret_len change",
678 os_memcpy(secret
, buf
, *secret_len
);
679 forced_memzero(buf
, sizeof(buf
));
683 if (EVP_PKEY_derive(ctx
, secret
, secret_len
) != 1) {
684 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
685 ERR_error_string(ERR_get_error(), NULL
));
693 EVP_PKEY_CTX_free(ctx
);
698 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
700 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
704 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
709 msg
= wpabuf_alloc(8 + len
);
712 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
713 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
714 wpabuf_put_be24(msg
, OUI_WFA
);
715 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
716 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
717 wpabuf_put_u8(msg
, type
);
722 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
725 const u8
*pos
= buf
, *end
= buf
+ len
;
727 while (end
- pos
>= 4) {
728 id
= WPA_GET_LE16(pos
);
730 alen
= WPA_GET_LE16(pos
);
732 if (alen
> end
- pos
)
745 static const u8
* dpp_get_attr_next(const u8
*prev
, const u8
*buf
, size_t len
,
746 u16 req_id
, u16
*ret_len
)
749 const u8
*pos
, *end
= buf
+ len
;
754 pos
= prev
+ WPA_GET_LE16(prev
- 2);
755 while (end
- pos
>= 4) {
756 id
= WPA_GET_LE16(pos
);
758 alen
= WPA_GET_LE16(pos
);
760 if (alen
> end
- pos
)
773 int dpp_check_attrs(const u8
*buf
, size_t len
)
776 int wrapped_data
= 0;
780 while (end
- pos
>= 4) {
783 id
= WPA_GET_LE16(pos
);
785 alen
= WPA_GET_LE16(pos
);
787 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
789 if (alen
> end
- pos
) {
790 wpa_printf(MSG_DEBUG
,
791 "DPP: Truncated message - not enough room for the attribute - dropped");
795 wpa_printf(MSG_DEBUG
,
796 "DPP: An unexpected attribute included after the Wrapped Data attribute");
799 if (id
== DPP_ATTR_WRAPPED_DATA
)
805 wpa_printf(MSG_DEBUG
,
806 "DPP: Unexpected octets (%d) after the last attribute",
815 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
821 EVP_PKEY_free(info
->pubkey
);
826 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
829 case DPP_BOOTSTRAP_QR_CODE
:
831 case DPP_BOOTSTRAP_PKEX
:
838 static int dpp_uri_valid_info(const char *info
)
841 unsigned char val
= *info
++;
843 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
851 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
853 bi
->uri
= os_strdup(uri
);
854 return bi
->uri
? 0 : -1;
858 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
859 const char *chan_list
)
861 const char *pos
= chan_list
, *pos2
;
862 int opclass
= -1, channel
, freq
;
864 while (pos
&& *pos
&& *pos
!= ';') {
866 while (*pos2
>= '0' && *pos2
<= '9')
877 while (*pos
>= '0' && *pos
<= '9')
879 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
880 wpa_printf(MSG_DEBUG
,
881 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
882 opclass
, channel
, freq
);
884 wpa_printf(MSG_DEBUG
,
885 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
887 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
888 wpa_printf(MSG_DEBUG
,
889 "DPP: Too many channels in URI channel-list - ignore list");
893 bi
->freq
[bi
->num_freq
++] = freq
;
896 if (*pos
== ';' || *pos
== '\0')
905 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
910 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
915 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
916 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
920 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
926 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
933 end
= os_strchr(info
, ';');
935 end
= info
+ os_strlen(info
);
936 bi
->info
= os_malloc(end
- info
+ 1);
939 os_memcpy(bi
->info
, info
, end
- info
);
940 bi
->info
[end
- info
] = '\0';
941 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
942 if (!dpp_uri_valid_info(bi
->info
)) {
943 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
951 static const struct dpp_curve_params
*
952 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
957 for (i
= 0; dpp_curves
[i
].name
; i
++) {
958 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
959 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
960 return &dpp_curves
[i
];
966 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
972 for (i
= 0; dpp_curves
[i
].name
; i
++) {
973 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
975 return &dpp_curves
[i
];
981 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
987 const unsigned char *p
;
989 X509_PUBKEY
*pub
= NULL
;
991 const unsigned char *pk
;
994 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
995 (defined(LIBRESSL_VERSION_NUMBER) && \
996 LIBRESSL_VERSION_NUMBER < 0x20800000L)
999 const ASN1_OBJECT
*pa_oid
;
1003 const ASN1_OBJECT
*poid
;
1006 end
= os_strchr(info
, ';');
1010 data
= base64_decode(info
, end
- info
, &data_len
);
1012 wpa_printf(MSG_DEBUG
,
1013 "DPP: Invalid base64 encoding on URI public-key");
1016 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
1019 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
1020 bi
->pubkey_hash
) < 0) {
1021 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1025 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
1026 bi
->pubkey_hash
, SHA256_MAC_LEN
);
1028 /* DER encoded ASN.1 SubjectPublicKeyInfo
1030 * SubjectPublicKeyInfo ::= SEQUENCE {
1031 * algorithm AlgorithmIdentifier,
1032 * subjectPublicKey BIT STRING }
1034 * AlgorithmIdentifier ::= SEQUENCE {
1035 * algorithm OBJECT IDENTIFIER,
1036 * parameters ANY DEFINED BY algorithm OPTIONAL }
1038 * subjectPublicKey = compressed format public key per ANSI X9.63
1039 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1040 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1041 * prime256v1 (1.2.840.10045.3.1.7)
1045 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
1049 wpa_printf(MSG_DEBUG
,
1050 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1054 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
1055 wpa_printf(MSG_DEBUG
,
1056 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1057 EVP_PKEY_free(pkey
);
1061 res
= X509_PUBKEY_set(&pub
, pkey
);
1063 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
1067 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
1069 wpa_printf(MSG_DEBUG
,
1070 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1073 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
1074 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1075 wpa_printf(MSG_DEBUG
,
1076 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1079 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
1080 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
1081 wpa_printf(MSG_DEBUG
,
1082 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1086 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
1087 if (ptype
!= V_ASN1_OBJECT
) {
1088 wpa_printf(MSG_DEBUG
,
1089 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1093 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
1094 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1095 wpa_printf(MSG_DEBUG
,
1096 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1099 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
1100 bi
->curve
= dpp_get_curve_oid(poid
);
1102 wpa_printf(MSG_DEBUG
,
1103 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1108 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
1110 X509_PUBKEY_free(pub
);
1114 X509_PUBKEY_free(pub
);
1115 EVP_PKEY_free(pkey
);
1120 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1122 const char *pos
= uri
;
1124 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1125 struct dpp_bootstrap_info
*bi
;
1127 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1129 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1130 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1136 end
= os_strchr(pos
, ';');
1141 /* Handle terminating ";;" and ignore unexpected ";"
1142 * for parsing robustness. */
1147 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1148 chan_list
= pos
+ 2;
1149 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1151 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1153 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1156 wpa_hexdump_ascii(MSG_DEBUG
,
1157 "DPP: Ignore unrecognized URI parameter",
1163 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1167 bi
= os_zalloc(sizeof(*bi
));
1171 if (dpp_clone_uri(bi
, uri
) < 0 ||
1172 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1173 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1174 dpp_parse_uri_info(bi
, info
) < 0 ||
1175 dpp_parse_uri_pk(bi
, pk
) < 0) {
1176 dpp_bootstrap_info_free(bi
);
1184 struct dpp_bootstrap_info
* dpp_parse_qr_code(const char *uri
)
1186 struct dpp_bootstrap_info
*bi
;
1188 bi
= dpp_parse_uri(uri
);
1190 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
1195 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1202 unsigned char *der
= NULL
;
1204 const EC_GROUP
*group
;
1205 const EC_POINT
*point
;
1207 out
= BIO_new(BIO_s_mem());
1211 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1212 rlen
= BIO_ctrl_pending(out
);
1213 txt
= os_malloc(rlen
+ 1);
1215 res
= BIO_read(out
, txt
, rlen
);
1218 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1224 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1228 group
= EC_KEY_get0_group(eckey
);
1229 point
= EC_KEY_get0_public_key(eckey
);
1231 dpp_debug_print_point(title
, group
, point
);
1233 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1235 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1239 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1241 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1249 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1251 EVP_PKEY_CTX
*kctx
= NULL
;
1252 EC_KEY
*ec_params
= NULL
;
1253 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1256 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1258 nid
= OBJ_txt2nid(curve
->name
);
1259 if (nid
== NID_undef
) {
1260 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1264 ec_params
= EC_KEY_new_by_curve_name(nid
);
1266 wpa_printf(MSG_ERROR
,
1267 "DPP: Failed to generate EC_KEY parameters");
1270 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1271 params
= EVP_PKEY_new();
1272 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1273 wpa_printf(MSG_ERROR
,
1274 "DPP: Failed to generate EVP_PKEY parameters");
1278 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1280 EVP_PKEY_keygen_init(kctx
) != 1 ||
1281 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1282 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1287 if (wpa_debug_show_keys
)
1288 dpp_debug_print_key("Own generated key", key
);
1291 EC_KEY_free(ec_params
);
1292 EVP_PKEY_free(params
);
1293 EVP_PKEY_CTX_free(kctx
);
1298 static const struct dpp_curve_params
*
1299 dpp_get_curve_name(const char *name
)
1303 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1304 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1305 (dpp_curves
[i
].jwk_crv
&&
1306 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1307 return &dpp_curves
[i
];
1313 static const struct dpp_curve_params
*
1314 dpp_get_curve_jwk_crv(const char *name
)
1318 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1319 if (dpp_curves
[i
].jwk_crv
&&
1320 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1321 return &dpp_curves
[i
];
1327 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1328 const u8
*privkey
, size_t privkey_len
)
1332 const EC_GROUP
*group
;
1335 pkey
= EVP_PKEY_new();
1338 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1340 wpa_printf(MSG_INFO
,
1341 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1342 ERR_error_string(ERR_get_error(), NULL
));
1343 EVP_PKEY_free(pkey
);
1346 group
= EC_KEY_get0_group(eckey
);
1349 EVP_PKEY_free(pkey
);
1352 nid
= EC_GROUP_get_curve_name(group
);
1353 *curve
= dpp_get_curve_nid(nid
);
1355 wpa_printf(MSG_INFO
,
1356 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1359 EVP_PKEY_free(pkey
);
1363 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1365 EVP_PKEY_free(pkey
);
1373 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1374 * as an OID identifying the curve */
1376 /* Compressed format public key per ANSI X9.63 */
1377 ASN1_BIT_STRING
*pub_key
;
1378 } DPP_BOOTSTRAPPING_KEY
;
1380 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1381 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1382 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1383 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1385 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1388 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1390 unsigned char *der
= NULL
;
1393 struct wpabuf
*ret
= NULL
;
1395 const EC_GROUP
*group
;
1396 const EC_POINT
*point
;
1398 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1402 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1406 group
= EC_KEY_get0_group(eckey
);
1407 point
= EC_KEY_get0_public_key(eckey
);
1408 if (!group
|| !point
)
1410 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1411 nid
= EC_GROUP_get_curve_name(group
);
1413 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1415 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1416 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1419 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1424 der
= OPENSSL_malloc(len
);
1427 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1430 OPENSSL_free(bootstrap
->pub_key
->data
);
1431 bootstrap
->pub_key
->data
= der
;
1433 bootstrap
->pub_key
->length
= len
;
1434 /* No unused bits */
1435 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1436 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1438 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1440 wpa_printf(MSG_ERROR
,
1441 "DDP: Failed to build DER encoded public key");
1445 ret
= wpabuf_alloc_copy(der
, der_len
);
1447 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1455 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1462 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1465 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1468 addr
[0] = wpabuf_head(der
);
1469 len
[0] = wpabuf_len(der
);
1470 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1472 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1474 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1481 char * dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1482 const u8
*privkey
, size_t privkey_len
)
1484 char *base64
= NULL
;
1487 struct wpabuf
*der
= NULL
;
1492 bi
->curve
= &dpp_curves
[0];
1494 bi
->curve
= dpp_get_curve_name(curve
);
1496 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1502 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1504 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1509 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1512 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1515 addr
[0] = wpabuf_head(der
);
1516 len
= wpabuf_len(der
);
1517 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1519 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1522 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1525 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1533 pos
= os_strchr(pos
, '\n');
1536 os_memmove(pos
, pos
+ 1, end
- pos
);
1546 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1547 unsigned int hash_len
)
1549 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1550 const char *info
= "first intermediate key";
1553 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1555 /* HKDF-Extract(<>, M.x) */
1556 os_memset(salt
, 0, hash_len
);
1557 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1559 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1562 /* HKDF-Expand(PRK, info, L) */
1563 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1564 os_memset(prk
, 0, hash_len
);
1568 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1574 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1575 unsigned int hash_len
)
1577 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1578 const char *info
= "second intermediate key";
1581 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1583 /* HKDF-Extract(<>, N.x) */
1584 os_memset(salt
, 0, hash_len
);
1585 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1588 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1591 /* HKDF-Expand(PRK, info, L) */
1592 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1593 os_memset(prk
, 0, hash_len
);
1597 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1603 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1604 unsigned int hash_len
)
1607 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1608 const char *info_ke
= "DPP Key";
1609 u8 prk
[DPP_MAX_HASH_LEN
];
1613 size_t num_elem
= 0;
1615 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1616 wpa_printf(MSG_DEBUG
,
1617 "DPP: Mx/Nx not available - cannot derive ke");
1621 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1623 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1624 nonce_len
= auth
->curve
->nonce_len
;
1625 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1626 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1627 addr
[num_elem
] = auth
->Mx
;
1628 len
[num_elem
] = auth
->Mx_len
;
1630 addr
[num_elem
] = auth
->Nx
;
1631 len
[num_elem
] = auth
->Nx_len
;
1633 if (auth
->peer_bi
&& auth
->own_bi
) {
1634 if (!auth
->Lx_len
) {
1635 wpa_printf(MSG_DEBUG
,
1636 "DPP: Lx not available - cannot derive ke");
1639 addr
[num_elem
] = auth
->Lx
;
1640 len
[num_elem
] = auth
->secret_len
;
1643 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1644 num_elem
, addr
, len
, prk
);
1647 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1650 /* HKDF-Expand(PRK, info, L) */
1651 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1652 os_memset(prk
, 0, hash_len
);
1656 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1662 static void dpp_build_attr_status(struct wpabuf
*msg
,
1663 enum dpp_status_error status
)
1665 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1666 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1667 wpabuf_put_le16(msg
, 1);
1668 wpabuf_put_u8(msg
, status
);
1672 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1676 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1677 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1678 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1679 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1684 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1688 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1689 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1690 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1691 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1696 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1697 const struct wpabuf
*pi
,
1699 const u8
*r_pubkey_hash
,
1700 const u8
*i_pubkey_hash
,
1701 unsigned int neg_freq
)
1704 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1705 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1708 size_t len
[2], siv_len
, attr_len
;
1709 u8
*attr_start
, *attr_end
;
1711 /* Build DPP Authentication Request frame attributes */
1712 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1713 4 + sizeof(wrapped_data
);
1718 #endif /* CONFIG_DPP2 */
1719 #ifdef CONFIG_TESTING_OPTIONS
1720 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1722 #endif /* CONFIG_TESTING_OPTIONS */
1723 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1727 attr_start
= wpabuf_put(msg
, 0);
1729 /* Responder Bootstrapping Key Hash */
1730 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1732 /* Initiator Bootstrapping Key Hash */
1733 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1735 /* Initiator Protocol Key */
1737 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1738 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1739 wpabuf_put_buf(msg
, pi
);
1744 u8 op_class
, channel
;
1746 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1748 NUM_HOSTAPD_MODES
) {
1749 wpa_printf(MSG_INFO
,
1750 "DPP: Unsupported negotiation frequency request: %d",
1755 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1756 wpabuf_put_le16(msg
, 2);
1757 wpabuf_put_u8(msg
, op_class
);
1758 wpabuf_put_u8(msg
, channel
);
1762 /* Protocol Version */
1763 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1764 wpabuf_put_le16(msg
, 1);
1765 wpabuf_put_u8(msg
, 2);
1766 #endif /* CONFIG_DPP2 */
1768 #ifdef CONFIG_TESTING_OPTIONS
1769 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1770 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1771 goto skip_wrapped_data
;
1773 #endif /* CONFIG_TESTING_OPTIONS */
1775 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1778 #ifdef CONFIG_TESTING_OPTIONS
1779 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1780 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1783 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1784 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1785 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1787 WPA_PUT_LE16(pos
, nonce_len
- 1);
1789 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1790 pos
+= nonce_len
- 1;
1793 #endif /* CONFIG_TESTING_OPTIONS */
1796 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1798 WPA_PUT_LE16(pos
, nonce_len
);
1800 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1803 #ifdef CONFIG_TESTING_OPTIONS
1805 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1806 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1809 #endif /* CONFIG_TESTING_OPTIONS */
1811 /* I-capabilities */
1812 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1814 WPA_PUT_LE16(pos
, 1);
1816 auth
->i_capab
= auth
->allowed_roles
;
1817 *pos
++ = auth
->i_capab
;
1818 #ifdef CONFIG_TESTING_OPTIONS
1819 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1820 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1824 #endif /* CONFIG_TESTING_OPTIONS */
1826 attr_end
= wpabuf_put(msg
, 0);
1828 /* OUI, OUI type, Crypto Suite, DPP frame type */
1829 addr
[0] = wpabuf_head_u8(msg
) + 2;
1830 len
[0] = 3 + 1 + 1 + 1;
1831 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1833 /* Attributes before Wrapped Data */
1834 addr
[1] = attr_start
;
1835 len
[1] = attr_end
- attr_start
;
1836 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1838 siv_len
= pos
- clear
;
1839 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1840 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1841 2, addr
, len
, wrapped_data
) < 0) {
1845 siv_len
+= AES_BLOCK_SIZE
;
1846 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1847 wrapped_data
, siv_len
);
1849 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1850 wpabuf_put_le16(msg
, siv_len
);
1851 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1853 #ifdef CONFIG_TESTING_OPTIONS
1854 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1855 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1856 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1859 #endif /* CONFIG_TESTING_OPTIONS */
1861 wpa_hexdump_buf(MSG_DEBUG
,
1862 "DPP: Authentication Request frame attributes", msg
);
1868 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1869 enum dpp_status_error status
,
1870 const struct wpabuf
*pr
,
1872 const u8
*r_pubkey_hash
,
1873 const u8
*i_pubkey_hash
,
1874 const u8
*r_nonce
, const u8
*i_nonce
,
1875 const u8
*wrapped_r_auth
,
1876 size_t wrapped_r_auth_len
,
1880 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1881 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1882 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1883 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1885 size_t len
[2], siv_len
, attr_len
;
1886 u8
*attr_start
, *attr_end
, *pos
;
1888 auth
->waiting_auth_conf
= 1;
1889 auth
->auth_resp_tries
= 0;
1891 /* Build DPP Authentication Response frame attributes */
1892 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1893 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1896 #endif /* CONFIG_DPP2 */
1897 #ifdef CONFIG_TESTING_OPTIONS
1898 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1900 #endif /* CONFIG_TESTING_OPTIONS */
1901 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1905 attr_start
= wpabuf_put(msg
, 0);
1909 dpp_build_attr_status(msg
, status
);
1911 /* Responder Bootstrapping Key Hash */
1912 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1914 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1915 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1917 /* Responder Protocol Key */
1919 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1920 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1921 wpabuf_put_buf(msg
, pr
);
1925 /* Protocol Version */
1926 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1927 wpabuf_put_le16(msg
, 1);
1928 wpabuf_put_u8(msg
, 2);
1929 #endif /* CONFIG_DPP2 */
1931 attr_end
= wpabuf_put(msg
, 0);
1933 #ifdef CONFIG_TESTING_OPTIONS
1934 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
1935 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1936 goto skip_wrapped_data
;
1938 #endif /* CONFIG_TESTING_OPTIONS */
1940 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
1945 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
1947 WPA_PUT_LE16(pos
, nonce_len
);
1949 os_memcpy(pos
, r_nonce
, nonce_len
);
1955 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1957 WPA_PUT_LE16(pos
, nonce_len
);
1959 os_memcpy(pos
, i_nonce
, nonce_len
);
1960 #ifdef CONFIG_TESTING_OPTIONS
1961 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
1962 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
1963 pos
[nonce_len
/ 2] ^= 0x01;
1965 #endif /* CONFIG_TESTING_OPTIONS */
1969 #ifdef CONFIG_TESTING_OPTIONS
1970 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
1971 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
1974 #endif /* CONFIG_TESTING_OPTIONS */
1976 /* R-capabilities */
1977 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
1979 WPA_PUT_LE16(pos
, 1);
1981 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
1983 *pos
++ = auth
->r_capab
;
1984 #ifdef CONFIG_TESTING_OPTIONS
1985 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
1986 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
1988 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
1989 wpa_printf(MSG_INFO
,
1990 "DPP: TESTING - incompatible R-capabilities");
1991 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
1992 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
1995 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
1996 DPP_CAPAB_CONFIGURATOR
;
1999 #endif /* CONFIG_TESTING_OPTIONS */
2001 if (wrapped_r_auth
) {
2003 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
2005 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
2007 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
2008 pos
+= wrapped_r_auth_len
;
2011 /* OUI, OUI type, Crypto Suite, DPP frame type */
2012 addr
[0] = wpabuf_head_u8(msg
) + 2;
2013 len
[0] = 3 + 1 + 1 + 1;
2014 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2016 /* Attributes before Wrapped Data */
2017 addr
[1] = attr_start
;
2018 len
[1] = attr_end
- attr_start
;
2019 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2021 siv_len
= pos
- clear
;
2022 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
2023 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
2024 2, addr
, len
, wrapped_data
) < 0) {
2028 siv_len
+= AES_BLOCK_SIZE
;
2029 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2030 wrapped_data
, siv_len
);
2032 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2033 wpabuf_put_le16(msg
, siv_len
);
2034 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2036 #ifdef CONFIG_TESTING_OPTIONS
2037 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
2038 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2039 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2042 #endif /* CONFIG_TESTING_OPTIONS */
2044 wpa_hexdump_buf(MSG_DEBUG
,
2045 "DPP: Authentication Response frame attributes", msg
);
2050 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
2051 u16 num_modes
, unsigned int freq
)
2056 if (!own_modes
|| !num_modes
)
2059 for (m
= 0; m
< num_modes
; m
++) {
2060 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2061 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
2064 flag
= own_modes
[m
].channels
[c
].flag
;
2065 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
2066 HOSTAPD_CHAN_NO_IR
|
2067 HOSTAPD_CHAN_RADAR
)))
2072 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
2077 static int freq_included(const unsigned int freqs
[], unsigned int num
,
2081 if (freqs
[--num
] == freq
)
2088 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
2093 for (i
= 0; i
< num
; i
++) {
2094 if (freqs
[i
] == freq
)
2097 if (i
== 0 || i
>= num
)
2099 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
2104 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
2105 struct hostapd_hw_modes
*own_modes
,
2108 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
2109 unsigned int i
, freq
;
2111 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2112 freq
= peer_bi
->freq
[i
];
2113 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2115 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2116 auth
->freq
[auth
->num_freq
++] = freq
;
2118 if (!auth
->num_freq
) {
2119 wpa_printf(MSG_INFO
,
2120 "DPP: No available channels for initiating DPP Authentication");
2123 auth
->curr_freq
= auth
->freq
[0];
2128 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2129 struct hostapd_hw_modes
*own_modes
,
2138 if (!own_modes
|| !num_modes
) {
2139 auth
->freq
[0] = 2412;
2140 auth
->freq
[1] = 2437;
2141 auth
->freq
[2] = 2462;
2146 for (m
= 0; m
< num_modes
; m
++) {
2147 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2148 freq
= own_modes
[m
].channels
[c
].freq
;
2149 flag
= own_modes
[m
].channels
[c
].flag
;
2150 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2151 HOSTAPD_CHAN_NO_IR
|
2152 HOSTAPD_CHAN_RADAR
))
2154 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2156 auth
->freq
[auth
->num_freq
++] = freq
;
2157 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2164 return auth
->num_freq
== 0 ? -1 : 0;
2168 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2169 struct hostapd_hw_modes
*own_modes
,
2173 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2176 if (auth
->peer_bi
->num_freq
> 0)
2177 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2179 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2183 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2184 * likely channels first. */
2185 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2186 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2187 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2190 auth
->curr_freq
= auth
->freq
[0];
2193 end
= pos
+ sizeof(freqs
);
2194 for (i
= 0; i
< auth
->num_freq
; i
++) {
2195 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2196 if (os_snprintf_error(end
- pos
, res
))
2201 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2208 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2210 struct dpp_bootstrap_info
*bi
;
2215 return 0; /* already generated */
2217 bi
= os_zalloc(sizeof(*bi
));
2220 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2221 pk
= dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0);
2225 len
= 4; /* "DPP:" */
2226 len
+= 4 + os_strlen(pk
);
2227 bi
->uri
= os_malloc(len
+ 1);
2230 os_snprintf(bi
->uri
, len
+ 1, "DPP:K:%s;;", pk
);
2231 wpa_printf(MSG_DEBUG
,
2232 "DPP: Auto-generated own bootstrapping key info: URI %s",
2235 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2242 dpp_bootstrap_info_free(bi
);
2247 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2248 struct dpp_bootstrap_info
*peer_bi
,
2249 struct dpp_bootstrap_info
*own_bi
,
2250 u8 dpp_allowed_roles
,
2251 unsigned int neg_freq
,
2252 struct hostapd_hw_modes
*own_modes
,
2255 struct dpp_authentication
*auth
;
2258 struct wpabuf
*pi
= NULL
;
2259 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2260 #ifdef CONFIG_TESTING_OPTIONS
2261 u8 test_hash
[SHA256_MAC_LEN
];
2262 #endif /* CONFIG_TESTING_OPTIONS */
2264 auth
= os_zalloc(sizeof(*auth
));
2267 auth
->msg_ctx
= msg_ctx
;
2268 auth
->initiator
= 1;
2269 auth
->waiting_auth_resp
= 1;
2270 auth
->allowed_roles
= dpp_allowed_roles
;
2271 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2272 auth
->peer_bi
= peer_bi
;
2273 auth
->own_bi
= own_bi
;
2274 auth
->curve
= peer_bi
->curve
;
2276 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2277 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2280 #ifdef CONFIG_TESTING_OPTIONS
2281 if (dpp_nonce_override_len
> 0) {
2282 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2283 nonce_len
= dpp_nonce_override_len
;
2284 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2286 nonce_len
= auth
->curve
->nonce_len
;
2287 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2288 wpa_printf(MSG_ERROR
,
2289 "DPP: Failed to generate I-nonce");
2293 #else /* CONFIG_TESTING_OPTIONS */
2294 nonce_len
= auth
->curve
->nonce_len
;
2295 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2296 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2299 #endif /* CONFIG_TESTING_OPTIONS */
2300 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2302 #ifdef CONFIG_TESTING_OPTIONS
2303 if (dpp_protocol_key_override_len
) {
2304 const struct dpp_curve_params
*tmp_curve
;
2306 wpa_printf(MSG_INFO
,
2307 "DPP: TESTING - override protocol key");
2308 auth
->own_protocol_key
= dpp_set_keypair(
2309 &tmp_curve
, dpp_protocol_key_override
,
2310 dpp_protocol_key_override_len
);
2312 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2314 #else /* CONFIG_TESTING_OPTIONS */
2315 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2316 #endif /* CONFIG_TESTING_OPTIONS */
2317 if (!auth
->own_protocol_key
)
2320 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2324 /* ECDH: M = pI * BR */
2325 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2326 auth
->Mx
, &secret_len
) < 0)
2328 auth
->secret_len
= secret_len
;
2330 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2331 auth
->Mx
, auth
->secret_len
);
2332 auth
->Mx_len
= auth
->secret_len
;
2334 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2335 auth
->curve
->hash_len
) < 0)
2338 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2339 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2341 #ifdef CONFIG_TESTING_OPTIONS
2342 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2343 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2344 r_pubkey_hash
= NULL
;
2345 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2346 wpa_printf(MSG_INFO
,
2347 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2348 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2349 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2350 r_pubkey_hash
= test_hash
;
2351 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2352 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2353 i_pubkey_hash
= NULL
;
2354 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2355 wpa_printf(MSG_INFO
,
2356 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2357 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2358 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2359 i_pubkey_hash
= test_hash
;
2360 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2361 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2364 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2365 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2367 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2368 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2371 #endif /* CONFIG_TESTING_OPTIONS */
2373 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2374 i_pubkey_hash
, neg_freq
);
2382 dpp_auth_deinit(auth
);
2388 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2392 size_t json_len
, clear_len
;
2393 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2397 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2399 nonce_len
= auth
->curve
->nonce_len
;
2400 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2401 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2404 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2405 json_len
= os_strlen(json
);
2406 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configRequest JSON", json
, json_len
);
2408 /* { E-nonce, configAttrib }ke */
2409 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2410 clear
= wpabuf_alloc(clear_len
);
2411 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2412 #ifdef CONFIG_TESTING_OPTIONS
2413 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2415 #endif /* CONFIG_TESTING_OPTIONS */
2416 msg
= wpabuf_alloc(attr_len
);
2420 #ifdef CONFIG_TESTING_OPTIONS
2421 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2422 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2425 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2426 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2427 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2428 wpabuf_put_le16(clear
, nonce_len
- 1);
2429 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2432 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2433 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2434 goto skip_wrapped_data
;
2436 #endif /* CONFIG_TESTING_OPTIONS */
2439 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2440 wpabuf_put_le16(clear
, nonce_len
);
2441 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2443 #ifdef CONFIG_TESTING_OPTIONS
2445 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2446 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2447 goto skip_conf_attr_obj
;
2449 #endif /* CONFIG_TESTING_OPTIONS */
2452 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2453 wpabuf_put_le16(clear
, json_len
);
2454 wpabuf_put_data(clear
, json
, json_len
);
2456 #ifdef CONFIG_TESTING_OPTIONS
2458 #endif /* CONFIG_TESTING_OPTIONS */
2460 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2461 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2462 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2465 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2466 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2467 wpabuf_head(clear
), wpabuf_len(clear
),
2468 0, NULL
, NULL
, wrapped
) < 0)
2470 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2471 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2473 #ifdef CONFIG_TESTING_OPTIONS
2474 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2475 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2476 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2479 #endif /* CONFIG_TESTING_OPTIONS */
2481 wpa_hexdump_buf(MSG_DEBUG
,
2482 "DPP: Configuration Request frame attributes", msg
);
2493 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2495 /* Advertisement Protocol IE */
2496 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2497 wpabuf_put_u8(buf
, 8); /* Length */
2498 wpabuf_put_u8(buf
, 0x7f);
2499 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2500 wpabuf_put_u8(buf
, 5);
2501 wpabuf_put_be24(buf
, OUI_WFA
);
2502 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2503 wpabuf_put_u8(buf
, 0x01);
2507 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2510 wpabuf_put_le16(buf
, wpabuf_len(query
));
2511 wpabuf_put_buf(buf
, query
);
2515 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2518 struct wpabuf
*buf
, *conf_req
;
2520 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2522 wpa_printf(MSG_DEBUG
,
2523 "DPP: No configuration request data available");
2527 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2529 wpabuf_free(conf_req
);
2533 dpp_write_adv_proto(buf
);
2534 dpp_write_gas_query(buf
, conf_req
);
2535 wpabuf_free(conf_req
);
2536 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2542 struct wpabuf
* dpp_build_conf_req_helper(struct dpp_authentication
*auth
,
2543 const char *name
, int netrole_ap
,
2544 const char *mud_url
, int *opclasses
)
2546 size_t len
, name_len
;
2547 const char *tech
= "infra";
2548 const char *dpp_name
;
2549 struct wpabuf
*buf
, *json
;
2551 #ifdef CONFIG_TESTING_OPTIONS
2552 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
2553 static const char *bogus_tech
= "knfra";
2555 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
2558 #endif /* CONFIG_TESTING_OPTIONS */
2560 dpp_name
= name
? name
: "Test";
2561 name_len
= os_strlen(dpp_name
);
2563 len
= 100 + name_len
* 6 + 1 + int_array_len(opclasses
) * 4;
2564 if (mud_url
&& mud_url
[0])
2565 len
+= 10 + os_strlen(mud_url
);
2566 json
= wpabuf_alloc(len
);
2570 json_start_object(json
, NULL
);
2571 if (json_add_string_escape(json
, "name", dpp_name
, name_len
) < 0) {
2575 json_value_sep(json
);
2576 json_add_string(json
, "wi-fi_tech", tech
);
2577 json_value_sep(json
);
2578 json_add_string(json
, "netRole", netrole_ap
? "ap" : "sta");
2579 if (mud_url
&& mud_url
[0]) {
2580 json_value_sep(json
);
2581 json_add_string(json
, "mudurl", mud_url
);
2586 json_value_sep(json
);
2587 json_start_array(json
, "bandSupport");
2588 for (i
= 0; opclasses
[i
]; i
++)
2589 wpabuf_printf(json
, "%s%u", i
? "," : "", opclasses
[i
]);
2590 json_end_array(json
);
2592 json_end_object(json
);
2594 buf
= dpp_build_conf_req(auth
, wpabuf_head(json
));
2601 static void dpp_auth_success(struct dpp_authentication
*auth
)
2603 wpa_printf(MSG_DEBUG
,
2604 "DPP: Authentication success - clear temporary keys");
2605 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2607 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2609 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2611 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2612 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2614 auth
->auth_success
= 1;
2618 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2620 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2623 size_t i
, num_elem
= 0;
2628 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2629 nonce_len
= auth
->curve
->nonce_len
;
2631 if (auth
->initiator
) {
2632 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2633 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2635 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2638 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2640 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2641 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2643 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2646 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2648 if (!pix
|| !prx
|| !brx
)
2651 addr
[num_elem
] = auth
->i_nonce
;
2652 len
[num_elem
] = nonce_len
;
2655 addr
[num_elem
] = auth
->r_nonce
;
2656 len
[num_elem
] = nonce_len
;
2659 addr
[num_elem
] = wpabuf_head(pix
);
2660 len
[num_elem
] = wpabuf_len(pix
) / 2;
2663 addr
[num_elem
] = wpabuf_head(prx
);
2664 len
[num_elem
] = wpabuf_len(prx
) / 2;
2668 addr
[num_elem
] = wpabuf_head(bix
);
2669 len
[num_elem
] = wpabuf_len(bix
) / 2;
2673 addr
[num_elem
] = wpabuf_head(brx
);
2674 len
[num_elem
] = wpabuf_len(brx
) / 2;
2677 addr
[num_elem
] = &zero
;
2681 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2682 for (i
= 0; i
< num_elem
; i
++)
2683 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2684 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2686 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2687 auth
->curve
->hash_len
);
2697 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2699 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2702 size_t i
, num_elem
= 0;
2707 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2708 nonce_len
= auth
->curve
->nonce_len
;
2710 if (auth
->initiator
) {
2711 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2712 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2714 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2719 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2721 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2722 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2724 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2729 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2731 if (!pix
|| !prx
|| !brx
)
2734 addr
[num_elem
] = auth
->r_nonce
;
2735 len
[num_elem
] = nonce_len
;
2738 addr
[num_elem
] = auth
->i_nonce
;
2739 len
[num_elem
] = nonce_len
;
2742 addr
[num_elem
] = wpabuf_head(prx
);
2743 len
[num_elem
] = wpabuf_len(prx
) / 2;
2746 addr
[num_elem
] = wpabuf_head(pix
);
2747 len
[num_elem
] = wpabuf_len(pix
) / 2;
2750 addr
[num_elem
] = wpabuf_head(brx
);
2751 len
[num_elem
] = wpabuf_len(brx
) / 2;
2755 addr
[num_elem
] = wpabuf_head(bix
);
2756 len
[num_elem
] = wpabuf_len(bix
) / 2;
2760 addr
[num_elem
] = &one
;
2764 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2765 for (i
= 0; i
< num_elem
; i
++)
2766 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2767 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2769 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2770 auth
->curve
->hash_len
);
2780 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2782 const EC_GROUP
*group
;
2784 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2785 const EC_POINT
*BI_point
;
2787 BIGNUM
*lx
, *sum
, *q
;
2788 const BIGNUM
*bR_bn
, *pR_bn
;
2791 /* L = ((bR + pR) modulo q) * BI */
2793 bnctx
= BN_CTX_new();
2797 if (!bnctx
|| !sum
|| !q
|| !lx
)
2799 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2802 BI_point
= EC_KEY_get0_public_key(BI
);
2803 group
= EC_KEY_get0_group(BI
);
2807 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2808 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2811 bR_bn
= EC_KEY_get0_private_key(bR
);
2812 pR_bn
= EC_KEY_get0_private_key(pR
);
2813 if (!bR_bn
|| !pR_bn
)
2815 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2816 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2818 l
= EC_POINT_new(group
);
2820 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2821 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2823 wpa_printf(MSG_ERROR
,
2824 "OpenSSL: failed: %s",
2825 ERR_error_string(ERR_get_error(), NULL
));
2829 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2831 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2832 auth
->Lx_len
= auth
->secret_len
;
2835 EC_POINT_clear_free(l
);
2847 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2849 const EC_GROUP
*group
;
2850 EC_POINT
*l
= NULL
, *sum
= NULL
;
2851 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2852 const EC_POINT
*BR_point
, *PR_point
;
2855 const BIGNUM
*bI_bn
;
2858 /* L = bI * (BR + PR) */
2860 bnctx
= BN_CTX_new();
2864 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2865 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2868 BR_point
= EC_KEY_get0_public_key(BR
);
2869 PR_point
= EC_KEY_get0_public_key(PR
);
2871 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2874 group
= EC_KEY_get0_group(bI
);
2875 bI_bn
= EC_KEY_get0_private_key(bI
);
2876 if (!group
|| !bI_bn
)
2878 sum
= EC_POINT_new(group
);
2879 l
= EC_POINT_new(group
);
2881 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2882 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2883 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2885 wpa_printf(MSG_ERROR
,
2886 "OpenSSL: failed: %s",
2887 ERR_error_string(ERR_get_error(), NULL
));
2891 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2893 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2894 auth
->Lx_len
= auth
->secret_len
;
2897 EC_POINT_clear_free(l
);
2898 EC_POINT_clear_free(sum
);
2908 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
2912 struct wpabuf
*msg
, *pr
= NULL
;
2913 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
2914 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
2915 size_t wrapped_r_auth_len
;
2917 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
2918 enum dpp_status_error status
= DPP_STATUS_OK
;
2919 #ifdef CONFIG_TESTING_OPTIONS
2920 u8 test_hash
[SHA256_MAC_LEN
];
2921 #endif /* CONFIG_TESTING_OPTIONS */
2923 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
2927 #ifdef CONFIG_TESTING_OPTIONS
2928 if (dpp_nonce_override_len
> 0) {
2929 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
2930 nonce_len
= dpp_nonce_override_len
;
2931 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
2933 nonce_len
= auth
->curve
->nonce_len
;
2934 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2935 wpa_printf(MSG_ERROR
,
2936 "DPP: Failed to generate R-nonce");
2940 #else /* CONFIG_TESTING_OPTIONS */
2941 nonce_len
= auth
->curve
->nonce_len
;
2942 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
2943 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
2946 #endif /* CONFIG_TESTING_OPTIONS */
2947 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
2949 EVP_PKEY_free(auth
->own_protocol_key
);
2950 #ifdef CONFIG_TESTING_OPTIONS
2951 if (dpp_protocol_key_override_len
) {
2952 const struct dpp_curve_params
*tmp_curve
;
2954 wpa_printf(MSG_INFO
,
2955 "DPP: TESTING - override protocol key");
2956 auth
->own_protocol_key
= dpp_set_keypair(
2957 &tmp_curve
, dpp_protocol_key_override
,
2958 dpp_protocol_key_override_len
);
2960 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2962 #else /* CONFIG_TESTING_OPTIONS */
2963 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2964 #endif /* CONFIG_TESTING_OPTIONS */
2965 if (!auth
->own_protocol_key
)
2968 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2972 /* ECDH: N = pR * PI */
2973 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
2974 auth
->Nx
, &secret_len
) < 0)
2977 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
2978 auth
->Nx
, auth
->secret_len
);
2979 auth
->Nx_len
= auth
->secret_len
;
2981 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
2982 auth
->curve
->hash_len
) < 0)
2985 if (auth
->own_bi
&& auth
->peer_bi
) {
2986 /* Mutual authentication */
2987 if (dpp_auth_derive_l_responder(auth
) < 0)
2991 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
2994 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2995 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
2996 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
2997 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
2999 #ifdef CONFIG_TESTING_OPTIONS
3000 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
3001 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
3002 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3004 #endif /* CONFIG_TESTING_OPTIONS */
3005 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3006 r_auth
, 4 + auth
->curve
->hash_len
,
3007 0, NULL
, NULL
, wrapped_r_auth
) < 0)
3009 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
3010 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
3011 wrapped_r_auth
, wrapped_r_auth_len
);
3012 w_r_auth
= wrapped_r_auth
;
3014 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3016 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3018 i_pubkey_hash
= NULL
;
3020 i_nonce
= auth
->i_nonce
;
3021 r_nonce
= auth
->r_nonce
;
3023 #ifdef CONFIG_TESTING_OPTIONS
3024 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3025 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3026 r_pubkey_hash
= NULL
;
3027 } else if (dpp_test
==
3028 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3029 wpa_printf(MSG_INFO
,
3030 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3031 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3032 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3033 r_pubkey_hash
= test_hash
;
3034 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3035 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3036 i_pubkey_hash
= NULL
;
3037 } else if (dpp_test
==
3038 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3039 wpa_printf(MSG_INFO
,
3040 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3042 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3044 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3045 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3046 i_pubkey_hash
= test_hash
;
3047 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
3048 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
3051 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
3052 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
3054 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
3055 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
3057 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
3058 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
3060 wrapped_r_auth_len
= 0;
3061 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3062 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3064 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
3065 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3067 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
3068 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
3070 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3071 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3074 #endif /* CONFIG_TESTING_OPTIONS */
3076 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
3077 r_pubkey_hash
, i_pubkey_hash
,
3079 w_r_auth
, wrapped_r_auth_len
,
3083 wpabuf_free(auth
->resp_msg
);
3084 auth
->resp_msg
= msg
;
3092 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3093 enum dpp_status_error status
)
3096 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3097 #ifdef CONFIG_TESTING_OPTIONS
3098 u8 test_hash
[SHA256_MAC_LEN
];
3099 #endif /* CONFIG_TESTING_OPTIONS */
3103 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3105 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3107 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3109 i_pubkey_hash
= NULL
;
3111 i_nonce
= auth
->i_nonce
;
3113 #ifdef CONFIG_TESTING_OPTIONS
3114 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3115 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3116 r_pubkey_hash
= NULL
;
3117 } else if (dpp_test
==
3118 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3119 wpa_printf(MSG_INFO
,
3120 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3121 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3122 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3123 r_pubkey_hash
= test_hash
;
3124 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3125 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3126 i_pubkey_hash
= NULL
;
3127 } else if (dpp_test
==
3128 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3129 wpa_printf(MSG_INFO
,
3130 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3132 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3134 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3135 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3136 i_pubkey_hash
= test_hash
;
3137 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3138 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3140 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3141 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3144 #endif /* CONFIG_TESTING_OPTIONS */
3146 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3147 r_pubkey_hash
, i_pubkey_hash
,
3148 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3151 wpabuf_free(auth
->resp_msg
);
3152 auth
->resp_msg
= msg
;
3157 struct dpp_authentication
*
3158 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3159 struct dpp_bootstrap_info
*peer_bi
,
3160 struct dpp_bootstrap_info
*own_bi
,
3161 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3164 EVP_PKEY
*pi
= NULL
;
3165 EVP_PKEY_CTX
*ctx
= NULL
;
3169 u8
*unwrapped
= NULL
;
3170 size_t unwrapped_len
= 0;
3171 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3173 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3174 i_bootstrap_len
, channel_len
;
3175 struct dpp_authentication
*auth
= NULL
;
3179 #endif /* CONFIG_DPP2 */
3181 #ifdef CONFIG_TESTING_OPTIONS
3182 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3183 wpa_printf(MSG_INFO
,
3184 "DPP: TESTING - stop at Authentication Request");
3187 #endif /* CONFIG_TESTING_OPTIONS */
3189 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3191 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3192 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3193 "Missing or invalid required Wrapped Data attribute");
3196 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3197 wrapped_data
, wrapped_data_len
);
3198 attr_len
= wrapped_data
- 4 - attr_start
;
3200 auth
= os_zalloc(sizeof(*auth
));
3203 auth
->msg_ctx
= msg_ctx
;
3204 auth
->peer_bi
= peer_bi
;
3205 auth
->own_bi
= own_bi
;
3206 auth
->curve
= own_bi
->curve
;
3207 auth
->curr_freq
= freq
;
3209 auth
->peer_version
= 1; /* default to the first version */
3211 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3214 if (version_len
< 1 || version
[0] == 0) {
3216 "Invalid Protocol Version attribute");
3219 auth
->peer_version
= version
[0];
3220 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3221 auth
->peer_version
);
3223 #endif /* CONFIG_DPP2 */
3225 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3230 if (channel_len
< 2) {
3231 dpp_auth_fail(auth
, "Too short Channel attribute");
3235 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3236 wpa_printf(MSG_DEBUG
,
3237 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3238 channel
[0], channel
[1], neg_freq
);
3241 "Unsupported Channel attribute value");
3245 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3246 wpa_printf(MSG_DEBUG
,
3247 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3249 auth
->curr_freq
= neg_freq
;
3253 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3257 "Missing required Initiator Protocol Key attribute");
3260 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3261 i_proto
, i_proto_len
);
3264 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3266 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3269 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3271 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3273 auth
->secret_len
= secret_len
;
3275 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3276 auth
->Mx
, auth
->secret_len
);
3277 auth
->Mx_len
= auth
->secret_len
;
3279 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3280 auth
->curve
->hash_len
) < 0)
3284 len
[0] = DPP_HDR_LEN
;
3285 addr
[1] = attr_start
;
3287 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3288 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3289 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3290 wrapped_data
, wrapped_data_len
);
3291 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3292 unwrapped
= os_malloc(unwrapped_len
);
3295 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3296 wrapped_data
, wrapped_data_len
,
3297 2, addr
, len
, unwrapped
) < 0) {
3298 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3301 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3302 unwrapped
, unwrapped_len
);
3304 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3305 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3309 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3311 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3312 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3315 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3316 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3318 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3319 DPP_ATTR_I_CAPABILITIES
,
3321 if (!i_capab
|| i_capab_len
< 1) {
3322 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3325 auth
->i_capab
= i_capab
[0];
3326 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3328 bin_clear_free(unwrapped
, unwrapped_len
);
3331 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3332 case DPP_CAPAB_ENROLLEE
:
3333 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3334 wpa_printf(MSG_DEBUG
,
3335 "DPP: Local policy does not allow Configurator role");
3336 goto not_compatible
;
3338 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3339 auth
->configurator
= 1;
3341 case DPP_CAPAB_CONFIGURATOR
:
3342 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3343 wpa_printf(MSG_DEBUG
,
3344 "DPP: Local policy does not allow Enrollee role");
3345 goto not_compatible
;
3347 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3348 auth
->configurator
= 0;
3350 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3351 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3352 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3353 auth
->configurator
= 0;
3354 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3355 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3356 auth
->configurator
= 1;
3358 wpa_printf(MSG_DEBUG
,
3359 "DPP: Local policy does not allow Configurator/Enrollee role");
3360 goto not_compatible
;
3364 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3365 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3366 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3367 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3371 auth
->peer_protocol_key
= pi
;
3373 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3374 char hex
[SHA256_MAC_LEN
* 2 + 1];
3376 wpa_printf(MSG_DEBUG
,
3377 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3378 if (dpp_auth_build_resp_status(auth
,
3379 DPP_STATUS_RESPONSE_PENDING
) < 0)
3381 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3382 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3384 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3385 auth
->response_pending
= 1;
3386 os_memcpy(auth
->waiting_pubkey_hash
,
3387 i_bootstrap
, i_bootstrap_len
);
3388 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3394 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3398 if (dpp_auth_build_resp_ok(auth
) < 0)
3404 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3405 "i-capab=0x%02x", auth
->i_capab
);
3406 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3407 auth
->configurator
= 1;
3409 auth
->configurator
= 0;
3410 auth
->peer_protocol_key
= pi
;
3412 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3415 auth
->remove_on_tx_status
= 1;
3418 bin_clear_free(unwrapped
, unwrapped_len
);
3420 EVP_PKEY_CTX_free(ctx
);
3421 dpp_auth_deinit(auth
);
3426 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3427 struct dpp_bootstrap_info
*peer_bi
)
3429 if (!auth
|| !auth
->response_pending
||
3430 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3431 SHA256_MAC_LEN
) != 0)
3434 wpa_printf(MSG_DEBUG
,
3435 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3436 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3437 auth
->peer_bi
= peer_bi
;
3439 if (dpp_auth_build_resp_ok(auth
) < 0)
3446 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3447 enum dpp_status_error status
)
3450 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3452 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3455 size_t len
[2], attr_len
;
3457 u8
*wrapped_r_nonce
;
3458 u8
*attr_start
, *attr_end
;
3459 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3460 #ifdef CONFIG_TESTING_OPTIONS
3461 u8 test_hash
[SHA256_MAC_LEN
];
3462 #endif /* CONFIG_TESTING_OPTIONS */
3464 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3466 i_auth_len
= 4 + auth
->curve
->hash_len
;
3467 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3468 /* Build DPP Authentication Confirmation frame attributes */
3469 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3470 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3471 #ifdef CONFIG_TESTING_OPTIONS
3472 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3474 #endif /* CONFIG_TESTING_OPTIONS */
3475 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3479 attr_start
= wpabuf_put(msg
, 0);
3481 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3483 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3485 i_pubkey_hash
= NULL
;
3487 #ifdef CONFIG_TESTING_OPTIONS
3488 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3489 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3491 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3492 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3495 #endif /* CONFIG_TESTING_OPTIONS */
3498 dpp_build_attr_status(msg
, status
);
3500 #ifdef CONFIG_TESTING_OPTIONS
3502 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3503 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3504 r_pubkey_hash
= NULL
;
3505 } else if (dpp_test
==
3506 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3507 wpa_printf(MSG_INFO
,
3508 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3509 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3510 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3511 r_pubkey_hash
= test_hash
;
3512 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3513 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3514 i_pubkey_hash
= NULL
;
3515 } else if (dpp_test
==
3516 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3517 wpa_printf(MSG_INFO
,
3518 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3520 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3522 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3523 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3524 i_pubkey_hash
= test_hash
;
3526 #endif /* CONFIG_TESTING_OPTIONS */
3528 /* Responder Bootstrapping Key Hash */
3529 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3531 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3532 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3534 #ifdef CONFIG_TESTING_OPTIONS
3535 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3536 goto skip_wrapped_data
;
3537 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3539 #endif /* CONFIG_TESTING_OPTIONS */
3541 attr_end
= wpabuf_put(msg
, 0);
3543 /* OUI, OUI type, Crypto Suite, DPP frame type */
3544 addr
[0] = wpabuf_head_u8(msg
) + 2;
3545 len
[0] = 3 + 1 + 1 + 1;
3546 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3548 /* Attributes before Wrapped Data */
3549 addr
[1] = attr_start
;
3550 len
[1] = attr_end
- attr_start
;
3551 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3553 if (status
== DPP_STATUS_OK
) {
3554 /* I-auth wrapped with ke */
3555 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3556 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3557 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3559 #ifdef CONFIG_TESTING_OPTIONS
3560 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3562 #endif /* CONFIG_TESTING_OPTIONS */
3564 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3566 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3567 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3568 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3571 #ifdef CONFIG_TESTING_OPTIONS
3572 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3573 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3574 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3577 #endif /* CONFIG_TESTING_OPTIONS */
3578 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3580 2, addr
, len
, wrapped_i_auth
) < 0)
3582 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3583 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3585 /* R-nonce wrapped with k2 */
3586 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3587 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3588 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3590 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3591 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3592 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3594 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3595 r_nonce
, r_nonce_len
,
3596 2, addr
, len
, wrapped_r_nonce
) < 0)
3598 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3599 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3602 #ifdef CONFIG_TESTING_OPTIONS
3603 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3604 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3605 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3608 #endif /* CONFIG_TESTING_OPTIONS */
3610 wpa_hexdump_buf(MSG_DEBUG
,
3611 "DPP: Authentication Confirmation frame attributes",
3613 if (status
== DPP_STATUS_OK
)
3614 dpp_auth_success(auth
);
3625 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3626 const u8
*attr_start
, size_t attr_len
,
3627 const u8
*wrapped_data
, u16 wrapped_data_len
,
3628 enum dpp_status_error status
)
3632 u8
*unwrapped
= NULL
;
3633 size_t unwrapped_len
= 0;
3634 const u8
*i_nonce
, *r_capab
;
3635 u16 i_nonce_len
, r_capab_len
;
3637 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3638 wpa_printf(MSG_DEBUG
,
3639 "DPP: Responder reported incompatible roles");
3640 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3641 wpa_printf(MSG_DEBUG
,
3642 "DPP: Responder reported more time needed");
3644 wpa_printf(MSG_DEBUG
,
3645 "DPP: Responder reported failure (status %d)",
3647 dpp_auth_fail(auth
, "Responder reported failure");
3652 len
[0] = DPP_HDR_LEN
;
3653 addr
[1] = attr_start
;
3655 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3656 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3657 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3658 wrapped_data
, wrapped_data_len
);
3659 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3660 unwrapped
= os_malloc(unwrapped_len
);
3663 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3664 wrapped_data
, wrapped_data_len
,
3665 2, addr
, len
, unwrapped
) < 0) {
3666 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3669 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3670 unwrapped
, unwrapped_len
);
3672 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3673 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3677 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3679 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3680 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3683 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3684 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3685 dpp_auth_fail(auth
, "I-nonce mismatch");
3689 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3690 DPP_ATTR_R_CAPABILITIES
,
3692 if (!r_capab
|| r_capab_len
< 1) {
3693 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3696 auth
->r_capab
= r_capab
[0];
3697 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3698 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3699 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3700 "r-capab=0x%02x", auth
->r_capab
);
3701 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3702 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3704 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3705 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3706 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3707 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3710 wpa_printf(MSG_DEBUG
,
3711 "DPP: Continue waiting for full DPP Authentication Response");
3712 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3713 DPP_EVENT_RESPONSE_PENDING
"%s",
3714 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3718 bin_clear_free(unwrapped
, unwrapped_len
);
3723 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3724 const u8
*attr_start
, size_t attr_len
)
3730 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3731 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3732 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3733 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3734 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3735 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3736 wrapped2_len
, r_auth_len
;
3737 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3742 #endif /* CONFIG_DPP2 */
3744 #ifdef CONFIG_TESTING_OPTIONS
3745 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3746 wpa_printf(MSG_INFO
,
3747 "DPP: TESTING - stop at Authentication Response");
3750 #endif /* CONFIG_TESTING_OPTIONS */
3752 if (!auth
->initiator
|| !auth
->peer_bi
) {
3753 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3757 auth
->waiting_auth_resp
= 0;
3759 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3761 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3763 "Missing or invalid required Wrapped Data attribute");
3766 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3767 wrapped_data
, wrapped_data_len
);
3769 attr_len
= wrapped_data
- 4 - attr_start
;
3771 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3772 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3774 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3776 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3779 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3780 r_bootstrap
, r_bootstrap_len
);
3781 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3782 SHA256_MAC_LEN
) != 0) {
3784 "Unexpected Responder Bootstrapping Key Hash value");
3785 wpa_hexdump(MSG_DEBUG
,
3786 "DPP: Expected Responder Bootstrapping Key Hash",
3787 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3791 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3792 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3795 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3797 "Invalid Initiator Bootstrapping Key Hash attribute");
3800 wpa_hexdump(MSG_MSGDUMP
,
3801 "DPP: Initiator Bootstrapping Key Hash",
3802 i_bootstrap
, i_bootstrap_len
);
3803 if (!auth
->own_bi
||
3804 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3805 SHA256_MAC_LEN
) != 0) {
3807 "Initiator Bootstrapping Key Hash attribute did not match");
3810 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3811 /* PKEX bootstrapping mandates use of mutual authentication */
3813 "Missing Initiator Bootstrapping Key Hash attribute");
3817 auth
->peer_version
= 1; /* default to the first version */
3819 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3822 if (version_len
< 1 || version
[0] == 0) {
3824 "Invalid Protocol Version attribute");
3827 auth
->peer_version
= version
[0];
3828 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3829 auth
->peer_version
);
3831 #endif /* CONFIG_DPP2 */
3833 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3835 if (!status
|| status_len
< 1) {
3837 "Missing or invalid required DPP Status attribute");
3840 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3841 auth
->auth_resp_status
= status
[0];
3842 if (status
[0] != DPP_STATUS_OK
) {
3843 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3844 attr_len
, wrapped_data
,
3845 wrapped_data_len
, status
[0]);
3849 if (!i_bootstrap
&& auth
->own_bi
) {
3850 wpa_printf(MSG_DEBUG
,
3851 "DPP: Responder decided not to use mutual authentication");
3852 auth
->own_bi
= NULL
;
3855 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3856 auth
->own_bi
!= NULL
);
3858 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3862 "Missing required Responder Protocol Key attribute");
3865 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3866 r_proto
, r_proto_len
);
3869 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3871 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3874 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3876 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
3877 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3880 EVP_PKEY_free(auth
->peer_protocol_key
);
3881 auth
->peer_protocol_key
= pr
;
3884 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3885 auth
->Nx
, auth
->secret_len
);
3886 auth
->Nx_len
= auth
->secret_len
;
3888 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3889 auth
->curve
->hash_len
) < 0)
3893 len
[0] = DPP_HDR_LEN
;
3894 addr
[1] = attr_start
;
3896 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3897 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3898 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3899 wrapped_data
, wrapped_data_len
);
3900 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3901 unwrapped
= os_malloc(unwrapped_len
);
3904 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3905 wrapped_data
, wrapped_data_len
,
3906 2, addr
, len
, unwrapped
) < 0) {
3907 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3910 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3911 unwrapped
, unwrapped_len
);
3913 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3914 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3918 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
3920 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
3921 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
3924 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
3925 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
3927 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3929 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3930 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3933 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3934 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3935 dpp_auth_fail(auth
, "I-nonce mismatch");
3940 /* Mutual authentication */
3941 if (dpp_auth_derive_l_initiator(auth
) < 0)
3945 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3946 DPP_ATTR_R_CAPABILITIES
,
3948 if (!r_capab
|| r_capab_len
< 1) {
3949 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3952 auth
->r_capab
= r_capab
[0];
3953 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3954 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3955 if ((auth
->allowed_roles
==
3956 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
3957 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
3958 /* Peer selected its role, so move from "either role" to the
3959 * role that is compatible with peer's selection. */
3960 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
3961 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
3962 auth
->configurator
? "Configurator" : "Enrollee");
3963 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3964 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3965 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
3966 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3967 "Unexpected role in R-capabilities 0x%02x",
3969 if (role
!= DPP_CAPAB_ENROLLEE
&&
3970 role
!= DPP_CAPAB_CONFIGURATOR
)
3972 bin_clear_free(unwrapped
, unwrapped_len
);
3973 auth
->remove_on_tx_status
= 1;
3974 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
3977 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
3978 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
3979 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
3981 "Missing or invalid Secondary Wrapped Data");
3985 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3986 wrapped2
, wrapped2_len
);
3988 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3991 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
3992 unwrapped2
= os_malloc(unwrapped2_len
);
3995 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
3996 wrapped2
, wrapped2_len
,
3997 0, NULL
, NULL
, unwrapped2
) < 0) {
3998 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4001 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4002 unwrapped2
, unwrapped2_len
);
4004 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
4006 "Invalid attribute in secondary unwrapped data");
4010 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
4012 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
4014 "Missing or invalid Responder Authenticating Tag");
4017 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
4018 r_auth
, r_auth_len
);
4019 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4020 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
4022 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
4023 r_auth2
, r_auth_len
);
4024 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
4025 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
4026 bin_clear_free(unwrapped
, unwrapped_len
);
4027 bin_clear_free(unwrapped2
, unwrapped2_len
);
4028 auth
->remove_on_tx_status
= 1;
4029 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
4032 bin_clear_free(unwrapped
, unwrapped_len
);
4033 bin_clear_free(unwrapped2
, unwrapped2_len
);
4035 #ifdef CONFIG_TESTING_OPTIONS
4036 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
4037 wpa_printf(MSG_INFO
,
4038 "DPP: TESTING - Authentication Response in place of Confirm");
4039 if (dpp_auth_build_resp_ok(auth
) < 0)
4041 return wpabuf_dup(auth
->resp_msg
);
4043 #endif /* CONFIG_TESTING_OPTIONS */
4045 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
4048 bin_clear_free(unwrapped
, unwrapped_len
);
4049 bin_clear_free(unwrapped2
, unwrapped2_len
);
4055 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
4057 const u8
*attr_start
, size_t attr_len
,
4058 const u8
*wrapped_data
,
4059 u16 wrapped_data_len
,
4060 enum dpp_status_error status
)
4064 u8
*unwrapped
= NULL
;
4065 size_t unwrapped_len
= 0;
4069 /* Authentication Confirm failure cases are expected to include
4070 * {R-nonce}k2 in the Wrapped Data attribute. */
4073 len
[0] = DPP_HDR_LEN
;
4074 addr
[1] = attr_start
;
4076 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4077 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4078 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4079 wrapped_data
, wrapped_data_len
);
4080 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4081 unwrapped
= os_malloc(unwrapped_len
);
4083 dpp_auth_fail(auth
, "Authentication failed");
4086 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4087 wrapped_data
, wrapped_data_len
,
4088 2, addr
, len
, unwrapped
) < 0) {
4089 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4092 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4093 unwrapped
, unwrapped_len
);
4095 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4096 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4100 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4102 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4103 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4106 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4107 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4108 r_nonce
, r_nonce_len
);
4109 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4110 auth
->r_nonce
, r_nonce_len
);
4111 dpp_auth_fail(auth
, "R-nonce mismatch");
4115 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4116 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4117 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4118 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4121 bin_clear_free(unwrapped
, unwrapped_len
);
4126 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4127 const u8
*attr_start
, size_t attr_len
)
4129 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4130 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4134 u8
*unwrapped
= NULL
;
4135 size_t unwrapped_len
= 0;
4136 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4138 #ifdef CONFIG_TESTING_OPTIONS
4139 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4140 wpa_printf(MSG_INFO
,
4141 "DPP: TESTING - stop at Authentication Confirm");
4144 #endif /* CONFIG_TESTING_OPTIONS */
4146 if (auth
->initiator
|| !auth
->own_bi
) {
4147 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4151 auth
->waiting_auth_conf
= 0;
4153 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4155 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4157 "Missing or invalid required Wrapped Data attribute");
4160 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4161 wrapped_data
, wrapped_data_len
);
4163 attr_len
= wrapped_data
- 4 - attr_start
;
4165 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4166 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4168 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4170 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4173 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4174 r_bootstrap
, r_bootstrap_len
);
4175 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4176 SHA256_MAC_LEN
) != 0) {
4177 wpa_hexdump(MSG_DEBUG
,
4178 "DPP: Expected Responder Bootstrapping Key Hash",
4179 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4181 "Responder Bootstrapping Key Hash mismatch");
4185 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4186 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4189 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4191 "Invalid Initiator Bootstrapping Key Hash attribute");
4194 wpa_hexdump(MSG_MSGDUMP
,
4195 "DPP: Initiator Bootstrapping Key Hash",
4196 i_bootstrap
, i_bootstrap_len
);
4197 if (!auth
->peer_bi
||
4198 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4199 SHA256_MAC_LEN
) != 0) {
4201 "Initiator Bootstrapping Key Hash mismatch");
4204 } else if (auth
->peer_bi
) {
4205 /* Mutual authentication and peer did not include its
4206 * Bootstrapping Key Hash attribute. */
4208 "Missing Initiator Bootstrapping Key Hash attribute");
4212 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4214 if (!status
|| status_len
< 1) {
4216 "Missing or invalid required DPP Status attribute");
4219 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4220 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4221 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4222 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4223 attr_len
, wrapped_data
,
4224 wrapped_data_len
, status
[0]);
4226 if (status
[0] != DPP_STATUS_OK
) {
4227 dpp_auth_fail(auth
, "Authentication failed");
4232 len
[0] = DPP_HDR_LEN
;
4233 addr
[1] = attr_start
;
4235 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4236 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4237 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4238 wrapped_data
, wrapped_data_len
);
4239 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4240 unwrapped
= os_malloc(unwrapped_len
);
4243 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4244 wrapped_data
, wrapped_data_len
,
4245 2, addr
, len
, unwrapped
) < 0) {
4246 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4249 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4250 unwrapped
, unwrapped_len
);
4252 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4253 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4257 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4259 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4261 "Missing or invalid Initiator Authenticating Tag");
4264 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4265 i_auth
, i_auth_len
);
4266 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4267 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4269 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4270 i_auth2
, i_auth_len
);
4271 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4272 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4276 bin_clear_free(unwrapped
, unwrapped_len
);
4277 dpp_auth_success(auth
);
4280 bin_clear_free(unwrapped
, unwrapped_len
);
4285 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4287 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4291 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4293 struct dpp_configuration
*conf
;
4297 conf
= os_zalloc(sizeof(*conf
));
4301 end
= os_strchr(type
, ' ');
4305 len
= os_strlen(type
);
4307 if (bin_str_eq(type
, len
, "psk"))
4308 conf
->akm
= DPP_AKM_PSK
;
4309 else if (bin_str_eq(type
, len
, "sae"))
4310 conf
->akm
= DPP_AKM_SAE
;
4311 else if (bin_str_eq(type
, len
, "psk-sae") ||
4312 bin_str_eq(type
, len
, "psk+sae"))
4313 conf
->akm
= DPP_AKM_PSK_SAE
;
4314 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4315 bin_str_eq(type
, len
, "dpp+sae"))
4316 conf
->akm
= DPP_AKM_SAE_DPP
;
4317 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4318 bin_str_eq(type
, len
, "dpp+psk+sae"))
4319 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4320 else if (bin_str_eq(type
, len
, "dpp"))
4321 conf
->akm
= DPP_AKM_DPP
;
4327 dpp_configuration_free(conf
);
4332 int dpp_akm_psk(enum dpp_akm akm
)
4334 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4335 akm
== DPP_AKM_PSK_SAE_DPP
;
4339 int dpp_akm_sae(enum dpp_akm akm
)
4341 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4342 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4346 int dpp_akm_legacy(enum dpp_akm akm
)
4348 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4353 int dpp_akm_dpp(enum dpp_akm akm
)
4355 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4356 akm
== DPP_AKM_PSK_SAE_DPP
;
4360 int dpp_akm_ver2(enum dpp_akm akm
)
4362 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4366 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4368 if (conf
->ssid_len
== 0)
4370 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4372 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4378 void dpp_configuration_free(struct dpp_configuration
*conf
)
4382 str_clear_free(conf
->passphrase
);
4383 os_free(conf
->group_id
);
4384 bin_clear_free(conf
, sizeof(*conf
));
4388 static int dpp_configuration_parse_helper(struct dpp_authentication
*auth
,
4389 const char *cmd
, int idx
)
4391 const char *pos
, *end
;
4392 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4393 struct dpp_configuration
*conf
= NULL
;
4395 pos
= os_strstr(cmd
, " conf=sta-");
4397 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4400 conf_sta
->netrole
= DPP_NETROLE_STA
;
4404 pos
= os_strstr(cmd
, " conf=ap-");
4406 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4409 conf_ap
->netrole
= DPP_NETROLE_AP
;
4416 pos
= os_strstr(cmd
, " ssid=");
4419 end
= os_strchr(pos
, ' ');
4420 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4421 conf
->ssid_len
/= 2;
4422 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4423 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4426 #ifdef CONFIG_TESTING_OPTIONS
4427 /* use a default SSID for legacy testing reasons */
4428 os_memcpy(conf
->ssid
, "test", 4);
4430 #else /* CONFIG_TESTING_OPTIONS */
4432 #endif /* CONFIG_TESTING_OPTIONS */
4435 pos
= os_strstr(cmd
, " pass=");
4440 end
= os_strchr(pos
, ' ');
4441 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4443 if (pass_len
> 63 || pass_len
< 8)
4445 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4446 if (!conf
->passphrase
||
4447 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4451 pos
= os_strstr(cmd
, " psk=");
4454 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4459 pos
= os_strstr(cmd
, " group_id=");
4461 size_t group_id_len
;
4464 end
= os_strchr(pos
, ' ');
4465 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4466 conf
->group_id
= os_malloc(group_id_len
+ 1);
4467 if (!conf
->group_id
)
4469 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4470 conf
->group_id
[group_id_len
] = '\0';
4473 pos
= os_strstr(cmd
, " expiry=");
4478 val
= strtol(pos
, NULL
, 0);
4481 conf
->netaccesskey_expiry
= val
;
4484 if (!dpp_configuration_valid(conf
))
4488 auth
->conf_sta
= conf_sta
;
4489 auth
->conf_ap
= conf_ap
;
4490 } else if (idx
== 1) {
4491 auth
->conf2_sta
= conf_sta
;
4492 auth
->conf2_ap
= conf_ap
;
4499 dpp_configuration_free(conf_sta
);
4500 dpp_configuration_free(conf_ap
);
4505 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4513 pos
= os_strstr(cmd
, " @CONF-OBJ-SEP@ ");
4515 return dpp_configuration_parse_helper(auth
, cmd
, 0);
4518 tmp
= os_malloc(len
+ 1);
4521 os_memcpy(tmp
, cmd
, len
);
4523 res
= dpp_configuration_parse_helper(auth
, cmd
, 0);
4524 str_clear_free(tmp
);
4527 res
= dpp_configuration_parse_helper(auth
, cmd
+ len
, 1);
4532 dpp_configuration_free(auth
->conf_sta
);
4533 dpp_configuration_free(auth
->conf2_sta
);
4534 dpp_configuration_free(auth
->conf_ap
);
4535 dpp_configuration_free(auth
->conf2_ap
);
4540 static struct dpp_configurator
*
4541 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4543 struct dpp_configurator
*conf
;
4548 dl_list_for_each(conf
, &dpp
->configurator
,
4549 struct dpp_configurator
, list
) {
4557 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4558 struct dpp_authentication
*auth
,
4566 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4568 pos
= os_strstr(cmd
, " configurator=");
4571 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4573 wpa_printf(MSG_INFO
,
4574 "DPP: Could not find the specified configurator");
4579 pos
= os_strstr(cmd
, " conn_status=");
4582 auth
->send_conn_status
= atoi(pos
);
4585 pos
= os_strstr(cmd
, " akm_use_selector=");
4588 auth
->akm_use_selector
= atoi(pos
);
4591 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4592 wpa_msg(msg_ctx
, MSG_INFO
,
4593 "DPP: Failed to set configurator parameters");
4600 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4606 dpp_configuration_free(auth
->conf_ap
);
4607 dpp_configuration_free(auth
->conf2_ap
);
4608 dpp_configuration_free(auth
->conf_sta
);
4609 dpp_configuration_free(auth
->conf2_sta
);
4610 EVP_PKEY_free(auth
->own_protocol_key
);
4611 EVP_PKEY_free(auth
->peer_protocol_key
);
4612 wpabuf_free(auth
->req_msg
);
4613 wpabuf_free(auth
->resp_msg
);
4614 wpabuf_free(auth
->conf_req
);
4615 for (i
= 0; i
< auth
->num_conf_obj
; i
++) {
4616 struct dpp_config_obj
*conf
= &auth
->conf_obj
[i
];
4618 os_free(conf
->connector
);
4619 wpabuf_free(conf
->c_sign_key
);
4621 wpabuf_free(auth
->net_access_key
);
4622 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4623 #ifdef CONFIG_TESTING_OPTIONS
4624 os_free(auth
->config_obj_override
);
4625 os_free(auth
->discovery_override
);
4626 os_free(auth
->groups_override
);
4627 #endif /* CONFIG_TESTING_OPTIONS */
4628 bin_clear_free(auth
, sizeof(*auth
));
4632 static struct wpabuf
*
4633 dpp_build_conf_start(struct dpp_authentication
*auth
,
4634 struct dpp_configuration
*conf
, size_t tailroom
)
4638 #ifdef CONFIG_TESTING_OPTIONS
4639 if (auth
->discovery_override
)
4640 tailroom
+= os_strlen(auth
->discovery_override
);
4641 #endif /* CONFIG_TESTING_OPTIONS */
4643 buf
= wpabuf_alloc(200 + tailroom
);
4646 json_start_object(buf
, NULL
);
4647 json_add_string(buf
, "wi-fi_tech", "infra");
4648 json_value_sep(buf
);
4649 #ifdef CONFIG_TESTING_OPTIONS
4650 if (auth
->discovery_override
) {
4651 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4652 auth
->discovery_override
);
4653 wpabuf_put_str(buf
, "\"discovery\":");
4654 wpabuf_put_str(buf
, auth
->discovery_override
);
4655 json_value_sep(buf
);
4658 #endif /* CONFIG_TESTING_OPTIONS */
4659 json_start_object(buf
, "discovery");
4660 if (json_add_string_escape(buf
, "ssid", conf
->ssid
,
4661 conf
->ssid_len
) < 0) {
4665 json_end_object(buf
);
4666 json_value_sep(buf
);
4672 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4673 const char *kid
, const struct dpp_curve_params
*curve
)
4679 pub
= dpp_get_pubkey_point(key
, 0);
4683 json_start_object(buf
, name
);
4684 json_add_string(buf
, "kty", "EC");
4685 json_value_sep(buf
);
4686 json_add_string(buf
, "crv", curve
->jwk_crv
);
4687 json_value_sep(buf
);
4688 pos
= wpabuf_head(pub
);
4689 if (json_add_base64url(buf
, "x", pos
, curve
->prime_len
) < 0)
4691 json_value_sep(buf
);
4692 pos
+= curve
->prime_len
;
4693 if (json_add_base64url(buf
, "y", pos
, curve
->prime_len
) < 0)
4696 json_value_sep(buf
);
4697 json_add_string(buf
, "kid", kid
);
4699 json_end_object(buf
);
4707 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4708 struct dpp_configuration
*conf
)
4710 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4711 json_add_string_escape(buf
, "pass", conf
->passphrase
,
4712 os_strlen(conf
->passphrase
));
4713 } else if (conf
->psk_set
) {
4714 char psk
[2 * sizeof(conf
->psk
) + 1];
4716 wpa_snprintf_hex(psk
, sizeof(psk
),
4717 conf
->psk
, sizeof(conf
->psk
));
4718 json_add_string(buf
, "psk_hex", psk
);
4719 forced_memzero(psk
, sizeof(psk
));
4724 static const char * dpp_netrole_str(enum dpp_netrole netrole
)
4727 case DPP_NETROLE_STA
:
4729 case DPP_NETROLE_AP
:
4737 static struct wpabuf
*
4738 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
,
4739 struct dpp_configuration
*conf
)
4741 struct wpabuf
*buf
= NULL
;
4742 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4744 const struct dpp_curve_params
*curve
;
4745 struct wpabuf
*jws_prot_hdr
;
4746 size_t signed1_len
, signed2_len
, signed3_len
;
4747 struct wpabuf
*dppcon
= NULL
;
4748 unsigned char *signature
= NULL
;
4749 const unsigned char *p
;
4750 size_t signature_len
;
4751 EVP_MD_CTX
*md_ctx
= NULL
;
4752 ECDSA_SIG
*sig
= NULL
;
4754 const EVP_MD
*sign_md
;
4755 const BIGNUM
*r
, *s
;
4756 size_t extra_len
= 1000;
4759 const char *akm_str
;
4762 wpa_printf(MSG_INFO
,
4763 "DPP: No configurator specified - cannot generate DPP config object");
4766 curve
= auth
->conf
->curve
;
4767 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4768 sign_md
= EVP_sha256();
4769 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4770 sign_md
= EVP_sha384();
4771 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4772 sign_md
= EVP_sha512();
4774 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4779 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4780 wpa_printf(MSG_DEBUG
,
4781 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4785 #ifdef CONFIG_TESTING_OPTIONS
4786 if (auth
->groups_override
)
4787 extra_len
+= os_strlen(auth
->groups_override
);
4788 #endif /* CONFIG_TESTING_OPTIONS */
4791 extra_len
+= os_strlen(conf
->group_id
);
4793 /* Connector (JSON dppCon object) */
4794 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4797 #ifdef CONFIG_TESTING_OPTIONS
4798 if (auth
->groups_override
) {
4799 wpabuf_put_u8(dppcon
, '{');
4800 if (auth
->groups_override
) {
4801 wpa_printf(MSG_DEBUG
,
4802 "DPP: TESTING - groups override: '%s'",
4803 auth
->groups_override
);
4804 wpabuf_put_str(dppcon
, "\"groups\":");
4805 wpabuf_put_str(dppcon
, auth
->groups_override
);
4806 json_value_sep(dppcon
);
4810 #endif /* CONFIG_TESTING_OPTIONS */
4811 json_start_object(dppcon
, NULL
);
4812 json_start_array(dppcon
, "groups");
4813 json_start_object(dppcon
, NULL
);
4814 json_add_string(dppcon
, "groupId",
4815 conf
->group_id
? conf
->group_id
: "*");
4816 json_value_sep(dppcon
);
4817 json_add_string(dppcon
, "netRole", dpp_netrole_str(conf
->netrole
));
4818 json_end_object(dppcon
);
4819 json_end_array(dppcon
);
4820 json_value_sep(dppcon
);
4821 #ifdef CONFIG_TESTING_OPTIONS
4823 #endif /* CONFIG_TESTING_OPTIONS */
4824 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4826 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4829 if (conf
->netaccesskey_expiry
) {
4833 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4834 wpa_printf(MSG_DEBUG
,
4835 "DPP: Failed to generate expiry string");
4838 os_snprintf(expiry
, sizeof(expiry
),
4839 "%04u-%02u-%02uT%02u:%02u:%02uZ",
4840 tm
.year
, tm
.month
, tm
.day
,
4841 tm
.hour
, tm
.min
, tm
.sec
);
4842 json_value_sep(dppcon
);
4843 json_add_string(dppcon
, "expiry", expiry
);
4845 json_end_object(dppcon
);
4846 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4847 (const char *) wpabuf_head(dppcon
));
4849 jws_prot_hdr
= wpabuf_alloc(100);
4852 json_start_object(jws_prot_hdr
, NULL
);
4853 json_add_string(jws_prot_hdr
, "typ", "dppCon");
4854 json_value_sep(jws_prot_hdr
);
4855 json_add_string(jws_prot_hdr
, "kid", auth
->conf
->kid
);
4856 json_value_sep(jws_prot_hdr
);
4857 json_add_string(jws_prot_hdr
, "alg", curve
->jws_alg
);
4858 json_end_object(jws_prot_hdr
);
4859 signed1
= base64_url_encode(wpabuf_head(jws_prot_hdr
),
4860 wpabuf_len(jws_prot_hdr
),
4862 wpabuf_free(jws_prot_hdr
);
4863 signed2
= base64_url_encode(wpabuf_head(dppcon
), wpabuf_len(dppcon
),
4865 if (!signed1
|| !signed2
)
4868 md_ctx
= EVP_MD_CTX_create();
4873 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
4874 auth
->conf
->csign
) != 1) {
4875 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
4876 ERR_error_string(ERR_get_error(), NULL
));
4879 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
4880 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
4881 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
4882 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
4883 ERR_error_string(ERR_get_error(), NULL
));
4886 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
4887 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4888 ERR_error_string(ERR_get_error(), NULL
));
4891 signature
= os_malloc(signature_len
);
4894 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
4895 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
4896 ERR_error_string(ERR_get_error(), NULL
));
4899 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
4900 signature
, signature_len
);
4901 /* Convert to raw coordinates r,s */
4903 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
4906 ECDSA_SIG_get0(sig
, &r
, &s
);
4907 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
4908 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
4909 curve
->prime_len
) < 0)
4911 signature_len
= 2 * curve
->prime_len
;
4912 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
4913 signature
, signature_len
);
4914 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
4918 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
4920 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
4921 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
4924 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
4928 if (auth
->akm_use_selector
&& dpp_akm_ver2(akm
))
4929 akm_str
= dpp_akm_selector_str(akm
);
4931 akm_str
= dpp_akm_str(akm
);
4932 json_start_object(buf
, "cred");
4933 json_add_string(buf
, "akm", akm_str
);
4934 json_value_sep(buf
);
4936 dpp_build_legacy_cred_params(buf
, conf
);
4937 json_value_sep(buf
);
4939 wpabuf_put_str(buf
, "\"signedConnector\":\"");
4940 wpabuf_put_str(buf
, signed1
);
4941 wpabuf_put_u8(buf
, '.');
4942 wpabuf_put_str(buf
, signed2
);
4943 wpabuf_put_u8(buf
, '.');
4944 wpabuf_put_str(buf
, signed3
);
4945 wpabuf_put_str(buf
, "\"");
4946 json_value_sep(buf
);
4947 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
4949 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
4953 json_end_object(buf
);
4954 json_end_object(buf
);
4956 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
4957 wpabuf_head(buf
), wpabuf_len(buf
));
4960 EVP_MD_CTX_destroy(md_ctx
);
4961 ECDSA_SIG_free(sig
);
4966 wpabuf_free(dppcon
);
4969 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
4976 static struct wpabuf
*
4977 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
,
4978 struct dpp_configuration
*conf
)
4981 const char *akm_str
;
4983 buf
= dpp_build_conf_start(auth
, conf
, 1000);
4987 if (auth
->akm_use_selector
&& dpp_akm_ver2(conf
->akm
))
4988 akm_str
= dpp_akm_selector_str(conf
->akm
);
4990 akm_str
= dpp_akm_str(conf
->akm
);
4991 json_start_object(buf
, "cred");
4992 json_add_string(buf
, "akm", akm_str
);
4993 json_value_sep(buf
);
4994 dpp_build_legacy_cred_params(buf
, conf
);
4995 json_end_object(buf
);
4996 json_end_object(buf
);
4998 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
4999 wpabuf_head(buf
), wpabuf_len(buf
));
5005 static struct wpabuf
*
5006 dpp_build_conf_obj(struct dpp_authentication
*auth
, int ap
, int idx
)
5008 struct dpp_configuration
*conf
;
5010 #ifdef CONFIG_TESTING_OPTIONS
5011 if (auth
->config_obj_override
) {
5014 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
5015 return wpabuf_alloc_copy(auth
->config_obj_override
,
5016 os_strlen(auth
->config_obj_override
));
5018 #endif /* CONFIG_TESTING_OPTIONS */
5021 conf
= ap
? auth
->conf_ap
: auth
->conf_sta
;
5023 conf
= ap
? auth
->conf2_ap
: auth
->conf2_sta
;
5028 wpa_printf(MSG_DEBUG
,
5029 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5034 if (dpp_akm_dpp(conf
->akm
))
5035 return dpp_build_conf_obj_dpp(auth
, conf
);
5036 return dpp_build_conf_obj_legacy(auth
, conf
);
5040 static struct wpabuf
*
5041 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
5042 u16 e_nonce_len
, int ap
)
5044 struct wpabuf
*conf
, *conf2
= NULL
;
5045 size_t clear_len
, attr_len
;
5046 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
5050 enum dpp_status_error status
;
5052 conf
= dpp_build_conf_obj(auth
, ap
, 0);
5054 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5055 wpabuf_head(conf
), wpabuf_len(conf
));
5056 conf2
= dpp_build_conf_obj(auth
, ap
, 1);
5058 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
5059 auth
->conf_resp_status
= status
;
5061 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
5062 clear_len
= 4 + e_nonce_len
;
5064 clear_len
+= 4 + wpabuf_len(conf
);
5066 clear_len
+= 4 + wpabuf_len(conf2
);
5067 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&& !ap
)
5069 clear
= wpabuf_alloc(clear_len
);
5070 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
5071 #ifdef CONFIG_TESTING_OPTIONS
5072 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
5074 #endif /* CONFIG_TESTING_OPTIONS */
5075 msg
= wpabuf_alloc(attr_len
);
5079 #ifdef CONFIG_TESTING_OPTIONS
5080 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
5081 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
5084 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
5085 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
5086 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5087 wpabuf_put_le16(clear
, e_nonce_len
);
5088 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
5089 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
5092 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
5093 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
5094 goto skip_wrapped_data
;
5096 #endif /* CONFIG_TESTING_OPTIONS */
5099 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5100 wpabuf_put_le16(clear
, e_nonce_len
);
5101 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
5103 #ifdef CONFIG_TESTING_OPTIONS
5105 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
5106 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
5107 goto skip_config_obj
;
5109 #endif /* CONFIG_TESTING_OPTIONS */
5112 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5113 wpabuf_put_le16(clear
, wpabuf_len(conf
));
5114 wpabuf_put_buf(clear
, conf
);
5116 if (auth
->peer_version
>= 2 && conf2
) {
5117 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5118 wpabuf_put_le16(clear
, wpabuf_len(conf2
));
5119 wpabuf_put_buf(clear
, conf2
);
5121 wpa_printf(MSG_DEBUG
,
5122 "DPP: Second Config Object available, but peer does not support more than one");
5125 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&& !ap
) {
5126 wpa_printf(MSG_DEBUG
, "DPP: sendConnStatus");
5127 wpabuf_put_le16(clear
, DPP_ATTR_SEND_CONN_STATUS
);
5128 wpabuf_put_le16(clear
, 0);
5131 #ifdef CONFIG_TESTING_OPTIONS
5133 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
5134 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
5137 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
5138 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5141 #endif /* CONFIG_TESTING_OPTIONS */
5144 dpp_build_attr_status(msg
, status
);
5146 #ifdef CONFIG_TESTING_OPTIONS
5148 #endif /* CONFIG_TESTING_OPTIONS */
5150 addr
[0] = wpabuf_head(msg
);
5151 len
[0] = wpabuf_len(msg
);
5152 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5154 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5155 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5156 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5158 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5159 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5160 wpabuf_head(clear
), wpabuf_len(clear
),
5161 1, addr
, len
, wrapped
) < 0)
5163 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5164 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5166 #ifdef CONFIG_TESTING_OPTIONS
5167 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
5168 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
5169 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
5172 #endif /* CONFIG_TESTING_OPTIONS */
5174 wpa_hexdump_buf(MSG_DEBUG
,
5175 "DPP: Configuration Response attributes", msg
);
5190 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
5193 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
5194 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
5195 u8
*unwrapped
= NULL
;
5196 size_t unwrapped_len
= 0;
5197 struct wpabuf
*resp
= NULL
;
5198 struct json_token
*root
= NULL
, *token
;
5201 #ifdef CONFIG_TESTING_OPTIONS
5202 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
5203 wpa_printf(MSG_INFO
,
5204 "DPP: TESTING - stop at Config Request");
5207 #endif /* CONFIG_TESTING_OPTIONS */
5209 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
5210 dpp_auth_fail(auth
, "Invalid attribute in config request");
5214 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5216 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5218 "Missing or invalid required Wrapped Data attribute");
5222 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5223 wrapped_data
, wrapped_data_len
);
5224 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5225 unwrapped
= os_malloc(unwrapped_len
);
5228 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5229 wrapped_data
, wrapped_data_len
,
5230 0, NULL
, NULL
, unwrapped
) < 0) {
5231 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5234 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5235 unwrapped
, unwrapped_len
);
5237 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5238 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5242 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5243 DPP_ATTR_ENROLLEE_NONCE
,
5245 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5247 "Missing or invalid Enrollee Nonce attribute");
5250 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5251 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5253 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5254 DPP_ATTR_CONFIG_ATTR_OBJ
,
5258 "Missing or invalid Config Attributes attribute");
5261 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5262 config_attr
, config_attr_len
);
5264 root
= json_parse((const char *) config_attr
, config_attr_len
);
5266 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5270 token
= json_get_member(root
, "name");
5271 if (!token
|| token
->type
!= JSON_STRING
) {
5272 dpp_auth_fail(auth
, "No Config Attributes - name");
5275 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5277 token
= json_get_member(root
, "wi-fi_tech");
5278 if (!token
|| token
->type
!= JSON_STRING
) {
5279 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5282 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5283 if (os_strcmp(token
->string
, "infra") != 0) {
5284 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5286 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5290 token
= json_get_member(root
, "netRole");
5291 if (!token
|| token
->type
!= JSON_STRING
) {
5292 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5295 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5296 if (os_strcmp(token
->string
, "sta") == 0) {
5298 } else if (os_strcmp(token
->string
, "ap") == 0) {
5301 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5303 dpp_auth_fail(auth
, "Unsupported netRole");
5307 token
= json_get_member(root
, "mudurl");
5308 if (token
&& token
->type
== JSON_STRING
)
5309 wpa_printf(MSG_DEBUG
, "DPP: mudurl = '%s'", token
->string
);
5311 token
= json_get_member(root
, "bandSupport");
5312 if (token
&& token
->type
== JSON_ARRAY
) {
5313 wpa_printf(MSG_DEBUG
, "DPP: bandSupport");
5314 token
= token
->child
;
5316 if (token
->type
!= JSON_NUMBER
)
5317 wpa_printf(MSG_DEBUG
,
5318 "DPP: Invalid bandSupport array member type");
5320 wpa_printf(MSG_DEBUG
,
5321 "DPP: Supported global operating class: %d",
5323 token
= token
->sibling
;
5327 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, ap
);
5336 static struct wpabuf
*
5337 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
5338 const u8
*prot_hdr
, u16 prot_hdr_len
,
5339 const EVP_MD
**ret_md
)
5341 struct json_token
*root
, *token
;
5342 struct wpabuf
*kid
= NULL
;
5344 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
5346 wpa_printf(MSG_DEBUG
,
5347 "DPP: JSON parsing failed for JWS Protected Header");
5351 if (root
->type
!= JSON_OBJECT
) {
5352 wpa_printf(MSG_DEBUG
,
5353 "DPP: JWS Protected Header root is not an object");
5357 token
= json_get_member(root
, "typ");
5358 if (!token
|| token
->type
!= JSON_STRING
) {
5359 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
5362 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
5364 if (os_strcmp(token
->string
, "dppCon") != 0) {
5365 wpa_printf(MSG_DEBUG
,
5366 "DPP: Unsupported JWS Protected Header typ=%s",
5371 token
= json_get_member(root
, "alg");
5372 if (!token
|| token
->type
!= JSON_STRING
) {
5373 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
5376 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
5378 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5379 wpa_printf(MSG_DEBUG
,
5380 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5381 token
->string
, curve
->jws_alg
);
5384 if (os_strcmp(token
->string
, "ES256") == 0 ||
5385 os_strcmp(token
->string
, "BS256") == 0)
5386 *ret_md
= EVP_sha256();
5387 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5388 os_strcmp(token
->string
, "BS384") == 0)
5389 *ret_md
= EVP_sha384();
5390 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5391 os_strcmp(token
->string
, "BS512") == 0)
5392 *ret_md
= EVP_sha512();
5396 wpa_printf(MSG_DEBUG
,
5397 "DPP: Unsupported JWS Protected Header alg=%s",
5402 kid
= json_get_member_base64url(root
, "kid");
5404 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5407 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5416 static int dpp_parse_cred_legacy(struct dpp_config_obj
*conf
,
5417 struct json_token
*cred
)
5419 struct json_token
*pass
, *psk_hex
;
5421 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5423 pass
= json_get_member(cred
, "pass");
5424 psk_hex
= json_get_member(cred
, "psk_hex");
5426 if (pass
&& pass
->type
== JSON_STRING
) {
5427 size_t len
= os_strlen(pass
->string
);
5429 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5431 if (len
< 8 || len
> 63)
5433 os_strlcpy(conf
->passphrase
, pass
->string
,
5434 sizeof(conf
->passphrase
));
5435 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5436 if (dpp_akm_sae(conf
->akm
) && !dpp_akm_psk(conf
->akm
)) {
5437 wpa_printf(MSG_DEBUG
,
5438 "DPP: Unexpected psk_hex with akm=sae");
5441 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5442 hexstr2bin(psk_hex
->string
, conf
->psk
, PMK_LEN
) < 0) {
5443 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5446 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5447 conf
->psk
, PMK_LEN
);
5450 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5454 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
[0]) {
5455 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5463 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5464 const struct dpp_curve_params
**key_curve
)
5466 struct json_token
*token
;
5467 const struct dpp_curve_params
*curve
;
5468 struct wpabuf
*x
= NULL
, *y
= NULL
;
5470 EVP_PKEY
*pkey
= NULL
;
5472 token
= json_get_member(jwk
, "kty");
5473 if (!token
|| token
->type
!= JSON_STRING
) {
5474 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5477 if (os_strcmp(token
->string
, "EC") != 0) {
5478 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5483 token
= json_get_member(jwk
, "crv");
5484 if (!token
|| token
->type
!= JSON_STRING
) {
5485 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5488 curve
= dpp_get_curve_jwk_crv(token
->string
);
5490 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5495 x
= json_get_member_base64url(jwk
, "x");
5497 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5500 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5501 if (wpabuf_len(x
) != curve
->prime_len
) {
5502 wpa_printf(MSG_DEBUG
,
5503 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5504 (unsigned int) wpabuf_len(x
),
5505 (unsigned int) curve
->prime_len
, curve
->name
);
5509 y
= json_get_member_base64url(jwk
, "y");
5511 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5514 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5515 if (wpabuf_len(y
) != curve
->prime_len
) {
5516 wpa_printf(MSG_DEBUG
,
5517 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5518 (unsigned int) wpabuf_len(y
),
5519 (unsigned int) curve
->prime_len
, curve
->name
);
5523 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5525 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5529 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5531 EC_GROUP_free(group
);
5542 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5545 unsigned int year
, month
, day
, hour
, min
, sec
;
5549 /* ISO 8601 date and time:
5551 * YYYY-MM-DDTHH:MM:SSZ
5552 * YYYY-MM-DDTHH:MM:SS+03:00
5554 if (os_strlen(timestamp
) < 19) {
5555 wpa_printf(MSG_DEBUG
,
5556 "DPP: Too short timestamp - assume expired key");
5559 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5560 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5561 wpa_printf(MSG_DEBUG
,
5562 "DPP: Failed to parse expiration day - assume expired key");
5566 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5567 wpa_printf(MSG_DEBUG
,
5568 "DPP: Invalid date/time information - assume expired key");
5572 pos
= timestamp
+ 19;
5573 if (*pos
== 'Z' || *pos
== '\0') {
5574 /* In UTC - no need to adjust */
5575 } else if (*pos
== '-' || *pos
== '+') {
5578 /* Adjust local time to UTC */
5579 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5581 wpa_printf(MSG_DEBUG
,
5582 "DPP: Invalid time zone designator (%s) - assume expired key",
5587 utime
+= 3600 * hour
;
5589 utime
-= 3600 * hour
;
5597 wpa_printf(MSG_DEBUG
,
5598 "DPP: Invalid time zone designator (%s) - assume expired key",
5605 if (os_get_time(&now
) < 0) {
5606 wpa_printf(MSG_DEBUG
,
5607 "DPP: Cannot get current time - assume expired key");
5611 if (now
.sec
> utime
) {
5612 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5621 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5622 struct dpp_config_obj
*conf
,
5623 const unsigned char *payload
,
5626 struct json_token
*root
, *groups
, *netkey
, *token
;
5628 EVP_PKEY
*key
= NULL
;
5629 const struct dpp_curve_params
*curve
;
5630 unsigned int rules
= 0;
5632 root
= json_parse((const char *) payload
, payload_len
);
5634 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5638 groups
= json_get_member(root
, "groups");
5639 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5640 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5643 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5644 struct json_token
*id
, *role
;
5646 id
= json_get_member(token
, "groupId");
5647 if (!id
|| id
->type
!= JSON_STRING
) {
5648 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5652 role
= json_get_member(token
, "netRole");
5653 if (!role
|| role
->type
!= JSON_STRING
) {
5654 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5657 wpa_printf(MSG_DEBUG
,
5658 "DPP: connector group: groupId='%s' netRole='%s'",
5659 id
->string
, role
->string
);
5665 wpa_printf(MSG_DEBUG
,
5666 "DPP: Connector includes no groups");
5670 token
= json_get_member(root
, "expiry");
5671 if (!token
|| token
->type
!= JSON_STRING
) {
5672 wpa_printf(MSG_DEBUG
,
5673 "DPP: No expiry string found - connector does not expire");
5675 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5676 if (dpp_key_expired(token
->string
,
5677 &auth
->net_access_key_expiry
)) {
5678 wpa_printf(MSG_DEBUG
,
5679 "DPP: Connector (netAccessKey) has expired");
5684 netkey
= json_get_member(root
, "netAccessKey");
5685 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5686 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5690 key
= dpp_parse_jwk(netkey
, &curve
);
5693 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5695 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5696 wpa_printf(MSG_DEBUG
,
5697 "DPP: netAccessKey in connector does not match own protocol key");
5698 #ifdef CONFIG_TESTING_OPTIONS
5699 if (auth
->ignore_netaccesskey_mismatch
) {
5700 wpa_printf(MSG_DEBUG
,
5701 "DPP: TESTING - skip netAccessKey mismatch");
5705 #else /* CONFIG_TESTING_OPTIONS */
5707 #endif /* CONFIG_TESTING_OPTIONS */
5718 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5720 struct wpabuf
*uncomp
;
5722 u8 hash
[SHA256_MAC_LEN
];
5726 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5728 uncomp
= dpp_get_pubkey_point(pub
, 1);
5731 addr
[0] = wpabuf_head(uncomp
);
5732 len
[0] = wpabuf_len(uncomp
);
5733 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5735 res
= sha256_vector(1, addr
, len
, hash
);
5736 wpabuf_free(uncomp
);
5739 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5740 wpa_printf(MSG_DEBUG
,
5741 "DPP: Received hash value does not match calculated public key hash value");
5742 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5743 hash
, SHA256_MAC_LEN
);
5750 static void dpp_copy_csign(struct dpp_config_obj
*conf
, EVP_PKEY
*csign
)
5752 unsigned char *der
= NULL
;
5755 der_len
= i2d_PUBKEY(csign
, &der
);
5758 wpabuf_free(conf
->c_sign_key
);
5759 conf
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5764 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
,
5765 struct dpp_config_obj
*conf
)
5767 unsigned char *der
= NULL
;
5771 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5775 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5780 wpabuf_free(auth
->net_access_key
);
5781 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5787 struct dpp_signed_connector_info
{
5788 unsigned char *payload
;
5792 static enum dpp_status_error
5793 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5794 EVP_PKEY
*csign_pub
, const char *connector
)
5796 enum dpp_status_error ret
= 255;
5797 const char *pos
, *end
, *signed_start
, *signed_end
;
5798 struct wpabuf
*kid
= NULL
;
5799 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5800 size_t prot_hdr_len
= 0, signature_len
= 0;
5801 const EVP_MD
*sign_md
= NULL
;
5802 unsigned char *der
= NULL
;
5805 EVP_MD_CTX
*md_ctx
= NULL
;
5806 ECDSA_SIG
*sig
= NULL
;
5807 BIGNUM
*r
= NULL
, *s
= NULL
;
5808 const struct dpp_curve_params
*curve
;
5810 const EC_GROUP
*group
;
5813 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5816 group
= EC_KEY_get0_group(eckey
);
5819 nid
= EC_GROUP_get_curve_name(group
);
5820 curve
= dpp_get_curve_nid(nid
);
5823 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5824 os_memset(info
, 0, sizeof(*info
));
5826 signed_start
= pos
= connector
;
5827 end
= os_strchr(pos
, '.');
5829 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5830 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5833 prot_hdr
= base64_url_decode(pos
, end
- pos
, &prot_hdr_len
);
5835 wpa_printf(MSG_DEBUG
,
5836 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5837 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5840 wpa_hexdump_ascii(MSG_DEBUG
,
5841 "DPP: signedConnector - JWS Protected Header",
5842 prot_hdr
, prot_hdr_len
);
5843 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5845 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5848 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5849 wpa_printf(MSG_DEBUG
,
5850 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5851 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5852 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5857 end
= os_strchr(pos
, '.');
5859 wpa_printf(MSG_DEBUG
,
5860 "DPP: Missing dot(2) in signedConnector");
5861 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5864 signed_end
= end
- 1;
5865 info
->payload
= base64_url_decode(pos
, end
- pos
, &info
->payload_len
);
5866 if (!info
->payload
) {
5867 wpa_printf(MSG_DEBUG
,
5868 "DPP: Failed to base64url decode signedConnector JWS Payload");
5869 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5872 wpa_hexdump_ascii(MSG_DEBUG
,
5873 "DPP: signedConnector - JWS Payload",
5874 info
->payload
, info
->payload_len
);
5876 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
5878 wpa_printf(MSG_DEBUG
,
5879 "DPP: Failed to base64url decode signedConnector signature");
5880 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5883 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
5884 signature
, signature_len
);
5886 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
5887 ret
= DPP_STATUS_NO_MATCH
;
5891 if (signature_len
& 0x01) {
5892 wpa_printf(MSG_DEBUG
,
5893 "DPP: Unexpected signedConnector signature length (%d)",
5894 (int) signature_len
);
5895 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5899 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
5900 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
5901 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
5902 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
5903 sig
= ECDSA_SIG_new();
5904 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
5909 der_len
= i2d_ECDSA_SIG(sig
, &der
);
5911 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
5914 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
5915 md_ctx
= EVP_MD_CTX_create();
5920 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
5921 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
5922 ERR_error_string(ERR_get_error(), NULL
));
5925 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
5926 signed_end
- signed_start
+ 1) != 1) {
5927 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
5928 ERR_error_string(ERR_get_error(), NULL
));
5931 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
5933 wpa_printf(MSG_DEBUG
,
5934 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
5935 res
, ERR_error_string(ERR_get_error(), NULL
));
5936 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5940 ret
= DPP_STATUS_OK
;
5943 EVP_MD_CTX_destroy(md_ctx
);
5947 ECDSA_SIG_free(sig
);
5955 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
5956 struct dpp_config_obj
*conf
,
5957 struct json_token
*cred
)
5959 struct dpp_signed_connector_info info
;
5960 struct json_token
*token
, *csign
;
5962 EVP_PKEY
*csign_pub
= NULL
;
5963 const struct dpp_curve_params
*key_curve
= NULL
;
5964 const char *signed_connector
;
5966 os_memset(&info
, 0, sizeof(info
));
5968 if (dpp_akm_psk(conf
->akm
) || dpp_akm_sae(conf
->akm
)) {
5969 wpa_printf(MSG_DEBUG
,
5970 "DPP: Legacy credential included in Connector credential");
5971 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
5975 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
5977 csign
= json_get_member(cred
, "csign");
5978 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
5979 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
5983 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
5985 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
5988 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
5990 token
= json_get_member(cred
, "signedConnector");
5991 if (!token
|| token
->type
!= JSON_STRING
) {
5992 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
5995 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
5996 token
->string
, os_strlen(token
->string
));
5997 signed_connector
= token
->string
;
5999 if (os_strchr(signed_connector
, '"') ||
6000 os_strchr(signed_connector
, '\n')) {
6001 wpa_printf(MSG_DEBUG
,
6002 "DPP: Unexpected character in signedConnector");
6006 if (dpp_process_signed_connector(&info
, csign_pub
,
6007 signed_connector
) != DPP_STATUS_OK
)
6010 if (dpp_parse_connector(auth
, conf
,
6011 info
.payload
, info
.payload_len
) < 0) {
6012 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
6016 os_free(conf
->connector
);
6017 conf
->connector
= os_strdup(signed_connector
);
6019 dpp_copy_csign(conf
, csign_pub
);
6020 dpp_copy_netaccesskey(auth
, conf
);
6024 EVP_PKEY_free(csign_pub
);
6025 os_free(info
.payload
);
6030 const char * dpp_akm_str(enum dpp_akm akm
)
6039 case DPP_AKM_PSK_SAE
:
6041 case DPP_AKM_SAE_DPP
:
6043 case DPP_AKM_PSK_SAE_DPP
:
6044 return "dpp+psk+sae";
6051 const char * dpp_akm_selector_str(enum dpp_akm akm
)
6057 return "000FAC02+000FAC06";
6060 case DPP_AKM_PSK_SAE
:
6061 return "000FAC02+000FAC06+000FAC08";
6062 case DPP_AKM_SAE_DPP
:
6063 return "506F9A02+000FAC08";
6064 case DPP_AKM_PSK_SAE_DPP
:
6065 return "506F9A02+000FAC08+000FAC02+000FAC06";
6072 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
6075 int dpp
= 0, psk
= 0, sae
= 0;
6077 if (os_strcmp(akm
, "psk") == 0)
6079 if (os_strcmp(akm
, "sae") == 0)
6081 if (os_strcmp(akm
, "psk+sae") == 0)
6082 return DPP_AKM_PSK_SAE
;
6083 if (os_strcmp(akm
, "dpp") == 0)
6085 if (os_strcmp(akm
, "dpp+sae") == 0)
6086 return DPP_AKM_SAE_DPP
;
6087 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
6088 return DPP_AKM_PSK_SAE_DPP
;
6092 if (os_strlen(pos
) < 8)
6094 if (os_strncasecmp(pos
, "506F9A02", 8) == 0)
6096 else if (os_strncasecmp(pos
, "000FAC02", 8) == 0)
6098 else if (os_strncasecmp(pos
, "000FAC06", 8) == 0)
6100 else if (os_strncasecmp(pos
, "000FAC08", 8) == 0)
6108 if (dpp
&& psk
&& sae
)
6109 return DPP_AKM_PSK_SAE_DPP
;
6111 return DPP_AKM_SAE_DPP
;
6115 return DPP_AKM_PSK_SAE
;
6121 return DPP_AKM_UNKNOWN
;
6125 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
6126 const u8
*conf_obj
, u16 conf_obj_len
)
6129 struct json_token
*root
, *token
, *discovery
, *cred
;
6130 struct dpp_config_obj
*conf
;
6132 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
6135 if (root
->type
!= JSON_OBJECT
) {
6136 dpp_auth_fail(auth
, "JSON root is not an object");
6140 token
= json_get_member(root
, "wi-fi_tech");
6141 if (!token
|| token
->type
!= JSON_STRING
) {
6142 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
6145 if (os_strcmp(token
->string
, "infra") != 0) {
6146 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
6148 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
6152 discovery
= json_get_member(root
, "discovery");
6153 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
6154 dpp_auth_fail(auth
, "No discovery object in JSON");
6158 token
= json_get_member(discovery
, "ssid");
6159 if (!token
|| token
->type
!= JSON_STRING
) {
6160 dpp_auth_fail(auth
, "No discovery::ssid string value found");
6163 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
6164 token
->string
, os_strlen(token
->string
));
6165 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
6166 dpp_auth_fail(auth
, "Too long discovery::ssid string value");
6170 if (auth
->num_conf_obj
== DPP_MAX_CONF_OBJ
) {
6171 wpa_printf(MSG_DEBUG
,
6172 "DPP: No room for this many Config Objects - ignore this one");
6176 conf
= &auth
->conf_obj
[auth
->num_conf_obj
++];
6178 conf
->ssid_len
= os_strlen(token
->string
);
6179 os_memcpy(conf
->ssid
, token
->string
, conf
->ssid_len
);
6181 cred
= json_get_member(root
, "cred");
6182 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
6183 dpp_auth_fail(auth
, "No cred object in JSON");
6187 token
= json_get_member(cred
, "akm");
6188 if (!token
|| token
->type
!= JSON_STRING
) {
6189 dpp_auth_fail(auth
, "No cred::akm string value found");
6192 conf
->akm
= dpp_akm_from_str(token
->string
);
6194 if (dpp_akm_legacy(conf
->akm
)) {
6195 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6197 } else if (dpp_akm_dpp(conf
->akm
)) {
6198 if (dpp_parse_cred_dpp(auth
, conf
, cred
) < 0)
6201 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
6203 dpp_auth_fail(auth
, "Unsupported akm");
6207 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
6215 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
6216 const struct wpabuf
*resp
)
6218 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
6219 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
6222 u8
*unwrapped
= NULL
;
6223 size_t unwrapped_len
= 0;
6226 auth
->conf_resp_status
= 255;
6228 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
6229 dpp_auth_fail(auth
, "Invalid attribute in config response");
6233 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
6234 DPP_ATTR_WRAPPED_DATA
,
6236 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6238 "Missing or invalid required Wrapped Data attribute");
6242 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6243 wrapped_data
, wrapped_data_len
);
6244 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6245 unwrapped
= os_malloc(unwrapped_len
);
6249 addr
[0] = wpabuf_head(resp
);
6250 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
6251 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
6253 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6254 wrapped_data
, wrapped_data_len
,
6255 1, addr
, len
, unwrapped
) < 0) {
6256 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6259 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6260 unwrapped
, unwrapped_len
);
6262 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6263 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6267 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6268 DPP_ATTR_ENROLLEE_NONCE
,
6270 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6272 "Missing or invalid Enrollee Nonce attribute");
6275 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6276 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6277 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6281 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
6282 DPP_ATTR_STATUS
, &status_len
);
6283 if (!status
|| status_len
< 1) {
6285 "Missing or invalid required DPP Status attribute");
6288 auth
->conf_resp_status
= status
[0];
6289 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
6290 if (status
[0] != DPP_STATUS_OK
) {
6291 dpp_auth_fail(auth
, "Configurator rejected configuration");
6295 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONFIG_OBJ
,
6299 "Missing required Configuration Object attribute");
6303 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
6304 conf_obj
, conf_obj_len
);
6305 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
6307 conf_obj
= dpp_get_attr_next(conf_obj
, unwrapped
, unwrapped_len
,
6308 DPP_ATTR_CONFIG_OBJ
,
6313 status
= dpp_get_attr(unwrapped
, unwrapped_len
,
6314 DPP_ATTR_SEND_CONN_STATUS
, &status_len
);
6316 wpa_printf(MSG_DEBUG
,
6317 "DPP: Configurator requested connection status result");
6318 auth
->conn_status_requested
= 1;
6320 #endif /* CONFIG_DPP2 */
6332 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
6334 const u8
*attr_start
, size_t attr_len
)
6336 const u8
*wrapped_data
, *status
, *e_nonce
;
6337 u16 wrapped_data_len
, status_len
, e_nonce_len
;
6340 u8
*unwrapped
= NULL
;
6341 size_t unwrapped_len
= 0;
6342 enum dpp_status_error ret
= 256;
6344 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
6346 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6348 "Missing or invalid required Wrapped Data attribute");
6351 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
6352 wrapped_data
, wrapped_data_len
);
6354 attr_len
= wrapped_data
- 4 - attr_start
;
6357 len
[0] = DPP_HDR_LEN
;
6358 addr
[1] = attr_start
;
6360 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6361 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6362 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6363 wrapped_data
, wrapped_data_len
);
6364 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6365 unwrapped
= os_malloc(unwrapped_len
);
6368 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6369 wrapped_data
, wrapped_data_len
,
6370 2, addr
, len
, unwrapped
) < 0) {
6371 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6374 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6375 unwrapped
, unwrapped_len
);
6377 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6378 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6382 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6383 DPP_ATTR_ENROLLEE_NONCE
,
6385 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6387 "Missing or invalid Enrollee Nonce attribute");
6390 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6391 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6392 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6393 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
6394 auth
->e_nonce
, e_nonce_len
);
6398 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
6400 if (!status
|| status_len
< 1) {
6402 "Missing or invalid required DPP Status attribute");
6405 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
6409 bin_clear_free(unwrapped
, unwrapped_len
);
6414 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
6415 enum dpp_status_error status
)
6417 struct wpabuf
*msg
, *clear
;
6418 size_t nonce_len
, clear_len
, attr_len
;
6423 nonce_len
= auth
->curve
->nonce_len
;
6424 clear_len
= 5 + 4 + nonce_len
;
6425 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6426 clear
= wpabuf_alloc(clear_len
);
6427 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
6432 dpp_build_attr_status(clear
, status
);
6435 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
6436 wpabuf_put_le16(clear
, nonce_len
);
6437 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
6439 /* OUI, OUI type, Crypto Suite, DPP frame type */
6440 addr
[0] = wpabuf_head_u8(msg
) + 2;
6441 len
[0] = 3 + 1 + 1 + 1;
6442 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6444 /* Attributes before Wrapped Data (none) */
6445 addr
[1] = wpabuf_put(msg
, 0);
6447 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6450 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6451 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6452 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6454 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6455 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
6456 wpabuf_head(clear
), wpabuf_len(clear
),
6457 2, addr
, len
, wrapped
) < 0)
6460 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
6470 static int valid_channel_list(const char *val
)
6473 if (!((*val
>= '0' && *val
<= '9') ||
6474 *val
== '/' || *val
== ','))
6483 enum dpp_status_error
dpp_conn_status_result_rx(struct dpp_authentication
*auth
,
6485 const u8
*attr_start
,
6487 u8
*ssid
, size_t *ssid_len
,
6488 char **channel_list
)
6490 const u8
*wrapped_data
, *status
, *e_nonce
;
6491 u16 wrapped_data_len
, status_len
, e_nonce_len
;
6494 u8
*unwrapped
= NULL
;
6495 size_t unwrapped_len
= 0;
6496 enum dpp_status_error ret
= 256;
6497 struct json_token
*root
= NULL
, *token
;
6498 struct wpabuf
*ssid64
;
6501 *channel_list
= NULL
;
6503 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
6505 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
6507 "Missing or invalid required Wrapped Data attribute");
6510 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
6511 wrapped_data
, wrapped_data_len
);
6513 attr_len
= wrapped_data
- 4 - attr_start
;
6516 len
[0] = DPP_HDR_LEN
;
6517 addr
[1] = attr_start
;
6519 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6520 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6521 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
6522 wrapped_data
, wrapped_data_len
);
6523 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
6524 unwrapped
= os_malloc(unwrapped_len
);
6527 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
6528 wrapped_data
, wrapped_data_len
,
6529 2, addr
, len
, unwrapped
) < 0) {
6530 dpp_auth_fail(auth
, "AES-SIV decryption failed");
6533 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
6534 unwrapped
, unwrapped_len
);
6536 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
6537 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
6541 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
6542 DPP_ATTR_ENROLLEE_NONCE
,
6544 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
6546 "Missing or invalid Enrollee Nonce attribute");
6549 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
6550 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
6551 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
6552 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
6553 auth
->e_nonce
, e_nonce_len
);
6557 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONN_STATUS
,
6561 "Missing required DPP Connection Status attribute");
6564 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
6565 status
, status_len
);
6567 root
= json_parse((const char *) status
, status_len
);
6569 dpp_auth_fail(auth
, "Could not parse connStatus");
6573 ssid64
= json_get_member_base64url(root
, "ssid64");
6574 if (ssid64
&& wpabuf_len(ssid64
) <= SSID_MAX_LEN
) {
6575 *ssid_len
= wpabuf_len(ssid64
);
6576 os_memcpy(ssid
, wpabuf_head(ssid64
), *ssid_len
);
6578 wpabuf_free(ssid64
);
6580 token
= json_get_member(root
, "channelList");
6581 if (token
&& token
->type
== JSON_STRING
&&
6582 valid_channel_list(token
->string
))
6583 *channel_list
= os_strdup(token
->string
);
6585 token
= json_get_member(root
, "result");
6586 if (!token
|| token
->type
!= JSON_NUMBER
) {
6587 dpp_auth_fail(auth
, "No connStatus - result");
6590 wpa_printf(MSG_DEBUG
, "DPP: result %d", token
->number
);
6591 ret
= token
->number
;
6595 bin_clear_free(unwrapped
, unwrapped_len
);
6600 struct wpabuf
* dpp_build_conn_status_result(struct dpp_authentication
*auth
,
6601 enum dpp_status_error result
,
6602 const u8
*ssid
, size_t ssid_len
,
6603 const char *channel_list
)
6605 struct wpabuf
*msg
= NULL
, *clear
= NULL
, *json
;
6606 size_t nonce_len
, clear_len
, attr_len
;
6611 json
= wpabuf_alloc(1000);
6614 json_start_object(json
, NULL
);
6615 json_add_int(json
, "result", result
);
6617 json_value_sep(json
);
6618 if (json_add_base64url(json
, "ssid64", ssid
, ssid_len
) < 0)
6622 json_value_sep(json
);
6623 json_add_string(json
, "channelList", channel_list
);
6625 json_end_object(json
);
6626 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
6627 wpabuf_head(json
), wpabuf_len(json
));
6629 nonce_len
= auth
->curve
->nonce_len
;
6630 clear_len
= 5 + 4 + nonce_len
+ 4 + wpabuf_len(json
);
6631 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
6632 clear
= wpabuf_alloc(clear_len
);
6633 msg
= dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT
, attr_len
);
6638 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
6639 wpabuf_put_le16(clear
, nonce_len
);
6640 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
6642 /* DPP Connection Status */
6643 wpabuf_put_le16(clear
, DPP_ATTR_CONN_STATUS
);
6644 wpabuf_put_le16(clear
, wpabuf_len(json
));
6645 wpabuf_put_buf(clear
, json
);
6647 /* OUI, OUI type, Crypto Suite, DPP frame type */
6648 addr
[0] = wpabuf_head_u8(msg
) + 2;
6649 len
[0] = 3 + 1 + 1 + 1;
6650 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
6652 /* Attributes before Wrapped Data (none) */
6653 addr
[1] = wpabuf_put(msg
, 0);
6655 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
6658 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
6659 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6660 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
6662 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
6663 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
6664 wpabuf_head(clear
), wpabuf_len(clear
),
6665 2, addr
, len
, wrapped
) < 0)
6668 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Connection Status Result attributes",
6680 #endif /* CONFIG_DPP2 */
6683 void dpp_configurator_free(struct dpp_configurator
*conf
)
6687 EVP_PKEY_free(conf
->csign
);
6693 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
6697 int key_len
, ret
= -1;
6698 unsigned char *key
= NULL
;
6703 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
6707 key_len
= i2d_ECPrivateKey(eckey
, &key
);
6709 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
6717 struct dpp_configurator
*
6718 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
6721 struct dpp_configurator
*conf
;
6722 struct wpabuf
*csign_pub
= NULL
;
6723 u8 kid_hash
[SHA256_MAC_LEN
];
6727 conf
= os_zalloc(sizeof(*conf
));
6732 conf
->curve
= &dpp_curves
[0];
6734 conf
->curve
= dpp_get_curve_name(curve
);
6736 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6743 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
6746 conf
->csign
= dpp_gen_keypair(conf
->curve
);
6751 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
6753 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
6757 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
6758 addr
[0] = wpabuf_head(csign_pub
);
6759 len
[0] = wpabuf_len(csign_pub
);
6760 if (sha256_vector(1, addr
, len
, kid_hash
) < 0) {
6761 wpa_printf(MSG_DEBUG
,
6762 "DPP: Failed to derive kid for C-sign-key");
6766 conf
->kid
= base64_url_encode(kid_hash
, sizeof(kid_hash
), NULL
);
6770 wpabuf_free(csign_pub
);
6773 dpp_configurator_free(conf
);
6779 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
6780 const char *curve
, int ap
)
6782 struct wpabuf
*conf_obj
;
6786 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
6791 auth
->curve
= &dpp_curves
[0];
6793 auth
->curve
= dpp_get_curve_name(curve
);
6795 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
6800 wpa_printf(MSG_DEBUG
,
6801 "DPP: Building own configuration/connector with curve %s",
6804 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
6805 if (!auth
->own_protocol_key
)
6807 dpp_copy_netaccesskey(auth
, &auth
->conf_obj
[0]);
6808 auth
->peer_protocol_key
= auth
->own_protocol_key
;
6809 dpp_copy_csign(&auth
->conf_obj
[0], auth
->conf
->csign
);
6811 conf_obj
= dpp_build_conf_obj(auth
, ap
, 0);
6814 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
6815 wpabuf_len(conf_obj
));
6817 wpabuf_free(conf_obj
);
6818 auth
->peer_protocol_key
= NULL
;
6823 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
6825 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
6826 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
6830 static int dpp_connector_compatible_group(struct json_token
*root
,
6831 const char *group_id
,
6832 const char *net_role
)
6834 struct json_token
*groups
, *token
;
6836 groups
= json_get_member(root
, "groups");
6837 if (!groups
|| groups
->type
!= JSON_ARRAY
)
6840 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6841 struct json_token
*id
, *role
;
6843 id
= json_get_member(token
, "groupId");
6844 if (!id
|| id
->type
!= JSON_STRING
)
6847 role
= json_get_member(token
, "netRole");
6848 if (!role
|| role
->type
!= JSON_STRING
)
6851 if (os_strcmp(id
->string
, "*") != 0 &&
6852 os_strcmp(group_id
, "*") != 0 &&
6853 os_strcmp(id
->string
, group_id
) != 0)
6856 if (dpp_compatible_netrole(role
->string
, net_role
))
6864 static int dpp_connector_match_groups(struct json_token
*own_root
,
6865 struct json_token
*peer_root
)
6867 struct json_token
*groups
, *token
;
6869 groups
= json_get_member(peer_root
, "groups");
6870 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6871 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
6875 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6876 struct json_token
*id
, *role
;
6878 id
= json_get_member(token
, "groupId");
6879 if (!id
|| id
->type
!= JSON_STRING
) {
6880 wpa_printf(MSG_DEBUG
,
6881 "DPP: Missing peer groupId string");
6885 role
= json_get_member(token
, "netRole");
6886 if (!role
|| role
->type
!= JSON_STRING
) {
6887 wpa_printf(MSG_DEBUG
,
6888 "DPP: Missing peer groups::netRole string");
6891 wpa_printf(MSG_DEBUG
,
6892 "DPP: peer connector group: groupId='%s' netRole='%s'",
6893 id
->string
, role
->string
);
6894 if (dpp_connector_compatible_group(own_root
, id
->string
,
6896 wpa_printf(MSG_DEBUG
,
6897 "DPP: Compatible group/netRole in own connector");
6906 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
6907 unsigned int hash_len
)
6909 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
6910 const char *info
= "DPP PMK";
6913 /* PMK = HKDF(<>, "DPP PMK", N.x) */
6915 /* HKDF-Extract(<>, N.x) */
6916 os_memset(salt
, 0, hash_len
);
6917 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
6919 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
6922 /* HKDF-Expand(PRK, info, L) */
6923 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
6924 os_memset(prk
, 0, hash_len
);
6928 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
6934 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
6935 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
6937 struct wpabuf
*nkx
, *pkx
;
6941 u8 hash
[SHA256_MAC_LEN
];
6943 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
6944 nkx
= dpp_get_pubkey_point(own_key
, 0);
6945 pkx
= dpp_get_pubkey_point(peer_key
, 0);
6948 addr
[0] = wpabuf_head(nkx
);
6949 len
[0] = wpabuf_len(nkx
) / 2;
6950 addr
[1] = wpabuf_head(pkx
);
6951 len
[1] = wpabuf_len(pkx
) / 2;
6952 if (len
[0] != len
[1])
6954 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
6955 addr
[0] = wpabuf_head(pkx
);
6956 addr
[1] = wpabuf_head(nkx
);
6958 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
6959 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
6960 res
= sha256_vector(2, addr
, len
, hash
);
6963 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
6964 os_memcpy(pmkid
, hash
, PMKID_LEN
);
6965 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
6974 enum dpp_status_error
6975 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
6976 const u8
*net_access_key
, size_t net_access_key_len
,
6977 const u8
*csign_key
, size_t csign_key_len
,
6978 const u8
*peer_connector
, size_t peer_connector_len
,
6981 struct json_token
*root
= NULL
, *netkey
, *token
;
6982 struct json_token
*own_root
= NULL
;
6983 enum dpp_status_error ret
= 255, res
;
6984 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
6985 struct wpabuf
*own_key_pub
= NULL
;
6986 const struct dpp_curve_params
*curve
, *own_curve
;
6987 struct dpp_signed_connector_info info
;
6988 const unsigned char *p
;
6989 EVP_PKEY
*csign
= NULL
;
6990 char *signed_connector
= NULL
;
6991 const char *pos
, *end
;
6992 unsigned char *own_conn
= NULL
;
6993 size_t own_conn_len
;
6995 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
6997 os_memset(intro
, 0, sizeof(*intro
));
6998 os_memset(&info
, 0, sizeof(info
));
7003 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
7005 wpa_printf(MSG_ERROR
,
7006 "DPP: Failed to parse local C-sign-key information");
7010 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
7011 net_access_key_len
);
7013 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
7017 pos
= os_strchr(own_connector
, '.');
7019 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
7023 end
= os_strchr(pos
, '.');
7025 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
7028 own_conn
= base64_url_decode(pos
, end
- pos
, &own_conn_len
);
7030 wpa_printf(MSG_DEBUG
,
7031 "DPP: Failed to base64url decode own signedConnector JWS Payload");
7035 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
7037 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
7041 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
7042 peer_connector
, peer_connector_len
);
7043 signed_connector
= os_malloc(peer_connector_len
+ 1);
7044 if (!signed_connector
)
7046 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
7047 signed_connector
[peer_connector_len
] = '\0';
7049 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
7050 if (res
!= DPP_STATUS_OK
) {
7055 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
7057 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
7058 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7062 if (!dpp_connector_match_groups(own_root
, root
)) {
7063 wpa_printf(MSG_DEBUG
,
7064 "DPP: Peer connector does not include compatible group netrole with own connector");
7065 ret
= DPP_STATUS_NO_MATCH
;
7069 token
= json_get_member(root
, "expiry");
7070 if (!token
|| token
->type
!= JSON_STRING
) {
7071 wpa_printf(MSG_DEBUG
,
7072 "DPP: No expiry string found - connector does not expire");
7074 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
7075 if (dpp_key_expired(token
->string
, expiry
)) {
7076 wpa_printf(MSG_DEBUG
,
7077 "DPP: Connector (netAccessKey) has expired");
7078 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7083 netkey
= json_get_member(root
, "netAccessKey");
7084 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
7085 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
7086 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7090 peer_key
= dpp_parse_jwk(netkey
, &curve
);
7092 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7095 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
7097 if (own_curve
!= curve
) {
7098 wpa_printf(MSG_DEBUG
,
7099 "DPP: Mismatching netAccessKey curves (%s != %s)",
7100 own_curve
->name
, curve
->name
);
7101 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7105 /* ECDH: N = nk * PK */
7106 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
7109 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
7112 /* PMK = HKDF(<>, "DPP PMK", N.x) */
7113 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
7114 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
7117 intro
->pmk_len
= curve
->hash_len
;
7119 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
7120 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
7121 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
7125 ret
= DPP_STATUS_OK
;
7127 if (ret
!= DPP_STATUS_OK
)
7128 os_memset(intro
, 0, sizeof(*intro
));
7129 os_memset(Nx
, 0, sizeof(Nx
));
7131 os_free(signed_connector
);
7132 os_free(info
.payload
);
7133 EVP_PKEY_free(own_key
);
7134 wpabuf_free(own_key_pub
);
7135 EVP_PKEY_free(peer_key
);
7136 EVP_PKEY_free(csign
);
7138 json_free(own_root
);
7143 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
7147 size_t len
= curve
->prime_len
;
7151 switch (curve
->ike_group
) {
7153 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
7154 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
7157 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
7158 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
7161 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
7162 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
7165 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
7166 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
7169 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
7170 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
7173 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
7174 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
7180 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
7183 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
7184 EC_GROUP_free(group
);
7189 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
7190 const u8
*mac_init
, const char *code
,
7191 const char *identifier
, BN_CTX
*bnctx
,
7192 EC_GROUP
**ret_group
)
7194 u8 hash
[DPP_MAX_HASH_LEN
];
7197 unsigned int num_elem
= 0;
7198 EC_POINT
*Qi
= NULL
;
7199 EVP_PKEY
*Pi
= NULL
;
7200 EC_KEY
*Pi_ec
= NULL
;
7201 const EC_POINT
*Pi_point
;
7202 BIGNUM
*hash_bn
= NULL
;
7203 const EC_GROUP
*group
= NULL
;
7204 EC_GROUP
*group2
= NULL
;
7206 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7208 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
7209 addr
[num_elem
] = mac_init
;
7210 len
[num_elem
] = ETH_ALEN
;
7213 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
7215 addr
[num_elem
] = (const u8
*) identifier
;
7216 len
[num_elem
] = os_strlen(identifier
);
7219 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
7220 addr
[num_elem
] = (const u8
*) code
;
7221 len
[num_elem
] = os_strlen(code
);
7223 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
7225 wpa_hexdump_key(MSG_DEBUG
,
7226 "DPP: H(MAC-Initiator | [identifier |] code)",
7227 hash
, curve
->hash_len
);
7228 Pi
= dpp_pkex_get_role_elem(curve
, 1);
7231 dpp_debug_print_key("DPP: Pi", Pi
);
7232 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
7235 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
7237 group
= EC_KEY_get0_group(Pi_ec
);
7240 group2
= EC_GROUP_dup(group
);
7243 Qi
= EC_POINT_new(group2
);
7245 EC_GROUP_free(group2
);
7248 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
7250 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
7252 if (EC_POINT_is_at_infinity(group
, Qi
)) {
7253 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
7256 dpp_debug_print_point("DPP: Qi", group
, Qi
);
7260 BN_clear_free(hash_bn
);
7261 if (ret_group
&& Qi
)
7262 *ret_group
= group2
;
7264 EC_GROUP_free(group2
);
7273 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
7274 const u8
*mac_resp
, const char *code
,
7275 const char *identifier
, BN_CTX
*bnctx
,
7276 EC_GROUP
**ret_group
)
7278 u8 hash
[DPP_MAX_HASH_LEN
];
7281 unsigned int num_elem
= 0;
7282 EC_POINT
*Qr
= NULL
;
7283 EVP_PKEY
*Pr
= NULL
;
7284 EC_KEY
*Pr_ec
= NULL
;
7285 const EC_POINT
*Pr_point
;
7286 BIGNUM
*hash_bn
= NULL
;
7287 const EC_GROUP
*group
= NULL
;
7288 EC_GROUP
*group2
= NULL
;
7290 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7292 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
7293 addr
[num_elem
] = mac_resp
;
7294 len
[num_elem
] = ETH_ALEN
;
7297 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
7299 addr
[num_elem
] = (const u8
*) identifier
;
7300 len
[num_elem
] = os_strlen(identifier
);
7303 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
7304 addr
[num_elem
] = (const u8
*) code
;
7305 len
[num_elem
] = os_strlen(code
);
7307 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
7309 wpa_hexdump_key(MSG_DEBUG
,
7310 "DPP: H(MAC-Responder | [identifier |] code)",
7311 hash
, curve
->hash_len
);
7312 Pr
= dpp_pkex_get_role_elem(curve
, 0);
7315 dpp_debug_print_key("DPP: Pr", Pr
);
7316 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
7319 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
7321 group
= EC_KEY_get0_group(Pr_ec
);
7324 group2
= EC_GROUP_dup(group
);
7327 Qr
= EC_POINT_new(group2
);
7329 EC_GROUP_free(group2
);
7332 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
7334 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
7336 if (EC_POINT_is_at_infinity(group
, Qr
)) {
7337 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
7340 dpp_debug_print_point("DPP: Qr", group
, Qr
);
7344 BN_clear_free(hash_bn
);
7345 if (ret_group
&& Qr
)
7346 *ret_group
= group2
;
7348 EC_GROUP_free(group2
);
7357 #ifdef CONFIG_TESTING_OPTIONS
7358 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
7359 const struct dpp_curve_params
*curve
)
7367 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
7372 point
= EC_POINT_new(group
);
7375 if (!ctx
|| !point
|| !x
|| !y
)
7378 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
7381 /* Generate a random y coordinate that results in a point that is not
7384 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
7387 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
7389 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
7390 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
7391 * return an error from EC_POINT_set_affine_coordinates_GFp()
7392 * when the point is not on the curve. */
7394 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
7396 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
7399 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
7403 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
7404 curve
->prime_len
) < 0 ||
7405 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
7406 curve
->prime_len
) < 0)
7412 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
7415 EC_POINT_free(point
);
7417 EC_GROUP_free(group
);
7421 #endif /* CONFIG_TESTING_OPTIONS */
7424 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
7426 EC_KEY
*X_ec
= NULL
;
7427 const EC_POINT
*X_point
;
7428 BN_CTX
*bnctx
= NULL
;
7429 EC_GROUP
*group
= NULL
;
7430 EC_POINT
*Qi
= NULL
, *M
= NULL
;
7431 struct wpabuf
*M_buf
= NULL
;
7432 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7433 struct wpabuf
*msg
= NULL
;
7435 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7437 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
7439 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7440 bnctx
= BN_CTX_new();
7443 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
7444 pkex
->identifier
, bnctx
, &group
);
7448 /* Generate a random ephemeral keypair x/X */
7449 #ifdef CONFIG_TESTING_OPTIONS
7450 if (dpp_pkex_ephemeral_key_override_len
) {
7451 const struct dpp_curve_params
*tmp_curve
;
7453 wpa_printf(MSG_INFO
,
7454 "DPP: TESTING - override ephemeral key x/X");
7455 pkex
->x
= dpp_set_keypair(&tmp_curve
,
7456 dpp_pkex_ephemeral_key_override
,
7457 dpp_pkex_ephemeral_key_override_len
);
7459 pkex
->x
= dpp_gen_keypair(curve
);
7461 #else /* CONFIG_TESTING_OPTIONS */
7462 pkex
->x
= dpp_gen_keypair(curve
);
7463 #endif /* CONFIG_TESTING_OPTIONS */
7468 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
7471 X_point
= EC_KEY_get0_public_key(X_ec
);
7474 dpp_debug_print_point("DPP: X", group
, X_point
);
7475 M
= EC_POINT_new(group
);
7478 if (!M
|| !Mx
|| !My
||
7479 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
7480 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
7482 dpp_debug_print_point("DPP: M", group
, M
);
7484 /* Initiator -> Responder: group, [identifier,] M */
7486 if (pkex
->identifier
)
7487 attr_len
+= 4 + os_strlen(pkex
->identifier
);
7488 attr_len
+= 4 + 2 * curve
->prime_len
;
7489 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
7493 #ifdef CONFIG_TESTING_OPTIONS
7494 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
7495 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
7496 goto skip_finite_cyclic_group
;
7498 #endif /* CONFIG_TESTING_OPTIONS */
7500 /* Finite Cyclic Group attribute */
7501 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7502 wpabuf_put_le16(msg
, 2);
7503 wpabuf_put_le16(msg
, curve
->ike_group
);
7505 #ifdef CONFIG_TESTING_OPTIONS
7506 skip_finite_cyclic_group
:
7507 #endif /* CONFIG_TESTING_OPTIONS */
7509 /* Code Identifier attribute */
7510 if (pkex
->identifier
) {
7511 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
7512 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
7513 wpabuf_put_str(msg
, pkex
->identifier
);
7516 #ifdef CONFIG_TESTING_OPTIONS
7517 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
7518 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
7521 #endif /* CONFIG_TESTING_OPTIONS */
7523 /* M in Encrypted Key attribute */
7524 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
7525 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7527 #ifdef CONFIG_TESTING_OPTIONS
7528 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
7529 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7530 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7534 #endif /* CONFIG_TESTING_OPTIONS */
7536 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
7537 curve
->prime_len
) < 0 ||
7538 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
7539 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
7540 curve
->prime_len
) < 0)
7551 EC_GROUP_free(group
);
7554 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
7561 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
7563 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
7567 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
7569 const char *identifier
,
7572 struct dpp_pkex
*pkex
;
7574 #ifdef CONFIG_TESTING_OPTIONS
7575 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7576 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7577 MAC2STR(dpp_pkex_own_mac_override
));
7578 own_mac
= dpp_pkex_own_mac_override
;
7580 #endif /* CONFIG_TESTING_OPTIONS */
7582 pkex
= os_zalloc(sizeof(*pkex
));
7585 pkex
->msg_ctx
= msg_ctx
;
7586 pkex
->initiator
= 1;
7588 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7590 pkex
->identifier
= os_strdup(identifier
);
7591 if (!pkex
->identifier
)
7594 pkex
->code
= os_strdup(code
);
7597 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
7598 if (!pkex
->exchange_req
)
7602 dpp_pkex_free(pkex
);
7607 static struct wpabuf
*
7608 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
7609 enum dpp_status_error status
,
7610 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
7612 struct wpabuf
*msg
= NULL
;
7614 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
7616 /* Initiator -> Responder: DPP Status, [identifier,] N */
7618 if (pkex
->identifier
)
7619 attr_len
+= 4 + os_strlen(pkex
->identifier
);
7620 attr_len
+= 4 + 2 * curve
->prime_len
;
7621 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
7625 #ifdef CONFIG_TESTING_OPTIONS
7626 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
7627 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
7631 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
7632 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
7635 #endif /* CONFIG_TESTING_OPTIONS */
7638 dpp_build_attr_status(msg
, status
);
7640 #ifdef CONFIG_TESTING_OPTIONS
7642 #endif /* CONFIG_TESTING_OPTIONS */
7644 /* Code Identifier attribute */
7645 if (pkex
->identifier
) {
7646 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
7647 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
7648 wpabuf_put_str(msg
, pkex
->identifier
);
7651 if (status
!= DPP_STATUS_OK
)
7652 goto skip_encrypted_key
;
7654 #ifdef CONFIG_TESTING_OPTIONS
7655 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7656 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
7657 goto skip_encrypted_key
;
7659 #endif /* CONFIG_TESTING_OPTIONS */
7661 /* N in Encrypted Key attribute */
7662 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
7663 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
7665 #ifdef CONFIG_TESTING_OPTIONS
7666 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
7667 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
7668 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
7670 goto skip_encrypted_key
;
7672 #endif /* CONFIG_TESTING_OPTIONS */
7674 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
7675 curve
->prime_len
) < 0 ||
7676 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
7677 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
7678 curve
->prime_len
) < 0)
7682 if (status
== DPP_STATUS_BAD_GROUP
) {
7683 /* Finite Cyclic Group attribute */
7684 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
7685 wpabuf_put_le16(msg
, 2);
7686 wpabuf_put_le16(msg
, curve
->ike_group
);
7696 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
7697 const u8
*Mx
, size_t Mx_len
,
7698 const u8
*Nx
, size_t Nx_len
,
7700 const u8
*Kx
, size_t Kx_len
,
7701 u8
*z
, unsigned int hash_len
)
7703 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7708 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7711 /* HKDF-Extract(<>, IKM=K.x) */
7712 os_memset(salt
, 0, hash_len
);
7713 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
7715 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
7717 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
7718 info
= os_malloc(info_len
);
7722 os_memcpy(pos
, mac_init
, ETH_ALEN
);
7724 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
7726 os_memcpy(pos
, Mx
, Mx_len
);
7728 os_memcpy(pos
, Nx
, Nx_len
);
7730 os_memcpy(pos
, code
, os_strlen(code
));
7732 /* HKDF-Expand(PRK, info, L) */
7734 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7736 else if (hash_len
== 48)
7737 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7739 else if (hash_len
== 64)
7740 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
7745 os_memset(prk
, 0, hash_len
);
7749 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
7755 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
7756 const char *identifier
)
7758 if (!attr_id
&& identifier
) {
7759 wpa_printf(MSG_DEBUG
,
7760 "DPP: No PKEX code identifier received, but expected one");
7764 if (attr_id
&& !identifier
) {
7765 wpa_printf(MSG_DEBUG
,
7766 "DPP: PKEX code identifier received, but not expecting one");
7770 if (attr_id
&& identifier
&&
7771 (os_strlen(identifier
) != attr_id_len
||
7772 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
7773 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
7781 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
7782 struct dpp_bootstrap_info
*bi
,
7785 const char *identifier
,
7787 const u8
*buf
, size_t len
)
7789 const u8
*attr_group
, *attr_id
, *attr_key
;
7790 u16 attr_group_len
, attr_id_len
, attr_key_len
;
7791 const struct dpp_curve_params
*curve
= bi
->curve
;
7793 struct dpp_pkex
*pkex
= NULL
;
7794 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
7795 BN_CTX
*bnctx
= NULL
;
7796 EC_GROUP
*group
= NULL
;
7797 BIGNUM
*Mx
= NULL
, *My
= NULL
;
7798 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
7799 const EC_POINT
*Y_point
;
7800 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
7801 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
7805 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
7806 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7807 "PKEX counter t limit reached - ignore message");
7811 #ifdef CONFIG_TESTING_OPTIONS
7812 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
7813 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
7814 MAC2STR(dpp_pkex_peer_mac_override
));
7815 peer_mac
= dpp_pkex_peer_mac_override
;
7817 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
7818 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
7819 MAC2STR(dpp_pkex_own_mac_override
));
7820 own_mac
= dpp_pkex_own_mac_override
;
7822 #endif /* CONFIG_TESTING_OPTIONS */
7825 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
7827 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
7830 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
7832 if (!attr_group
|| attr_group_len
!= 2) {
7833 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7834 "Missing or invalid Finite Cyclic Group attribute");
7837 ike_group
= WPA_GET_LE16(attr_group
);
7838 if (ike_group
!= curve
->ike_group
) {
7839 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7840 "Mismatching PKEX curve: peer=%u own=%u",
7841 ike_group
, curve
->ike_group
);
7842 pkex
= os_zalloc(sizeof(*pkex
));
7847 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
7848 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
7849 if (!pkex
->exchange_resp
)
7854 /* M in Encrypted Key attribute */
7855 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
7857 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
7858 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
7859 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7860 "Missing Encrypted Key attribute");
7864 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
7865 bnctx
= BN_CTX_new();
7868 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
7874 X
= EC_POINT_new(group
);
7875 M
= EC_POINT_new(group
);
7876 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
7877 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
7878 if (!X
|| !M
|| !Mx
|| !My
||
7879 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
7880 EC_POINT_is_at_infinity(group
, M
) ||
7881 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
7882 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
7883 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
7884 EC_POINT_is_at_infinity(group
, X
) ||
7885 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
7886 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
7887 "Invalid Encrypted Key value");
7891 dpp_debug_print_point("DPP: M", group
, M
);
7892 dpp_debug_print_point("DPP: X'", group
, X
);
7894 pkex
= os_zalloc(sizeof(*pkex
));
7897 pkex
->t
= bi
->pkex_t
;
7898 pkex
->msg_ctx
= msg_ctx
;
7900 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
7901 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
7903 pkex
->identifier
= os_strdup(identifier
);
7904 if (!pkex
->identifier
)
7907 pkex
->code
= os_strdup(code
);
7911 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
7913 X_ec
= EC_KEY_new();
7915 EC_KEY_set_group(X_ec
, group
) != 1 ||
7916 EC_KEY_set_public_key(X_ec
, X
) != 1)
7918 pkex
->x
= EVP_PKEY_new();
7920 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
7923 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
7924 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
7928 /* Generate a random ephemeral keypair y/Y */
7929 #ifdef CONFIG_TESTING_OPTIONS
7930 if (dpp_pkex_ephemeral_key_override_len
) {
7931 const struct dpp_curve_params
*tmp_curve
;
7933 wpa_printf(MSG_INFO
,
7934 "DPP: TESTING - override ephemeral key y/Y");
7935 pkex
->y
= dpp_set_keypair(&tmp_curve
,
7936 dpp_pkex_ephemeral_key_override
,
7937 dpp_pkex_ephemeral_key_override_len
);
7939 pkex
->y
= dpp_gen_keypair(curve
);
7941 #else /* CONFIG_TESTING_OPTIONS */
7942 pkex
->y
= dpp_gen_keypair(curve
);
7943 #endif /* CONFIG_TESTING_OPTIONS */
7948 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
7951 Y_point
= EC_KEY_get0_public_key(Y_ec
);
7954 dpp_debug_print_point("DPP: Y", group
, Y_point
);
7955 N
= EC_POINT_new(group
);
7958 if (!N
|| !Nx
|| !Ny
||
7959 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
7960 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
7962 dpp_debug_print_point("DPP: N", group
, N
);
7964 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
7966 if (!pkex
->exchange_resp
)
7970 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
7973 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
7976 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
7978 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
7979 pkex
->Mx
, curve
->prime_len
,
7980 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
7981 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
7982 os_memset(Kx
, 0, Kx_len
);
7986 pkex
->exchange_done
= 1;
8001 EC_GROUP_free(group
);
8004 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
8005 dpp_pkex_free(pkex
);
8011 static struct wpabuf
*
8012 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
8013 const struct wpabuf
*A_pub
, const u8
*u
)
8015 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8016 struct wpabuf
*msg
= NULL
;
8017 size_t clear_len
, attr_len
;
8018 struct wpabuf
*clear
= NULL
;
8024 /* {A, u, [bootstrapping info]}z */
8025 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
8026 clear
= wpabuf_alloc(clear_len
);
8027 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8028 #ifdef CONFIG_TESTING_OPTIONS
8029 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
8031 #endif /* CONFIG_TESTING_OPTIONS */
8032 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
8036 #ifdef CONFIG_TESTING_OPTIONS
8037 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
8038 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
8039 goto skip_bootstrap_key
;
8041 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
8042 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
8043 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8044 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
8045 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
8047 goto skip_bootstrap_key
;
8049 #endif /* CONFIG_TESTING_OPTIONS */
8051 /* A in Bootstrap Key attribute */
8052 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8053 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
8054 wpabuf_put_buf(clear
, A_pub
);
8056 #ifdef CONFIG_TESTING_OPTIONS
8058 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
8059 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
8060 goto skip_i_auth_tag
;
8062 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
8063 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
8064 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
8065 wpabuf_put_le16(clear
, curve
->hash_len
);
8066 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
8067 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
8068 goto skip_i_auth_tag
;
8070 #endif /* CONFIG_TESTING_OPTIONS */
8072 /* u in I-Auth tag attribute */
8073 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
8074 wpabuf_put_le16(clear
, curve
->hash_len
);
8075 wpabuf_put_data(clear
, u
, curve
->hash_len
);
8077 #ifdef CONFIG_TESTING_OPTIONS
8079 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
8080 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
8081 goto skip_wrapped_data
;
8083 #endif /* CONFIG_TESTING_OPTIONS */
8085 addr
[0] = wpabuf_head_u8(msg
) + 2;
8086 len
[0] = DPP_HDR_LEN
;
8089 len
[1] = sizeof(octet
);
8090 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8091 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8093 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8094 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8095 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8097 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8098 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
8099 wpabuf_head(clear
), wpabuf_len(clear
),
8100 2, addr
, len
, wrapped
) < 0)
8102 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8103 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8105 #ifdef CONFIG_TESTING_OPTIONS
8106 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
8107 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
8108 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
8111 #endif /* CONFIG_TESTING_OPTIONS */
8124 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
8126 const u8
*buf
, size_t buflen
)
8128 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
8129 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
8130 EC_GROUP
*group
= NULL
;
8131 BN_CTX
*bnctx
= NULL
;
8132 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8133 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8134 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
8135 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
8136 EC_KEY
*Y_ec
= NULL
;
8137 size_t Jx_len
, Kx_len
;
8138 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
8141 u8 u
[DPP_MAX_HASH_LEN
];
8144 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8147 #ifdef CONFIG_TESTING_OPTIONS
8148 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
8149 wpa_printf(MSG_INFO
,
8150 "DPP: TESTING - stop at PKEX Exchange Response");
8155 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
8156 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
8157 MAC2STR(dpp_pkex_peer_mac_override
));
8158 peer_mac
= dpp_pkex_peer_mac_override
;
8160 #endif /* CONFIG_TESTING_OPTIONS */
8162 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
8164 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
8166 if (!attr_status
|| attr_status_len
!= 1) {
8167 dpp_pkex_fail(pkex
, "No DPP Status attribute");
8170 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
8172 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
8173 attr_group
= dpp_get_attr(buf
, buflen
,
8174 DPP_ATTR_FINITE_CYCLIC_GROUP
,
8176 if (attr_group
&& attr_group_len
== 2) {
8177 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8178 "Peer indicated mismatching PKEX group - proposed %u",
8179 WPA_GET_LE16(attr_group
));
8184 if (attr_status
[0] != DPP_STATUS_OK
) {
8185 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
8190 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
8192 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
8193 pkex
->identifier
)) {
8194 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
8198 /* N in Encrypted Key attribute */
8199 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
8201 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
8202 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
8206 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
8207 bnctx
= BN_CTX_new();
8210 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
8211 pkex
->identifier
, bnctx
, &group
);
8216 Y
= EC_POINT_new(group
);
8217 N
= EC_POINT_new(group
);
8218 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
8219 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
8220 if (!Y
|| !N
|| !Nx
|| !Ny
||
8221 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
8222 EC_POINT_is_at_infinity(group
, N
) ||
8223 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
8224 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
8225 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
8226 EC_POINT_is_at_infinity(group
, Y
) ||
8227 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
8228 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
8232 dpp_debug_print_point("DPP: N", group
, N
);
8233 dpp_debug_print_point("DPP: Y'", group
, Y
);
8235 pkex
->exchange_done
= 1;
8237 /* ECDH: J = a * Y’ */
8238 Y_ec
= EC_KEY_new();
8240 EC_KEY_set_group(Y_ec
, group
) != 1 ||
8241 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
8243 pkex
->y
= EVP_PKEY_new();
8245 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
8247 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
8250 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
8253 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
8254 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
8255 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8256 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8257 if (!A_pub
|| !Y_pub
|| !X_pub
)
8259 addr
[0] = pkex
->own_mac
;
8261 addr
[1] = wpabuf_head(A_pub
);
8262 len
[1] = wpabuf_len(A_pub
) / 2;
8263 addr
[2] = wpabuf_head(Y_pub
);
8264 len
[2] = wpabuf_len(Y_pub
) / 2;
8265 addr
[3] = wpabuf_head(X_pub
);
8266 len
[3] = wpabuf_len(X_pub
) / 2;
8267 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
8269 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
8272 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
8275 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
8278 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
8280 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
8281 pkex
->Mx
, curve
->prime_len
,
8282 attr_key
/* N.x */, attr_key_len
/ 2,
8283 pkex
->code
, Kx
, Kx_len
,
8284 pkex
->z
, curve
->hash_len
);
8285 os_memset(Kx
, 0, Kx_len
);
8289 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
8304 EC_GROUP_free(group
);
8307 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
8312 static struct wpabuf
*
8313 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
8314 const struct wpabuf
*B_pub
, const u8
*v
)
8316 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8317 struct wpabuf
*msg
= NULL
;
8322 struct wpabuf
*clear
= NULL
;
8323 size_t clear_len
, attr_len
;
8325 /* {B, v [bootstrapping info]}z */
8326 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
8327 clear
= wpabuf_alloc(clear_len
);
8328 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8329 #ifdef CONFIG_TESTING_OPTIONS
8330 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
8332 #endif /* CONFIG_TESTING_OPTIONS */
8333 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
8337 #ifdef CONFIG_TESTING_OPTIONS
8338 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
8339 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
8340 goto skip_bootstrap_key
;
8342 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
8343 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
8344 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8345 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
8346 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
8348 goto skip_bootstrap_key
;
8350 #endif /* CONFIG_TESTING_OPTIONS */
8352 /* B in Bootstrap Key attribute */
8353 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8354 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
8355 wpabuf_put_buf(clear
, B_pub
);
8357 #ifdef CONFIG_TESTING_OPTIONS
8359 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
8360 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
8361 goto skip_r_auth_tag
;
8363 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
8364 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
8365 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
8366 wpabuf_put_le16(clear
, curve
->hash_len
);
8367 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
8368 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
8369 goto skip_r_auth_tag
;
8371 #endif /* CONFIG_TESTING_OPTIONS */
8373 /* v in R-Auth tag attribute */
8374 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
8375 wpabuf_put_le16(clear
, curve
->hash_len
);
8376 wpabuf_put_data(clear
, v
, curve
->hash_len
);
8378 #ifdef CONFIG_TESTING_OPTIONS
8380 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
8381 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
8382 goto skip_wrapped_data
;
8384 #endif /* CONFIG_TESTING_OPTIONS */
8386 addr
[0] = wpabuf_head_u8(msg
) + 2;
8387 len
[0] = DPP_HDR_LEN
;
8390 len
[1] = sizeof(octet
);
8391 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8392 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8394 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8395 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8396 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8398 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8399 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
8400 wpabuf_head(clear
), wpabuf_len(clear
),
8401 2, addr
, len
, wrapped
) < 0)
8403 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8404 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8406 #ifdef CONFIG_TESTING_OPTIONS
8407 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
8408 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
8409 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
8412 #endif /* CONFIG_TESTING_OPTIONS */
8425 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
8427 const u8
*buf
, size_t buflen
)
8429 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8430 size_t Jx_len
, Lx_len
;
8431 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
8432 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
8433 const u8
*wrapped_data
, *b_key
, *peer_u
;
8434 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
8438 u8
*unwrapped
= NULL
;
8439 size_t unwrapped_len
= 0;
8440 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8441 struct wpabuf
*B_pub
= NULL
;
8442 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
8444 #ifdef CONFIG_TESTING_OPTIONS
8445 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
8446 wpa_printf(MSG_INFO
,
8447 "DPP: TESTING - stop at PKEX CR Request");
8451 #endif /* CONFIG_TESTING_OPTIONS */
8453 if (!pkex
->exchange_done
|| pkex
->failed
||
8454 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
8457 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8459 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8461 "Missing or invalid required Wrapped Data attribute");
8465 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8466 wrapped_data
, wrapped_data_len
);
8467 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8468 unwrapped
= os_malloc(unwrapped_len
);
8473 len
[0] = DPP_HDR_LEN
;
8476 len
[1] = sizeof(octet
);
8477 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8478 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8480 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8481 wrapped_data
, wrapped_data_len
,
8482 2, addr
, len
, unwrapped
) < 0) {
8484 "AES-SIV decryption failed - possible PKEX code mismatch");
8489 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8490 unwrapped
, unwrapped_len
);
8492 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8493 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8497 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8499 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8500 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8503 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8505 if (!pkex
->peer_bootstrap_key
) {
8506 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8509 dpp_debug_print_key("DPP: Peer bootstrap public key",
8510 pkex
->peer_bootstrap_key
);
8512 /* ECDH: J' = y * A' */
8513 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
8516 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
8519 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
8520 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8521 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8522 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8523 if (!A_pub
|| !Y_pub
|| !X_pub
)
8525 addr
[0] = pkex
->peer_mac
;
8527 addr
[1] = wpabuf_head(A_pub
);
8528 len
[1] = wpabuf_len(A_pub
) / 2;
8529 addr
[2] = wpabuf_head(Y_pub
);
8530 len
[2] = wpabuf_len(Y_pub
) / 2;
8531 addr
[3] = wpabuf_head(X_pub
);
8532 len
[3] = wpabuf_len(X_pub
) / 2;
8533 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
8536 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
8538 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
8539 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
8540 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
8541 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
8542 u
, curve
->hash_len
);
8543 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
8547 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
8549 /* ECDH: L = b * X' */
8550 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
8553 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8556 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
8557 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
8560 addr
[0] = pkex
->own_mac
;
8562 addr
[1] = wpabuf_head(B_pub
);
8563 len
[1] = wpabuf_len(B_pub
) / 2;
8564 addr
[2] = wpabuf_head(X_pub
);
8565 len
[2] = wpabuf_len(X_pub
) / 2;
8566 addr
[3] = wpabuf_head(Y_pub
);
8567 len
[3] = wpabuf_len(Y_pub
) / 2;
8568 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8570 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
8572 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
8584 wpa_printf(MSG_DEBUG
,
8585 "DPP: PKEX Commit-Reveal Request processing failed");
8590 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
8591 const u8
*buf
, size_t buflen
)
8593 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8594 const u8
*wrapped_data
, *b_key
, *peer_v
;
8595 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
8599 u8
*unwrapped
= NULL
;
8600 size_t unwrapped_len
= 0;
8602 u8 v
[DPP_MAX_HASH_LEN
];
8604 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
8605 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
8607 #ifdef CONFIG_TESTING_OPTIONS
8608 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
8609 wpa_printf(MSG_INFO
,
8610 "DPP: TESTING - stop at PKEX CR Response");
8614 #endif /* CONFIG_TESTING_OPTIONS */
8616 if (!pkex
->exchange_done
|| pkex
->failed
||
8617 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
8620 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
8622 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
8624 "Missing or invalid required Wrapped Data attribute");
8628 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8629 wrapped_data
, wrapped_data_len
);
8630 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
8631 unwrapped
= os_malloc(unwrapped_len
);
8636 len
[0] = DPP_HDR_LEN
;
8639 len
[1] = sizeof(octet
);
8640 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8641 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8643 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
8644 wrapped_data
, wrapped_data_len
,
8645 2, addr
, len
, unwrapped
) < 0) {
8647 "AES-SIV decryption failed - possible PKEX code mismatch");
8651 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
8652 unwrapped
, unwrapped_len
);
8654 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
8655 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
8659 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
8661 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
8662 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
8665 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
8667 if (!pkex
->peer_bootstrap_key
) {
8668 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
8671 dpp_debug_print_key("DPP: Peer bootstrap public key",
8672 pkex
->peer_bootstrap_key
);
8674 /* ECDH: L' = x * B' */
8675 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
8678 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
8681 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
8682 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
8683 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
8684 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
8685 if (!B_pub
|| !X_pub
|| !Y_pub
)
8687 addr
[0] = pkex
->peer_mac
;
8689 addr
[1] = wpabuf_head(B_pub
);
8690 len
[1] = wpabuf_len(B_pub
) / 2;
8691 addr
[2] = wpabuf_head(X_pub
);
8692 len
[2] = wpabuf_len(X_pub
) / 2;
8693 addr
[3] = wpabuf_head(Y_pub
);
8694 len
[3] = wpabuf_len(Y_pub
) / 2;
8695 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
8698 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
8700 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
8701 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
8702 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
8703 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
8704 v
, curve
->hash_len
);
8705 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
8709 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
8723 void dpp_pkex_free(struct dpp_pkex
*pkex
)
8728 os_free(pkex
->identifier
);
8729 os_free(pkex
->code
);
8730 EVP_PKEY_free(pkex
->x
);
8731 EVP_PKEY_free(pkex
->y
);
8732 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
8733 wpabuf_free(pkex
->exchange_req
);
8734 wpabuf_free(pkex
->exchange_resp
);
8739 #ifdef CONFIG_TESTING_OPTIONS
8740 char * dpp_corrupt_connector_signature(const char *connector
)
8742 char *tmp
, *pos
, *signed3
= NULL
;
8743 unsigned char *signature
= NULL
;
8744 size_t signature_len
= 0, signed3_len
;
8746 tmp
= os_zalloc(os_strlen(connector
) + 5);
8749 os_memcpy(tmp
, connector
, os_strlen(connector
));
8751 pos
= os_strchr(tmp
, '.');
8755 pos
= os_strchr(pos
+ 1, '.');
8760 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
8762 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
8763 if (!signature
|| signature_len
== 0)
8765 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
8766 signature
, signature_len
);
8767 signature
[signature_len
- 1] ^= 0x01;
8768 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
8769 signature
, signature_len
);
8770 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
8773 os_memcpy(pos
, signed3
, signed3_len
);
8774 pos
[signed3_len
] = '\0';
8775 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
8787 #endif /* CONFIG_TESTING_OPTIONS */
8792 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
8793 size_t net_access_key_len
)
8795 struct wpabuf
*pub
= NULL
;
8797 struct dpp_pfs
*pfs
;
8799 pfs
= os_zalloc(sizeof(*pfs
));
8803 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
8804 net_access_key_len
);
8806 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8809 EVP_PKEY_free(own_key
);
8811 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
8815 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
8816 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
8820 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
8823 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
8824 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
8825 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
8826 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
8827 wpabuf_put_buf(pfs
->ie
, pub
);
8829 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
8840 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
8842 if (peer_ie_len
< 2)
8844 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
8845 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
8849 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
8851 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
8853 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
8856 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
8861 void dpp_pfs_free(struct dpp_pfs
*pfs
)
8865 crypto_ecdh_deinit(pfs
->ecdh
);
8866 wpabuf_free(pfs
->ie
);
8867 wpabuf_clear_free(pfs
->secret
);
8871 #endif /* CONFIG_DPP2 */
8874 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
8876 struct dpp_bootstrap_info
*bi
;
8877 unsigned int max_id
= 0;
8879 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
8880 if (bi
->id
> max_id
)
8887 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
8889 struct dpp_bootstrap_info
*bi
, *tmp
;
8895 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
8896 struct dpp_bootstrap_info
, list
) {
8897 if (id
&& bi
->id
!= id
)
8900 dl_list_del(&bi
->list
);
8901 dpp_bootstrap_info_free(bi
);
8905 return 0; /* flush succeeds regardless of entries found */
8906 return found
? 0 : -1;
8910 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
8913 struct dpp_bootstrap_info
*bi
;
8918 bi
= dpp_parse_qr_code(uri
);
8922 bi
->id
= dpp_next_id(dpp
);
8923 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
8928 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
8930 char *chan
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
, *curve
= NULL
;
8933 size_t privkey_len
= 0;
8936 struct dpp_bootstrap_info
*bi
;
8941 bi
= os_zalloc(sizeof(*bi
));
8945 if (os_strstr(cmd
, "type=qrcode"))
8946 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
8947 else if (os_strstr(cmd
, "type=pkex"))
8948 bi
->type
= DPP_BOOTSTRAP_PKEX
;
8952 chan
= get_param(cmd
, " chan=");
8953 mac
= get_param(cmd
, " mac=");
8954 info
= get_param(cmd
, " info=");
8955 curve
= get_param(cmd
, " curve=");
8956 key
= get_param(cmd
, " key=");
8959 privkey_len
= os_strlen(key
) / 2;
8960 privkey
= os_malloc(privkey_len
);
8962 hexstr2bin(key
, privkey
, privkey_len
) < 0)
8966 pk
= dpp_keygen(bi
, curve
, privkey
, privkey_len
);
8970 len
= 4; /* "DPP:" */
8972 if (dpp_parse_uri_chan_list(bi
, chan
) < 0)
8974 len
+= 3 + os_strlen(chan
); /* C:...; */
8977 if (dpp_parse_uri_mac(bi
, mac
) < 0)
8979 len
+= 3 + os_strlen(mac
); /* M:...; */
8982 if (dpp_parse_uri_info(bi
, info
) < 0)
8984 len
+= 3 + os_strlen(info
); /* I:...; */
8986 len
+= 4 + os_strlen(pk
);
8987 bi
->uri
= os_malloc(len
+ 1);
8990 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
8991 chan
? "C:" : "", chan
? chan
: "", chan
? ";" : "",
8992 mac
? "M:" : "", mac
? mac
: "", mac
? ";" : "",
8993 info
? "I:" : "", info
? info
: "", info
? ";" : "",
8995 bi
->id
= dpp_next_id(dpp
);
8996 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9005 str_clear_free(key
);
9006 bin_clear_free(privkey
, privkey_len
);
9007 dpp_bootstrap_info_free(bi
);
9012 struct dpp_bootstrap_info
*
9013 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
9015 struct dpp_bootstrap_info
*bi
;
9020 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
9028 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
9030 unsigned int id_val
;
9032 if (os_strcmp(id
, "*") == 0) {
9040 return dpp_bootstrap_del(dpp
, id_val
);
9044 struct dpp_bootstrap_info
*
9045 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
9048 struct dpp_bootstrap_info
*bi
;
9050 bi
= os_zalloc(sizeof(*bi
));
9053 bi
->id
= dpp_next_id(dpp
);
9054 bi
->type
= DPP_BOOTSTRAP_PKEX
;
9055 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
9058 bi
->curve
= pkex
->own_bi
->curve
;
9059 bi
->pubkey
= pkex
->peer_bootstrap_key
;
9060 pkex
->peer_bootstrap_key
= NULL
;
9061 if (dpp_bootstrap_key_hash(bi
) < 0) {
9062 dpp_bootstrap_info_free(bi
);
9065 dpp_pkex_free(pkex
);
9066 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9071 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
9073 struct dpp_bootstrap_info
*bi
;
9075 bi
= dpp_bootstrap_get_id(dpp
, id
);
9082 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
9083 char *reply
, int reply_size
)
9085 struct dpp_bootstrap_info
*bi
;
9086 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
9088 bi
= dpp_bootstrap_get_id(dpp
, id
);
9091 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
9093 return os_snprintf(reply
, reply_size
, "type=%s\n"
9094 "mac_addr=" MACSTR
"\n"
9099 dpp_bootstrap_type_txt(bi
->type
),
9100 MAC2STR(bi
->mac_addr
),
9101 bi
->info
? bi
->info
: "",
9108 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
9109 const u8
*r_bootstrap
,
9110 struct dpp_bootstrap_info
**own_bi
,
9111 struct dpp_bootstrap_info
**peer_bi
)
9113 struct dpp_bootstrap_info
*bi
;
9120 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
9121 if (!*own_bi
&& bi
->own
&&
9122 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
9123 SHA256_MAC_LEN
) == 0) {
9124 wpa_printf(MSG_DEBUG
,
9125 "DPP: Found matching own bootstrapping information");
9129 if (!*peer_bi
&& !bi
->own
&&
9130 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
9131 SHA256_MAC_LEN
) == 0) {
9132 wpa_printf(MSG_DEBUG
,
9133 "DPP: Found matching peer bootstrapping information");
9137 if (*own_bi
&& *peer_bi
)
9144 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
9146 struct dpp_configurator
*conf
;
9147 unsigned int max_id
= 0;
9149 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
9151 if (conf
->id
> max_id
)
9158 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
9163 size_t privkey_len
= 0;
9165 struct dpp_configurator
*conf
= NULL
;
9167 curve
= get_param(cmd
, " curve=");
9168 key
= get_param(cmd
, " key=");
9171 privkey_len
= os_strlen(key
) / 2;
9172 privkey
= os_malloc(privkey_len
);
9174 hexstr2bin(key
, privkey
, privkey_len
) < 0)
9178 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
9182 conf
->id
= dpp_next_configurator_id(dpp
);
9183 dl_list_add(&dpp
->configurator
, &conf
->list
);
9188 str_clear_free(key
);
9189 bin_clear_free(privkey
, privkey_len
);
9190 dpp_configurator_free(conf
);
9195 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
9197 struct dpp_configurator
*conf
, *tmp
;
9203 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
9204 struct dpp_configurator
, list
) {
9205 if (id
&& conf
->id
!= id
)
9208 dl_list_del(&conf
->list
);
9209 dpp_configurator_free(conf
);
9213 return 0; /* flush succeeds regardless of entries found */
9214 return found
? 0 : -1;
9218 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
9220 unsigned int id_val
;
9222 if (os_strcmp(id
, "*") == 0) {
9230 return dpp_configurator_del(dpp
, id_val
);
9234 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
9235 char *buf
, size_t buflen
)
9237 struct dpp_configurator
*conf
;
9239 conf
= dpp_configurator_get_id(dpp
, id
);
9243 return dpp_configurator_get_key(conf
, buf
, buflen
);
9249 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
9253 static void dpp_connection_free(struct dpp_connection
*conn
)
9255 if (conn
->sock
>= 0) {
9256 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
9258 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
9259 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
9262 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout
,
9264 wpabuf_free(conn
->msg
);
9265 wpabuf_free(conn
->msg_out
);
9266 dpp_auth_deinit(conn
->auth
);
9271 static void dpp_connection_remove(struct dpp_connection
*conn
)
9273 dl_list_del(&conn
->list
);
9274 dpp_connection_free(conn
);
9278 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
9280 struct dpp_connection
*conn
, *tmp
;
9282 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
9284 dpp_connection_remove(conn
);
9288 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
9290 struct dpp_connection
*conn
, *tmp
;
9292 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
9294 dpp_connection_remove(conn
);
9299 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
9301 struct dpp_relay_controller
*ctrl
, *tmp
;
9306 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
9307 struct dpp_relay_controller
, list
) {
9308 dl_list_del(&ctrl
->list
);
9309 dpp_relay_controller_free(ctrl
);
9313 #endif /* CONFIG_DPP2 */
9316 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
9318 struct dpp_global
*dpp
;
9320 dpp
= os_zalloc(sizeof(*dpp
));
9323 dpp
->msg_ctx
= config
->msg_ctx
;
9325 dpp
->cb_ctx
= config
->cb_ctx
;
9326 dpp
->process_conf_obj
= config
->process_conf_obj
;
9327 #endif /* CONFIG_DPP2 */
9329 dl_list_init(&dpp
->bootstrap
);
9330 dl_list_init(&dpp
->configurator
);
9332 dl_list_init(&dpp
->controllers
);
9333 dl_list_init(&dpp
->tcp_init
);
9334 #endif /* CONFIG_DPP2 */
9340 void dpp_global_clear(struct dpp_global
*dpp
)
9345 dpp_bootstrap_del(dpp
, 0);
9346 dpp_configurator_del(dpp
, 0);
9348 dpp_tcp_init_flush(dpp
);
9349 dpp_relay_flush_controllers(dpp
);
9350 dpp_controller_stop(dpp
);
9351 #endif /* CONFIG_DPP2 */
9355 void dpp_global_deinit(struct dpp_global
*dpp
)
9357 dpp_global_clear(dpp
);
9364 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
9365 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
9366 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
9370 int dpp_relay_add_controller(struct dpp_global
*dpp
,
9371 struct dpp_relay_config
*config
)
9373 struct dpp_relay_controller
*ctrl
;
9378 ctrl
= os_zalloc(sizeof(*ctrl
));
9381 dl_list_init(&ctrl
->conn
);
9383 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
9384 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
9385 ctrl
->cb_ctx
= config
->cb_ctx
;
9386 ctrl
->tx
= config
->tx
;
9387 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
9388 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
9393 static struct dpp_relay_controller
*
9394 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
9396 struct dpp_relay_controller
*ctrl
;
9401 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
9403 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
9411 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
9413 struct dpp_authentication
*auth
= conn
->auth
;
9415 if (auth
->peer_version
>= 2 &&
9416 auth
->conf_resp_status
== DPP_STATUS_OK
) {
9417 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
9418 auth
->waiting_conf_result
= 1;
9422 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
9423 dpp_connection_remove(conn
);
9427 static int dpp_tcp_send(struct dpp_connection
*conn
)
9431 if (!conn
->msg_out
) {
9432 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
9433 conn
->write_eloop
= 0;
9436 res
= send(conn
->sock
,
9437 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
9438 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
9440 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
9442 dpp_connection_remove(conn
);
9446 conn
->msg_out_pos
+= res
;
9447 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
9448 wpa_printf(MSG_DEBUG
,
9449 "DPP: %u/%u bytes of message sent to Controller",
9450 (unsigned int) conn
->msg_out_pos
,
9451 (unsigned int) wpabuf_len(conn
->msg_out
));
9452 if (!conn
->write_eloop
&&
9453 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9454 dpp_conn_tx_ready
, conn
, NULL
) == 0)
9455 conn
->write_eloop
= 1;
9459 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
9460 wpabuf_free(conn
->msg_out
);
9461 conn
->msg_out
= NULL
;
9462 conn
->msg_out_pos
= 0;
9463 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
9464 conn
->write_eloop
= 0;
9465 if (!conn
->read_eloop
&&
9466 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
9467 dpp_controller_rx
, conn
, NULL
) == 0)
9468 conn
->read_eloop
= 1;
9469 if (conn
->on_tcp_tx_complete_remove
) {
9470 dpp_connection_remove(conn
);
9471 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
9473 dpp_controller_gas_done(conn
);
9474 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
9475 conn
->on_tcp_tx_complete_auth_ok
= 0;
9476 dpp_controller_auth_success(conn
, 1);
9483 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
9485 struct dpp_authentication
*auth
= conn
->auth
;
9487 int netrole_ap
= 0; /* TODO: make this configurable */
9489 buf
= dpp_build_conf_req_helper(auth
, "Test", netrole_ap
, NULL
, NULL
);
9491 wpa_printf(MSG_DEBUG
,
9492 "DPP: No configuration request data available");
9496 wpabuf_free(conn
->msg_out
);
9497 conn
->msg_out_pos
= 0;
9498 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
9499 if (!conn
->msg_out
) {
9503 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
9504 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
9505 wpabuf_len(buf
) - 1);
9508 if (dpp_tcp_send(conn
) == 1) {
9509 if (!conn
->write_eloop
) {
9510 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9514 conn
->write_eloop
= 1;
9520 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
9523 struct dpp_authentication
*auth
= conn
->auth
;
9528 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
9529 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
9530 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
9531 #ifdef CONFIG_TESTING_OPTIONS
9532 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
9533 wpa_printf(MSG_INFO
,
9534 "DPP: TESTING - stop at Authentication Confirm");
9535 if (auth
->configurator
) {
9536 /* Prevent GAS response */
9537 auth
->auth_success
= 0;
9541 #endif /* CONFIG_TESTING_OPTIONS */
9543 if (!auth
->configurator
)
9544 dpp_controller_start_gas_client(conn
);
9548 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
9550 struct dpp_connection
*conn
= eloop_ctx
;
9552 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
9557 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
9558 const struct hostapd_ip_addr
*ipaddr
,
9561 struct sockaddr_in
*dst
;
9563 struct sockaddr_in6
*dst6
;
9564 #endif /* CONFIG_IPV6 */
9566 switch (ipaddr
->af
) {
9568 dst
= (struct sockaddr_in
*) addr
;
9569 os_memset(dst
, 0, sizeof(*dst
));
9570 dst
->sin_family
= AF_INET
;
9571 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
9572 dst
->sin_port
= htons(port
);
9573 *addrlen
= sizeof(*dst
);
9577 dst6
= (struct sockaddr_in6
*) addr
;
9578 os_memset(dst6
, 0, sizeof(*dst6
));
9579 dst6
->sin6_family
= AF_INET6
;
9580 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
9581 sizeof(struct in6_addr
));
9582 dst6
->sin6_port
= htons(port
);
9583 *addrlen
= sizeof(*dst6
);
9585 #endif /* CONFIG_IPV6 */
9594 static struct dpp_connection
*
9595 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
9598 struct dpp_connection
*conn
;
9599 struct sockaddr_storage addr
;
9603 if (dl_list_len(&ctrl
->conn
) >= 15) {
9604 wpa_printf(MSG_DEBUG
,
9605 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
9609 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
9610 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
9613 conn
= os_zalloc(sizeof(*conn
));
9617 conn
->global
= ctrl
->global
;
9619 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
9622 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
9625 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
9626 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
9628 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
9629 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
9634 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
9635 if (errno
!= EINPROGRESS
) {
9636 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
9642 * Continue connecting in the background; eloop will call us
9643 * once the connection is ready (or failed).
9647 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9648 dpp_conn_tx_ready
, conn
, NULL
) < 0)
9650 conn
->write_eloop
= 1;
9652 /* TODO: eloop timeout to clear a connection if it does not complete
9655 dl_list_add(&ctrl
->conn
, &conn
->list
);
9658 dpp_connection_free(conn
);
9663 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
9667 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
9670 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
9671 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
9672 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
9673 wpabuf_put_data(msg
, buf
, len
);
9674 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9679 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
9680 const u8
*buf
, size_t len
)
9682 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9684 wpa_printf(MSG_DEBUG
,
9685 "DPP: Continue already established Relay/Controller connection for this session");
9686 wpabuf_free(conn
->msg_out
);
9687 conn
->msg_out_pos
= 0;
9688 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9689 if (!conn
->msg_out
) {
9690 dpp_connection_remove(conn
);
9694 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
9696 if (type
== DPP_PA_CONFIGURATION_RESULT
)
9697 conn
->on_tcp_tx_complete_remove
= 1;
9703 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
9704 const u8
*buf
, size_t len
, unsigned int freq
,
9705 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
9707 struct dpp_relay_controller
*ctrl
;
9708 struct dpp_connection
*conn
;
9709 u8 type
= hdr
[DPP_HDR_LEN
- 1];
9711 /* Check if there is an already started session for this peer and if so,
9712 * continue that session (send this over TCP) and return 0.
9714 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
9715 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
9716 dl_list_for_each(ctrl
, &dpp
->controllers
,
9717 struct dpp_relay_controller
, list
) {
9718 dl_list_for_each(conn
, &ctrl
->conn
,
9719 struct dpp_connection
, list
) {
9720 if (os_memcmp(src
, conn
->mac_addr
,
9722 return dpp_relay_tx(conn
, hdr
, buf
, len
);
9730 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
9734 wpa_printf(MSG_DEBUG
,
9735 "DPP: Authentication Request for a configured Controller");
9736 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
9740 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
9741 if (!conn
->msg_out
) {
9742 dpp_connection_remove(conn
);
9745 /* Message will be sent in dpp_conn_tx_ready() */
9751 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
9754 struct dpp_relay_controller
*ctrl
;
9755 struct dpp_connection
*conn
, *found
= NULL
;
9758 /* Check if there is a successfully completed authentication for this
9759 * and if so, continue that session (send this over TCP) and return 0.
9761 dl_list_for_each(ctrl
, &dpp
->controllers
,
9762 struct dpp_relay_controller
, list
) {
9765 dl_list_for_each(conn
, &ctrl
->conn
,
9766 struct dpp_connection
, list
) {
9767 if (os_memcmp(src
, conn
->mac_addr
,
9778 msg
= wpabuf_alloc(4 + 1 + data_len
);
9781 wpabuf_put_be32(msg
, 1 + data_len
);
9782 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
9783 wpabuf_put_data(msg
, data
, data_len
);
9784 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
9786 wpabuf_free(conn
->msg_out
);
9787 conn
->msg_out_pos
= 0;
9788 conn
->msg_out
= msg
;
9794 static void dpp_controller_free(struct dpp_controller
*ctrl
)
9796 struct dpp_connection
*conn
, *tmp
;
9801 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
9803 dpp_connection_remove(conn
);
9805 if (ctrl
->sock
>= 0) {
9807 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
9809 os_free(ctrl
->configurator_params
);
9814 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
9815 const u8
*hdr
, const u8
*buf
, size_t len
)
9817 const u8
*r_bootstrap
, *i_bootstrap
;
9818 u16 r_bootstrap_len
, i_bootstrap_len
;
9819 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
9824 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
9826 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
9828 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
9829 wpa_printf(MSG_INFO
,
9830 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
9833 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
9834 r_bootstrap
, r_bootstrap_len
);
9836 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
9838 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
9839 wpa_printf(MSG_INFO
,
9840 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
9843 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
9844 i_bootstrap
, i_bootstrap_len
);
9846 /* Try to find own and peer bootstrapping key matches based on the
9847 * received hash values */
9848 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
9851 wpa_printf(MSG_INFO
,
9852 "No matching own bootstrapping key found - ignore message");
9857 wpa_printf(MSG_INFO
,
9858 "Already in DPP authentication exchange - ignore new one");
9862 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
9863 conn
->ctrl
->allowed_roles
,
9864 conn
->ctrl
->qr_mutual
,
9865 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
9867 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
9871 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
9873 conn
->ctrl
->configurator_params
) < 0) {
9874 dpp_connection_remove(conn
);
9878 wpabuf_free(conn
->msg_out
);
9879 conn
->msg_out_pos
= 0;
9880 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
9883 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
9884 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
9885 wpabuf_len(conn
->auth
->resp_msg
) - 1);
9887 if (dpp_tcp_send(conn
) == 1) {
9888 if (!conn
->write_eloop
) {
9889 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9893 conn
->write_eloop
= 1;
9901 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
9902 const u8
*hdr
, const u8
*buf
, size_t len
)
9904 struct dpp_authentication
*auth
= conn
->auth
;
9910 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
9912 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
9914 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
9915 wpa_printf(MSG_DEBUG
,
9916 "DPP: Start wait for full response");
9919 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
9920 dpp_connection_remove(conn
);
9924 wpabuf_free(conn
->msg_out
);
9925 conn
->msg_out_pos
= 0;
9926 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
9927 if (!conn
->msg_out
) {
9931 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
9932 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
9933 wpabuf_len(msg
) - 1);
9936 conn
->on_tcp_tx_complete_auth_ok
= 1;
9937 if (dpp_tcp_send(conn
) == 1) {
9938 if (!conn
->write_eloop
) {
9939 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
9943 conn
->write_eloop
= 1;
9951 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
9952 const u8
*hdr
, const u8
*buf
, size_t len
)
9954 struct dpp_authentication
*auth
= conn
->auth
;
9956 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
9959 wpa_printf(MSG_DEBUG
,
9960 "DPP: No DPP Authentication in progress - drop");
9964 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
9965 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
9969 dpp_controller_auth_success(conn
, 0);
9974 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
9977 struct dpp_connection
*conn
= eloop_ctx
;
9979 if (!conn
->auth
->waiting_conf_result
)
9982 wpa_printf(MSG_DEBUG
,
9983 "DPP: Timeout while waiting for Connection Status Result");
9984 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
9985 DPP_EVENT_CONN_STATUS_RESULT
"timeout");
9986 dpp_connection_remove(conn
);
9990 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
9991 const u8
*hdr
, const u8
*buf
,
9994 struct dpp_authentication
*auth
= conn
->auth
;
9995 enum dpp_status_error status
;
10000 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
10002 if (!auth
|| !auth
->waiting_conf_result
) {
10003 wpa_printf(MSG_DEBUG
,
10004 "DPP: No DPP Configuration waiting for result - drop");
10008 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
10009 if (status
== DPP_STATUS_OK
&& auth
->send_conn_status
) {
10010 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
10011 DPP_EVENT_CONF_SENT
"wait_conn_status=1");
10012 wpa_printf(MSG_DEBUG
, "DPP: Wait for Connection Status Result");
10013 eloop_cancel_timeout(
10014 dpp_controller_conn_status_result_wait_timeout
,
10016 eloop_register_timeout(
10017 16, 0, dpp_controller_conn_status_result_wait_timeout
,
10021 if (status
== DPP_STATUS_OK
)
10022 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
10023 DPP_EVENT_CONF_SENT
);
10025 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
10026 DPP_EVENT_CONF_FAILED
);
10027 return -1; /* to remove the completed connection */
10031 static int dpp_controller_rx_conn_status_result(struct dpp_connection
*conn
,
10032 const u8
*hdr
, const u8
*buf
,
10035 struct dpp_authentication
*auth
= conn
->auth
;
10036 enum dpp_status_error status
;
10037 u8 ssid
[SSID_MAX_LEN
];
10038 size_t ssid_len
= 0;
10039 char *channel_list
= NULL
;
10044 wpa_printf(MSG_DEBUG
, "DPP: Connection Status Result");
10046 if (!auth
|| !auth
->waiting_conn_status_result
) {
10047 wpa_printf(MSG_DEBUG
,
10048 "DPP: No DPP Configuration waiting for connection status result - drop");
10052 status
= dpp_conn_status_result_rx(auth
, hdr
, buf
, len
,
10053 ssid
, &ssid_len
, &channel_list
);
10054 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
10055 DPP_EVENT_CONN_STATUS_RESULT
10056 "result=%d ssid=%s channel_list=%s",
10057 status
, wpa_ssid_txt(ssid
, ssid_len
),
10058 channel_list
? channel_list
: "N/A");
10059 os_free(channel_list
);
10060 return -1; /* to remove the completed connection */
10064 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
10067 const u8
*pos
, *end
;
10070 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
10074 if (end
- pos
< DPP_HDR_LEN
||
10075 WPA_GET_BE24(pos
) != OUI_WFA
||
10076 pos
[3] != DPP_OUI_TYPE
) {
10077 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
10082 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
10087 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
10088 pos
+= DPP_HDR_LEN
;
10090 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
10092 if (dpp_check_attrs(pos
, end
- pos
) < 0)
10096 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
10097 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
10098 conn
->freq
, msg
, len
);
10103 case DPP_PA_AUTHENTICATION_REQ
:
10104 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
10105 case DPP_PA_AUTHENTICATION_RESP
:
10106 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
10107 case DPP_PA_AUTHENTICATION_CONF
:
10108 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
10109 case DPP_PA_CONFIGURATION_RESULT
:
10110 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
10111 case DPP_PA_CONNECTION_STATUS_RESULT
:
10112 return dpp_controller_rx_conn_status_result(conn
, msg
, pos
,
10115 /* TODO: missing messages types */
10116 wpa_printf(MSG_DEBUG
,
10117 "DPP: Unsupported frame subtype %d", type
);
10123 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
10126 const u8
*pos
, *end
, *next
;
10128 const u8
*adv_proto
;
10130 struct wpabuf
*resp
, *buf
;
10131 struct dpp_authentication
*auth
= conn
->auth
;
10136 wpa_printf(MSG_DEBUG
,
10137 "DPP: Received DPP Configuration Request over TCP");
10139 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
10140 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
10147 dialog_token
= *pos
++;
10150 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
10151 slen
> end
- pos
|| slen
< 2)
10155 pos
++; /* skip QueryRespLenLimit and PAME-BI */
10157 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
10158 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
10159 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
10163 /* Query Request */
10166 slen
= WPA_GET_LE16(pos
);
10168 if (slen
> end
- pos
)
10171 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
10175 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
10181 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
10183 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
10184 wpabuf_put_u8(buf
, dialog_token
);
10185 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
10186 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
10188 dpp_write_adv_proto(buf
);
10189 dpp_write_gas_query(buf
, resp
);
10192 /* Send Config Response over TCP; GAS fragmentation is taken care of by
10194 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
10195 wpabuf_free(conn
->msg_out
);
10196 conn
->msg_out_pos
= 0;
10197 conn
->msg_out
= buf
;
10198 conn
->on_tcp_tx_complete_gas_done
= 1;
10199 dpp_tcp_send(conn
);
10204 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
10206 struct dpp_authentication
*auth
= conn
->auth
;
10208 struct wpabuf
*msg
, *encaps
;
10209 enum dpp_status_error status
;
10211 wpa_printf(MSG_DEBUG
,
10212 "DPP: Configuration Response for local stack from TCP");
10214 res
= dpp_conf_resp_rx(auth
, resp
);
10217 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
10221 if (conn
->global
->process_conf_obj
)
10222 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
10227 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
10231 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
10232 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
10233 msg
= dpp_build_conf_result(auth
, status
);
10237 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
10242 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
10243 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
10245 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
10247 wpabuf_free(conn
->msg_out
);
10248 conn
->msg_out_pos
= 0;
10249 conn
->msg_out
= encaps
;
10250 conn
->on_tcp_tx_complete_remove
= 1;
10251 dpp_tcp_send(conn
);
10253 /* This exchange will be terminated in the TX status handler */
10256 #else /* CONFIG_DPP2 */
10258 #endif /* CONFIG_DPP2 */
10262 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
10265 struct wpabuf
*buf
;
10267 const u8
*pos
, *end
, *next
, *adv_proto
;
10273 wpa_printf(MSG_DEBUG
,
10274 "DPP: Received DPP Configuration Response over TCP");
10279 dialog_token
= *pos
++;
10280 status
= WPA_GET_LE16(pos
);
10281 if (status
!= WLAN_STATUS_SUCCESS
) {
10282 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
10286 pos
+= 2; /* ignore GAS Comeback Delay */
10290 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
10291 slen
> end
- pos
|| slen
< 2)
10295 pos
++; /* skip QueryRespLenLimit and PAME-BI */
10297 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
10298 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
10299 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
10303 /* Query Response */
10306 slen
= WPA_GET_LE16(pos
);
10308 if (slen
> end
- pos
)
10311 buf
= wpabuf_alloc(slen
);
10314 wpabuf_put_data(buf
, pos
, slen
);
10316 if (!conn
->relay
&& !conn
->ctrl
)
10317 return dpp_tcp_rx_gas_resp(conn
, buf
);
10319 if (!conn
->relay
) {
10320 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
10324 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
10325 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
10326 dialog_token
, 0, buf
);
10332 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
10334 struct dpp_connection
*conn
= eloop_ctx
;
10338 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
10341 if (conn
->msg_len_octets
< 4) {
10344 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
10345 4 - conn
->msg_len_octets
, 0);
10347 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
10349 dpp_connection_remove(conn
);
10353 wpa_printf(MSG_DEBUG
,
10354 "DPP: No more data available over TCP");
10355 dpp_connection_remove(conn
);
10358 wpa_printf(MSG_DEBUG
,
10359 "DPP: Received %d/%d octet(s) of message length field",
10360 res
, (int) (4 - conn
->msg_len_octets
));
10361 conn
->msg_len_octets
+= res
;
10363 if (conn
->msg_len_octets
< 4) {
10364 wpa_printf(MSG_DEBUG
,
10365 "DPP: Need %d more octets of message length field",
10366 (int) (4 - conn
->msg_len_octets
));
10370 msglen
= WPA_GET_BE32(conn
->msg_len
);
10371 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
10372 if (msglen
> 65535) {
10373 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
10374 dpp_connection_remove(conn
);
10378 wpabuf_free(conn
->msg
);
10379 conn
->msg
= wpabuf_alloc(msglen
);
10383 wpa_printf(MSG_DEBUG
,
10384 "DPP: No buffer available for receiving the message");
10385 dpp_connection_remove(conn
);
10389 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
10390 (unsigned int) wpabuf_tailroom(conn
->msg
));
10392 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
10394 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
10395 dpp_connection_remove(conn
);
10399 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
10400 dpp_connection_remove(conn
);
10403 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
10404 wpabuf_put(conn
->msg
, res
);
10406 if (wpabuf_tailroom(conn
->msg
) > 0) {
10407 wpa_printf(MSG_DEBUG
,
10408 "DPP: Need %u more octets of message payload",
10409 (unsigned int) wpabuf_tailroom(conn
->msg
));
10413 conn
->msg_len_octets
= 0;
10414 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
10415 if (wpabuf_len(conn
->msg
) < 1) {
10416 dpp_connection_remove(conn
);
10420 pos
= wpabuf_head(conn
->msg
);
10422 case WLAN_PA_VENDOR_SPECIFIC
:
10423 if (dpp_controller_rx_action(conn
, pos
+ 1,
10424 wpabuf_len(conn
->msg
) - 1) < 0)
10425 dpp_connection_remove(conn
);
10427 case WLAN_PA_GAS_INITIAL_REQ
:
10428 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
10429 wpabuf_len(conn
->msg
) - 1) < 0)
10430 dpp_connection_remove(conn
);
10432 case WLAN_PA_GAS_INITIAL_RESP
:
10433 if (dpp_rx_gas_resp(conn
, pos
+ 1,
10434 wpabuf_len(conn
->msg
) - 1) < 0)
10435 dpp_connection_remove(conn
);
10438 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
10445 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
10447 struct dpp_controller
*ctrl
= eloop_ctx
;
10448 struct sockaddr_in addr
;
10449 socklen_t addr_len
= sizeof(addr
);
10451 struct dpp_connection
*conn
;
10453 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
10455 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
10457 wpa_printf(MSG_DEBUG
,
10458 "DPP: Failed to accept new connection: %s",
10462 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
10463 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
10465 conn
= os_zalloc(sizeof(*conn
));
10469 conn
->global
= ctrl
->global
;
10473 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
10474 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10479 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
10480 dpp_controller_rx
, conn
, NULL
) < 0)
10482 conn
->read_eloop
= 1;
10484 /* TODO: eloop timeout to expire connections that do not complete in
10485 * reasonable time */
10486 dl_list_add(&ctrl
->conn
, &conn
->list
);
10495 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
10496 const struct hostapd_ip_addr
*addr
, int port
)
10498 struct dpp_connection
*conn
;
10499 struct sockaddr_storage saddr
;
10501 const u8
*hdr
, *pos
, *end
;
10504 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
10505 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
10506 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
10508 dpp_auth_deinit(auth
);
10512 conn
= os_zalloc(sizeof(*conn
));
10514 dpp_auth_deinit(auth
);
10518 conn
->global
= dpp
;
10520 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10521 if (conn
->sock
< 0)
10524 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
10525 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10530 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
10531 if (errno
!= EINPROGRESS
) {
10532 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
10538 * Continue connecting in the background; eloop will call us
10539 * once the connection is ready (or failed).
10543 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10544 dpp_conn_tx_ready
, conn
, NULL
) < 0)
10546 conn
->write_eloop
= 1;
10548 hdr
= wpabuf_head(auth
->req_msg
);
10549 end
= hdr
+ wpabuf_len(auth
->req_msg
);
10550 hdr
+= 2; /* skip Category and Actiom */
10551 pos
= hdr
+ DPP_HDR_LEN
;
10552 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
10553 if (!conn
->msg_out
)
10555 /* Message will be sent in dpp_conn_tx_ready() */
10557 /* TODO: eloop timeout to clear a connection if it does not complete
10559 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
10562 dpp_connection_free(conn
);
10567 int dpp_controller_start(struct dpp_global
*dpp
,
10568 struct dpp_controller_config
*config
)
10570 struct dpp_controller
*ctrl
;
10572 struct sockaddr_in sin
;
10575 if (!dpp
|| dpp
->controller
)
10578 ctrl
= os_zalloc(sizeof(*ctrl
));
10581 ctrl
->global
= dpp
;
10582 if (config
->configurator_params
)
10583 ctrl
->configurator_params
=
10584 os_strdup(config
->configurator_params
);
10585 dl_list_init(&ctrl
->conn
);
10586 /* TODO: configure these somehow */
10587 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
10588 ctrl
->qr_mutual
= 0;
10590 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10591 if (ctrl
->sock
< 0)
10594 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
10595 &on
, sizeof(on
)) < 0) {
10596 wpa_printf(MSG_DEBUG
,
10597 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
10599 /* try to continue anyway */
10602 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
10603 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10609 os_memset(&sin
, 0, sizeof(sin
));
10610 sin
.sin_family
= AF_INET
;
10611 sin
.sin_addr
.s_addr
= INADDR_ANY
;
10612 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
10613 sin
.sin_port
= htons(port
);
10614 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
10615 wpa_printf(MSG_INFO
,
10616 "DPP: Failed to bind Controller TCP port: %s",
10620 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
10621 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
10622 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
10623 dpp_controller_tcp_cb
, ctrl
, NULL
))
10626 dpp
->controller
= ctrl
;
10627 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
10630 dpp_controller_free(ctrl
);
10635 void dpp_controller_stop(struct dpp_global
*dpp
)
10638 dpp_controller_free(dpp
->controller
);
10639 dpp
->controller
= NULL
;
10643 #endif /* CONFIG_DPP2 */