2 * DPP functionality shared between hostapd and wpa_supplicant
3 * Copyright (c) 2017, Qualcomm Atheros, Inc.
4 * Copyright (c) 2018-2020, The Linux Foundation
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
10 #include "utils/includes.h"
12 #include <openssl/opensslv.h>
13 #include <openssl/err.h>
14 #include <openssl/asn1.h>
15 #include <openssl/asn1t.h>
17 #include "utils/common.h"
18 #include "utils/base64.h"
19 #include "utils/json.h"
20 #include "utils/ip_addr.h"
21 #include "utils/eloop.h"
22 #include "common/ieee802_11_common.h"
23 #include "common/ieee802_11_defs.h"
24 #include "common/wpa_ctrl.h"
25 #include "common/gas.h"
26 #include "crypto/crypto.h"
27 #include "crypto/random.h"
28 #include "crypto/aes.h"
29 #include "crypto/aes_siv.h"
30 #include "crypto/sha384.h"
31 #include "crypto/sha512.h"
33 #include "drivers/driver.h"
37 static const char * dpp_netrole_str(enum dpp_netrole netrole
);
39 #ifdef CONFIG_TESTING_OPTIONS
40 enum dpp_test_behavior dpp_test
= DPP_TEST_DISABLED
;
41 u8 dpp_pkex_own_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
42 u8 dpp_pkex_peer_mac_override
[ETH_ALEN
] = { 0, 0, 0, 0, 0, 0 };
43 u8 dpp_pkex_ephemeral_key_override
[600];
44 size_t dpp_pkex_ephemeral_key_override_len
= 0;
45 u8 dpp_protocol_key_override
[600];
46 size_t dpp_protocol_key_override_len
= 0;
47 u8 dpp_nonce_override
[DPP_MAX_NONCE_LEN
];
48 size_t dpp_nonce_override_len
= 0;
50 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
51 const struct dpp_curve_params
*curve
);
52 #endif /* CONFIG_TESTING_OPTIONS */
54 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
55 (defined(LIBRESSL_VERSION_NUMBER) && \
56 LIBRESSL_VERSION_NUMBER < 0x20700000L)
57 /* Compatibility wrappers for older versions. */
59 static int ECDSA_SIG_set0(ECDSA_SIG
*sig
, BIGNUM
*r
, BIGNUM
*s
)
67 static void ECDSA_SIG_get0(const ECDSA_SIG
*sig
, const BIGNUM
**pr
,
79 struct dpp_connection
{
81 struct dpp_controller
*ctrl
;
82 struct dpp_relay_controller
*relay
;
83 struct dpp_global
*global
;
84 struct dpp_authentication
*auth
;
86 u8 mac_addr
[ETH_ALEN
];
89 size_t msg_len_octets
;
91 struct wpabuf
*msg_out
;
93 unsigned int read_eloop
:1;
94 unsigned int write_eloop
:1;
95 unsigned int on_tcp_tx_complete_gas_done
:1;
96 unsigned int on_tcp_tx_complete_remove
:1;
97 unsigned int on_tcp_tx_complete_auth_ok
:1;
100 /* Remote Controller */
101 struct dpp_relay_controller
{
103 struct dpp_global
*global
;
104 u8 pkhash
[SHA256_MAC_LEN
];
105 struct hostapd_ip_addr ipaddr
;
107 void (*tx
)(void *ctx
, const u8
*addr
, unsigned int freq
, const u8
*msg
,
109 void (*gas_resp_tx
)(void *ctx
, const u8
*addr
, u8 dialog_token
,
110 int prot
, struct wpabuf
*buf
);
111 struct dl_list conn
; /* struct dpp_connection */
114 /* Local Controller */
115 struct dpp_controller
{
116 struct dpp_global
*global
;
120 struct dl_list conn
; /* struct dpp_connection */
121 char *configurator_params
;
126 struct dl_list bootstrap
; /* struct dpp_bootstrap_info */
127 struct dl_list configurator
; /* struct dpp_configurator */
129 struct dl_list controllers
; /* struct dpp_relay_controller */
130 struct dpp_controller
*controller
;
131 struct dl_list tcp_init
; /* struct dpp_connection */
133 int (*process_conf_obj
)(void *ctx
, struct dpp_authentication
*auth
);
134 #endif /* CONFIG_DPP2 */
137 static const struct dpp_curve_params dpp_curves
[] = {
138 /* The mandatory to support and the default NIST P-256 curve needs to
139 * be the first entry on this list. */
140 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" },
141 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" },
142 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" },
143 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" },
144 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" },
145 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" },
146 { NULL
, 0, 0, 0, 0, NULL
, 0, NULL
}
150 /* Role-specific elements for PKEX */
153 static const u8 pkex_init_x_p256
[32] = {
154 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
155 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
156 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
157 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25
159 static const u8 pkex_init_y_p256
[32] = {
160 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
161 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
162 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
163 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
165 static const u8 pkex_resp_x_p256
[32] = {
166 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
167 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
168 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
169 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76
171 static const u8 pkex_resp_y_p256
[32] = {
172 0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
173 0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
174 0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
175 0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
179 static const u8 pkex_init_x_p384
[48] = {
180 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa,
181 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68,
182 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53,
183 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac,
184 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12,
185 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3
187 static const u8 pkex_init_y_p384
[48] = {
188 0x76, 0x2f, 0x68, 0x84, 0xa6, 0xb0, 0x59, 0x29,
189 0x83, 0xa2, 0x6c, 0xa4, 0x6c, 0x3b, 0xf8, 0x56,
190 0x76, 0x11, 0x2a, 0x32, 0x90, 0xbd, 0x07, 0xc7,
191 0x37, 0x39, 0x9d, 0xdb, 0x96, 0xf3, 0x2b, 0xb6,
192 0x27, 0xbb, 0x29, 0x3c, 0x17, 0x33, 0x9d, 0x94,
193 0xc3, 0xda, 0xac, 0x46, 0xb0, 0x8e, 0x07, 0x18
195 static const u8 pkex_resp_x_p384
[48] = {
196 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98,
197 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97,
198 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92,
199 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44,
200 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf,
201 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf
203 static const u8 pkex_resp_y_p384
[48] = {
204 0xab, 0xa7, 0xdf, 0x52, 0xaa, 0xe2, 0x35, 0x0c,
205 0xe3, 0x75, 0x32, 0xe6, 0xbf, 0x06, 0xc8, 0x7c,
206 0x38, 0x29, 0x4c, 0xec, 0x82, 0xac, 0xd7, 0xa3,
207 0x09, 0xd2, 0x0e, 0x22, 0x5a, 0x74, 0x52, 0xa1,
208 0x7e, 0x54, 0x4e, 0xfe, 0xc6, 0x29, 0x33, 0x63,
209 0x15, 0xe1, 0x7b, 0xe3, 0x40, 0x1c, 0xca, 0x06
213 static const u8 pkex_init_x_p521
[66] = {
214 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23,
215 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0,
216 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76,
217 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5,
218 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38,
219 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01,
220 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e,
221 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d,
224 static const u8 pkex_init_y_p521
[66] = {
225 0x00, 0xb3, 0x8e, 0x02, 0xe4, 0x2a, 0x63, 0x59,
226 0x12, 0xc6, 0x10, 0xba, 0x3a, 0xf9, 0x02, 0x99,
227 0x3f, 0x14, 0xf0, 0x40, 0xde, 0x5c, 0xc9, 0x8b,
228 0x02, 0x55, 0xfa, 0x91, 0xb1, 0xcc, 0x6a, 0xbd,
229 0xe5, 0x62, 0xc0, 0xc5, 0xe3, 0xa1, 0x57, 0x9f,
230 0x08, 0x1a, 0xa6, 0xe2, 0xf8, 0x55, 0x90, 0xbf,
231 0xf5, 0xa6, 0xc3, 0xd8, 0x52, 0x1f, 0xb7, 0x02,
232 0x2e, 0x7c, 0xc8, 0xb3, 0x20, 0x1e, 0x79, 0x8d,
235 static const u8 pkex_resp_x_p521
[66] = {
236 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a,
237 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44,
238 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f,
239 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb,
240 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48,
241 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e,
242 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a,
243 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97,
246 static const u8 pkex_resp_y_p521
[66] = {
247 0x00, 0x46, 0x63, 0x39, 0xbe, 0xcd, 0xa4, 0x2d,
248 0xca, 0x27, 0x74, 0xd4, 0x1b, 0x91, 0x33, 0x20,
249 0x83, 0xc7, 0x3b, 0xa4, 0x09, 0x8b, 0x8e, 0xa3,
250 0x88, 0xe9, 0x75, 0x7f, 0x56, 0x7b, 0x38, 0x84,
251 0x62, 0x02, 0x7c, 0x90, 0x51, 0x07, 0xdb, 0xe9,
252 0xd0, 0xde, 0xda, 0x9a, 0x5d, 0xe5, 0x94, 0xd2,
253 0xcf, 0x9d, 0x4c, 0x33, 0x91, 0xa6, 0xc3, 0x80,
254 0xa7, 0x6e, 0x7e, 0x8d, 0xf8, 0x73, 0x6e, 0x53,
258 /* Brainpool P-256r1 */
259 static const u8 pkex_init_x_bp_p256r1
[32] = {
260 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10,
261 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca,
262 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75,
263 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8
265 static const u8 pkex_init_y_bp_p256r1
[32] = {
266 0x93, 0xca, 0xef, 0xa9, 0x66, 0x3e, 0x87, 0xcd,
267 0x52, 0x6e, 0x54, 0x13, 0xef, 0x31, 0x67, 0x30,
268 0x15, 0x13, 0x9d, 0x6d, 0xc0, 0x95, 0x32, 0xbe,
269 0x4f, 0xab, 0x5d, 0xf7, 0xbf, 0x5e, 0xaa, 0x0b
271 static const u8 pkex_resp_x_bp_p256r1
[32] = {
272 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f,
273 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a,
274 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a,
275 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3
277 static const u8 pkex_resp_y_bp_p256r1
[32] = {
278 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd,
279 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2,
280 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e,
281 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64
284 /* Brainpool P-384r1 */
285 static const u8 pkex_init_x_bp_p384r1
[48] = {
286 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd,
287 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19,
288 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06,
289 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62,
290 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30,
291 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe
293 static const u8 pkex_init_y_bp_p384r1
[48] = {
294 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99,
295 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86,
296 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32,
297 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9,
298 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e,
299 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52
301 static const u8 pkex_resp_x_bp_p384r1
[48] = {
302 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0,
303 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25,
304 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b,
305 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71,
306 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce,
307 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c
309 static const u8 pkex_resp_y_bp_p384r1
[48] = {
310 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65,
311 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04,
312 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70,
313 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c,
314 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb,
315 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1
318 /* Brainpool P-512r1 */
319 static const u8 pkex_init_x_bp_p512r1
[64] = {
320 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c,
321 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51,
322 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc,
323 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95,
324 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d,
325 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff,
326 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc,
327 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f
329 static const u8 pkex_init_y_bp_p512r1
[64] = {
330 0x50, 0xb5, 0x9b, 0xfa, 0x45, 0x67, 0x75, 0x94,
331 0x44, 0xe7, 0x68, 0xb0, 0xeb, 0x3e, 0xb3, 0xb8,
332 0xf9, 0x99, 0x05, 0xef, 0xae, 0x6c, 0xbc, 0xe3,
333 0xe1, 0xd2, 0x51, 0x54, 0xdf, 0x59, 0xd4, 0x45,
334 0x41, 0x3a, 0xa8, 0x0b, 0x76, 0x32, 0x44, 0x0e,
335 0x07, 0x60, 0x3a, 0x6e, 0xbe, 0xfe, 0xe0, 0x58,
336 0x52, 0xa0, 0xaa, 0x8b, 0xd8, 0x5b, 0xf2, 0x71,
337 0x11, 0x9a, 0x9e, 0x8f, 0x1a, 0xd1, 0xc9, 0x99
339 static const u8 pkex_resp_x_bp_p512r1
[64] = {
340 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72,
341 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76,
342 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19,
343 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e,
344 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9,
345 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88,
346 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29,
347 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e
349 static const u8 pkex_resp_y_bp_p512r1
[64] = {
350 0x80, 0x1f, 0x43, 0xd2, 0x17, 0x35, 0xec, 0x81,
351 0xd9, 0x4b, 0xdc, 0x81, 0x19, 0xd9, 0x5f, 0x68,
352 0x16, 0x84, 0xfe, 0x63, 0x4b, 0x8d, 0x5d, 0xaa,
353 0x88, 0x4a, 0x47, 0x48, 0xd4, 0xea, 0xab, 0x7d,
354 0x6a, 0xbf, 0xe1, 0x28, 0x99, 0x6a, 0x87, 0x1c,
355 0x30, 0xb4, 0x44, 0x2d, 0x75, 0xac, 0x35, 0x09,
356 0x73, 0x24, 0x3d, 0xb4, 0x43, 0xb1, 0xc1, 0x56,
357 0x56, 0xad, 0x30, 0x87, 0xf4, 0xc3, 0x00, 0xc7
361 static void dpp_debug_print_point(const char *title
, const EC_GROUP
*group
,
362 const EC_POINT
*point
)
366 char *x_str
= NULL
, *y_str
= NULL
;
368 if (!wpa_debug_show_keys
)
374 if (!ctx
|| !x
|| !y
||
375 EC_POINT_get_affine_coordinates_GFp(group
, point
, x
, y
, ctx
) != 1)
378 x_str
= BN_bn2hex(x
);
379 y_str
= BN_bn2hex(y
);
380 if (!x_str
|| !y_str
)
383 wpa_printf(MSG_DEBUG
, "%s (%s,%s)", title
, x_str
, y_str
);
394 static int dpp_hash_vector(const struct dpp_curve_params
*curve
,
395 size_t num_elem
, const u8
*addr
[], const size_t *len
,
398 if (curve
->hash_len
== 32)
399 return sha256_vector(num_elem
, addr
, len
, mac
);
400 if (curve
->hash_len
== 48)
401 return sha384_vector(num_elem
, addr
, len
, mac
);
402 if (curve
->hash_len
== 64)
403 return sha512_vector(num_elem
, addr
, len
, mac
);
408 static int dpp_hkdf_expand(size_t hash_len
, const u8
*secret
, size_t secret_len
,
409 const char *label
, u8
*out
, size_t outlen
)
412 return hmac_sha256_kdf(secret
, secret_len
, NULL
,
413 (const u8
*) label
, os_strlen(label
),
416 return hmac_sha384_kdf(secret
, secret_len
, NULL
,
417 (const u8
*) label
, os_strlen(label
),
420 return hmac_sha512_kdf(secret
, secret_len
, NULL
,
421 (const u8
*) label
, os_strlen(label
),
427 static int dpp_hmac_vector(size_t hash_len
, const u8
*key
, size_t key_len
,
428 size_t num_elem
, const u8
*addr
[],
429 const size_t *len
, u8
*mac
)
432 return hmac_sha256_vector(key
, key_len
, num_elem
, addr
, len
,
435 return hmac_sha384_vector(key
, key_len
, num_elem
, addr
, len
,
438 return hmac_sha512_vector(key
, key_len
, num_elem
, addr
, len
,
444 static int dpp_hmac(size_t hash_len
, const u8
*key
, size_t key_len
,
445 const u8
*data
, size_t data_len
, u8
*mac
)
448 return hmac_sha256(key
, key_len
, data
, data_len
, mac
);
450 return hmac_sha384(key
, key_len
, data
, data_len
, mac
);
452 return hmac_sha512(key
, key_len
, data
, data_len
, mac
);
459 static int dpp_pbkdf2_f(size_t hash_len
,
460 const u8
*password
, size_t password_len
,
461 const u8
*salt
, size_t salt_len
,
462 unsigned int iterations
, unsigned int count
, u8
*digest
)
464 unsigned char tmp
[DPP_MAX_HASH_LEN
], tmp2
[DPP_MAX_HASH_LEN
];
476 /* F(P, S, c, i) = U1 xor U2 xor ... Uc
477 * U1 = PRF(P, S || i)
482 WPA_PUT_BE32(count_buf
, count
);
483 if (dpp_hmac_vector(hash_len
, password
, password_len
, 2, addr
, len
,
486 os_memcpy(digest
, tmp
, hash_len
);
488 for (i
= 1; i
< iterations
; i
++) {
489 if (dpp_hmac(hash_len
, password
, password_len
, tmp
, hash_len
,
492 os_memcpy(tmp
, tmp2
, hash_len
);
493 for (j
= 0; j
< hash_len
; j
++)
494 digest
[j
] ^= tmp2
[j
];
501 static int dpp_pbkdf2(size_t hash_len
, const u8
*password
, size_t password_len
,
502 const u8
*salt
, size_t salt_len
, unsigned int iterations
,
503 u8
*buf
, size_t buflen
)
505 unsigned int count
= 0;
506 unsigned char *pos
= buf
;
507 size_t left
= buflen
, plen
;
508 unsigned char digest
[DPP_MAX_HASH_LEN
];
512 if (dpp_pbkdf2_f(hash_len
, password
, password_len
,
513 salt
, salt_len
, iterations
, count
, digest
))
515 plen
= left
> hash_len
? hash_len
: left
;
516 os_memcpy(pos
, digest
, plen
);
524 #endif /* CONFIG_DPP2 */
527 static int dpp_bn2bin_pad(const BIGNUM
*bn
, u8
*pos
, size_t len
)
529 int num_bytes
, offset
;
531 num_bytes
= BN_num_bytes(bn
);
532 if ((size_t) num_bytes
> len
)
534 offset
= len
- num_bytes
;
535 os_memset(pos
, 0, offset
);
536 BN_bn2bin(bn
, pos
+ offset
);
541 static struct wpabuf
* dpp_get_pubkey_point(EVP_PKEY
*pkey
, int prefix
)
548 eckey
= EVP_PKEY_get1_EC_KEY(pkey
);
551 EC_KEY_set_conv_form(eckey
, POINT_CONVERSION_UNCOMPRESSED
);
552 len
= i2o_ECPublicKey(eckey
, NULL
);
554 wpa_printf(MSG_ERROR
,
555 "DDP: Failed to determine public key encoding length");
560 buf
= wpabuf_alloc(len
);
566 pos
= wpabuf_put(buf
, len
);
567 res
= i2o_ECPublicKey(eckey
, &pos
);
570 wpa_printf(MSG_ERROR
,
571 "DDP: Failed to encode public key (res=%d/%d)",
578 /* Remove 0x04 prefix to match DPP definition */
579 pos
= wpabuf_mhead(buf
);
580 os_memmove(pos
, pos
+ 1, len
- 1);
588 static EVP_PKEY
* dpp_set_pubkey_point_group(const EC_GROUP
*group
,
589 const u8
*buf_x
, const u8
*buf_y
,
592 EC_KEY
*eckey
= NULL
;
594 EC_POINT
*point
= NULL
;
595 BIGNUM
*x
= NULL
, *y
= NULL
;
596 EVP_PKEY
*pkey
= NULL
;
600 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
604 point
= EC_POINT_new(group
);
605 x
= BN_bin2bn(buf_x
, len
, NULL
);
606 y
= BN_bin2bn(buf_y
, len
, NULL
);
607 if (!point
|| !x
|| !y
) {
608 wpa_printf(MSG_ERROR
, "DPP: Out of memory");
612 if (!EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
, ctx
)) {
613 wpa_printf(MSG_ERROR
,
614 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
615 ERR_error_string(ERR_get_error(), NULL
));
619 if (!EC_POINT_is_on_curve(group
, point
, ctx
) ||
620 EC_POINT_is_at_infinity(group
, point
)) {
621 wpa_printf(MSG_ERROR
, "DPP: Invalid point");
624 dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group
, point
);
626 eckey
= EC_KEY_new();
628 EC_KEY_set_group(eckey
, group
) != 1 ||
629 EC_KEY_set_public_key(eckey
, point
) != 1) {
630 wpa_printf(MSG_ERROR
,
631 "DPP: Failed to set EC_KEY: %s",
632 ERR_error_string(ERR_get_error(), NULL
));
635 EC_KEY_set_asn1_flag(eckey
, OPENSSL_EC_NAMED_CURVE
);
637 pkey
= EVP_PKEY_new();
638 if (!pkey
|| EVP_PKEY_set1_EC_KEY(pkey
, eckey
) != 1) {
639 wpa_printf(MSG_ERROR
, "DPP: Could not create EVP_PKEY");
647 EC_POINT_free(point
);
657 static EVP_PKEY
* dpp_set_pubkey_point(EVP_PKEY
*group_key
,
658 const u8
*buf
, size_t len
)
661 const EC_GROUP
*group
;
662 EVP_PKEY
*pkey
= NULL
;
667 eckey
= EVP_PKEY_get1_EC_KEY(group_key
);
669 wpa_printf(MSG_ERROR
,
670 "DPP: Could not get EC_KEY from group_key");
674 group
= EC_KEY_get0_group(eckey
);
676 pkey
= dpp_set_pubkey_point_group(group
, buf
, buf
+ len
/ 2,
679 wpa_printf(MSG_ERROR
, "DPP: Could not get EC group");
686 static int dpp_ecdh(EVP_PKEY
*own
, EVP_PKEY
*peer
,
687 u8
*secret
, size_t *secret_len
)
695 ctx
= EVP_PKEY_CTX_new(own
, NULL
);
697 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_CTX_new failed: %s",
698 ERR_error_string(ERR_get_error(), NULL
));
702 if (EVP_PKEY_derive_init(ctx
) != 1) {
703 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive_init failed: %s",
704 ERR_error_string(ERR_get_error(), NULL
));
708 if (EVP_PKEY_derive_set_peer(ctx
, peer
) != 1) {
709 wpa_printf(MSG_ERROR
,
710 "DPP: EVP_PKEY_derive_set_peet failed: %s",
711 ERR_error_string(ERR_get_error(), NULL
));
715 if (EVP_PKEY_derive(ctx
, NULL
, secret_len
) != 1) {
716 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive(NULL) failed: %s",
717 ERR_error_string(ERR_get_error(), NULL
));
721 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
723 int level
= *secret_len
> 200 ? MSG_ERROR
: MSG_DEBUG
;
725 /* It looks like OpenSSL can return unexpectedly large buffer
726 * need for shared secret from EVP_PKEY_derive(NULL) in some
727 * cases. For example, group 19 has shown cases where secret_len
728 * is set to 72 even though the actual length ends up being
729 * updated to 32 when EVP_PKEY_derive() is called with a buffer
730 * for the value. Work around this by trying to fetch the value
731 * and continue if it is within supported range even when the
732 * initial buffer need is claimed to be larger. */
734 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
736 if (*secret_len
> 200)
738 if (EVP_PKEY_derive(ctx
, buf
, secret_len
) != 1) {
739 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
740 ERR_error_string(ERR_get_error(), NULL
));
743 if (*secret_len
> DPP_MAX_SHARED_SECRET_LEN
) {
744 wpa_printf(MSG_ERROR
,
745 "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
749 wpa_hexdump_key(MSG_DEBUG
, "DPP: Unexpected secret_len change",
751 os_memcpy(secret
, buf
, *secret_len
);
752 forced_memzero(buf
, sizeof(buf
));
756 if (EVP_PKEY_derive(ctx
, secret
, secret_len
) != 1) {
757 wpa_printf(MSG_ERROR
, "DPP: EVP_PKEY_derive failed: %s",
758 ERR_error_string(ERR_get_error(), NULL
));
766 EVP_PKEY_CTX_free(ctx
);
771 static void dpp_auth_fail(struct dpp_authentication
*auth
, const char *txt
)
773 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
777 struct wpabuf
* dpp_alloc_msg(enum dpp_public_action_frame_type type
,
782 msg
= wpabuf_alloc(8 + len
);
785 wpabuf_put_u8(msg
, WLAN_ACTION_PUBLIC
);
786 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
787 wpabuf_put_be24(msg
, OUI_WFA
);
788 wpabuf_put_u8(msg
, DPP_OUI_TYPE
);
789 wpabuf_put_u8(msg
, 1); /* Crypto Suite */
790 wpabuf_put_u8(msg
, type
);
795 const u8
* dpp_get_attr(const u8
*buf
, size_t len
, u16 req_id
, u16
*ret_len
)
798 const u8
*pos
= buf
, *end
= buf
+ len
;
800 while (end
- pos
>= 4) {
801 id
= WPA_GET_LE16(pos
);
803 alen
= WPA_GET_LE16(pos
);
805 if (alen
> end
- pos
)
818 static const u8
* dpp_get_attr_next(const u8
*prev
, const u8
*buf
, size_t len
,
819 u16 req_id
, u16
*ret_len
)
822 const u8
*pos
, *end
= buf
+ len
;
827 pos
= prev
+ WPA_GET_LE16(prev
- 2);
828 while (end
- pos
>= 4) {
829 id
= WPA_GET_LE16(pos
);
831 alen
= WPA_GET_LE16(pos
);
833 if (alen
> end
- pos
)
846 int dpp_check_attrs(const u8
*buf
, size_t len
)
849 int wrapped_data
= 0;
853 while (end
- pos
>= 4) {
856 id
= WPA_GET_LE16(pos
);
858 alen
= WPA_GET_LE16(pos
);
860 wpa_printf(MSG_MSGDUMP
, "DPP: Attribute ID %04x len %u",
862 if (alen
> end
- pos
) {
863 wpa_printf(MSG_DEBUG
,
864 "DPP: Truncated message - not enough room for the attribute - dropped");
868 wpa_printf(MSG_DEBUG
,
869 "DPP: An unexpected attribute included after the Wrapped Data attribute");
872 if (id
== DPP_ATTR_WRAPPED_DATA
)
878 wpa_printf(MSG_DEBUG
,
879 "DPP: Unexpected octets (%d) after the last attribute",
888 void dpp_bootstrap_info_free(struct dpp_bootstrap_info
*info
)
896 EVP_PKEY_free(info
->pubkey
);
901 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type
)
904 case DPP_BOOTSTRAP_QR_CODE
:
906 case DPP_BOOTSTRAP_PKEX
:
908 case DPP_BOOTSTRAP_NFC_URI
:
915 static int dpp_uri_valid_info(const char *info
)
918 unsigned char val
= *info
++;
920 if (val
< 0x20 || val
> 0x7e || val
== 0x3b)
928 static int dpp_clone_uri(struct dpp_bootstrap_info
*bi
, const char *uri
)
930 bi
->uri
= os_strdup(uri
);
931 return bi
->uri
? 0 : -1;
935 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info
*bi
,
936 const char *chan_list
)
938 const char *pos
= chan_list
, *pos2
;
939 int opclass
= -1, channel
, freq
;
941 while (pos
&& *pos
&& *pos
!= ';') {
943 while (*pos2
>= '0' && *pos2
<= '9')
954 while (*pos
>= '0' && *pos
<= '9')
956 freq
= ieee80211_chan_to_freq(NULL
, opclass
, channel
);
957 wpa_printf(MSG_DEBUG
,
958 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d",
959 opclass
, channel
, freq
);
961 wpa_printf(MSG_DEBUG
,
962 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)",
964 } else if (bi
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
965 wpa_printf(MSG_DEBUG
,
966 "DPP: Too many channels in URI channel-list - ignore list");
970 bi
->freq
[bi
->num_freq
++] = freq
;
973 if (*pos
== ';' || *pos
== '\0')
982 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI channel-list");
987 int dpp_parse_uri_mac(struct dpp_bootstrap_info
*bi
, const char *mac
)
992 if (hwaddr_aton2(mac
, bi
->mac_addr
) < 0) {
993 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI mac");
997 wpa_printf(MSG_DEBUG
, "DPP: URI mac: " MACSTR
, MAC2STR(bi
->mac_addr
));
1003 int dpp_parse_uri_info(struct dpp_bootstrap_info
*bi
, const char *info
)
1010 end
= os_strchr(info
, ';');
1012 end
= info
+ os_strlen(info
);
1013 bi
->info
= os_malloc(end
- info
+ 1);
1016 os_memcpy(bi
->info
, info
, end
- info
);
1017 bi
->info
[end
- info
] = '\0';
1018 wpa_printf(MSG_DEBUG
, "DPP: URI(information): %s", bi
->info
);
1019 if (!dpp_uri_valid_info(bi
->info
)) {
1020 wpa_printf(MSG_DEBUG
, "DPP: Invalid URI information payload");
1028 static const struct dpp_curve_params
*
1029 dpp_get_curve_oid(const ASN1_OBJECT
*poid
)
1034 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1035 oid
= OBJ_txt2obj(dpp_curves
[i
].name
, 0);
1036 if (oid
&& OBJ_cmp(poid
, oid
) == 0)
1037 return &dpp_curves
[i
];
1043 static const struct dpp_curve_params
* dpp_get_curve_nid(int nid
)
1049 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1050 tmp
= OBJ_txt2nid(dpp_curves
[i
].name
);
1052 return &dpp_curves
[i
];
1058 static int dpp_parse_uri_pk(struct dpp_bootstrap_info
*bi
, const char *info
)
1064 const unsigned char *p
;
1066 X509_PUBKEY
*pub
= NULL
;
1067 ASN1_OBJECT
*ppkalg
;
1068 const unsigned char *pk
;
1071 #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
1072 (defined(LIBRESSL_VERSION_NUMBER) && \
1073 LIBRESSL_VERSION_NUMBER < 0x20800000L)
1074 ASN1_OBJECT
*pa_oid
;
1076 const ASN1_OBJECT
*pa_oid
;
1080 const ASN1_OBJECT
*poid
;
1083 end
= os_strchr(info
, ';');
1087 data
= base64_decode(info
, end
- info
, &data_len
);
1089 wpa_printf(MSG_DEBUG
,
1090 "DPP: Invalid base64 encoding on URI public-key");
1093 wpa_hexdump(MSG_DEBUG
, "DPP: Base64 decoded URI public-key",
1096 if (sha256_vector(1, (const u8
**) &data
, &data_len
,
1097 bi
->pubkey_hash
) < 0) {
1098 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1102 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash",
1103 bi
->pubkey_hash
, SHA256_MAC_LEN
);
1105 /* DER encoded ASN.1 SubjectPublicKeyInfo
1107 * SubjectPublicKeyInfo ::= SEQUENCE {
1108 * algorithm AlgorithmIdentifier,
1109 * subjectPublicKey BIT STRING }
1111 * AlgorithmIdentifier ::= SEQUENCE {
1112 * algorithm OBJECT IDENTIFIER,
1113 * parameters ANY DEFINED BY algorithm OPTIONAL }
1115 * subjectPublicKey = compressed format public key per ANSI X9.63
1116 * algorithm = ecPublicKey (1.2.840.10045.2.1)
1117 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
1118 * prime256v1 (1.2.840.10045.3.1.7)
1122 pkey
= d2i_PUBKEY(NULL
, &p
, data_len
);
1126 wpa_printf(MSG_DEBUG
,
1127 "DPP: Could not parse URI public-key SubjectPublicKeyInfo");
1131 if (EVP_PKEY_type(EVP_PKEY_id(pkey
)) != EVP_PKEY_EC
) {
1132 wpa_printf(MSG_DEBUG
,
1133 "DPP: SubjectPublicKeyInfo does not describe an EC key");
1134 EVP_PKEY_free(pkey
);
1138 res
= X509_PUBKEY_set(&pub
, pkey
);
1140 wpa_printf(MSG_DEBUG
, "DPP: Could not set pubkey");
1144 res
= X509_PUBKEY_get0_param(&ppkalg
, &pk
, &ppklen
, &pa
, pub
);
1146 wpa_printf(MSG_DEBUG
,
1147 "DPP: Could not extract SubjectPublicKeyInfo parameters");
1150 res
= OBJ_obj2txt(buf
, sizeof(buf
), ppkalg
, 0);
1151 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1152 wpa_printf(MSG_DEBUG
,
1153 "DPP: Could not extract SubjectPublicKeyInfo algorithm");
1156 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey algorithm: %s", buf
);
1157 if (os_strcmp(buf
, "id-ecPublicKey") != 0) {
1158 wpa_printf(MSG_DEBUG
,
1159 "DPP: Unsupported SubjectPublicKeyInfo algorithm");
1163 X509_ALGOR_get0(&pa_oid
, &ptype
, (void *) &pval
, pa
);
1164 if (ptype
!= V_ASN1_OBJECT
) {
1165 wpa_printf(MSG_DEBUG
,
1166 "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
1170 res
= OBJ_obj2txt(buf
, sizeof(buf
), poid
, 0);
1171 if (res
< 0 || (size_t) res
>= sizeof(buf
)) {
1172 wpa_printf(MSG_DEBUG
,
1173 "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
1176 wpa_printf(MSG_DEBUG
, "DPP: URI subjectPublicKey parameters: %s", buf
);
1177 bi
->curve
= dpp_get_curve_oid(poid
);
1179 wpa_printf(MSG_DEBUG
,
1180 "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
1185 wpa_hexdump(MSG_DEBUG
, "DPP: URI subjectPublicKey", pk
, ppklen
);
1187 X509_PUBKEY_free(pub
);
1191 X509_PUBKEY_free(pub
);
1192 EVP_PKEY_free(pkey
);
1197 static struct dpp_bootstrap_info
* dpp_parse_uri(const char *uri
)
1199 const char *pos
= uri
;
1201 const char *chan_list
= NULL
, *mac
= NULL
, *info
= NULL
, *pk
= NULL
;
1202 struct dpp_bootstrap_info
*bi
;
1204 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: URI", uri
, os_strlen(uri
));
1206 if (os_strncmp(pos
, "DPP:", 4) != 0) {
1207 wpa_printf(MSG_INFO
, "DPP: Not a DPP URI");
1213 end
= os_strchr(pos
, ';');
1218 /* Handle terminating ";;" and ignore unexpected ";"
1219 * for parsing robustness. */
1224 if (pos
[0] == 'C' && pos
[1] == ':' && !chan_list
)
1225 chan_list
= pos
+ 2;
1226 else if (pos
[0] == 'M' && pos
[1] == ':' && !mac
)
1228 else if (pos
[0] == 'I' && pos
[1] == ':' && !info
)
1230 else if (pos
[0] == 'K' && pos
[1] == ':' && !pk
)
1233 wpa_hexdump_ascii(MSG_DEBUG
,
1234 "DPP: Ignore unrecognized URI parameter",
1240 wpa_printf(MSG_INFO
, "DPP: URI missing public-key");
1244 bi
= os_zalloc(sizeof(*bi
));
1248 if (dpp_clone_uri(bi
, uri
) < 0 ||
1249 dpp_parse_uri_chan_list(bi
, chan_list
) < 0 ||
1250 dpp_parse_uri_mac(bi
, mac
) < 0 ||
1251 dpp_parse_uri_info(bi
, info
) < 0 ||
1252 dpp_parse_uri_pk(bi
, pk
) < 0) {
1253 dpp_bootstrap_info_free(bi
);
1261 static void dpp_debug_print_key(const char *title
, EVP_PKEY
*key
)
1268 unsigned char *der
= NULL
;
1270 const EC_GROUP
*group
;
1271 const EC_POINT
*point
;
1273 out
= BIO_new(BIO_s_mem());
1277 EVP_PKEY_print_private(out
, key
, 0, NULL
);
1278 rlen
= BIO_ctrl_pending(out
);
1279 txt
= os_malloc(rlen
+ 1);
1281 res
= BIO_read(out
, txt
, rlen
);
1284 wpa_printf(MSG_DEBUG
, "%s: %s", title
, txt
);
1290 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1294 group
= EC_KEY_get0_group(eckey
);
1295 point
= EC_KEY_get0_public_key(eckey
);
1297 dpp_debug_print_point(title
, group
, point
);
1299 der_len
= i2d_ECPrivateKey(eckey
, &der
);
1301 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECPrivateKey", der
, der_len
);
1305 der_len
= i2d_EC_PUBKEY(eckey
, &der
);
1307 wpa_hexdump(MSG_DEBUG
, "DPP: EC_PUBKEY", der
, der_len
);
1315 static EVP_PKEY
* dpp_gen_keypair(const struct dpp_curve_params
*curve
)
1317 EVP_PKEY_CTX
*kctx
= NULL
;
1318 EC_KEY
*ec_params
= NULL
;
1319 EVP_PKEY
*params
= NULL
, *key
= NULL
;
1322 wpa_printf(MSG_DEBUG
, "DPP: Generating a keypair");
1324 nid
= OBJ_txt2nid(curve
->name
);
1325 if (nid
== NID_undef
) {
1326 wpa_printf(MSG_INFO
, "DPP: Unsupported curve %s", curve
->name
);
1330 ec_params
= EC_KEY_new_by_curve_name(nid
);
1332 wpa_printf(MSG_ERROR
,
1333 "DPP: Failed to generate EC_KEY parameters");
1336 EC_KEY_set_asn1_flag(ec_params
, OPENSSL_EC_NAMED_CURVE
);
1337 params
= EVP_PKEY_new();
1338 if (!params
|| EVP_PKEY_set1_EC_KEY(params
, ec_params
) != 1) {
1339 wpa_printf(MSG_ERROR
,
1340 "DPP: Failed to generate EVP_PKEY parameters");
1344 kctx
= EVP_PKEY_CTX_new(params
, NULL
);
1346 EVP_PKEY_keygen_init(kctx
) != 1 ||
1347 EVP_PKEY_keygen(kctx
, &key
) != 1) {
1348 wpa_printf(MSG_ERROR
, "DPP: Failed to generate EC key");
1353 if (wpa_debug_show_keys
)
1354 dpp_debug_print_key("Own generated key", key
);
1357 EC_KEY_free(ec_params
);
1358 EVP_PKEY_free(params
);
1359 EVP_PKEY_CTX_free(kctx
);
1364 static const struct dpp_curve_params
*
1365 dpp_get_curve_name(const char *name
)
1369 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1370 if (os_strcmp(name
, dpp_curves
[i
].name
) == 0 ||
1371 (dpp_curves
[i
].jwk_crv
&&
1372 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0))
1373 return &dpp_curves
[i
];
1379 static const struct dpp_curve_params
*
1380 dpp_get_curve_jwk_crv(const char *name
)
1384 for (i
= 0; dpp_curves
[i
].name
; i
++) {
1385 if (dpp_curves
[i
].jwk_crv
&&
1386 os_strcmp(name
, dpp_curves
[i
].jwk_crv
) == 0)
1387 return &dpp_curves
[i
];
1393 static EVP_PKEY
* dpp_set_keypair(const struct dpp_curve_params
**curve
,
1394 const u8
*privkey
, size_t privkey_len
)
1398 const EC_GROUP
*group
;
1401 pkey
= EVP_PKEY_new();
1404 eckey
= d2i_ECPrivateKey(NULL
, &privkey
, privkey_len
);
1406 wpa_printf(MSG_INFO
,
1407 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
1408 ERR_error_string(ERR_get_error(), NULL
));
1409 EVP_PKEY_free(pkey
);
1412 group
= EC_KEY_get0_group(eckey
);
1415 EVP_PKEY_free(pkey
);
1418 nid
= EC_GROUP_get_curve_name(group
);
1419 *curve
= dpp_get_curve_nid(nid
);
1421 wpa_printf(MSG_INFO
,
1422 "DPP: Unsupported curve (nid=%d) in pre-assigned key",
1425 EVP_PKEY_free(pkey
);
1429 if (EVP_PKEY_assign_EC_KEY(pkey
, eckey
) != 1) {
1431 EVP_PKEY_free(pkey
);
1439 /* AlgorithmIdentifier ecPublicKey with optional parameters present
1440 * as an OID identifying the curve */
1442 /* Compressed format public key per ANSI X9.63 */
1443 ASN1_BIT_STRING
*pub_key
;
1444 } DPP_BOOTSTRAPPING_KEY
;
1446 ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY
) = {
1447 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, alg
, X509_ALGOR
),
1448 ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY
, pub_key
, ASN1_BIT_STRING
)
1449 } ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY
);
1451 IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY
);
1454 static struct wpabuf
* dpp_bootstrap_key_der(EVP_PKEY
*key
)
1456 unsigned char *der
= NULL
;
1459 struct wpabuf
*ret
= NULL
;
1461 const EC_GROUP
*group
;
1462 const EC_POINT
*point
;
1464 DPP_BOOTSTRAPPING_KEY
*bootstrap
= NULL
;
1468 eckey
= EVP_PKEY_get1_EC_KEY(key
);
1472 group
= EC_KEY_get0_group(eckey
);
1473 point
= EC_KEY_get0_public_key(eckey
);
1474 if (!group
|| !point
)
1476 dpp_debug_print_point("DPP: bootstrap public key", group
, point
);
1477 nid
= EC_GROUP_get_curve_name(group
);
1479 bootstrap
= DPP_BOOTSTRAPPING_KEY_new();
1481 X509_ALGOR_set0(bootstrap
->alg
, OBJ_nid2obj(EVP_PKEY_EC
),
1482 V_ASN1_OBJECT
, (void *) OBJ_nid2obj(nid
)) != 1)
1485 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1490 der
= OPENSSL_malloc(len
);
1493 len
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
,
1496 OPENSSL_free(bootstrap
->pub_key
->data
);
1497 bootstrap
->pub_key
->data
= der
;
1499 bootstrap
->pub_key
->length
= len
;
1500 /* No unused bits */
1501 bootstrap
->pub_key
->flags
&= ~(ASN1_STRING_FLAG_BITS_LEFT
| 0x07);
1502 bootstrap
->pub_key
->flags
|= ASN1_STRING_FLAG_BITS_LEFT
;
1504 der_len
= i2d_DPP_BOOTSTRAPPING_KEY(bootstrap
, &der
);
1506 wpa_printf(MSG_ERROR
,
1507 "DDP: Failed to build DER encoded public key");
1511 ret
= wpabuf_alloc_copy(der
, der_len
);
1513 DPP_BOOTSTRAPPING_KEY_free(bootstrap
);
1521 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info
*bi
)
1528 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1531 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1534 addr
[0] = wpabuf_head(der
);
1535 len
[0] = wpabuf_len(der
);
1536 res
= sha256_vector(1, addr
, len
, bi
->pubkey_hash
);
1538 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1540 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1547 static int dpp_keygen(struct dpp_bootstrap_info
*bi
, const char *curve
,
1548 const u8
*privkey
, size_t privkey_len
)
1550 char *base64
= NULL
;
1553 struct wpabuf
*der
= NULL
;
1558 bi
->curve
= &dpp_curves
[0];
1560 bi
->curve
= dpp_get_curve_name(curve
);
1562 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
1568 bi
->pubkey
= dpp_set_keypair(&bi
->curve
, privkey
, privkey_len
);
1570 bi
->pubkey
= dpp_gen_keypair(bi
->curve
);
1575 der
= dpp_bootstrap_key_der(bi
->pubkey
);
1578 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Compressed public key (DER)",
1581 addr
[0] = wpabuf_head(der
);
1582 len
= wpabuf_len(der
);
1583 res
= sha256_vector(1, addr
, &len
, bi
->pubkey_hash
);
1585 wpa_printf(MSG_DEBUG
, "DPP: Failed to hash public key");
1588 wpa_hexdump(MSG_DEBUG
, "DPP: Public key hash", bi
->pubkey_hash
,
1591 base64
= base64_encode(wpabuf_head(der
), wpabuf_len(der
), &len
);
1599 pos
= os_strchr(pos
, '\n');
1602 os_memmove(pos
, pos
+ 1, end
- pos
);
1614 static int dpp_derive_k1(const u8
*Mx
, size_t Mx_len
, u8
*k1
,
1615 unsigned int hash_len
)
1617 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1618 const char *info
= "first intermediate key";
1621 /* k1 = HKDF(<>, "first intermediate key", M.x) */
1623 /* HKDF-Extract(<>, M.x) */
1624 os_memset(salt
, 0, hash_len
);
1625 if (dpp_hmac(hash_len
, salt
, hash_len
, Mx
, Mx_len
, prk
) < 0)
1627 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)",
1630 /* HKDF-Expand(PRK, info, L) */
1631 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k1
, hash_len
);
1632 os_memset(prk
, 0, hash_len
);
1636 wpa_hexdump_key(MSG_DEBUG
, "DPP: k1 = HKDF-Expand(PRK, info, L)",
1642 static int dpp_derive_k2(const u8
*Nx
, size_t Nx_len
, u8
*k2
,
1643 unsigned int hash_len
)
1645 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
1646 const char *info
= "second intermediate key";
1649 /* k2 = HKDF(<>, "second intermediate key", N.x) */
1651 /* HKDF-Extract(<>, N.x) */
1652 os_memset(salt
, 0, hash_len
);
1653 res
= dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
);
1656 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
1659 /* HKDF-Expand(PRK, info, L) */
1660 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, k2
, hash_len
);
1661 os_memset(prk
, 0, hash_len
);
1665 wpa_hexdump_key(MSG_DEBUG
, "DPP: k2 = HKDF-Expand(PRK, info, L)",
1671 static int dpp_derive_ke(struct dpp_authentication
*auth
, u8
*ke
,
1672 unsigned int hash_len
)
1675 u8 nonces
[2 * DPP_MAX_NONCE_LEN
];
1676 const char *info_ke
= "DPP Key";
1677 u8 prk
[DPP_MAX_HASH_LEN
];
1681 size_t num_elem
= 0;
1683 if (!auth
->Mx_len
|| !auth
->Nx_len
) {
1684 wpa_printf(MSG_DEBUG
,
1685 "DPP: Mx/Nx not available - cannot derive ke");
1689 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */
1691 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */
1692 nonce_len
= auth
->curve
->nonce_len
;
1693 os_memcpy(nonces
, auth
->i_nonce
, nonce_len
);
1694 os_memcpy(&nonces
[nonce_len
], auth
->r_nonce
, nonce_len
);
1695 addr
[num_elem
] = auth
->Mx
;
1696 len
[num_elem
] = auth
->Mx_len
;
1698 addr
[num_elem
] = auth
->Nx
;
1699 len
[num_elem
] = auth
->Nx_len
;
1701 if (auth
->peer_bi
&& auth
->own_bi
) {
1702 if (!auth
->Lx_len
) {
1703 wpa_printf(MSG_DEBUG
,
1704 "DPP: Lx not available - cannot derive ke");
1707 addr
[num_elem
] = auth
->Lx
;
1708 len
[num_elem
] = auth
->secret_len
;
1711 res
= dpp_hmac_vector(hash_len
, nonces
, 2 * nonce_len
,
1712 num_elem
, addr
, len
, prk
);
1715 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
1718 /* HKDF-Expand(PRK, info, L) */
1719 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info_ke
, ke
, hash_len
);
1720 os_memset(prk
, 0, hash_len
);
1724 wpa_hexdump_key(MSG_DEBUG
, "DPP: ke = HKDF-Expand(PRK, info, L)",
1730 static void dpp_build_attr_status(struct wpabuf
*msg
,
1731 enum dpp_status_error status
)
1733 wpa_printf(MSG_DEBUG
, "DPP: Status %d", status
);
1734 wpabuf_put_le16(msg
, DPP_ATTR_STATUS
);
1735 wpabuf_put_le16(msg
, 1);
1736 wpabuf_put_u8(msg
, status
);
1740 static void dpp_build_attr_r_bootstrap_key_hash(struct wpabuf
*msg
,
1744 wpa_printf(MSG_DEBUG
, "DPP: R-Bootstrap Key Hash");
1745 wpabuf_put_le16(msg
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
);
1746 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1747 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1752 static void dpp_build_attr_i_bootstrap_key_hash(struct wpabuf
*msg
,
1756 wpa_printf(MSG_DEBUG
, "DPP: I-Bootstrap Key Hash");
1757 wpabuf_put_le16(msg
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
);
1758 wpabuf_put_le16(msg
, SHA256_MAC_LEN
);
1759 wpabuf_put_data(msg
, hash
, SHA256_MAC_LEN
);
1764 static struct wpabuf
* dpp_auth_build_req(struct dpp_authentication
*auth
,
1765 const struct wpabuf
*pi
,
1767 const u8
*r_pubkey_hash
,
1768 const u8
*i_pubkey_hash
,
1769 unsigned int neg_freq
)
1772 u8 clear
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1];
1773 u8 wrapped_data
[4 + DPP_MAX_NONCE_LEN
+ 4 + 1 + AES_BLOCK_SIZE
];
1776 size_t len
[2], siv_len
, attr_len
;
1777 u8
*attr_start
, *attr_end
;
1779 /* Build DPP Authentication Request frame attributes */
1780 attr_len
= 2 * (4 + SHA256_MAC_LEN
) + 4 + (pi
? wpabuf_len(pi
) : 0) +
1781 4 + sizeof(wrapped_data
);
1786 #endif /* CONFIG_DPP2 */
1787 #ifdef CONFIG_TESTING_OPTIONS
1788 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
)
1790 #endif /* CONFIG_TESTING_OPTIONS */
1791 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ
, attr_len
);
1795 attr_start
= wpabuf_put(msg
, 0);
1797 /* Responder Bootstrapping Key Hash */
1798 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1800 /* Initiator Bootstrapping Key Hash */
1801 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1803 /* Initiator Protocol Key */
1805 wpabuf_put_le16(msg
, DPP_ATTR_I_PROTOCOL_KEY
);
1806 wpabuf_put_le16(msg
, wpabuf_len(pi
));
1807 wpabuf_put_buf(msg
, pi
);
1812 u8 op_class
, channel
;
1814 if (ieee80211_freq_to_channel_ext(neg_freq
, 0, 0, &op_class
,
1816 NUM_HOSTAPD_MODES
) {
1817 wpa_printf(MSG_INFO
,
1818 "DPP: Unsupported negotiation frequency request: %d",
1823 wpabuf_put_le16(msg
, DPP_ATTR_CHANNEL
);
1824 wpabuf_put_le16(msg
, 2);
1825 wpabuf_put_u8(msg
, op_class
);
1826 wpabuf_put_u8(msg
, channel
);
1830 /* Protocol Version */
1831 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1832 wpabuf_put_le16(msg
, 1);
1833 wpabuf_put_u8(msg
, 2);
1834 #endif /* CONFIG_DPP2 */
1836 #ifdef CONFIG_TESTING_OPTIONS
1837 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ
) {
1838 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
1839 goto skip_wrapped_data
;
1841 #endif /* CONFIG_TESTING_OPTIONS */
1843 /* Wrapped data ({I-nonce, I-capabilities}k1) */
1846 #ifdef CONFIG_TESTING_OPTIONS
1847 if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_REQ
) {
1848 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
1851 if (dpp_test
== DPP_TEST_INVALID_I_NONCE_AUTH_REQ
) {
1852 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-nonce");
1853 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1855 WPA_PUT_LE16(pos
, nonce_len
- 1);
1857 os_memcpy(pos
, auth
->i_nonce
, nonce_len
- 1);
1858 pos
+= nonce_len
- 1;
1861 #endif /* CONFIG_TESTING_OPTIONS */
1864 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
1866 WPA_PUT_LE16(pos
, nonce_len
);
1868 os_memcpy(pos
, auth
->i_nonce
, nonce_len
);
1871 #ifdef CONFIG_TESTING_OPTIONS
1873 if (dpp_test
== DPP_TEST_NO_I_CAPAB_AUTH_REQ
) {
1874 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-capab");
1877 #endif /* CONFIG_TESTING_OPTIONS */
1879 /* I-capabilities */
1880 WPA_PUT_LE16(pos
, DPP_ATTR_I_CAPABILITIES
);
1882 WPA_PUT_LE16(pos
, 1);
1884 auth
->i_capab
= auth
->allowed_roles
;
1885 *pos
++ = auth
->i_capab
;
1886 #ifdef CONFIG_TESTING_OPTIONS
1887 if (dpp_test
== DPP_TEST_ZERO_I_CAPAB
) {
1888 wpa_printf(MSG_INFO
, "DPP: TESTING - zero I-capabilities");
1892 #endif /* CONFIG_TESTING_OPTIONS */
1894 attr_end
= wpabuf_put(msg
, 0);
1896 /* OUI, OUI type, Crypto Suite, DPP frame type */
1897 addr
[0] = wpabuf_head_u8(msg
) + 2;
1898 len
[0] = 3 + 1 + 1 + 1;
1899 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
1901 /* Attributes before Wrapped Data */
1902 addr
[1] = attr_start
;
1903 len
[1] = attr_end
- attr_start
;
1904 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
1906 siv_len
= pos
- clear
;
1907 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
1908 if (aes_siv_encrypt(auth
->k1
, auth
->curve
->hash_len
, clear
, siv_len
,
1909 2, addr
, len
, wrapped_data
) < 0) {
1913 siv_len
+= AES_BLOCK_SIZE
;
1914 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
1915 wrapped_data
, siv_len
);
1917 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
1918 wpabuf_put_le16(msg
, siv_len
);
1919 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
1921 #ifdef CONFIG_TESTING_OPTIONS
1922 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ
) {
1923 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
1924 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
1927 #endif /* CONFIG_TESTING_OPTIONS */
1929 wpa_hexdump_buf(MSG_DEBUG
,
1930 "DPP: Authentication Request frame attributes", msg
);
1936 static struct wpabuf
* dpp_auth_build_resp(struct dpp_authentication
*auth
,
1937 enum dpp_status_error status
,
1938 const struct wpabuf
*pr
,
1940 const u8
*r_pubkey_hash
,
1941 const u8
*i_pubkey_hash
,
1942 const u8
*r_nonce
, const u8
*i_nonce
,
1943 const u8
*wrapped_r_auth
,
1944 size_t wrapped_r_auth_len
,
1948 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \
1949 4 + 4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE
1950 u8 clear
[DPP_AUTH_RESP_CLEAR_LEN
];
1951 u8 wrapped_data
[DPP_AUTH_RESP_CLEAR_LEN
+ AES_BLOCK_SIZE
];
1953 size_t len
[2], siv_len
, attr_len
;
1954 u8
*attr_start
, *attr_end
, *pos
;
1956 auth
->waiting_auth_conf
= 1;
1957 auth
->auth_resp_tries
= 0;
1959 /* Build DPP Authentication Response frame attributes */
1960 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
1961 4 + (pr
? wpabuf_len(pr
) : 0) + 4 + sizeof(wrapped_data
);
1964 #endif /* CONFIG_DPP2 */
1965 #ifdef CONFIG_TESTING_OPTIONS
1966 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
)
1968 #endif /* CONFIG_TESTING_OPTIONS */
1969 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP
, attr_len
);
1973 attr_start
= wpabuf_put(msg
, 0);
1977 dpp_build_attr_status(msg
, status
);
1979 /* Responder Bootstrapping Key Hash */
1980 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
1982 /* Initiator Bootstrapping Key Hash (mutual authentication) */
1983 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
1985 /* Responder Protocol Key */
1987 wpabuf_put_le16(msg
, DPP_ATTR_R_PROTOCOL_KEY
);
1988 wpabuf_put_le16(msg
, wpabuf_len(pr
));
1989 wpabuf_put_buf(msg
, pr
);
1993 /* Protocol Version */
1994 if (auth
->peer_version
>= 2) {
1995 wpabuf_put_le16(msg
, DPP_ATTR_PROTOCOL_VERSION
);
1996 wpabuf_put_le16(msg
, 1);
1997 wpabuf_put_u8(msg
, 2);
1999 #endif /* CONFIG_DPP2 */
2001 attr_end
= wpabuf_put(msg
, 0);
2003 #ifdef CONFIG_TESTING_OPTIONS
2004 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP
) {
2005 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2006 goto skip_wrapped_data
;
2008 #endif /* CONFIG_TESTING_OPTIONS */
2010 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */
2015 WPA_PUT_LE16(pos
, DPP_ATTR_R_NONCE
);
2017 WPA_PUT_LE16(pos
, nonce_len
);
2019 os_memcpy(pos
, r_nonce
, nonce_len
);
2025 WPA_PUT_LE16(pos
, DPP_ATTR_I_NONCE
);
2027 WPA_PUT_LE16(pos
, nonce_len
);
2029 os_memcpy(pos
, i_nonce
, nonce_len
);
2030 #ifdef CONFIG_TESTING_OPTIONS
2031 if (dpp_test
== DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP
) {
2032 wpa_printf(MSG_INFO
, "DPP: TESTING - I-nonce mismatch");
2033 pos
[nonce_len
/ 2] ^= 0x01;
2035 #endif /* CONFIG_TESTING_OPTIONS */
2039 #ifdef CONFIG_TESTING_OPTIONS
2040 if (dpp_test
== DPP_TEST_NO_R_CAPAB_AUTH_RESP
) {
2041 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-capab");
2044 #endif /* CONFIG_TESTING_OPTIONS */
2046 /* R-capabilities */
2047 WPA_PUT_LE16(pos
, DPP_ATTR_R_CAPABILITIES
);
2049 WPA_PUT_LE16(pos
, 1);
2051 auth
->r_capab
= auth
->configurator
? DPP_CAPAB_CONFIGURATOR
:
2053 *pos
++ = auth
->r_capab
;
2054 #ifdef CONFIG_TESTING_OPTIONS
2055 if (dpp_test
== DPP_TEST_ZERO_R_CAPAB
) {
2056 wpa_printf(MSG_INFO
, "DPP: TESTING - zero R-capabilities");
2058 } else if (dpp_test
== DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP
) {
2059 wpa_printf(MSG_INFO
,
2060 "DPP: TESTING - incompatible R-capabilities");
2061 if ((auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) ==
2062 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
))
2065 pos
[-1] = auth
->configurator
? DPP_CAPAB_ENROLLEE
:
2066 DPP_CAPAB_CONFIGURATOR
;
2069 #endif /* CONFIG_TESTING_OPTIONS */
2071 if (wrapped_r_auth
) {
2073 WPA_PUT_LE16(pos
, DPP_ATTR_WRAPPED_DATA
);
2075 WPA_PUT_LE16(pos
, wrapped_r_auth_len
);
2077 os_memcpy(pos
, wrapped_r_auth
, wrapped_r_auth_len
);
2078 pos
+= wrapped_r_auth_len
;
2081 /* OUI, OUI type, Crypto Suite, DPP frame type */
2082 addr
[0] = wpabuf_head_u8(msg
) + 2;
2083 len
[0] = 3 + 1 + 1 + 1;
2084 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
2086 /* Attributes before Wrapped Data */
2087 addr
[1] = attr_start
;
2088 len
[1] = attr_end
- attr_start
;
2089 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
2091 siv_len
= pos
- clear
;
2092 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
, siv_len
);
2093 if (aes_siv_encrypt(siv_key
, auth
->curve
->hash_len
, clear
, siv_len
,
2094 2, addr
, len
, wrapped_data
) < 0) {
2098 siv_len
+= AES_BLOCK_SIZE
;
2099 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2100 wrapped_data
, siv_len
);
2102 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2103 wpabuf_put_le16(msg
, siv_len
);
2104 wpabuf_put_data(msg
, wrapped_data
, siv_len
);
2106 #ifdef CONFIG_TESTING_OPTIONS
2107 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP
) {
2108 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2109 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2112 #endif /* CONFIG_TESTING_OPTIONS */
2114 wpa_hexdump_buf(MSG_DEBUG
,
2115 "DPP: Authentication Response frame attributes", msg
);
2120 static int dpp_channel_ok_init(struct hostapd_hw_modes
*own_modes
,
2121 u16 num_modes
, unsigned int freq
)
2126 if (!own_modes
|| !num_modes
)
2129 for (m
= 0; m
< num_modes
; m
++) {
2130 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2131 if ((unsigned int) own_modes
[m
].channels
[c
].freq
!=
2134 flag
= own_modes
[m
].channels
[c
].flag
;
2135 if (!(flag
& (HOSTAPD_CHAN_DISABLED
|
2136 HOSTAPD_CHAN_NO_IR
|
2137 HOSTAPD_CHAN_RADAR
)))
2142 wpa_printf(MSG_DEBUG
, "DPP: Peer channel %u MHz not supported", freq
);
2147 static int freq_included(const unsigned int freqs
[], unsigned int num
,
2151 if (freqs
[--num
] == freq
)
2158 static void freq_to_start(unsigned int freqs
[], unsigned int num
,
2163 for (i
= 0; i
< num
; i
++) {
2164 if (freqs
[i
] == freq
)
2167 if (i
== 0 || i
>= num
)
2169 os_memmove(&freqs
[1], &freqs
[0], i
* sizeof(freqs
[0]));
2174 static int dpp_channel_intersect(struct dpp_authentication
*auth
,
2175 struct hostapd_hw_modes
*own_modes
,
2178 struct dpp_bootstrap_info
*peer_bi
= auth
->peer_bi
;
2179 unsigned int i
, freq
;
2181 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
2182 freq
= peer_bi
->freq
[i
];
2183 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2185 if (dpp_channel_ok_init(own_modes
, num_modes
, freq
))
2186 auth
->freq
[auth
->num_freq
++] = freq
;
2188 if (!auth
->num_freq
) {
2189 wpa_printf(MSG_INFO
,
2190 "DPP: No available channels for initiating DPP Authentication");
2193 auth
->curr_freq
= auth
->freq
[0];
2198 static int dpp_channel_local_list(struct dpp_authentication
*auth
,
2199 struct hostapd_hw_modes
*own_modes
,
2208 if (!own_modes
|| !num_modes
) {
2209 auth
->freq
[0] = 2412;
2210 auth
->freq
[1] = 2437;
2211 auth
->freq
[2] = 2462;
2216 for (m
= 0; m
< num_modes
; m
++) {
2217 for (c
= 0; c
< own_modes
[m
].num_channels
; c
++) {
2218 freq
= own_modes
[m
].channels
[c
].freq
;
2219 flag
= own_modes
[m
].channels
[c
].flag
;
2220 if (flag
& (HOSTAPD_CHAN_DISABLED
|
2221 HOSTAPD_CHAN_NO_IR
|
2222 HOSTAPD_CHAN_RADAR
))
2224 if (freq_included(auth
->freq
, auth
->num_freq
, freq
))
2226 auth
->freq
[auth
->num_freq
++] = freq
;
2227 if (auth
->num_freq
== DPP_BOOTSTRAP_MAX_FREQ
) {
2234 return auth
->num_freq
== 0 ? -1 : 0;
2238 static int dpp_prepare_channel_list(struct dpp_authentication
*auth
,
2239 struct hostapd_hw_modes
*own_modes
,
2243 char freqs
[DPP_BOOTSTRAP_MAX_FREQ
* 6 + 10], *pos
, *end
;
2246 if (auth
->peer_bi
->num_freq
> 0)
2247 res
= dpp_channel_intersect(auth
, own_modes
, num_modes
);
2249 res
= dpp_channel_local_list(auth
, own_modes
, num_modes
);
2253 /* Prioritize 2.4 GHz channels 6, 1, 11 (in this order) to hit the most
2254 * likely channels first. */
2255 freq_to_start(auth
->freq
, auth
->num_freq
, 2462);
2256 freq_to_start(auth
->freq
, auth
->num_freq
, 2412);
2257 freq_to_start(auth
->freq
, auth
->num_freq
, 2437);
2260 auth
->curr_freq
= auth
->freq
[0];
2263 end
= pos
+ sizeof(freqs
);
2264 for (i
= 0; i
< auth
->num_freq
; i
++) {
2265 res
= os_snprintf(pos
, end
- pos
, " %u", auth
->freq
[i
]);
2266 if (os_snprintf_error(end
- pos
, res
))
2271 wpa_printf(MSG_DEBUG
, "DPP: Possible frequencies for initiating:%s",
2278 static int dpp_gen_uri(struct dpp_bootstrap_info
*bi
)
2280 char macstr
[ETH_ALEN
* 2 + 10];
2283 len
= 4; /* "DPP:" */
2285 len
+= 3 + os_strlen(bi
->chan
); /* C:...; */
2286 if (is_zero_ether_addr(bi
->mac_addr
))
2289 os_snprintf(macstr
, sizeof(macstr
), "M:" COMPACT_MACSTR
";",
2290 MAC2STR(bi
->mac_addr
));
2291 len
+= os_strlen(macstr
); /* M:...; */
2293 len
+= 3 + os_strlen(bi
->info
); /* I:...; */
2294 len
+= 4 + os_strlen(bi
->pk
); /* K:...;; */
2297 bi
->uri
= os_malloc(len
+ 1);
2300 os_snprintf(bi
->uri
, len
+ 1, "DPP:%s%s%s%s%s%s%sK:%s;;",
2301 bi
->chan
? "C:" : "", bi
->chan
? bi
->chan
: "",
2302 bi
->chan
? ";" : "",
2304 bi
->info
? "I:" : "", bi
->info
? bi
->info
: "",
2305 bi
->info
? ";" : "",
2311 static int dpp_autogen_bootstrap_key(struct dpp_authentication
*auth
)
2313 struct dpp_bootstrap_info
*bi
;
2316 return 0; /* already generated */
2318 bi
= os_zalloc(sizeof(*bi
));
2321 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
2322 if (dpp_keygen(bi
, auth
->peer_bi
->curve
->name
, NULL
, 0) < 0 ||
2323 dpp_gen_uri(bi
) < 0)
2325 wpa_printf(MSG_DEBUG
,
2326 "DPP: Auto-generated own bootstrapping key info: URI %s",
2329 auth
->tmp_own_bi
= auth
->own_bi
= bi
;
2333 dpp_bootstrap_info_free(bi
);
2338 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2339 struct dpp_bootstrap_info
*peer_bi
,
2340 struct dpp_bootstrap_info
*own_bi
,
2341 u8 dpp_allowed_roles
,
2342 unsigned int neg_freq
,
2343 struct hostapd_hw_modes
*own_modes
,
2346 struct dpp_authentication
*auth
;
2349 struct wpabuf
*pi
= NULL
;
2350 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2351 #ifdef CONFIG_TESTING_OPTIONS
2352 u8 test_hash
[SHA256_MAC_LEN
];
2353 #endif /* CONFIG_TESTING_OPTIONS */
2355 auth
= os_zalloc(sizeof(*auth
));
2358 auth
->msg_ctx
= msg_ctx
;
2359 auth
->initiator
= 1;
2360 auth
->waiting_auth_resp
= 1;
2361 auth
->allowed_roles
= dpp_allowed_roles
;
2362 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2363 auth
->peer_bi
= peer_bi
;
2364 auth
->own_bi
= own_bi
;
2365 auth
->curve
= peer_bi
->curve
;
2367 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2368 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2371 #ifdef CONFIG_TESTING_OPTIONS
2372 if (dpp_nonce_override_len
> 0) {
2373 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2374 nonce_len
= dpp_nonce_override_len
;
2375 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2377 nonce_len
= auth
->curve
->nonce_len
;
2378 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2379 wpa_printf(MSG_ERROR
,
2380 "DPP: Failed to generate I-nonce");
2384 #else /* CONFIG_TESTING_OPTIONS */
2385 nonce_len
= auth
->curve
->nonce_len
;
2386 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2387 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2390 #endif /* CONFIG_TESTING_OPTIONS */
2391 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2393 #ifdef CONFIG_TESTING_OPTIONS
2394 if (dpp_protocol_key_override_len
) {
2395 const struct dpp_curve_params
*tmp_curve
;
2397 wpa_printf(MSG_INFO
,
2398 "DPP: TESTING - override protocol key");
2399 auth
->own_protocol_key
= dpp_set_keypair(
2400 &tmp_curve
, dpp_protocol_key_override
,
2401 dpp_protocol_key_override_len
);
2403 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2405 #else /* CONFIG_TESTING_OPTIONS */
2406 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2407 #endif /* CONFIG_TESTING_OPTIONS */
2408 if (!auth
->own_protocol_key
)
2411 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2415 /* ECDH: M = pI * BR */
2416 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2417 auth
->Mx
, &secret_len
) < 0)
2419 auth
->secret_len
= secret_len
;
2421 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2422 auth
->Mx
, auth
->secret_len
);
2423 auth
->Mx_len
= auth
->secret_len
;
2425 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2426 auth
->curve
->hash_len
) < 0)
2429 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2430 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2432 #ifdef CONFIG_TESTING_OPTIONS
2433 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2434 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2435 r_pubkey_hash
= NULL
;
2436 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2437 wpa_printf(MSG_INFO
,
2438 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2439 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2440 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2441 r_pubkey_hash
= test_hash
;
2442 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2443 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2444 i_pubkey_hash
= NULL
;
2445 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2446 wpa_printf(MSG_INFO
,
2447 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2448 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2449 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2450 i_pubkey_hash
= test_hash
;
2451 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2452 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2455 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2456 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2458 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2459 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2462 #endif /* CONFIG_TESTING_OPTIONS */
2464 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2465 i_pubkey_hash
, neg_freq
);
2473 dpp_auth_deinit(auth
);
2479 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2483 size_t json_len
, clear_len
;
2484 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2488 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2490 nonce_len
= auth
->curve
->nonce_len
;
2491 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2492 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2495 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2496 json_len
= os_strlen(json
);
2497 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configRequest JSON", json
, json_len
);
2499 /* { E-nonce, configAttrib }ke */
2500 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2501 clear
= wpabuf_alloc(clear_len
);
2502 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2503 #ifdef CONFIG_TESTING_OPTIONS
2504 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2506 #endif /* CONFIG_TESTING_OPTIONS */
2507 msg
= wpabuf_alloc(attr_len
);
2511 #ifdef CONFIG_TESTING_OPTIONS
2512 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2513 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2516 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2517 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2518 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2519 wpabuf_put_le16(clear
, nonce_len
- 1);
2520 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2523 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2524 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2525 goto skip_wrapped_data
;
2527 #endif /* CONFIG_TESTING_OPTIONS */
2530 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2531 wpabuf_put_le16(clear
, nonce_len
);
2532 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2534 #ifdef CONFIG_TESTING_OPTIONS
2536 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2537 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2538 goto skip_conf_attr_obj
;
2540 #endif /* CONFIG_TESTING_OPTIONS */
2543 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2544 wpabuf_put_le16(clear
, json_len
);
2545 wpabuf_put_data(clear
, json
, json_len
);
2547 #ifdef CONFIG_TESTING_OPTIONS
2549 #endif /* CONFIG_TESTING_OPTIONS */
2551 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2552 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2553 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2556 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2557 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2558 wpabuf_head(clear
), wpabuf_len(clear
),
2559 0, NULL
, NULL
, wrapped
) < 0)
2561 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2562 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2564 #ifdef CONFIG_TESTING_OPTIONS
2565 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2566 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2567 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2570 #endif /* CONFIG_TESTING_OPTIONS */
2572 wpa_hexdump_buf(MSG_DEBUG
,
2573 "DPP: Configuration Request frame attributes", msg
);
2584 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2586 /* Advertisement Protocol IE */
2587 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2588 wpabuf_put_u8(buf
, 8); /* Length */
2589 wpabuf_put_u8(buf
, 0x7f);
2590 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2591 wpabuf_put_u8(buf
, 5);
2592 wpabuf_put_be24(buf
, OUI_WFA
);
2593 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2594 wpabuf_put_u8(buf
, 0x01);
2598 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2601 wpabuf_put_le16(buf
, wpabuf_len(query
));
2602 wpabuf_put_buf(buf
, query
);
2606 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2609 struct wpabuf
*buf
, *conf_req
;
2611 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2613 wpa_printf(MSG_DEBUG
,
2614 "DPP: No configuration request data available");
2618 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2620 wpabuf_free(conf_req
);
2624 dpp_write_adv_proto(buf
);
2625 dpp_write_gas_query(buf
, conf_req
);
2626 wpabuf_free(conf_req
);
2627 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2633 struct wpabuf
* dpp_build_conf_req_helper(struct dpp_authentication
*auth
,
2635 enum dpp_netrole netrole
,
2636 const char *mud_url
, int *opclasses
)
2638 size_t len
, name_len
;
2639 const char *tech
= "infra";
2640 const char *dpp_name
;
2641 struct wpabuf
*buf
, *json
;
2643 #ifdef CONFIG_TESTING_OPTIONS
2644 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
2645 static const char *bogus_tech
= "knfra";
2647 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
2650 #endif /* CONFIG_TESTING_OPTIONS */
2652 dpp_name
= name
? name
: "Test";
2653 name_len
= os_strlen(dpp_name
);
2655 len
= 100 + name_len
* 6 + 1 + int_array_len(opclasses
) * 4;
2656 if (mud_url
&& mud_url
[0])
2657 len
+= 10 + os_strlen(mud_url
);
2658 json
= wpabuf_alloc(len
);
2662 json_start_object(json
, NULL
);
2663 if (json_add_string_escape(json
, "name", dpp_name
, name_len
) < 0) {
2667 json_value_sep(json
);
2668 json_add_string(json
, "wi-fi_tech", tech
);
2669 json_value_sep(json
);
2670 json_add_string(json
, "netRole", dpp_netrole_str(netrole
));
2671 if (mud_url
&& mud_url
[0]) {
2672 json_value_sep(json
);
2673 json_add_string(json
, "mudurl", mud_url
);
2678 json_value_sep(json
);
2679 json_start_array(json
, "bandSupport");
2680 for (i
= 0; opclasses
[i
]; i
++)
2681 wpabuf_printf(json
, "%s%u", i
? "," : "", opclasses
[i
]);
2682 json_end_array(json
);
2684 json_end_object(json
);
2686 buf
= dpp_build_conf_req(auth
, wpabuf_head(json
));
2693 static void dpp_auth_success(struct dpp_authentication
*auth
)
2695 wpa_printf(MSG_DEBUG
,
2696 "DPP: Authentication success - clear temporary keys");
2697 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2699 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2701 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2703 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2704 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2706 auth
->auth_success
= 1;
2710 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2712 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2715 size_t i
, num_elem
= 0;
2720 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2721 nonce_len
= auth
->curve
->nonce_len
;
2723 if (auth
->initiator
) {
2724 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2725 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2727 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2730 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2732 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2733 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2735 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2738 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2740 if (!pix
|| !prx
|| !brx
)
2743 addr
[num_elem
] = auth
->i_nonce
;
2744 len
[num_elem
] = nonce_len
;
2747 addr
[num_elem
] = auth
->r_nonce
;
2748 len
[num_elem
] = nonce_len
;
2751 addr
[num_elem
] = wpabuf_head(pix
);
2752 len
[num_elem
] = wpabuf_len(pix
) / 2;
2755 addr
[num_elem
] = wpabuf_head(prx
);
2756 len
[num_elem
] = wpabuf_len(prx
) / 2;
2760 addr
[num_elem
] = wpabuf_head(bix
);
2761 len
[num_elem
] = wpabuf_len(bix
) / 2;
2765 addr
[num_elem
] = wpabuf_head(brx
);
2766 len
[num_elem
] = wpabuf_len(brx
) / 2;
2769 addr
[num_elem
] = &zero
;
2773 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2774 for (i
= 0; i
< num_elem
; i
++)
2775 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2776 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2778 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2779 auth
->curve
->hash_len
);
2789 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2791 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2794 size_t i
, num_elem
= 0;
2799 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2800 nonce_len
= auth
->curve
->nonce_len
;
2802 if (auth
->initiator
) {
2803 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2804 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2806 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2811 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2813 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2814 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2816 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2821 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2823 if (!pix
|| !prx
|| !brx
)
2826 addr
[num_elem
] = auth
->r_nonce
;
2827 len
[num_elem
] = nonce_len
;
2830 addr
[num_elem
] = auth
->i_nonce
;
2831 len
[num_elem
] = nonce_len
;
2834 addr
[num_elem
] = wpabuf_head(prx
);
2835 len
[num_elem
] = wpabuf_len(prx
) / 2;
2838 addr
[num_elem
] = wpabuf_head(pix
);
2839 len
[num_elem
] = wpabuf_len(pix
) / 2;
2842 addr
[num_elem
] = wpabuf_head(brx
);
2843 len
[num_elem
] = wpabuf_len(brx
) / 2;
2847 addr
[num_elem
] = wpabuf_head(bix
);
2848 len
[num_elem
] = wpabuf_len(bix
) / 2;
2852 addr
[num_elem
] = &one
;
2856 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2857 for (i
= 0; i
< num_elem
; i
++)
2858 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2859 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2861 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2862 auth
->curve
->hash_len
);
2872 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2874 const EC_GROUP
*group
;
2876 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2877 const EC_POINT
*BI_point
;
2879 BIGNUM
*lx
, *sum
, *q
;
2880 const BIGNUM
*bR_bn
, *pR_bn
;
2883 /* L = ((bR + pR) modulo q) * BI */
2885 bnctx
= BN_CTX_new();
2889 if (!bnctx
|| !sum
|| !q
|| !lx
)
2891 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2894 BI_point
= EC_KEY_get0_public_key(BI
);
2895 group
= EC_KEY_get0_group(BI
);
2899 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2900 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2903 bR_bn
= EC_KEY_get0_private_key(bR
);
2904 pR_bn
= EC_KEY_get0_private_key(pR
);
2905 if (!bR_bn
|| !pR_bn
)
2907 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2908 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2910 l
= EC_POINT_new(group
);
2912 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2913 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2915 wpa_printf(MSG_ERROR
,
2916 "OpenSSL: failed: %s",
2917 ERR_error_string(ERR_get_error(), NULL
));
2921 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2923 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2924 auth
->Lx_len
= auth
->secret_len
;
2927 EC_POINT_clear_free(l
);
2939 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2941 const EC_GROUP
*group
;
2942 EC_POINT
*l
= NULL
, *sum
= NULL
;
2943 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2944 const EC_POINT
*BR_point
, *PR_point
;
2947 const BIGNUM
*bI_bn
;
2950 /* L = bI * (BR + PR) */
2952 bnctx
= BN_CTX_new();
2956 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2957 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2960 BR_point
= EC_KEY_get0_public_key(BR
);
2961 PR_point
= EC_KEY_get0_public_key(PR
);
2963 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2966 group
= EC_KEY_get0_group(bI
);
2967 bI_bn
= EC_KEY_get0_private_key(bI
);
2968 if (!group
|| !bI_bn
)
2970 sum
= EC_POINT_new(group
);
2971 l
= EC_POINT_new(group
);
2973 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2974 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2975 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2977 wpa_printf(MSG_ERROR
,
2978 "OpenSSL: failed: %s",
2979 ERR_error_string(ERR_get_error(), NULL
));
2983 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2985 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2986 auth
->Lx_len
= auth
->secret_len
;
2989 EC_POINT_clear_free(l
);
2990 EC_POINT_clear_free(sum
);
3000 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
3004 struct wpabuf
*msg
, *pr
= NULL
;
3005 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
3006 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
3007 size_t wrapped_r_auth_len
;
3009 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
3010 enum dpp_status_error status
= DPP_STATUS_OK
;
3011 #ifdef CONFIG_TESTING_OPTIONS
3012 u8 test_hash
[SHA256_MAC_LEN
];
3013 #endif /* CONFIG_TESTING_OPTIONS */
3015 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3019 #ifdef CONFIG_TESTING_OPTIONS
3020 if (dpp_nonce_override_len
> 0) {
3021 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
3022 nonce_len
= dpp_nonce_override_len
;
3023 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
3025 nonce_len
= auth
->curve
->nonce_len
;
3026 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3027 wpa_printf(MSG_ERROR
,
3028 "DPP: Failed to generate R-nonce");
3032 #else /* CONFIG_TESTING_OPTIONS */
3033 nonce_len
= auth
->curve
->nonce_len
;
3034 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3035 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
3038 #endif /* CONFIG_TESTING_OPTIONS */
3039 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
3041 EVP_PKEY_free(auth
->own_protocol_key
);
3042 #ifdef CONFIG_TESTING_OPTIONS
3043 if (dpp_protocol_key_override_len
) {
3044 const struct dpp_curve_params
*tmp_curve
;
3046 wpa_printf(MSG_INFO
,
3047 "DPP: TESTING - override protocol key");
3048 auth
->own_protocol_key
= dpp_set_keypair(
3049 &tmp_curve
, dpp_protocol_key_override
,
3050 dpp_protocol_key_override_len
);
3052 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3054 #else /* CONFIG_TESTING_OPTIONS */
3055 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3056 #endif /* CONFIG_TESTING_OPTIONS */
3057 if (!auth
->own_protocol_key
)
3060 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
3064 /* ECDH: N = pR * PI */
3065 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
3066 auth
->Nx
, &secret_len
) < 0)
3069 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3070 auth
->Nx
, auth
->secret_len
);
3071 auth
->Nx_len
= auth
->secret_len
;
3073 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3074 auth
->curve
->hash_len
) < 0)
3077 if (auth
->own_bi
&& auth
->peer_bi
) {
3078 /* Mutual authentication */
3079 if (dpp_auth_derive_l_responder(auth
) < 0)
3083 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3086 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3087 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
3088 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
3089 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
3091 #ifdef CONFIG_TESTING_OPTIONS
3092 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
3093 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
3094 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3096 #endif /* CONFIG_TESTING_OPTIONS */
3097 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3098 r_auth
, 4 + auth
->curve
->hash_len
,
3099 0, NULL
, NULL
, wrapped_r_auth
) < 0)
3101 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
3102 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
3103 wrapped_r_auth
, wrapped_r_auth_len
);
3104 w_r_auth
= wrapped_r_auth
;
3106 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3108 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3110 i_pubkey_hash
= NULL
;
3112 i_nonce
= auth
->i_nonce
;
3113 r_nonce
= auth
->r_nonce
;
3115 #ifdef CONFIG_TESTING_OPTIONS
3116 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3117 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3118 r_pubkey_hash
= NULL
;
3119 } else if (dpp_test
==
3120 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3121 wpa_printf(MSG_INFO
,
3122 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3123 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3124 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3125 r_pubkey_hash
= test_hash
;
3126 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3127 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3128 i_pubkey_hash
= NULL
;
3129 } else if (dpp_test
==
3130 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3131 wpa_printf(MSG_INFO
,
3132 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3134 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3136 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3137 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3138 i_pubkey_hash
= test_hash
;
3139 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
3140 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
3143 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
3144 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
3146 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
3147 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
3149 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
3150 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
3152 wrapped_r_auth_len
= 0;
3153 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3154 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3156 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
3157 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3159 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
3160 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
3162 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3163 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3166 #endif /* CONFIG_TESTING_OPTIONS */
3168 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
3169 r_pubkey_hash
, i_pubkey_hash
,
3171 w_r_auth
, wrapped_r_auth_len
,
3175 wpabuf_free(auth
->resp_msg
);
3176 auth
->resp_msg
= msg
;
3184 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3185 enum dpp_status_error status
)
3188 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3189 #ifdef CONFIG_TESTING_OPTIONS
3190 u8 test_hash
[SHA256_MAC_LEN
];
3191 #endif /* CONFIG_TESTING_OPTIONS */
3195 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3197 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3199 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3201 i_pubkey_hash
= NULL
;
3203 i_nonce
= auth
->i_nonce
;
3205 #ifdef CONFIG_TESTING_OPTIONS
3206 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3207 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3208 r_pubkey_hash
= NULL
;
3209 } else if (dpp_test
==
3210 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3211 wpa_printf(MSG_INFO
,
3212 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3213 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3214 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3215 r_pubkey_hash
= test_hash
;
3216 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3217 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3218 i_pubkey_hash
= NULL
;
3219 } else if (dpp_test
==
3220 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3221 wpa_printf(MSG_INFO
,
3222 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3224 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3226 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3227 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3228 i_pubkey_hash
= test_hash
;
3229 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3230 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3232 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3233 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3236 #endif /* CONFIG_TESTING_OPTIONS */
3238 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3239 r_pubkey_hash
, i_pubkey_hash
,
3240 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3243 wpabuf_free(auth
->resp_msg
);
3244 auth
->resp_msg
= msg
;
3249 struct dpp_authentication
*
3250 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3251 struct dpp_bootstrap_info
*peer_bi
,
3252 struct dpp_bootstrap_info
*own_bi
,
3253 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3256 EVP_PKEY
*pi
= NULL
;
3257 EVP_PKEY_CTX
*ctx
= NULL
;
3261 u8
*unwrapped
= NULL
;
3262 size_t unwrapped_len
= 0;
3263 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3265 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3266 i_bootstrap_len
, channel_len
;
3267 struct dpp_authentication
*auth
= NULL
;
3271 #endif /* CONFIG_DPP2 */
3273 #ifdef CONFIG_TESTING_OPTIONS
3274 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3275 wpa_printf(MSG_INFO
,
3276 "DPP: TESTING - stop at Authentication Request");
3279 #endif /* CONFIG_TESTING_OPTIONS */
3281 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3283 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3284 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3285 "Missing or invalid required Wrapped Data attribute");
3288 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3289 wrapped_data
, wrapped_data_len
);
3290 attr_len
= wrapped_data
- 4 - attr_start
;
3292 auth
= os_zalloc(sizeof(*auth
));
3295 auth
->msg_ctx
= msg_ctx
;
3296 auth
->peer_bi
= peer_bi
;
3297 auth
->own_bi
= own_bi
;
3298 auth
->curve
= own_bi
->curve
;
3299 auth
->curr_freq
= freq
;
3301 auth
->peer_version
= 1; /* default to the first version */
3303 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3306 if (version_len
< 1 || version
[0] == 0) {
3308 "Invalid Protocol Version attribute");
3311 auth
->peer_version
= version
[0];
3312 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3313 auth
->peer_version
);
3315 #endif /* CONFIG_DPP2 */
3317 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3322 if (channel_len
< 2) {
3323 dpp_auth_fail(auth
, "Too short Channel attribute");
3327 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3328 wpa_printf(MSG_DEBUG
,
3329 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3330 channel
[0], channel
[1], neg_freq
);
3333 "Unsupported Channel attribute value");
3337 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3338 wpa_printf(MSG_DEBUG
,
3339 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3341 auth
->curr_freq
= neg_freq
;
3345 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3349 "Missing required Initiator Protocol Key attribute");
3352 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3353 i_proto
, i_proto_len
);
3356 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3358 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3361 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3363 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3365 auth
->secret_len
= secret_len
;
3367 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3368 auth
->Mx
, auth
->secret_len
);
3369 auth
->Mx_len
= auth
->secret_len
;
3371 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3372 auth
->curve
->hash_len
) < 0)
3376 len
[0] = DPP_HDR_LEN
;
3377 addr
[1] = attr_start
;
3379 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3380 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3381 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3382 wrapped_data
, wrapped_data_len
);
3383 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3384 unwrapped
= os_malloc(unwrapped_len
);
3387 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3388 wrapped_data
, wrapped_data_len
,
3389 2, addr
, len
, unwrapped
) < 0) {
3390 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3393 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3394 unwrapped
, unwrapped_len
);
3396 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3397 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3401 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3403 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3404 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3407 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3408 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3410 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3411 DPP_ATTR_I_CAPABILITIES
,
3413 if (!i_capab
|| i_capab_len
< 1) {
3414 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3417 auth
->i_capab
= i_capab
[0];
3418 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3420 bin_clear_free(unwrapped
, unwrapped_len
);
3423 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3424 case DPP_CAPAB_ENROLLEE
:
3425 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3426 wpa_printf(MSG_DEBUG
,
3427 "DPP: Local policy does not allow Configurator role");
3428 goto not_compatible
;
3430 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3431 auth
->configurator
= 1;
3433 case DPP_CAPAB_CONFIGURATOR
:
3434 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3435 wpa_printf(MSG_DEBUG
,
3436 "DPP: Local policy does not allow Enrollee role");
3437 goto not_compatible
;
3439 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3440 auth
->configurator
= 0;
3442 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3443 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3444 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3445 auth
->configurator
= 0;
3446 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3447 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3448 auth
->configurator
= 1;
3450 wpa_printf(MSG_DEBUG
,
3451 "DPP: Local policy does not allow Configurator/Enrollee role");
3452 goto not_compatible
;
3456 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3457 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3458 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3459 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3463 auth
->peer_protocol_key
= pi
;
3465 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3466 char hex
[SHA256_MAC_LEN
* 2 + 1];
3468 wpa_printf(MSG_DEBUG
,
3469 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3470 if (dpp_auth_build_resp_status(auth
,
3471 DPP_STATUS_RESPONSE_PENDING
) < 0)
3473 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3474 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3476 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3477 auth
->response_pending
= 1;
3478 os_memcpy(auth
->waiting_pubkey_hash
,
3479 i_bootstrap
, i_bootstrap_len
);
3480 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3486 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3490 if (dpp_auth_build_resp_ok(auth
) < 0)
3496 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3497 "i-capab=0x%02x", auth
->i_capab
);
3498 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3499 auth
->configurator
= 1;
3501 auth
->configurator
= 0;
3502 auth
->peer_protocol_key
= pi
;
3504 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3507 auth
->remove_on_tx_status
= 1;
3510 bin_clear_free(unwrapped
, unwrapped_len
);
3512 EVP_PKEY_CTX_free(ctx
);
3513 dpp_auth_deinit(auth
);
3518 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3519 struct dpp_bootstrap_info
*peer_bi
)
3521 if (!auth
|| !auth
->response_pending
||
3522 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3523 SHA256_MAC_LEN
) != 0)
3526 wpa_printf(MSG_DEBUG
,
3527 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3528 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3529 auth
->peer_bi
= peer_bi
;
3531 if (dpp_auth_build_resp_ok(auth
) < 0)
3538 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3539 enum dpp_status_error status
)
3542 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3544 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3547 size_t len
[2], attr_len
;
3549 u8
*wrapped_r_nonce
;
3550 u8
*attr_start
, *attr_end
;
3551 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3552 #ifdef CONFIG_TESTING_OPTIONS
3553 u8 test_hash
[SHA256_MAC_LEN
];
3554 #endif /* CONFIG_TESTING_OPTIONS */
3556 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3558 i_auth_len
= 4 + auth
->curve
->hash_len
;
3559 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3560 /* Build DPP Authentication Confirmation frame attributes */
3561 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3562 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3563 #ifdef CONFIG_TESTING_OPTIONS
3564 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3566 #endif /* CONFIG_TESTING_OPTIONS */
3567 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3571 attr_start
= wpabuf_put(msg
, 0);
3573 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3575 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3577 i_pubkey_hash
= NULL
;
3579 #ifdef CONFIG_TESTING_OPTIONS
3580 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3581 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3583 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3584 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3587 #endif /* CONFIG_TESTING_OPTIONS */
3590 dpp_build_attr_status(msg
, status
);
3592 #ifdef CONFIG_TESTING_OPTIONS
3594 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3595 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3596 r_pubkey_hash
= NULL
;
3597 } else if (dpp_test
==
3598 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3599 wpa_printf(MSG_INFO
,
3600 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3601 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3602 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3603 r_pubkey_hash
= test_hash
;
3604 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3605 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3606 i_pubkey_hash
= NULL
;
3607 } else if (dpp_test
==
3608 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3609 wpa_printf(MSG_INFO
,
3610 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3612 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3614 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3615 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3616 i_pubkey_hash
= test_hash
;
3618 #endif /* CONFIG_TESTING_OPTIONS */
3620 /* Responder Bootstrapping Key Hash */
3621 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3623 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3624 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3626 #ifdef CONFIG_TESTING_OPTIONS
3627 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3628 goto skip_wrapped_data
;
3629 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3631 #endif /* CONFIG_TESTING_OPTIONS */
3633 attr_end
= wpabuf_put(msg
, 0);
3635 /* OUI, OUI type, Crypto Suite, DPP frame type */
3636 addr
[0] = wpabuf_head_u8(msg
) + 2;
3637 len
[0] = 3 + 1 + 1 + 1;
3638 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3640 /* Attributes before Wrapped Data */
3641 addr
[1] = attr_start
;
3642 len
[1] = attr_end
- attr_start
;
3643 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3645 if (status
== DPP_STATUS_OK
) {
3646 /* I-auth wrapped with ke */
3647 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3648 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3649 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3651 #ifdef CONFIG_TESTING_OPTIONS
3652 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3654 #endif /* CONFIG_TESTING_OPTIONS */
3656 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3658 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3659 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3660 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3663 #ifdef CONFIG_TESTING_OPTIONS
3664 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3665 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3666 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3669 #endif /* CONFIG_TESTING_OPTIONS */
3670 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3672 2, addr
, len
, wrapped_i_auth
) < 0)
3674 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3675 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3677 /* R-nonce wrapped with k2 */
3678 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3679 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3680 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3682 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3683 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3684 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3686 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3687 r_nonce
, r_nonce_len
,
3688 2, addr
, len
, wrapped_r_nonce
) < 0)
3690 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3691 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3694 #ifdef CONFIG_TESTING_OPTIONS
3695 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3696 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3697 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3700 #endif /* CONFIG_TESTING_OPTIONS */
3702 wpa_hexdump_buf(MSG_DEBUG
,
3703 "DPP: Authentication Confirmation frame attributes",
3705 if (status
== DPP_STATUS_OK
)
3706 dpp_auth_success(auth
);
3717 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3718 const u8
*attr_start
, size_t attr_len
,
3719 const u8
*wrapped_data
, u16 wrapped_data_len
,
3720 enum dpp_status_error status
)
3724 u8
*unwrapped
= NULL
;
3725 size_t unwrapped_len
= 0;
3726 const u8
*i_nonce
, *r_capab
;
3727 u16 i_nonce_len
, r_capab_len
;
3729 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3730 wpa_printf(MSG_DEBUG
,
3731 "DPP: Responder reported incompatible roles");
3732 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3733 wpa_printf(MSG_DEBUG
,
3734 "DPP: Responder reported more time needed");
3736 wpa_printf(MSG_DEBUG
,
3737 "DPP: Responder reported failure (status %d)",
3739 dpp_auth_fail(auth
, "Responder reported failure");
3744 len
[0] = DPP_HDR_LEN
;
3745 addr
[1] = attr_start
;
3747 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3748 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3749 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3750 wrapped_data
, wrapped_data_len
);
3751 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3752 unwrapped
= os_malloc(unwrapped_len
);
3755 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3756 wrapped_data
, wrapped_data_len
,
3757 2, addr
, len
, unwrapped
) < 0) {
3758 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3761 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3762 unwrapped
, unwrapped_len
);
3764 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3765 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3769 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3771 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3772 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3775 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3776 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3777 dpp_auth_fail(auth
, "I-nonce mismatch");
3781 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3782 DPP_ATTR_R_CAPABILITIES
,
3784 if (!r_capab
|| r_capab_len
< 1) {
3785 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3788 auth
->r_capab
= r_capab
[0];
3789 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3790 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3791 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3792 "r-capab=0x%02x", auth
->r_capab
);
3793 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3794 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3796 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3797 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3798 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3799 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3802 wpa_printf(MSG_DEBUG
,
3803 "DPP: Continue waiting for full DPP Authentication Response");
3804 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3805 DPP_EVENT_RESPONSE_PENDING
"%s",
3806 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3810 bin_clear_free(unwrapped
, unwrapped_len
);
3815 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3816 const u8
*attr_start
, size_t attr_len
)
3822 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3823 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3824 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3825 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3826 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3827 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3828 wrapped2_len
, r_auth_len
;
3829 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3834 #endif /* CONFIG_DPP2 */
3836 #ifdef CONFIG_TESTING_OPTIONS
3837 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3838 wpa_printf(MSG_INFO
,
3839 "DPP: TESTING - stop at Authentication Response");
3842 #endif /* CONFIG_TESTING_OPTIONS */
3844 if (!auth
->initiator
|| !auth
->peer_bi
) {
3845 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3849 auth
->waiting_auth_resp
= 0;
3851 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3853 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3855 "Missing or invalid required Wrapped Data attribute");
3858 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3859 wrapped_data
, wrapped_data_len
);
3861 attr_len
= wrapped_data
- 4 - attr_start
;
3863 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3864 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3866 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3868 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3871 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3872 r_bootstrap
, r_bootstrap_len
);
3873 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3874 SHA256_MAC_LEN
) != 0) {
3876 "Unexpected Responder Bootstrapping Key Hash value");
3877 wpa_hexdump(MSG_DEBUG
,
3878 "DPP: Expected Responder Bootstrapping Key Hash",
3879 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3883 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3884 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3887 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3889 "Invalid Initiator Bootstrapping Key Hash attribute");
3892 wpa_hexdump(MSG_MSGDUMP
,
3893 "DPP: Initiator Bootstrapping Key Hash",
3894 i_bootstrap
, i_bootstrap_len
);
3895 if (!auth
->own_bi
||
3896 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3897 SHA256_MAC_LEN
) != 0) {
3899 "Initiator Bootstrapping Key Hash attribute did not match");
3902 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3903 /* PKEX bootstrapping mandates use of mutual authentication */
3905 "Missing Initiator Bootstrapping Key Hash attribute");
3909 auth
->peer_version
= 1; /* default to the first version */
3911 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3914 if (version_len
< 1 || version
[0] == 0) {
3916 "Invalid Protocol Version attribute");
3919 auth
->peer_version
= version
[0];
3920 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3921 auth
->peer_version
);
3923 #endif /* CONFIG_DPP2 */
3925 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3927 if (!status
|| status_len
< 1) {
3929 "Missing or invalid required DPP Status attribute");
3932 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3933 auth
->auth_resp_status
= status
[0];
3934 if (status
[0] != DPP_STATUS_OK
) {
3935 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3936 attr_len
, wrapped_data
,
3937 wrapped_data_len
, status
[0]);
3941 if (!i_bootstrap
&& auth
->own_bi
) {
3942 wpa_printf(MSG_DEBUG
,
3943 "DPP: Responder decided not to use mutual authentication");
3944 auth
->own_bi
= NULL
;
3947 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3948 auth
->own_bi
!= NULL
);
3950 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3954 "Missing required Responder Protocol Key attribute");
3957 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3958 r_proto
, r_proto_len
);
3961 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3963 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3966 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3968 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
3969 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3972 EVP_PKEY_free(auth
->peer_protocol_key
);
3973 auth
->peer_protocol_key
= pr
;
3976 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3977 auth
->Nx
, auth
->secret_len
);
3978 auth
->Nx_len
= auth
->secret_len
;
3980 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3981 auth
->curve
->hash_len
) < 0)
3985 len
[0] = DPP_HDR_LEN
;
3986 addr
[1] = attr_start
;
3988 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3989 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3990 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3991 wrapped_data
, wrapped_data_len
);
3992 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3993 unwrapped
= os_malloc(unwrapped_len
);
3996 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
3997 wrapped_data
, wrapped_data_len
,
3998 2, addr
, len
, unwrapped
) < 0) {
3999 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4002 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4003 unwrapped
, unwrapped_len
);
4005 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4006 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4010 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4012 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4013 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4016 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
4017 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
4019 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
4021 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
4022 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
4025 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
4026 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
4027 dpp_auth_fail(auth
, "I-nonce mismatch");
4032 /* Mutual authentication */
4033 if (dpp_auth_derive_l_initiator(auth
) < 0)
4037 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
4038 DPP_ATTR_R_CAPABILITIES
,
4040 if (!r_capab
|| r_capab_len
< 1) {
4041 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
4044 auth
->r_capab
= r_capab
[0];
4045 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
4046 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
4047 if ((auth
->allowed_roles
==
4048 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
4049 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
4050 /* Peer selected its role, so move from "either role" to the
4051 * role that is compatible with peer's selection. */
4052 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
4053 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
4054 auth
->configurator
? "Configurator" : "Enrollee");
4055 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
4056 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
4057 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
4058 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
4059 "Unexpected role in R-capabilities 0x%02x",
4061 if (role
!= DPP_CAPAB_ENROLLEE
&&
4062 role
!= DPP_CAPAB_CONFIGURATOR
)
4064 bin_clear_free(unwrapped
, unwrapped_len
);
4065 auth
->remove_on_tx_status
= 1;
4066 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
4069 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
4070 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
4071 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
4073 "Missing or invalid Secondary Wrapped Data");
4077 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4078 wrapped2
, wrapped2_len
);
4080 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
4083 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
4084 unwrapped2
= os_malloc(unwrapped2_len
);
4087 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4088 wrapped2
, wrapped2_len
,
4089 0, NULL
, NULL
, unwrapped2
) < 0) {
4090 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4093 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4094 unwrapped2
, unwrapped2_len
);
4096 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
4098 "Invalid attribute in secondary unwrapped data");
4102 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
4104 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
4106 "Missing or invalid Responder Authenticating Tag");
4109 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
4110 r_auth
, r_auth_len
);
4111 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4112 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
4114 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
4115 r_auth2
, r_auth_len
);
4116 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
4117 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
4118 bin_clear_free(unwrapped
, unwrapped_len
);
4119 bin_clear_free(unwrapped2
, unwrapped2_len
);
4120 auth
->remove_on_tx_status
= 1;
4121 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
4124 bin_clear_free(unwrapped
, unwrapped_len
);
4125 bin_clear_free(unwrapped2
, unwrapped2_len
);
4127 #ifdef CONFIG_TESTING_OPTIONS
4128 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
4129 wpa_printf(MSG_INFO
,
4130 "DPP: TESTING - Authentication Response in place of Confirm");
4131 if (dpp_auth_build_resp_ok(auth
) < 0)
4133 return wpabuf_dup(auth
->resp_msg
);
4135 #endif /* CONFIG_TESTING_OPTIONS */
4137 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
4140 bin_clear_free(unwrapped
, unwrapped_len
);
4141 bin_clear_free(unwrapped2
, unwrapped2_len
);
4147 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
4149 const u8
*attr_start
, size_t attr_len
,
4150 const u8
*wrapped_data
,
4151 u16 wrapped_data_len
,
4152 enum dpp_status_error status
)
4156 u8
*unwrapped
= NULL
;
4157 size_t unwrapped_len
= 0;
4161 /* Authentication Confirm failure cases are expected to include
4162 * {R-nonce}k2 in the Wrapped Data attribute. */
4165 len
[0] = DPP_HDR_LEN
;
4166 addr
[1] = attr_start
;
4168 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4169 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4170 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4171 wrapped_data
, wrapped_data_len
);
4172 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4173 unwrapped
= os_malloc(unwrapped_len
);
4175 dpp_auth_fail(auth
, "Authentication failed");
4178 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4179 wrapped_data
, wrapped_data_len
,
4180 2, addr
, len
, unwrapped
) < 0) {
4181 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4184 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4185 unwrapped
, unwrapped_len
);
4187 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4188 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4192 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4194 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4195 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4198 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4199 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4200 r_nonce
, r_nonce_len
);
4201 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4202 auth
->r_nonce
, r_nonce_len
);
4203 dpp_auth_fail(auth
, "R-nonce mismatch");
4207 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4208 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4209 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4210 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4213 bin_clear_free(unwrapped
, unwrapped_len
);
4218 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4219 const u8
*attr_start
, size_t attr_len
)
4221 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4222 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4226 u8
*unwrapped
= NULL
;
4227 size_t unwrapped_len
= 0;
4228 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4230 #ifdef CONFIG_TESTING_OPTIONS
4231 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4232 wpa_printf(MSG_INFO
,
4233 "DPP: TESTING - stop at Authentication Confirm");
4236 #endif /* CONFIG_TESTING_OPTIONS */
4238 if (auth
->initiator
|| !auth
->own_bi
) {
4239 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4243 auth
->waiting_auth_conf
= 0;
4245 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4247 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4249 "Missing or invalid required Wrapped Data attribute");
4252 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4253 wrapped_data
, wrapped_data_len
);
4255 attr_len
= wrapped_data
- 4 - attr_start
;
4257 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4258 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4260 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4262 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4265 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4266 r_bootstrap
, r_bootstrap_len
);
4267 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4268 SHA256_MAC_LEN
) != 0) {
4269 wpa_hexdump(MSG_DEBUG
,
4270 "DPP: Expected Responder Bootstrapping Key Hash",
4271 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4273 "Responder Bootstrapping Key Hash mismatch");
4277 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4278 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4281 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4283 "Invalid Initiator Bootstrapping Key Hash attribute");
4286 wpa_hexdump(MSG_MSGDUMP
,
4287 "DPP: Initiator Bootstrapping Key Hash",
4288 i_bootstrap
, i_bootstrap_len
);
4289 if (!auth
->peer_bi
||
4290 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4291 SHA256_MAC_LEN
) != 0) {
4293 "Initiator Bootstrapping Key Hash mismatch");
4296 } else if (auth
->peer_bi
) {
4297 /* Mutual authentication and peer did not include its
4298 * Bootstrapping Key Hash attribute. */
4300 "Missing Initiator Bootstrapping Key Hash attribute");
4304 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4306 if (!status
|| status_len
< 1) {
4308 "Missing or invalid required DPP Status attribute");
4311 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4312 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4313 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4314 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4315 attr_len
, wrapped_data
,
4316 wrapped_data_len
, status
[0]);
4318 if (status
[0] != DPP_STATUS_OK
) {
4319 dpp_auth_fail(auth
, "Authentication failed");
4324 len
[0] = DPP_HDR_LEN
;
4325 addr
[1] = attr_start
;
4327 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4328 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4329 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4330 wrapped_data
, wrapped_data_len
);
4331 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4332 unwrapped
= os_malloc(unwrapped_len
);
4335 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4336 wrapped_data
, wrapped_data_len
,
4337 2, addr
, len
, unwrapped
) < 0) {
4338 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4341 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4342 unwrapped
, unwrapped_len
);
4344 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4345 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4349 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4351 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4353 "Missing or invalid Initiator Authenticating Tag");
4356 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4357 i_auth
, i_auth_len
);
4358 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4359 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4361 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4362 i_auth2
, i_auth_len
);
4363 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4364 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4368 bin_clear_free(unwrapped
, unwrapped_len
);
4369 dpp_auth_success(auth
);
4372 bin_clear_free(unwrapped
, unwrapped_len
);
4377 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4379 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4383 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4385 struct dpp_configuration
*conf
;
4389 conf
= os_zalloc(sizeof(*conf
));
4393 end
= os_strchr(type
, ' ');
4397 len
= os_strlen(type
);
4399 if (bin_str_eq(type
, len
, "psk"))
4400 conf
->akm
= DPP_AKM_PSK
;
4401 else if (bin_str_eq(type
, len
, "sae"))
4402 conf
->akm
= DPP_AKM_SAE
;
4403 else if (bin_str_eq(type
, len
, "psk-sae") ||
4404 bin_str_eq(type
, len
, "psk+sae"))
4405 conf
->akm
= DPP_AKM_PSK_SAE
;
4406 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4407 bin_str_eq(type
, len
, "dpp+sae"))
4408 conf
->akm
= DPP_AKM_SAE_DPP
;
4409 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4410 bin_str_eq(type
, len
, "dpp+psk+sae"))
4411 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4412 else if (bin_str_eq(type
, len
, "dpp"))
4413 conf
->akm
= DPP_AKM_DPP
;
4419 dpp_configuration_free(conf
);
4424 int dpp_akm_psk(enum dpp_akm akm
)
4426 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4427 akm
== DPP_AKM_PSK_SAE_DPP
;
4431 int dpp_akm_sae(enum dpp_akm akm
)
4433 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4434 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4438 int dpp_akm_legacy(enum dpp_akm akm
)
4440 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4445 int dpp_akm_dpp(enum dpp_akm akm
)
4447 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4448 akm
== DPP_AKM_PSK_SAE_DPP
;
4452 int dpp_akm_ver2(enum dpp_akm akm
)
4454 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4458 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4460 if (conf
->ssid_len
== 0)
4462 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4464 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4470 void dpp_configuration_free(struct dpp_configuration
*conf
)
4474 str_clear_free(conf
->passphrase
);
4475 os_free(conf
->group_id
);
4476 bin_clear_free(conf
, sizeof(*conf
));
4480 static int dpp_configuration_parse_helper(struct dpp_authentication
*auth
,
4481 const char *cmd
, int idx
)
4483 const char *pos
, *end
;
4484 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4485 struct dpp_configuration
*conf
= NULL
;
4487 pos
= os_strstr(cmd
, " conf=sta-");
4489 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4492 conf_sta
->netrole
= DPP_NETROLE_STA
;
4496 pos
= os_strstr(cmd
, " conf=ap-");
4498 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4501 conf_ap
->netrole
= DPP_NETROLE_AP
;
4508 pos
= os_strstr(cmd
, " ssid=");
4511 end
= os_strchr(pos
, ' ');
4512 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4513 conf
->ssid_len
/= 2;
4514 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4515 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4518 #ifdef CONFIG_TESTING_OPTIONS
4519 /* use a default SSID for legacy testing reasons */
4520 os_memcpy(conf
->ssid
, "test", 4);
4522 #else /* CONFIG_TESTING_OPTIONS */
4524 #endif /* CONFIG_TESTING_OPTIONS */
4527 pos
= os_strstr(cmd
, " ssid_charset=");
4530 wpa_printf(MSG_INFO
,
4531 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4534 conf
->ssid_charset
= atoi(pos
+ 14);
4537 pos
= os_strstr(cmd
, " pass=");
4542 end
= os_strchr(pos
, ' ');
4543 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4545 if (pass_len
> 63 || pass_len
< 8)
4547 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4548 if (!conf
->passphrase
||
4549 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4553 pos
= os_strstr(cmd
, " psk=");
4556 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4561 pos
= os_strstr(cmd
, " group_id=");
4563 size_t group_id_len
;
4566 end
= os_strchr(pos
, ' ');
4567 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4568 conf
->group_id
= os_malloc(group_id_len
+ 1);
4569 if (!conf
->group_id
)
4571 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4572 conf
->group_id
[group_id_len
] = '\0';
4575 pos
= os_strstr(cmd
, " expiry=");
4580 val
= strtol(pos
, NULL
, 0);
4583 conf
->netaccesskey_expiry
= val
;
4586 if (!dpp_configuration_valid(conf
))
4590 auth
->conf_sta
= conf_sta
;
4591 auth
->conf_ap
= conf_ap
;
4592 } else if (idx
== 1) {
4593 auth
->conf2_sta
= conf_sta
;
4594 auth
->conf2_ap
= conf_ap
;
4601 dpp_configuration_free(conf_sta
);
4602 dpp_configuration_free(conf_ap
);
4607 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4615 pos
= os_strstr(cmd
, " @CONF-OBJ-SEP@ ");
4617 return dpp_configuration_parse_helper(auth
, cmd
, 0);
4620 tmp
= os_malloc(len
+ 1);
4623 os_memcpy(tmp
, cmd
, len
);
4625 res
= dpp_configuration_parse_helper(auth
, cmd
, 0);
4626 str_clear_free(tmp
);
4629 res
= dpp_configuration_parse_helper(auth
, cmd
+ len
, 1);
4634 dpp_configuration_free(auth
->conf_sta
);
4635 dpp_configuration_free(auth
->conf2_sta
);
4636 dpp_configuration_free(auth
->conf_ap
);
4637 dpp_configuration_free(auth
->conf2_ap
);
4642 static struct dpp_configurator
*
4643 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4645 struct dpp_configurator
*conf
;
4650 dl_list_for_each(conf
, &dpp
->configurator
,
4651 struct dpp_configurator
, list
) {
4659 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4660 struct dpp_authentication
*auth
,
4668 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4670 pos
= os_strstr(cmd
, " configurator=");
4673 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4675 wpa_printf(MSG_INFO
,
4676 "DPP: Could not find the specified configurator");
4681 pos
= os_strstr(cmd
, " conn_status=");
4684 auth
->send_conn_status
= atoi(pos
);
4687 pos
= os_strstr(cmd
, " akm_use_selector=");
4690 auth
->akm_use_selector
= atoi(pos
);
4693 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4694 wpa_msg(msg_ctx
, MSG_INFO
,
4695 "DPP: Failed to set configurator parameters");
4702 static void dpp_free_asymmetric_key(struct dpp_asymmetric_key
*key
)
4705 struct dpp_asymmetric_key
*next
= key
->next
;
4707 EVP_PKEY_free(key
->csign
);
4708 str_clear_free(key
->config_template
);
4709 str_clear_free(key
->connector_template
);
4716 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4722 dpp_configuration_free(auth
->conf_ap
);
4723 dpp_configuration_free(auth
->conf2_ap
);
4724 dpp_configuration_free(auth
->conf_sta
);
4725 dpp_configuration_free(auth
->conf2_sta
);
4726 EVP_PKEY_free(auth
->own_protocol_key
);
4727 EVP_PKEY_free(auth
->peer_protocol_key
);
4728 wpabuf_free(auth
->req_msg
);
4729 wpabuf_free(auth
->resp_msg
);
4730 wpabuf_free(auth
->conf_req
);
4731 for (i
= 0; i
< auth
->num_conf_obj
; i
++) {
4732 struct dpp_config_obj
*conf
= &auth
->conf_obj
[i
];
4734 os_free(conf
->connector
);
4735 wpabuf_free(conf
->c_sign_key
);
4737 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
4738 wpabuf_free(auth
->net_access_key
);
4739 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4740 #ifdef CONFIG_TESTING_OPTIONS
4741 os_free(auth
->config_obj_override
);
4742 os_free(auth
->discovery_override
);
4743 os_free(auth
->groups_override
);
4744 #endif /* CONFIG_TESTING_OPTIONS */
4745 bin_clear_free(auth
, sizeof(*auth
));
4749 static struct wpabuf
*
4750 dpp_build_conf_start(struct dpp_authentication
*auth
,
4751 struct dpp_configuration
*conf
, size_t tailroom
)
4755 #ifdef CONFIG_TESTING_OPTIONS
4756 if (auth
->discovery_override
)
4757 tailroom
+= os_strlen(auth
->discovery_override
);
4758 #endif /* CONFIG_TESTING_OPTIONS */
4760 buf
= wpabuf_alloc(200 + tailroom
);
4763 json_start_object(buf
, NULL
);
4764 json_add_string(buf
, "wi-fi_tech", "infra");
4765 json_value_sep(buf
);
4766 #ifdef CONFIG_TESTING_OPTIONS
4767 if (auth
->discovery_override
) {
4768 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4769 auth
->discovery_override
);
4770 wpabuf_put_str(buf
, "\"discovery\":");
4771 wpabuf_put_str(buf
, auth
->discovery_override
);
4772 json_value_sep(buf
);
4775 #endif /* CONFIG_TESTING_OPTIONS */
4776 json_start_object(buf
, "discovery");
4777 if (((!conf
->ssid_charset
|| auth
->peer_version
< 2) &&
4778 json_add_string_escape(buf
, "ssid", conf
->ssid
,
4779 conf
->ssid_len
) < 0) ||
4780 ((conf
->ssid_charset
&& auth
->peer_version
>= 2) &&
4781 json_add_base64url(buf
, "ssid64", conf
->ssid
,
4782 conf
->ssid_len
) < 0)) {
4786 if (conf
->ssid_charset
> 0) {
4787 json_value_sep(buf
);
4788 json_add_int(buf
, "ssid_charset", conf
->ssid_charset
);
4790 json_end_object(buf
);
4791 json_value_sep(buf
);
4797 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4798 const char *kid
, const struct dpp_curve_params
*curve
)
4804 pub
= dpp_get_pubkey_point(key
, 0);
4808 json_start_object(buf
, name
);
4809 json_add_string(buf
, "kty", "EC");
4810 json_value_sep(buf
);
4811 json_add_string(buf
, "crv", curve
->jwk_crv
);
4812 json_value_sep(buf
);
4813 pos
= wpabuf_head(pub
);
4814 if (json_add_base64url(buf
, "x", pos
, curve
->prime_len
) < 0)
4816 json_value_sep(buf
);
4817 pos
+= curve
->prime_len
;
4818 if (json_add_base64url(buf
, "y", pos
, curve
->prime_len
) < 0)
4821 json_value_sep(buf
);
4822 json_add_string(buf
, "kid", kid
);
4824 json_end_object(buf
);
4832 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4833 struct dpp_configuration
*conf
)
4835 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4836 json_add_string_escape(buf
, "pass", conf
->passphrase
,
4837 os_strlen(conf
->passphrase
));
4838 } else if (conf
->psk_set
) {
4839 char psk
[2 * sizeof(conf
->psk
) + 1];
4841 wpa_snprintf_hex(psk
, sizeof(psk
),
4842 conf
->psk
, sizeof(conf
->psk
));
4843 json_add_string(buf
, "psk_hex", psk
);
4844 forced_memzero(psk
, sizeof(psk
));
4849 static const char * dpp_netrole_str(enum dpp_netrole netrole
)
4852 case DPP_NETROLE_STA
:
4854 case DPP_NETROLE_AP
:
4856 case DPP_NETROLE_CONFIGURATOR
:
4857 return "configurator";
4864 static struct wpabuf
*
4865 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
,
4866 struct dpp_configuration
*conf
)
4868 struct wpabuf
*buf
= NULL
;
4869 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4871 const struct dpp_curve_params
*curve
;
4872 struct wpabuf
*jws_prot_hdr
;
4873 size_t signed1_len
, signed2_len
, signed3_len
;
4874 struct wpabuf
*dppcon
= NULL
;
4875 unsigned char *signature
= NULL
;
4876 const unsigned char *p
;
4877 size_t signature_len
;
4878 EVP_MD_CTX
*md_ctx
= NULL
;
4879 ECDSA_SIG
*sig
= NULL
;
4881 const EVP_MD
*sign_md
;
4882 const BIGNUM
*r
, *s
;
4883 size_t extra_len
= 1000;
4886 const char *akm_str
;
4889 wpa_printf(MSG_INFO
,
4890 "DPP: No configurator specified - cannot generate DPP config object");
4893 curve
= auth
->conf
->curve
;
4894 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4895 sign_md
= EVP_sha256();
4896 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4897 sign_md
= EVP_sha384();
4898 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4899 sign_md
= EVP_sha512();
4901 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4906 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4907 wpa_printf(MSG_DEBUG
,
4908 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4912 #ifdef CONFIG_TESTING_OPTIONS
4913 if (auth
->groups_override
)
4914 extra_len
+= os_strlen(auth
->groups_override
);
4915 #endif /* CONFIG_TESTING_OPTIONS */
4918 extra_len
+= os_strlen(conf
->group_id
);
4920 /* Connector (JSON dppCon object) */
4921 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4924 #ifdef CONFIG_TESTING_OPTIONS
4925 if (auth
->groups_override
) {
4926 wpabuf_put_u8(dppcon
, '{');
4927 if (auth
->groups_override
) {
4928 wpa_printf(MSG_DEBUG
,
4929 "DPP: TESTING - groups override: '%s'",
4930 auth
->groups_override
);
4931 wpabuf_put_str(dppcon
, "\"groups\":");
4932 wpabuf_put_str(dppcon
, auth
->groups_override
);
4933 json_value_sep(dppcon
);
4937 #endif /* CONFIG_TESTING_OPTIONS */
4938 json_start_object(dppcon
, NULL
);
4939 json_start_array(dppcon
, "groups");
4940 json_start_object(dppcon
, NULL
);
4941 json_add_string(dppcon
, "groupId",
4942 conf
->group_id
? conf
->group_id
: "*");
4943 json_value_sep(dppcon
);
4944 json_add_string(dppcon
, "netRole", dpp_netrole_str(conf
->netrole
));
4945 json_end_object(dppcon
);
4946 json_end_array(dppcon
);
4947 json_value_sep(dppcon
);
4948 #ifdef CONFIG_TESTING_OPTIONS
4950 #endif /* CONFIG_TESTING_OPTIONS */
4951 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4953 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4956 if (conf
->netaccesskey_expiry
) {
4960 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4961 wpa_printf(MSG_DEBUG
,
4962 "DPP: Failed to generate expiry string");
4965 os_snprintf(expiry
, sizeof(expiry
),
4966 "%04u-%02u-%02uT%02u:%02u:%02uZ",
4967 tm
.year
, tm
.month
, tm
.day
,
4968 tm
.hour
, tm
.min
, tm
.sec
);
4969 json_value_sep(dppcon
);
4970 json_add_string(dppcon
, "expiry", expiry
);
4972 json_end_object(dppcon
);
4973 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
4974 (const char *) wpabuf_head(dppcon
));
4976 jws_prot_hdr
= wpabuf_alloc(100);
4979 json_start_object(jws_prot_hdr
, NULL
);
4980 json_add_string(jws_prot_hdr
, "typ", "dppCon");
4981 json_value_sep(jws_prot_hdr
);
4982 json_add_string(jws_prot_hdr
, "kid", auth
->conf
->kid
);
4983 json_value_sep(jws_prot_hdr
);
4984 json_add_string(jws_prot_hdr
, "alg", curve
->jws_alg
);
4985 json_end_object(jws_prot_hdr
);
4986 signed1
= base64_url_encode(wpabuf_head(jws_prot_hdr
),
4987 wpabuf_len(jws_prot_hdr
),
4989 wpabuf_free(jws_prot_hdr
);
4990 signed2
= base64_url_encode(wpabuf_head(dppcon
), wpabuf_len(dppcon
),
4992 if (!signed1
|| !signed2
)
4995 md_ctx
= EVP_MD_CTX_create();
5000 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
5001 auth
->conf
->csign
) != 1) {
5002 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
5003 ERR_error_string(ERR_get_error(), NULL
));
5006 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
5007 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
5008 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
5009 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
5010 ERR_error_string(ERR_get_error(), NULL
));
5013 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
5014 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5015 ERR_error_string(ERR_get_error(), NULL
));
5018 signature
= os_malloc(signature_len
);
5021 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
5022 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5023 ERR_error_string(ERR_get_error(), NULL
));
5026 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
5027 signature
, signature_len
);
5028 /* Convert to raw coordinates r,s */
5030 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
5033 ECDSA_SIG_get0(sig
, &r
, &s
);
5034 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
5035 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
5036 curve
->prime_len
) < 0)
5038 signature_len
= 2 * curve
->prime_len
;
5039 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
5040 signature
, signature_len
);
5041 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
5045 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
5047 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
5048 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
5051 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
5055 if (auth
->akm_use_selector
&& dpp_akm_ver2(akm
))
5056 akm_str
= dpp_akm_selector_str(akm
);
5058 akm_str
= dpp_akm_str(akm
);
5059 json_start_object(buf
, "cred");
5060 json_add_string(buf
, "akm", akm_str
);
5061 json_value_sep(buf
);
5063 dpp_build_legacy_cred_params(buf
, conf
);
5064 json_value_sep(buf
);
5066 wpabuf_put_str(buf
, "\"signedConnector\":\"");
5067 wpabuf_put_str(buf
, signed1
);
5068 wpabuf_put_u8(buf
, '.');
5069 wpabuf_put_str(buf
, signed2
);
5070 wpabuf_put_u8(buf
, '.');
5071 wpabuf_put_str(buf
, signed3
);
5072 wpabuf_put_str(buf
, "\"");
5073 json_value_sep(buf
);
5074 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
5076 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
5080 json_end_object(buf
);
5081 json_end_object(buf
);
5083 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
5084 wpabuf_head(buf
), wpabuf_len(buf
));
5087 EVP_MD_CTX_destroy(md_ctx
);
5088 ECDSA_SIG_free(sig
);
5093 wpabuf_free(dppcon
);
5096 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
5103 static struct wpabuf
*
5104 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
,
5105 struct dpp_configuration
*conf
)
5108 const char *akm_str
;
5110 buf
= dpp_build_conf_start(auth
, conf
, 1000);
5114 if (auth
->akm_use_selector
&& dpp_akm_ver2(conf
->akm
))
5115 akm_str
= dpp_akm_selector_str(conf
->akm
);
5117 akm_str
= dpp_akm_str(conf
->akm
);
5118 json_start_object(buf
, "cred");
5119 json_add_string(buf
, "akm", akm_str
);
5120 json_value_sep(buf
);
5121 dpp_build_legacy_cred_params(buf
, conf
);
5122 json_end_object(buf
);
5123 json_end_object(buf
);
5125 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
5126 wpabuf_head(buf
), wpabuf_len(buf
));
5132 static struct wpabuf
*
5133 dpp_build_conf_obj(struct dpp_authentication
*auth
, enum dpp_netrole netrole
,
5136 struct dpp_configuration
*conf
= NULL
;
5138 #ifdef CONFIG_TESTING_OPTIONS
5139 if (auth
->config_obj_override
) {
5142 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
5143 return wpabuf_alloc_copy(auth
->config_obj_override
,
5144 os_strlen(auth
->config_obj_override
));
5146 #endif /* CONFIG_TESTING_OPTIONS */
5149 if (netrole
== DPP_NETROLE_STA
)
5150 conf
= auth
->conf_sta
;
5151 else if (netrole
== DPP_NETROLE_AP
)
5152 conf
= auth
->conf_ap
;
5153 } else if (idx
== 1) {
5154 if (netrole
== DPP_NETROLE_STA
)
5155 conf
= auth
->conf2_sta
;
5156 else if (netrole
== DPP_NETROLE_AP
)
5157 conf
= auth
->conf2_ap
;
5161 wpa_printf(MSG_DEBUG
,
5162 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5163 dpp_netrole_str(netrole
));
5167 if (dpp_akm_dpp(conf
->akm
))
5168 return dpp_build_conf_obj_dpp(auth
, conf
);
5169 return dpp_build_conf_obj_legacy(auth
, conf
);
5173 static struct wpabuf
*
5174 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
5175 u16 e_nonce_len
, enum dpp_netrole netrole
)
5177 struct wpabuf
*conf
, *conf2
= NULL
;
5178 size_t clear_len
, attr_len
;
5179 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
5183 enum dpp_status_error status
;
5185 conf
= dpp_build_conf_obj(auth
, netrole
, 0);
5187 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
5188 wpabuf_head(conf
), wpabuf_len(conf
));
5189 conf2
= dpp_build_conf_obj(auth
, netrole
, 1);
5191 status
= conf
? DPP_STATUS_OK
: DPP_STATUS_CONFIGURE_FAILURE
;
5192 auth
->conf_resp_status
= status
;
5194 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
5195 clear_len
= 4 + e_nonce_len
;
5197 clear_len
+= 4 + wpabuf_len(conf
);
5199 clear_len
+= 4 + wpabuf_len(conf2
);
5200 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5201 netrole
== DPP_NETROLE_STA
)
5203 clear
= wpabuf_alloc(clear_len
);
5204 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
5205 #ifdef CONFIG_TESTING_OPTIONS
5206 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
5208 #endif /* CONFIG_TESTING_OPTIONS */
5209 msg
= wpabuf_alloc(attr_len
);
5213 #ifdef CONFIG_TESTING_OPTIONS
5214 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
5215 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
5218 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
5219 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
5220 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5221 wpabuf_put_le16(clear
, e_nonce_len
);
5222 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
5223 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
5226 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
5227 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
5228 goto skip_wrapped_data
;
5230 #endif /* CONFIG_TESTING_OPTIONS */
5233 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5234 wpabuf_put_le16(clear
, e_nonce_len
);
5235 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
5237 #ifdef CONFIG_TESTING_OPTIONS
5239 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
5240 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
5241 goto skip_config_obj
;
5243 #endif /* CONFIG_TESTING_OPTIONS */
5246 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5247 wpabuf_put_le16(clear
, wpabuf_len(conf
));
5248 wpabuf_put_buf(clear
, conf
);
5250 if (auth
->peer_version
>= 2 && conf2
) {
5251 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5252 wpabuf_put_le16(clear
, wpabuf_len(conf2
));
5253 wpabuf_put_buf(clear
, conf2
);
5255 wpa_printf(MSG_DEBUG
,
5256 "DPP: Second Config Object available, but peer does not support more than one");
5259 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5260 netrole
== DPP_NETROLE_STA
) {
5261 wpa_printf(MSG_DEBUG
, "DPP: sendConnStatus");
5262 wpabuf_put_le16(clear
, DPP_ATTR_SEND_CONN_STATUS
);
5263 wpabuf_put_le16(clear
, 0);
5266 #ifdef CONFIG_TESTING_OPTIONS
5268 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
5269 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
5272 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
5273 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5276 #endif /* CONFIG_TESTING_OPTIONS */
5279 dpp_build_attr_status(msg
, status
);
5281 #ifdef CONFIG_TESTING_OPTIONS
5283 #endif /* CONFIG_TESTING_OPTIONS */
5285 addr
[0] = wpabuf_head(msg
);
5286 len
[0] = wpabuf_len(msg
);
5287 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5289 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5290 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5291 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5293 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5294 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5295 wpabuf_head(clear
), wpabuf_len(clear
),
5296 1, addr
, len
, wrapped
) < 0)
5298 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5299 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5301 #ifdef CONFIG_TESTING_OPTIONS
5302 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
5303 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
5304 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
5307 #endif /* CONFIG_TESTING_OPTIONS */
5309 wpa_hexdump_buf(MSG_DEBUG
,
5310 "DPP: Configuration Response attributes", msg
);
5325 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
5328 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
5329 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
5330 u8
*unwrapped
= NULL
;
5331 size_t unwrapped_len
= 0;
5332 struct wpabuf
*resp
= NULL
;
5333 struct json_token
*root
= NULL
, *token
;
5334 enum dpp_netrole netrole
;
5336 #ifdef CONFIG_TESTING_OPTIONS
5337 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
5338 wpa_printf(MSG_INFO
,
5339 "DPP: TESTING - stop at Config Request");
5342 #endif /* CONFIG_TESTING_OPTIONS */
5344 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
5345 dpp_auth_fail(auth
, "Invalid attribute in config request");
5349 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5351 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5353 "Missing or invalid required Wrapped Data attribute");
5357 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5358 wrapped_data
, wrapped_data_len
);
5359 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5360 unwrapped
= os_malloc(unwrapped_len
);
5363 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5364 wrapped_data
, wrapped_data_len
,
5365 0, NULL
, NULL
, unwrapped
) < 0) {
5366 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5369 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5370 unwrapped
, unwrapped_len
);
5372 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5373 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5377 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5378 DPP_ATTR_ENROLLEE_NONCE
,
5380 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5382 "Missing or invalid Enrollee Nonce attribute");
5385 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5386 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5388 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5389 DPP_ATTR_CONFIG_ATTR_OBJ
,
5393 "Missing or invalid Config Attributes attribute");
5396 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5397 config_attr
, config_attr_len
);
5399 root
= json_parse((const char *) config_attr
, config_attr_len
);
5401 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5405 token
= json_get_member(root
, "name");
5406 if (!token
|| token
->type
!= JSON_STRING
) {
5407 dpp_auth_fail(auth
, "No Config Attributes - name");
5410 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5412 token
= json_get_member(root
, "wi-fi_tech");
5413 if (!token
|| token
->type
!= JSON_STRING
) {
5414 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5417 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5418 if (os_strcmp(token
->string
, "infra") != 0) {
5419 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5421 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5425 token
= json_get_member(root
, "netRole");
5426 if (!token
|| token
->type
!= JSON_STRING
) {
5427 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5430 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5431 if (os_strcmp(token
->string
, "sta") == 0) {
5432 netrole
= DPP_NETROLE_STA
;
5433 } else if (os_strcmp(token
->string
, "ap") == 0) {
5434 netrole
= DPP_NETROLE_AP
;
5435 } else if (os_strcmp(token
->string
, "configurator") == 0) {
5436 netrole
= DPP_NETROLE_CONFIGURATOR
;
5438 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5440 dpp_auth_fail(auth
, "Unsupported netRole");
5444 token
= json_get_member(root
, "mudurl");
5445 if (token
&& token
->type
== JSON_STRING
)
5446 wpa_printf(MSG_DEBUG
, "DPP: mudurl = '%s'", token
->string
);
5448 token
= json_get_member(root
, "bandSupport");
5449 if (token
&& token
->type
== JSON_ARRAY
) {
5450 wpa_printf(MSG_DEBUG
, "DPP: bandSupport");
5451 token
= token
->child
;
5453 if (token
->type
!= JSON_NUMBER
)
5454 wpa_printf(MSG_DEBUG
,
5455 "DPP: Invalid bandSupport array member type");
5457 wpa_printf(MSG_DEBUG
,
5458 "DPP: Supported global operating class: %d",
5460 token
= token
->sibling
;
5464 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, netrole
);
5473 static struct wpabuf
*
5474 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
5475 const u8
*prot_hdr
, u16 prot_hdr_len
,
5476 const EVP_MD
**ret_md
)
5478 struct json_token
*root
, *token
;
5479 struct wpabuf
*kid
= NULL
;
5481 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
5483 wpa_printf(MSG_DEBUG
,
5484 "DPP: JSON parsing failed for JWS Protected Header");
5488 if (root
->type
!= JSON_OBJECT
) {
5489 wpa_printf(MSG_DEBUG
,
5490 "DPP: JWS Protected Header root is not an object");
5494 token
= json_get_member(root
, "typ");
5495 if (!token
|| token
->type
!= JSON_STRING
) {
5496 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
5499 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
5501 if (os_strcmp(token
->string
, "dppCon") != 0) {
5502 wpa_printf(MSG_DEBUG
,
5503 "DPP: Unsupported JWS Protected Header typ=%s",
5508 token
= json_get_member(root
, "alg");
5509 if (!token
|| token
->type
!= JSON_STRING
) {
5510 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
5513 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
5515 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
5516 wpa_printf(MSG_DEBUG
,
5517 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
5518 token
->string
, curve
->jws_alg
);
5521 if (os_strcmp(token
->string
, "ES256") == 0 ||
5522 os_strcmp(token
->string
, "BS256") == 0)
5523 *ret_md
= EVP_sha256();
5524 else if (os_strcmp(token
->string
, "ES384") == 0 ||
5525 os_strcmp(token
->string
, "BS384") == 0)
5526 *ret_md
= EVP_sha384();
5527 else if (os_strcmp(token
->string
, "ES512") == 0 ||
5528 os_strcmp(token
->string
, "BS512") == 0)
5529 *ret_md
= EVP_sha512();
5533 wpa_printf(MSG_DEBUG
,
5534 "DPP: Unsupported JWS Protected Header alg=%s",
5539 kid
= json_get_member_base64url(root
, "kid");
5541 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
5544 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
5553 static int dpp_parse_cred_legacy(struct dpp_config_obj
*conf
,
5554 struct json_token
*cred
)
5556 struct json_token
*pass
, *psk_hex
;
5558 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
5560 pass
= json_get_member(cred
, "pass");
5561 psk_hex
= json_get_member(cred
, "psk_hex");
5563 if (pass
&& pass
->type
== JSON_STRING
) {
5564 size_t len
= os_strlen(pass
->string
);
5566 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
5568 if (len
< 8 || len
> 63)
5570 os_strlcpy(conf
->passphrase
, pass
->string
,
5571 sizeof(conf
->passphrase
));
5572 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
5573 if (dpp_akm_sae(conf
->akm
) && !dpp_akm_psk(conf
->akm
)) {
5574 wpa_printf(MSG_DEBUG
,
5575 "DPP: Unexpected psk_hex with akm=sae");
5578 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
5579 hexstr2bin(psk_hex
->string
, conf
->psk
, PMK_LEN
) < 0) {
5580 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
5583 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
5584 conf
->psk
, PMK_LEN
);
5587 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
5591 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
[0]) {
5592 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
5600 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
5601 const struct dpp_curve_params
**key_curve
)
5603 struct json_token
*token
;
5604 const struct dpp_curve_params
*curve
;
5605 struct wpabuf
*x
= NULL
, *y
= NULL
;
5607 EVP_PKEY
*pkey
= NULL
;
5609 token
= json_get_member(jwk
, "kty");
5610 if (!token
|| token
->type
!= JSON_STRING
) {
5611 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
5614 if (os_strcmp(token
->string
, "EC") != 0) {
5615 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
5620 token
= json_get_member(jwk
, "crv");
5621 if (!token
|| token
->type
!= JSON_STRING
) {
5622 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
5625 curve
= dpp_get_curve_jwk_crv(token
->string
);
5627 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
5632 x
= json_get_member_base64url(jwk
, "x");
5634 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
5637 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
5638 if (wpabuf_len(x
) != curve
->prime_len
) {
5639 wpa_printf(MSG_DEBUG
,
5640 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
5641 (unsigned int) wpabuf_len(x
),
5642 (unsigned int) curve
->prime_len
, curve
->name
);
5646 y
= json_get_member_base64url(jwk
, "y");
5648 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
5651 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
5652 if (wpabuf_len(y
) != curve
->prime_len
) {
5653 wpa_printf(MSG_DEBUG
,
5654 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
5655 (unsigned int) wpabuf_len(y
),
5656 (unsigned int) curve
->prime_len
, curve
->name
);
5660 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
5662 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
5666 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
5668 EC_GROUP_free(group
);
5679 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
5682 unsigned int year
, month
, day
, hour
, min
, sec
;
5686 /* ISO 8601 date and time:
5688 * YYYY-MM-DDTHH:MM:SSZ
5689 * YYYY-MM-DDTHH:MM:SS+03:00
5691 if (os_strlen(timestamp
) < 19) {
5692 wpa_printf(MSG_DEBUG
,
5693 "DPP: Too short timestamp - assume expired key");
5696 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
5697 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
5698 wpa_printf(MSG_DEBUG
,
5699 "DPP: Failed to parse expiration day - assume expired key");
5703 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
5704 wpa_printf(MSG_DEBUG
,
5705 "DPP: Invalid date/time information - assume expired key");
5709 pos
= timestamp
+ 19;
5710 if (*pos
== 'Z' || *pos
== '\0') {
5711 /* In UTC - no need to adjust */
5712 } else if (*pos
== '-' || *pos
== '+') {
5715 /* Adjust local time to UTC */
5716 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
5718 wpa_printf(MSG_DEBUG
,
5719 "DPP: Invalid time zone designator (%s) - assume expired key",
5724 utime
+= 3600 * hour
;
5726 utime
-= 3600 * hour
;
5734 wpa_printf(MSG_DEBUG
,
5735 "DPP: Invalid time zone designator (%s) - assume expired key",
5742 if (os_get_time(&now
) < 0) {
5743 wpa_printf(MSG_DEBUG
,
5744 "DPP: Cannot get current time - assume expired key");
5748 if (now
.sec
> utime
) {
5749 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
5758 static int dpp_parse_connector(struct dpp_authentication
*auth
,
5759 struct dpp_config_obj
*conf
,
5760 const unsigned char *payload
,
5763 struct json_token
*root
, *groups
, *netkey
, *token
;
5765 EVP_PKEY
*key
= NULL
;
5766 const struct dpp_curve_params
*curve
;
5767 unsigned int rules
= 0;
5769 root
= json_parse((const char *) payload
, payload_len
);
5771 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
5775 groups
= json_get_member(root
, "groups");
5776 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
5777 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
5780 for (token
= groups
->child
; token
; token
= token
->sibling
) {
5781 struct json_token
*id
, *role
;
5783 id
= json_get_member(token
, "groupId");
5784 if (!id
|| id
->type
!= JSON_STRING
) {
5785 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
5789 role
= json_get_member(token
, "netRole");
5790 if (!role
|| role
->type
!= JSON_STRING
) {
5791 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
5794 wpa_printf(MSG_DEBUG
,
5795 "DPP: connector group: groupId='%s' netRole='%s'",
5796 id
->string
, role
->string
);
5802 wpa_printf(MSG_DEBUG
,
5803 "DPP: Connector includes no groups");
5807 token
= json_get_member(root
, "expiry");
5808 if (!token
|| token
->type
!= JSON_STRING
) {
5809 wpa_printf(MSG_DEBUG
,
5810 "DPP: No expiry string found - connector does not expire");
5812 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
5813 if (dpp_key_expired(token
->string
,
5814 &auth
->net_access_key_expiry
)) {
5815 wpa_printf(MSG_DEBUG
,
5816 "DPP: Connector (netAccessKey) has expired");
5821 netkey
= json_get_member(root
, "netAccessKey");
5822 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
5823 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
5827 key
= dpp_parse_jwk(netkey
, &curve
);
5830 dpp_debug_print_key("DPP: Received netAccessKey", key
);
5832 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
5833 wpa_printf(MSG_DEBUG
,
5834 "DPP: netAccessKey in connector does not match own protocol key");
5835 #ifdef CONFIG_TESTING_OPTIONS
5836 if (auth
->ignore_netaccesskey_mismatch
) {
5837 wpa_printf(MSG_DEBUG
,
5838 "DPP: TESTING - skip netAccessKey mismatch");
5842 #else /* CONFIG_TESTING_OPTIONS */
5844 #endif /* CONFIG_TESTING_OPTIONS */
5855 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
5857 struct wpabuf
*uncomp
;
5859 u8 hash
[SHA256_MAC_LEN
];
5863 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
5865 uncomp
= dpp_get_pubkey_point(pub
, 1);
5868 addr
[0] = wpabuf_head(uncomp
);
5869 len
[0] = wpabuf_len(uncomp
);
5870 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
5872 res
= sha256_vector(1, addr
, len
, hash
);
5873 wpabuf_free(uncomp
);
5876 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
5877 wpa_printf(MSG_DEBUG
,
5878 "DPP: Received hash value does not match calculated public key hash value");
5879 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
5880 hash
, SHA256_MAC_LEN
);
5887 static void dpp_copy_csign(struct dpp_config_obj
*conf
, EVP_PKEY
*csign
)
5889 unsigned char *der
= NULL
;
5892 der_len
= i2d_PUBKEY(csign
, &der
);
5895 wpabuf_free(conf
->c_sign_key
);
5896 conf
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
5901 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
,
5902 struct dpp_config_obj
*conf
)
5904 unsigned char *der
= NULL
;
5908 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
5912 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5917 wpabuf_free(auth
->net_access_key
);
5918 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
5924 struct dpp_signed_connector_info
{
5925 unsigned char *payload
;
5929 static enum dpp_status_error
5930 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
5931 EVP_PKEY
*csign_pub
, const char *connector
)
5933 enum dpp_status_error ret
= 255;
5934 const char *pos
, *end
, *signed_start
, *signed_end
;
5935 struct wpabuf
*kid
= NULL
;
5936 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
5937 size_t prot_hdr_len
= 0, signature_len
= 0;
5938 const EVP_MD
*sign_md
= NULL
;
5939 unsigned char *der
= NULL
;
5942 EVP_MD_CTX
*md_ctx
= NULL
;
5943 ECDSA_SIG
*sig
= NULL
;
5944 BIGNUM
*r
= NULL
, *s
= NULL
;
5945 const struct dpp_curve_params
*curve
;
5947 const EC_GROUP
*group
;
5950 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
5953 group
= EC_KEY_get0_group(eckey
);
5956 nid
= EC_GROUP_get_curve_name(group
);
5957 curve
= dpp_get_curve_nid(nid
);
5960 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
5961 os_memset(info
, 0, sizeof(*info
));
5963 signed_start
= pos
= connector
;
5964 end
= os_strchr(pos
, '.');
5966 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
5967 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5970 prot_hdr
= base64_url_decode(pos
, end
- pos
, &prot_hdr_len
);
5972 wpa_printf(MSG_DEBUG
,
5973 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
5974 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5977 wpa_hexdump_ascii(MSG_DEBUG
,
5978 "DPP: signedConnector - JWS Protected Header",
5979 prot_hdr
, prot_hdr_len
);
5980 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
5982 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5985 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
5986 wpa_printf(MSG_DEBUG
,
5987 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
5988 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
5989 ret
= DPP_STATUS_INVALID_CONNECTOR
;
5994 end
= os_strchr(pos
, '.');
5996 wpa_printf(MSG_DEBUG
,
5997 "DPP: Missing dot(2) in signedConnector");
5998 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6001 signed_end
= end
- 1;
6002 info
->payload
= base64_url_decode(pos
, end
- pos
, &info
->payload_len
);
6003 if (!info
->payload
) {
6004 wpa_printf(MSG_DEBUG
,
6005 "DPP: Failed to base64url decode signedConnector JWS Payload");
6006 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6009 wpa_hexdump_ascii(MSG_DEBUG
,
6010 "DPP: signedConnector - JWS Payload",
6011 info
->payload
, info
->payload_len
);
6013 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
6015 wpa_printf(MSG_DEBUG
,
6016 "DPP: Failed to base64url decode signedConnector signature");
6017 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6020 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
6021 signature
, signature_len
);
6023 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
6024 ret
= DPP_STATUS_NO_MATCH
;
6028 if (signature_len
& 0x01) {
6029 wpa_printf(MSG_DEBUG
,
6030 "DPP: Unexpected signedConnector signature length (%d)",
6031 (int) signature_len
);
6032 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6036 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6037 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6038 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
6039 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
6040 sig
= ECDSA_SIG_new();
6041 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
6046 der_len
= i2d_ECDSA_SIG(sig
, &der
);
6048 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
6051 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
6052 md_ctx
= EVP_MD_CTX_create();
6057 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
6058 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
6059 ERR_error_string(ERR_get_error(), NULL
));
6062 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
6063 signed_end
- signed_start
+ 1) != 1) {
6064 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
6065 ERR_error_string(ERR_get_error(), NULL
));
6068 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
6070 wpa_printf(MSG_DEBUG
,
6071 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6072 res
, ERR_error_string(ERR_get_error(), NULL
));
6073 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6077 ret
= DPP_STATUS_OK
;
6080 EVP_MD_CTX_destroy(md_ctx
);
6084 ECDSA_SIG_free(sig
);
6092 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
6093 struct dpp_config_obj
*conf
,
6094 struct json_token
*cred
)
6096 struct dpp_signed_connector_info info
;
6097 struct json_token
*token
, *csign
;
6099 EVP_PKEY
*csign_pub
= NULL
;
6100 const struct dpp_curve_params
*key_curve
= NULL
;
6101 const char *signed_connector
;
6103 os_memset(&info
, 0, sizeof(info
));
6105 if (dpp_akm_psk(conf
->akm
) || dpp_akm_sae(conf
->akm
)) {
6106 wpa_printf(MSG_DEBUG
,
6107 "DPP: Legacy credential included in Connector credential");
6108 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6112 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
6114 csign
= json_get_member(cred
, "csign");
6115 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
6116 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
6120 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
6122 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
6125 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
6127 token
= json_get_member(cred
, "signedConnector");
6128 if (!token
|| token
->type
!= JSON_STRING
) {
6129 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
6132 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
6133 token
->string
, os_strlen(token
->string
));
6134 signed_connector
= token
->string
;
6136 if (os_strchr(signed_connector
, '"') ||
6137 os_strchr(signed_connector
, '\n')) {
6138 wpa_printf(MSG_DEBUG
,
6139 "DPP: Unexpected character in signedConnector");
6143 if (dpp_process_signed_connector(&info
, csign_pub
,
6144 signed_connector
) != DPP_STATUS_OK
)
6147 if (dpp_parse_connector(auth
, conf
,
6148 info
.payload
, info
.payload_len
) < 0) {
6149 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
6153 os_free(conf
->connector
);
6154 conf
->connector
= os_strdup(signed_connector
);
6156 dpp_copy_csign(conf
, csign_pub
);
6157 dpp_copy_netaccesskey(auth
, conf
);
6161 EVP_PKEY_free(csign_pub
);
6162 os_free(info
.payload
);
6167 const char * dpp_akm_str(enum dpp_akm akm
)
6176 case DPP_AKM_PSK_SAE
:
6178 case DPP_AKM_SAE_DPP
:
6180 case DPP_AKM_PSK_SAE_DPP
:
6181 return "dpp+psk+sae";
6188 const char * dpp_akm_selector_str(enum dpp_akm akm
)
6194 return "000FAC02+000FAC06";
6197 case DPP_AKM_PSK_SAE
:
6198 return "000FAC02+000FAC06+000FAC08";
6199 case DPP_AKM_SAE_DPP
:
6200 return "506F9A02+000FAC08";
6201 case DPP_AKM_PSK_SAE_DPP
:
6202 return "506F9A02+000FAC08+000FAC02+000FAC06";
6209 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
6212 int dpp
= 0, psk
= 0, sae
= 0;
6214 if (os_strcmp(akm
, "psk") == 0)
6216 if (os_strcmp(akm
, "sae") == 0)
6218 if (os_strcmp(akm
, "psk+sae") == 0)
6219 return DPP_AKM_PSK_SAE
;
6220 if (os_strcmp(akm
, "dpp") == 0)
6222 if (os_strcmp(akm
, "dpp+sae") == 0)
6223 return DPP_AKM_SAE_DPP
;
6224 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
6225 return DPP_AKM_PSK_SAE_DPP
;
6229 if (os_strlen(pos
) < 8)
6231 if (os_strncasecmp(pos
, "506F9A02", 8) == 0)
6233 else if (os_strncasecmp(pos
, "000FAC02", 8) == 0)
6235 else if (os_strncasecmp(pos
, "000FAC06", 8) == 0)
6237 else if (os_strncasecmp(pos
, "000FAC08", 8) == 0)
6245 if (dpp
&& psk
&& sae
)
6246 return DPP_AKM_PSK_SAE_DPP
;
6248 return DPP_AKM_SAE_DPP
;
6252 return DPP_AKM_PSK_SAE
;
6258 return DPP_AKM_UNKNOWN
;
6262 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
6263 const u8
*conf_obj
, u16 conf_obj_len
)
6266 struct json_token
*root
, *token
, *discovery
, *cred
;
6267 struct dpp_config_obj
*conf
;
6268 struct wpabuf
*ssid64
= NULL
;
6270 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
6273 if (root
->type
!= JSON_OBJECT
) {
6274 dpp_auth_fail(auth
, "JSON root is not an object");
6278 token
= json_get_member(root
, "wi-fi_tech");
6279 if (!token
|| token
->type
!= JSON_STRING
) {
6280 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
6283 if (os_strcmp(token
->string
, "infra") != 0) {
6284 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
6286 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
6290 discovery
= json_get_member(root
, "discovery");
6291 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
6292 dpp_auth_fail(auth
, "No discovery object in JSON");
6296 ssid64
= json_get_member_base64url(discovery
, "ssid64");
6298 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid64",
6299 wpabuf_head(ssid64
), wpabuf_len(ssid64
));
6300 if (wpabuf_len(ssid64
) > SSID_MAX_LEN
) {
6301 dpp_auth_fail(auth
, "Too long discovery::ssid64 value");
6305 token
= json_get_member(discovery
, "ssid");
6306 if (!token
|| token
->type
!= JSON_STRING
) {
6308 "No discovery::ssid string value found");
6311 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
6312 token
->string
, os_strlen(token
->string
));
6313 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
6315 "Too long discovery::ssid string value");
6320 if (auth
->num_conf_obj
== DPP_MAX_CONF_OBJ
) {
6321 wpa_printf(MSG_DEBUG
,
6322 "DPP: No room for this many Config Objects - ignore this one");
6326 conf
= &auth
->conf_obj
[auth
->num_conf_obj
++];
6329 conf
->ssid_len
= wpabuf_len(ssid64
);
6330 os_memcpy(conf
->ssid
, wpabuf_head(ssid64
), conf
->ssid_len
);
6332 conf
->ssid_len
= os_strlen(token
->string
);
6333 os_memcpy(conf
->ssid
, token
->string
, conf
->ssid_len
);
6336 token
= json_get_member(discovery
, "ssid_charset");
6337 if (token
&& token
->type
== JSON_NUMBER
) {
6338 conf
->ssid_charset
= token
->number
;
6339 wpa_printf(MSG_DEBUG
, "DPP: ssid_charset=%d",
6340 conf
->ssid_charset
);
6343 cred
= json_get_member(root
, "cred");
6344 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
6345 dpp_auth_fail(auth
, "No cred object in JSON");
6349 token
= json_get_member(cred
, "akm");
6350 if (!token
|| token
->type
!= JSON_STRING
) {
6351 dpp_auth_fail(auth
, "No cred::akm string value found");
6354 conf
->akm
= dpp_akm_from_str(token
->string
);
6356 if (dpp_akm_legacy(conf
->akm
)) {
6357 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6359 } else if (dpp_akm_dpp(conf
->akm
)) {
6360 if (dpp_parse_cred_dpp(auth
, conf
, cred
) < 0)
6363 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
6365 dpp_auth_fail(auth
, "Unsupported akm");
6369 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
6372 wpabuf_free(ssid64
);
6380 struct dpp_enveloped_data
{
6382 size_t enc_cont_len
;
6386 size_t pbkdf2_key_len
;
6387 size_t prf_hash_len
;
6391 static int dpp_parse_recipient_infos(const u8
*pos
, size_t len
,
6392 struct dpp_enveloped_data
*data
)
6394 struct asn1_hdr hdr
;
6395 const u8
*end
= pos
+ len
;
6396 const u8
*next
, *e_end
;
6397 struct asn1_oid oid
;
6402 wpa_hexdump(MSG_MSGDUMP
, "DPP: RecipientInfos", pos
, len
);
6405 * RecipientInfo ::= CHOICE {
6406 * ktri KeyTransRecipientInfo,
6407 * kari [1] KeyAgreeRecipientInfo,
6408 * kekri [2] KEKRecipientInfo,
6409 * pwri [3] PasswordRecipientInfo,
6410 * ori [4] OtherRecipientInfo}
6412 * Shall always use the pwri CHOICE.
6415 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6416 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 3) {
6417 wpa_printf(MSG_DEBUG
,
6418 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
6419 hdr
.class, hdr
.tag
);
6422 wpa_hexdump(MSG_MSGDUMP
, "DPP: PasswordRecipientInfo",
6423 hdr
.payload
, hdr
.length
);
6425 end
= pos
+ hdr
.length
;
6428 * PasswordRecipientInfo ::= SEQUENCE {
6429 * version CMSVersion,
6430 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
6431 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
6432 * encryptedKey EncryptedKey}
6434 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
6435 * parameters contains PBKDF2-params SEQUENCE.
6438 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
6442 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
6445 wpa_printf(MSG_DEBUG
, "DPP: pwri.version != 0");
6449 wpa_hexdump(MSG_MSGDUMP
, "DPP: Remaining PasswordRecipientInfo after version",
6452 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6453 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
6454 wpa_printf(MSG_DEBUG
,
6455 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
6456 hdr
.class, hdr
.tag
);
6460 e_end
= pos
+ hdr
.length
;
6462 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
6463 if (asn1_get_alg_id(pos
, e_end
- pos
, &oid
, ¶ms
, ¶ms_len
,
6466 if (!asn1_oid_equal(&oid
, &asn1_pbkdf2_oid
)) {
6469 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
6470 wpa_printf(MSG_DEBUG
,
6471 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
6477 * PBKDF2-params ::= SEQUENCE {
6479 * specified OCTET STRING,
6480 * otherSource AlgorithmIdentifier}
6481 * iterationCount INTEGER (1..MAX),
6482 * keyLength INTEGER (1..MAX),
6483 * prf AlgorithmIdentifier}
6485 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
6486 * on Configurator signing key length, prf is
6487 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
6490 asn1_get_sequence(params
, params_len
, &hdr
, &e_end
) < 0)
6494 if (asn1_get_next(pos
, e_end
- pos
, &hdr
) < 0 ||
6495 hdr
.class != ASN1_CLASS_UNIVERSAL
||
6496 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
6497 wpa_printf(MSG_DEBUG
,
6498 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
6499 hdr
.class, hdr
.tag
);
6502 wpa_hexdump(MSG_MSGDUMP
, "DPP: salt.specified",
6503 hdr
.payload
, hdr
.length
);
6504 if (hdr
.length
!= 64) {
6505 wpa_printf(MSG_DEBUG
, "DPP: Unexpected salt length %u",
6509 data
->salt
= hdr
.payload
;
6510 pos
= hdr
.payload
+ hdr
.length
;
6512 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
6515 wpa_printf(MSG_DEBUG
, "DPP: Unexpected iterationCount %d", val
);
6519 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
6521 if (val
!= 32 && val
!= 48 && val
!= 64) {
6522 wpa_printf(MSG_DEBUG
, "DPP: Unexpected keyLength %d", val
);
6525 data
->pbkdf2_key_len
= val
;
6527 if (asn1_get_sequence(pos
, e_end
- pos
, &hdr
, NULL
) < 0 ||
6528 asn1_get_oid(hdr
.payload
, hdr
.length
, &oid
, &pos
) < 0) {
6529 wpa_printf(MSG_DEBUG
, "DPP: Could not parse prf");
6532 if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha256_oid
)) {
6533 data
->prf_hash_len
= 32;
6534 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha384_oid
)) {
6535 data
->prf_hash_len
= 48;
6536 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha512_oid
)) {
6537 data
->prf_hash_len
= 64;
6541 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
6542 wpa_printf(MSG_DEBUG
, "DPP: Unexpected PBKDF2-params.prf %s",
6549 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
6551 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
6553 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
6554 * id-alg-AES-SIV-CMAC-aed-512. */
6555 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
6557 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
6558 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
6559 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
6562 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
6563 wpa_printf(MSG_DEBUG
,
6564 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
6570 * encryptedKey EncryptedKey
6572 * EncryptedKey ::= OCTET STRING
6574 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6575 hdr
.class != ASN1_CLASS_UNIVERSAL
||
6576 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
6577 wpa_printf(MSG_DEBUG
,
6578 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
6579 hdr
.class, hdr
.tag
);
6582 wpa_hexdump(MSG_MSGDUMP
, "DPP: pwri.encryptedKey",
6583 hdr
.payload
, hdr
.length
);
6584 data
->enc_key
= hdr
.payload
;
6585 data
->enc_key_len
= hdr
.length
;
6591 static int dpp_parse_encrypted_content_info(const u8
*pos
, const u8
*end
,
6592 struct dpp_enveloped_data
*data
)
6594 struct asn1_hdr hdr
;
6595 struct asn1_oid oid
;
6598 * EncryptedContentInfo ::= SEQUENCE {
6599 * contentType ContentType,
6600 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
6601 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
6603 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
6605 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContentInfo",
6606 hdr
.payload
, hdr
.length
);
6608 wpa_hexdump(MSG_DEBUG
,
6609 "DPP: Unexpected extra data after EncryptedContentInfo",
6617 /* ContentType ::= OBJECT IDENTIFIER */
6618 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0) {
6619 wpa_printf(MSG_DEBUG
, "DPP: Could not parse ContentType");
6622 if (!asn1_oid_equal(&oid
, &asn1_dpp_asymmetric_key_package_oid
)) {
6625 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
6626 wpa_printf(MSG_DEBUG
, "DPP: Unexpected ContentType %s", buf
);
6630 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
6631 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
6633 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
6634 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
6635 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
6638 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
6639 wpa_printf(MSG_DEBUG
,
6640 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
6644 /* ignore optional parameters */
6646 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
6647 * EncryptedContent ::= OCTET STRING */
6648 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6649 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
6650 wpa_printf(MSG_DEBUG
,
6651 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
6652 hdr
.class, hdr
.tag
);
6655 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContent",
6656 hdr
.payload
, hdr
.length
);
6657 data
->enc_cont
= hdr
.payload
;
6658 data
->enc_cont_len
= hdr
.length
;
6663 static int dpp_parse_enveloped_data(const u8
*env_data
, size_t env_data_len
,
6664 struct dpp_enveloped_data
*data
)
6666 struct asn1_hdr hdr
;
6667 const u8
*pos
, *end
;
6670 os_memset(data
, 0, sizeof(*data
));
6673 * DPPEnvelopedData ::= EnvelopedData
6675 * EnvelopedData ::= SEQUENCE {
6676 * version CMSVersion,
6677 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
6678 * recipientInfos RecipientInfos,
6679 * encryptedContentInfo EncryptedContentInfo,
6680 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
6682 * CMSVersion ::= INTEGER
6684 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
6686 * For DPP, version is 3, both originatorInfo and
6687 * unprotectedAttrs are omitted, and recipientInfos contains a single
6690 if (asn1_get_sequence(env_data
, env_data_len
, &hdr
, &end
) < 0)
6693 if (end
< env_data
+ env_data_len
) {
6694 wpa_hexdump(MSG_DEBUG
,
6695 "DPP: Unexpected extra data after DPPEnvelopedData",
6696 end
, env_data
+ env_data_len
- end
);
6700 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
6703 wpa_printf(MSG_DEBUG
, "DPP: EnvelopedData.version != 3");
6707 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6708 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
6709 wpa_printf(MSG_DEBUG
,
6710 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
6711 hdr
.class, hdr
.tag
);
6715 if (dpp_parse_recipient_infos(hdr
.payload
, hdr
.length
, data
) < 0)
6717 return dpp_parse_encrypted_content_info(hdr
.payload
+ hdr
.length
, end
,
6722 static struct dpp_asymmetric_key
*
6723 dpp_parse_one_asymmetric_key(const u8
*buf
, size_t len
)
6725 struct asn1_hdr hdr
;
6726 const u8
*pos
= buf
, *end
= buf
+ len
, *next
;
6730 struct asn1_oid oid
;
6732 struct dpp_asymmetric_key
*key
;
6735 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: OneAsymmetricKey", buf
, len
);
6737 key
= os_zalloc(sizeof(*key
));
6742 * OneAsymmetricKey ::= SEQUENCE {
6744 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
6745 * privateKey PrivateKey,
6746 * attributes [0] Attributes OPTIONAL,
6748 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
6752 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
6756 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
6757 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
6760 wpa_printf(MSG_DEBUG
,
6761 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
6766 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
6767 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, ¶ms
, ¶ms_len
,
6770 if (!asn1_oid_equal(&oid
, &asn1_ec_public_key_oid
)) {
6771 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
6772 wpa_printf(MSG_DEBUG
,
6773 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
6777 wpa_hexdump(MSG_MSGDUMP
, "DPP: PrivateKeyAlgorithmIdentifier params",
6778 params
, params_len
);
6780 * ECParameters ::= CHOICE {
6781 * namedCurve OBJECT IDENTIFIER
6782 * -- implicitCurve NULL
6783 * -- specifiedCurve SpecifiedECDomain}
6785 if (!params
|| asn1_get_oid(params
, params_len
, &oid
, &next
) < 0) {
6786 wpa_printf(MSG_DEBUG
,
6787 "DPP: Could not parse ECParameters.namedCurve");
6790 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
6791 wpa_printf(MSG_MSGDUMP
, "DPP: namedCurve %s", txt
);
6792 /* Assume the curve is identified within ECPrivateKey, so that this
6793 * separate indication is not really needed. */
6796 * PrivateKey ::= OCTET STRING
6797 * (Contains DER encoding of ECPrivateKey)
6799 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6800 hdr
.class != ASN1_CLASS_UNIVERSAL
||
6801 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
6802 wpa_printf(MSG_DEBUG
,
6803 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
6804 hdr
.class, hdr
.tag
);
6807 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: PrivateKey",
6808 hdr
.payload
, hdr
.length
);
6809 pos
= hdr
.payload
+ hdr
.length
;
6810 eckey
= d2i_ECPrivateKey(NULL
, &hdr
.payload
, hdr
.length
);
6812 wpa_printf(MSG_INFO
,
6813 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
6814 ERR_error_string(ERR_get_error(), NULL
));
6817 key
->csign
= EVP_PKEY_new();
6818 if (!key
->csign
|| EVP_PKEY_assign_EC_KEY(key
->csign
, eckey
) != 1) {
6822 if (wpa_debug_show_keys
)
6823 dpp_debug_print_key("DPP: Received c-sign-key", key
->csign
);
6826 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
6828 * Exactly one instance of type Attribute in OneAsymmetricKey.
6830 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6831 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
6832 wpa_printf(MSG_DEBUG
,
6833 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
6834 hdr
.class, hdr
.tag
);
6837 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: Attributes",
6838 hdr
.payload
, hdr
.length
);
6839 if (hdr
.payload
+ hdr
.length
< end
) {
6840 wpa_hexdump_key(MSG_MSGDUMP
,
6841 "DPP: Ignore additional data at the end of OneAsymmetricKey",
6842 hdr
.payload
+ hdr
.length
,
6843 end
- (hdr
.payload
+ hdr
.length
));
6846 end
= hdr
.payload
+ hdr
.length
;
6848 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6849 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
6850 wpa_printf(MSG_DEBUG
,
6851 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
6852 hdr
.class, hdr
.tag
);
6855 if (hdr
.payload
+ hdr
.length
< end
) {
6856 wpa_hexdump_key(MSG_MSGDUMP
,
6857 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
6858 hdr
.payload
+ hdr
.length
,
6859 end
- (hdr
.payload
+ hdr
.length
));
6862 end
= hdr
.payload
+ hdr
.length
;
6865 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
6866 * aa-DPPConfigurationParameters,
6867 * ... -- For local profiles
6870 * aa-DPPConfigurationParameters ATTRIBUTE ::=
6871 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
6873 * Attribute ::= SEQUENCE {
6874 * type OBJECT IDENTIFIER,
6875 * values SET SIZE(1..MAX) OF Type
6877 * Exactly one instance of ATTRIBUTE in attrValues.
6879 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
6882 wpa_hexdump_key(MSG_MSGDUMP
,
6883 "DPP: Ignore additional data at the end of ATTRIBUTE",
6889 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0)
6891 if (!asn1_oid_equal(&oid
, &asn1_dpp_config_params_oid
)) {
6892 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
6893 wpa_printf(MSG_DEBUG
,
6894 "DPP: Unexpected Attribute identifier %s", txt
);
6898 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6899 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
6900 wpa_printf(MSG_DEBUG
,
6901 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
6902 hdr
.class, hdr
.tag
);
6906 end
= hdr
.payload
+ hdr
.length
;
6909 * DPPConfigurationParameters ::= SEQUENCE {
6910 * configurationTemplate UTF8String,
6911 * connectorTemplate UTF8String OPTIONAL}
6914 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPConfigurationParameters",
6916 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
6919 wpa_hexdump_key(MSG_MSGDUMP
,
6920 "DPP: Ignore additional data after DPPConfigurationParameters",
6926 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6927 hdr
.class != ASN1_CLASS_UNIVERSAL
||
6928 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
6929 wpa_printf(MSG_DEBUG
,
6930 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
6931 hdr
.class, hdr
.tag
);
6934 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: configurationTemplate",
6935 hdr
.payload
, hdr
.length
);
6936 key
->config_template
= os_zalloc(hdr
.length
+ 1);
6937 if (!key
->config_template
)
6939 os_memcpy(key
->config_template
, hdr
.payload
, hdr
.length
);
6941 pos
= hdr
.payload
+ hdr
.length
;
6944 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6945 hdr
.class != ASN1_CLASS_UNIVERSAL
||
6946 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
6947 wpa_printf(MSG_DEBUG
,
6948 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
6949 hdr
.class, hdr
.tag
);
6952 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: connectorTemplate",
6953 hdr
.payload
, hdr
.length
);
6954 key
->connector_template
= os_zalloc(hdr
.length
+ 1);
6955 if (!key
->connector_template
)
6957 os_memcpy(key
->connector_template
, hdr
.payload
, hdr
.length
);
6962 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse OneAsymmetricKey");
6963 dpp_free_asymmetric_key(key
);
6968 static struct dpp_asymmetric_key
*
6969 dpp_parse_dpp_asymmetric_key_package(const u8
*key_pkg
, size_t key_pkg_len
)
6971 struct asn1_hdr hdr
;
6972 const u8
*pos
= key_pkg
, *end
= key_pkg
+ key_pkg_len
;
6973 struct dpp_asymmetric_key
*first
= NULL
, *last
= NULL
, *key
;
6975 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
6976 key_pkg
, key_pkg_len
);
6979 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
6981 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
6984 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0 ||
6985 !(key
= dpp_parse_one_asymmetric_key(hdr
.payload
,
6987 dpp_free_asymmetric_key(first
);
7002 static int dpp_conf_resp_env_data(struct dpp_authentication
*auth
,
7003 const u8
*env_data
, size_t env_data_len
)
7007 u8 kek
[DPP_MAX_HASH_LEN
];
7008 u8 cont_encr_key
[DPP_MAX_HASH_LEN
];
7009 size_t cont_encr_key_len
;
7013 struct dpp_enveloped_data data
;
7014 struct dpp_asymmetric_key
*keys
;
7016 wpa_hexdump(MSG_DEBUG
, "DPP: DPPEnvelopedData", env_data
, env_data_len
);
7018 if (dpp_parse_enveloped_data(env_data
, env_data_len
, &data
) < 0)
7021 /* TODO: For initial testing, use ke as the key. Replace this with a
7022 * new key once that has been defined. */
7024 key_len
= auth
->curve
->hash_len
;
7025 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
7027 if (dpp_pbkdf2(data
.prf_hash_len
, key
, key_len
, data
.salt
, 64, 1000,
7028 kek
, data
.pbkdf2_key_len
)) {
7029 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
7032 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
7033 kek
, data
.pbkdf2_key_len
);
7035 if (data
.enc_key_len
< AES_BLOCK_SIZE
||
7036 data
.enc_key_len
> sizeof(cont_encr_key
) + AES_BLOCK_SIZE
) {
7037 wpa_printf(MSG_DEBUG
, "DPP: Invalid encryptedKey length");
7040 res
= aes_siv_decrypt(kek
, data
.pbkdf2_key_len
,
7041 data
.enc_key
, data
.enc_key_len
,
7042 0, NULL
, NULL
, cont_encr_key
);
7043 forced_memzero(kek
, data
.pbkdf2_key_len
);
7045 wpa_printf(MSG_DEBUG
,
7046 "DPP: AES-SIV decryption of encryptedKey failed");
7049 cont_encr_key_len
= data
.enc_key_len
- AES_BLOCK_SIZE
;
7050 wpa_hexdump_key(MSG_DEBUG
, "DPP: content-encryption key",
7051 cont_encr_key
, cont_encr_key_len
);
7053 if (data
.enc_cont_len
< AES_BLOCK_SIZE
)
7055 key_pkg_len
= data
.enc_cont_len
- AES_BLOCK_SIZE
;
7056 key_pkg
= os_malloc(key_pkg_len
);
7059 res
= aes_siv_decrypt(cont_encr_key
, cont_encr_key_len
,
7060 data
.enc_cont
, data
.enc_cont_len
,
7061 0, NULL
, NULL
, key_pkg
);
7062 forced_memzero(cont_encr_key
, cont_encr_key_len
);
7064 bin_clear_free(key_pkg
, key_pkg_len
);
7065 wpa_printf(MSG_DEBUG
,
7066 "DPP: AES-SIV decryption of encryptedContent failed");
7070 keys
= dpp_parse_dpp_asymmetric_key_package(key_pkg
, key_pkg_len
);
7071 bin_clear_free(key_pkg
, key_pkg_len
);
7072 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
7073 auth
->conf_key_pkg
= keys
;
7075 return keys
!= NULL
;;
7078 #endif /* CONFIG_DPP2 */
7081 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
7082 const struct wpabuf
*resp
)
7084 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
7085 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
7090 u8
*unwrapped
= NULL
;
7091 size_t unwrapped_len
= 0;
7094 auth
->conf_resp_status
= 255;
7096 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
7097 dpp_auth_fail(auth
, "Invalid attribute in config response");
7101 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7102 DPP_ATTR_WRAPPED_DATA
,
7104 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7106 "Missing or invalid required Wrapped Data attribute");
7110 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7111 wrapped_data
, wrapped_data_len
);
7112 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7113 unwrapped
= os_malloc(unwrapped_len
);
7117 addr
[0] = wpabuf_head(resp
);
7118 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
7119 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
7121 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7122 wrapped_data
, wrapped_data_len
,
7123 1, addr
, len
, unwrapped
) < 0) {
7124 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7127 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7128 unwrapped
, unwrapped_len
);
7130 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7131 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7135 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7136 DPP_ATTR_ENROLLEE_NONCE
,
7138 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7140 "Missing or invalid Enrollee Nonce attribute");
7143 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7144 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7145 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7149 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7150 DPP_ATTR_STATUS
, &status_len
);
7151 if (!status
|| status_len
< 1) {
7153 "Missing or invalid required DPP Status attribute");
7156 auth
->conf_resp_status
= status
[0];
7157 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7158 if (status
[0] != DPP_STATUS_OK
) {
7159 dpp_auth_fail(auth
, "Configurator rejected configuration");
7163 env_data
= dpp_get_attr(unwrapped
, unwrapped_len
,
7164 DPP_ATTR_ENVELOPED_DATA
, &env_data_len
);
7167 dpp_conf_resp_env_data(auth
, env_data
, env_data_len
) < 0)
7169 #endif /* CONFIG_DPP2 */
7171 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONFIG_OBJ
,
7173 if (!conf_obj
&& !env_data
) {
7175 "Missing required Configuration Object attribute");
7179 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
7180 conf_obj
, conf_obj_len
);
7181 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
7183 conf_obj
= dpp_get_attr_next(conf_obj
, unwrapped
, unwrapped_len
,
7184 DPP_ATTR_CONFIG_OBJ
,
7189 status
= dpp_get_attr(unwrapped
, unwrapped_len
,
7190 DPP_ATTR_SEND_CONN_STATUS
, &status_len
);
7192 wpa_printf(MSG_DEBUG
,
7193 "DPP: Configurator requested connection status result");
7194 auth
->conn_status_requested
= 1;
7196 #endif /* CONFIG_DPP2 */
7208 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
7210 const u8
*attr_start
, size_t attr_len
)
7212 const u8
*wrapped_data
, *status
, *e_nonce
;
7213 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7216 u8
*unwrapped
= NULL
;
7217 size_t unwrapped_len
= 0;
7218 enum dpp_status_error ret
= 256;
7220 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7222 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7224 "Missing or invalid required Wrapped Data attribute");
7227 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7228 wrapped_data
, wrapped_data_len
);
7230 attr_len
= wrapped_data
- 4 - attr_start
;
7233 len
[0] = DPP_HDR_LEN
;
7234 addr
[1] = attr_start
;
7236 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7237 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7238 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7239 wrapped_data
, wrapped_data_len
);
7240 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7241 unwrapped
= os_malloc(unwrapped_len
);
7244 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7245 wrapped_data
, wrapped_data_len
,
7246 2, addr
, len
, unwrapped
) < 0) {
7247 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7250 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7251 unwrapped
, unwrapped_len
);
7253 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7254 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7258 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7259 DPP_ATTR_ENROLLEE_NONCE
,
7261 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7263 "Missing or invalid Enrollee Nonce attribute");
7266 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7267 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7268 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7269 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7270 auth
->e_nonce
, e_nonce_len
);
7274 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
7276 if (!status
|| status_len
< 1) {
7278 "Missing or invalid required DPP Status attribute");
7281 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7285 bin_clear_free(unwrapped
, unwrapped_len
);
7290 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
7291 enum dpp_status_error status
)
7293 struct wpabuf
*msg
, *clear
;
7294 size_t nonce_len
, clear_len
, attr_len
;
7299 nonce_len
= auth
->curve
->nonce_len
;
7300 clear_len
= 5 + 4 + nonce_len
;
7301 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7302 clear
= wpabuf_alloc(clear_len
);
7303 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
7308 dpp_build_attr_status(clear
, status
);
7311 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
7312 wpabuf_put_le16(clear
, nonce_len
);
7313 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
7315 /* OUI, OUI type, Crypto Suite, DPP frame type */
7316 addr
[0] = wpabuf_head_u8(msg
) + 2;
7317 len
[0] = 3 + 1 + 1 + 1;
7318 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7320 /* Attributes before Wrapped Data (none) */
7321 addr
[1] = wpabuf_put(msg
, 0);
7323 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7326 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7327 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7328 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7330 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7331 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
7332 wpabuf_head(clear
), wpabuf_len(clear
),
7333 2, addr
, len
, wrapped
) < 0)
7336 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
7346 static int valid_channel_list(const char *val
)
7349 if (!((*val
>= '0' && *val
<= '9') ||
7350 *val
== '/' || *val
== ','))
7359 enum dpp_status_error
dpp_conn_status_result_rx(struct dpp_authentication
*auth
,
7361 const u8
*attr_start
,
7363 u8
*ssid
, size_t *ssid_len
,
7364 char **channel_list
)
7366 const u8
*wrapped_data
, *status
, *e_nonce
;
7367 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7370 u8
*unwrapped
= NULL
;
7371 size_t unwrapped_len
= 0;
7372 enum dpp_status_error ret
= 256;
7373 struct json_token
*root
= NULL
, *token
;
7374 struct wpabuf
*ssid64
;
7377 *channel_list
= NULL
;
7379 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7381 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7383 "Missing or invalid required Wrapped Data attribute");
7386 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7387 wrapped_data
, wrapped_data_len
);
7389 attr_len
= wrapped_data
- 4 - attr_start
;
7392 len
[0] = DPP_HDR_LEN
;
7393 addr
[1] = attr_start
;
7395 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7396 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7397 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7398 wrapped_data
, wrapped_data_len
);
7399 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7400 unwrapped
= os_malloc(unwrapped_len
);
7403 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7404 wrapped_data
, wrapped_data_len
,
7405 2, addr
, len
, unwrapped
) < 0) {
7406 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7409 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7410 unwrapped
, unwrapped_len
);
7412 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7413 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7417 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7418 DPP_ATTR_ENROLLEE_NONCE
,
7420 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7422 "Missing or invalid Enrollee Nonce attribute");
7425 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7426 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7427 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7428 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7429 auth
->e_nonce
, e_nonce_len
);
7433 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONN_STATUS
,
7437 "Missing required DPP Connection Status attribute");
7440 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
7441 status
, status_len
);
7443 root
= json_parse((const char *) status
, status_len
);
7445 dpp_auth_fail(auth
, "Could not parse connStatus");
7449 ssid64
= json_get_member_base64url(root
, "ssid64");
7450 if (ssid64
&& wpabuf_len(ssid64
) <= SSID_MAX_LEN
) {
7451 *ssid_len
= wpabuf_len(ssid64
);
7452 os_memcpy(ssid
, wpabuf_head(ssid64
), *ssid_len
);
7454 wpabuf_free(ssid64
);
7456 token
= json_get_member(root
, "channelList");
7457 if (token
&& token
->type
== JSON_STRING
&&
7458 valid_channel_list(token
->string
))
7459 *channel_list
= os_strdup(token
->string
);
7461 token
= json_get_member(root
, "result");
7462 if (!token
|| token
->type
!= JSON_NUMBER
) {
7463 dpp_auth_fail(auth
, "No connStatus - result");
7466 wpa_printf(MSG_DEBUG
, "DPP: result %d", token
->number
);
7467 ret
= token
->number
;
7471 bin_clear_free(unwrapped
, unwrapped_len
);
7476 struct wpabuf
* dpp_build_conn_status_result(struct dpp_authentication
*auth
,
7477 enum dpp_status_error result
,
7478 const u8
*ssid
, size_t ssid_len
,
7479 const char *channel_list
)
7481 struct wpabuf
*msg
= NULL
, *clear
= NULL
, *json
;
7482 size_t nonce_len
, clear_len
, attr_len
;
7487 json
= wpabuf_alloc(1000);
7490 json_start_object(json
, NULL
);
7491 json_add_int(json
, "result", result
);
7493 json_value_sep(json
);
7494 if (json_add_base64url(json
, "ssid64", ssid
, ssid_len
) < 0)
7498 json_value_sep(json
);
7499 json_add_string(json
, "channelList", channel_list
);
7501 json_end_object(json
);
7502 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
7503 wpabuf_head(json
), wpabuf_len(json
));
7505 nonce_len
= auth
->curve
->nonce_len
;
7506 clear_len
= 5 + 4 + nonce_len
+ 4 + wpabuf_len(json
);
7507 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7508 clear
= wpabuf_alloc(clear_len
);
7509 msg
= dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT
, attr_len
);
7514 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
7515 wpabuf_put_le16(clear
, nonce_len
);
7516 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
7518 /* DPP Connection Status */
7519 wpabuf_put_le16(clear
, DPP_ATTR_CONN_STATUS
);
7520 wpabuf_put_le16(clear
, wpabuf_len(json
));
7521 wpabuf_put_buf(clear
, json
);
7523 /* OUI, OUI type, Crypto Suite, DPP frame type */
7524 addr
[0] = wpabuf_head_u8(msg
) + 2;
7525 len
[0] = 3 + 1 + 1 + 1;
7526 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7528 /* Attributes before Wrapped Data (none) */
7529 addr
[1] = wpabuf_put(msg
, 0);
7531 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7534 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7535 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7536 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7538 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7539 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
7540 wpabuf_head(clear
), wpabuf_len(clear
),
7541 2, addr
, len
, wrapped
) < 0)
7544 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Connection Status Result attributes",
7556 #endif /* CONFIG_DPP2 */
7559 void dpp_configurator_free(struct dpp_configurator
*conf
)
7563 EVP_PKEY_free(conf
->csign
);
7569 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
7573 int key_len
, ret
= -1;
7574 unsigned char *key
= NULL
;
7579 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
7583 key_len
= i2d_ECPrivateKey(eckey
, &key
);
7585 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
7593 static int dpp_configurator_gen_kid(struct dpp_configurator
*conf
)
7595 struct wpabuf
*csign_pub
= NULL
;
7596 u8 kid_hash
[SHA256_MAC_LEN
];
7601 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
7603 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
7607 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
7608 addr
[0] = wpabuf_head(csign_pub
);
7609 len
[0] = wpabuf_len(csign_pub
);
7610 res
= sha256_vector(1, addr
, len
, kid_hash
);
7611 wpabuf_free(csign_pub
);
7613 wpa_printf(MSG_DEBUG
,
7614 "DPP: Failed to derive kid for C-sign-key");
7618 conf
->kid
= base64_url_encode(kid_hash
, sizeof(kid_hash
), NULL
);
7619 return conf
->kid
? 0 : -1;
7623 struct dpp_configurator
*
7624 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
7627 struct dpp_configurator
*conf
;
7629 conf
= os_zalloc(sizeof(*conf
));
7634 conf
->curve
= &dpp_curves
[0];
7636 conf
->curve
= dpp_get_curve_name(curve
);
7638 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
7645 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
7648 conf
->csign
= dpp_gen_keypair(conf
->curve
);
7653 if (dpp_configurator_gen_kid(conf
) < 0)
7657 dpp_configurator_free(conf
);
7662 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
7663 const char *curve
, int ap
)
7665 struct wpabuf
*conf_obj
;
7669 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
7674 auth
->curve
= &dpp_curves
[0];
7676 auth
->curve
= dpp_get_curve_name(curve
);
7678 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
7683 wpa_printf(MSG_DEBUG
,
7684 "DPP: Building own configuration/connector with curve %s",
7687 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
7688 if (!auth
->own_protocol_key
)
7690 dpp_copy_netaccesskey(auth
, &auth
->conf_obj
[0]);
7691 auth
->peer_protocol_key
= auth
->own_protocol_key
;
7692 dpp_copy_csign(&auth
->conf_obj
[0], auth
->conf
->csign
);
7694 conf_obj
= dpp_build_conf_obj(auth
, ap
, 0);
7696 wpabuf_free(auth
->conf_obj
[0].c_sign_key
);
7697 auth
->conf_obj
[0].c_sign_key
= NULL
;
7700 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
7701 wpabuf_len(conf_obj
));
7703 wpabuf_free(conf_obj
);
7704 auth
->peer_protocol_key
= NULL
;
7709 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
7711 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
7712 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
7716 static int dpp_connector_compatible_group(struct json_token
*root
,
7717 const char *group_id
,
7718 const char *net_role
)
7720 struct json_token
*groups
, *token
;
7722 groups
= json_get_member(root
, "groups");
7723 if (!groups
|| groups
->type
!= JSON_ARRAY
)
7726 for (token
= groups
->child
; token
; token
= token
->sibling
) {
7727 struct json_token
*id
, *role
;
7729 id
= json_get_member(token
, "groupId");
7730 if (!id
|| id
->type
!= JSON_STRING
)
7733 role
= json_get_member(token
, "netRole");
7734 if (!role
|| role
->type
!= JSON_STRING
)
7737 if (os_strcmp(id
->string
, "*") != 0 &&
7738 os_strcmp(group_id
, "*") != 0 &&
7739 os_strcmp(id
->string
, group_id
) != 0)
7742 if (dpp_compatible_netrole(role
->string
, net_role
))
7750 static int dpp_connector_match_groups(struct json_token
*own_root
,
7751 struct json_token
*peer_root
)
7753 struct json_token
*groups
, *token
;
7755 groups
= json_get_member(peer_root
, "groups");
7756 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
7757 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
7761 for (token
= groups
->child
; token
; token
= token
->sibling
) {
7762 struct json_token
*id
, *role
;
7764 id
= json_get_member(token
, "groupId");
7765 if (!id
|| id
->type
!= JSON_STRING
) {
7766 wpa_printf(MSG_DEBUG
,
7767 "DPP: Missing peer groupId string");
7771 role
= json_get_member(token
, "netRole");
7772 if (!role
|| role
->type
!= JSON_STRING
) {
7773 wpa_printf(MSG_DEBUG
,
7774 "DPP: Missing peer groups::netRole string");
7777 wpa_printf(MSG_DEBUG
,
7778 "DPP: peer connector group: groupId='%s' netRole='%s'",
7779 id
->string
, role
->string
);
7780 if (dpp_connector_compatible_group(own_root
, id
->string
,
7782 wpa_printf(MSG_DEBUG
,
7783 "DPP: Compatible group/netRole in own connector");
7792 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
7793 unsigned int hash_len
)
7795 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
7796 const char *info
= "DPP PMK";
7799 /* PMK = HKDF(<>, "DPP PMK", N.x) */
7801 /* HKDF-Extract(<>, N.x) */
7802 os_memset(salt
, 0, hash_len
);
7803 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
7805 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
7808 /* HKDF-Expand(PRK, info, L) */
7809 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
7810 os_memset(prk
, 0, hash_len
);
7814 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
7820 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
7821 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
7823 struct wpabuf
*nkx
, *pkx
;
7827 u8 hash
[SHA256_MAC_LEN
];
7829 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
7830 nkx
= dpp_get_pubkey_point(own_key
, 0);
7831 pkx
= dpp_get_pubkey_point(peer_key
, 0);
7834 addr
[0] = wpabuf_head(nkx
);
7835 len
[0] = wpabuf_len(nkx
) / 2;
7836 addr
[1] = wpabuf_head(pkx
);
7837 len
[1] = wpabuf_len(pkx
) / 2;
7838 if (len
[0] != len
[1])
7840 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
7841 addr
[0] = wpabuf_head(pkx
);
7842 addr
[1] = wpabuf_head(nkx
);
7844 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
7845 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
7846 res
= sha256_vector(2, addr
, len
, hash
);
7849 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
7850 os_memcpy(pmkid
, hash
, PMKID_LEN
);
7851 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
7860 enum dpp_status_error
7861 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
7862 const u8
*net_access_key
, size_t net_access_key_len
,
7863 const u8
*csign_key
, size_t csign_key_len
,
7864 const u8
*peer_connector
, size_t peer_connector_len
,
7867 struct json_token
*root
= NULL
, *netkey
, *token
;
7868 struct json_token
*own_root
= NULL
;
7869 enum dpp_status_error ret
= 255, res
;
7870 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
7871 struct wpabuf
*own_key_pub
= NULL
;
7872 const struct dpp_curve_params
*curve
, *own_curve
;
7873 struct dpp_signed_connector_info info
;
7874 const unsigned char *p
;
7875 EVP_PKEY
*csign
= NULL
;
7876 char *signed_connector
= NULL
;
7877 const char *pos
, *end
;
7878 unsigned char *own_conn
= NULL
;
7879 size_t own_conn_len
;
7881 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
7883 os_memset(intro
, 0, sizeof(*intro
));
7884 os_memset(&info
, 0, sizeof(info
));
7889 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
7891 wpa_printf(MSG_ERROR
,
7892 "DPP: Failed to parse local C-sign-key information");
7896 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
7897 net_access_key_len
);
7899 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
7903 pos
= os_strchr(own_connector
, '.');
7905 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
7909 end
= os_strchr(pos
, '.');
7911 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
7914 own_conn
= base64_url_decode(pos
, end
- pos
, &own_conn_len
);
7916 wpa_printf(MSG_DEBUG
,
7917 "DPP: Failed to base64url decode own signedConnector JWS Payload");
7921 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
7923 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
7927 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
7928 peer_connector
, peer_connector_len
);
7929 signed_connector
= os_malloc(peer_connector_len
+ 1);
7930 if (!signed_connector
)
7932 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
7933 signed_connector
[peer_connector_len
] = '\0';
7935 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
7936 if (res
!= DPP_STATUS_OK
) {
7941 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
7943 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
7944 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7948 if (!dpp_connector_match_groups(own_root
, root
)) {
7949 wpa_printf(MSG_DEBUG
,
7950 "DPP: Peer connector does not include compatible group netrole with own connector");
7951 ret
= DPP_STATUS_NO_MATCH
;
7955 token
= json_get_member(root
, "expiry");
7956 if (!token
|| token
->type
!= JSON_STRING
) {
7957 wpa_printf(MSG_DEBUG
,
7958 "DPP: No expiry string found - connector does not expire");
7960 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
7961 if (dpp_key_expired(token
->string
, expiry
)) {
7962 wpa_printf(MSG_DEBUG
,
7963 "DPP: Connector (netAccessKey) has expired");
7964 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7969 netkey
= json_get_member(root
, "netAccessKey");
7970 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
7971 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
7972 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7976 peer_key
= dpp_parse_jwk(netkey
, &curve
);
7978 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7981 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
7983 if (own_curve
!= curve
) {
7984 wpa_printf(MSG_DEBUG
,
7985 "DPP: Mismatching netAccessKey curves (%s != %s)",
7986 own_curve
->name
, curve
->name
);
7987 ret
= DPP_STATUS_INVALID_CONNECTOR
;
7991 /* ECDH: N = nk * PK */
7992 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
7995 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
7998 /* PMK = HKDF(<>, "DPP PMK", N.x) */
7999 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
8000 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
8003 intro
->pmk_len
= curve
->hash_len
;
8005 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8006 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
8007 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
8011 ret
= DPP_STATUS_OK
;
8013 if (ret
!= DPP_STATUS_OK
)
8014 os_memset(intro
, 0, sizeof(*intro
));
8015 os_memset(Nx
, 0, sizeof(Nx
));
8017 os_free(signed_connector
);
8018 os_free(info
.payload
);
8019 EVP_PKEY_free(own_key
);
8020 wpabuf_free(own_key_pub
);
8021 EVP_PKEY_free(peer_key
);
8022 EVP_PKEY_free(csign
);
8024 json_free(own_root
);
8029 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
8033 size_t len
= curve
->prime_len
;
8037 switch (curve
->ike_group
) {
8039 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
8040 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
8043 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
8044 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
8047 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
8048 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
8051 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
8052 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
8055 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
8056 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
8059 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
8060 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
8066 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8069 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
8070 EC_GROUP_free(group
);
8075 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
8076 const u8
*mac_init
, const char *code
,
8077 const char *identifier
, BN_CTX
*bnctx
,
8078 EC_GROUP
**ret_group
)
8080 u8 hash
[DPP_MAX_HASH_LEN
];
8083 unsigned int num_elem
= 0;
8084 EC_POINT
*Qi
= NULL
;
8085 EVP_PKEY
*Pi
= NULL
;
8086 EC_KEY
*Pi_ec
= NULL
;
8087 const EC_POINT
*Pi_point
;
8088 BIGNUM
*hash_bn
= NULL
;
8089 const EC_GROUP
*group
= NULL
;
8090 EC_GROUP
*group2
= NULL
;
8092 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8094 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
8095 addr
[num_elem
] = mac_init
;
8096 len
[num_elem
] = ETH_ALEN
;
8099 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8101 addr
[num_elem
] = (const u8
*) identifier
;
8102 len
[num_elem
] = os_strlen(identifier
);
8105 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8106 addr
[num_elem
] = (const u8
*) code
;
8107 len
[num_elem
] = os_strlen(code
);
8109 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8111 wpa_hexdump_key(MSG_DEBUG
,
8112 "DPP: H(MAC-Initiator | [identifier |] code)",
8113 hash
, curve
->hash_len
);
8114 Pi
= dpp_pkex_get_role_elem(curve
, 1);
8117 dpp_debug_print_key("DPP: Pi", Pi
);
8118 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
8121 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
8123 group
= EC_KEY_get0_group(Pi_ec
);
8126 group2
= EC_GROUP_dup(group
);
8129 Qi
= EC_POINT_new(group2
);
8131 EC_GROUP_free(group2
);
8134 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8136 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
8138 if (EC_POINT_is_at_infinity(group
, Qi
)) {
8139 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
8142 dpp_debug_print_point("DPP: Qi", group
, Qi
);
8146 BN_clear_free(hash_bn
);
8147 if (ret_group
&& Qi
)
8148 *ret_group
= group2
;
8150 EC_GROUP_free(group2
);
8159 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
8160 const u8
*mac_resp
, const char *code
,
8161 const char *identifier
, BN_CTX
*bnctx
,
8162 EC_GROUP
**ret_group
)
8164 u8 hash
[DPP_MAX_HASH_LEN
];
8167 unsigned int num_elem
= 0;
8168 EC_POINT
*Qr
= NULL
;
8169 EVP_PKEY
*Pr
= NULL
;
8170 EC_KEY
*Pr_ec
= NULL
;
8171 const EC_POINT
*Pr_point
;
8172 BIGNUM
*hash_bn
= NULL
;
8173 const EC_GROUP
*group
= NULL
;
8174 EC_GROUP
*group2
= NULL
;
8176 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8178 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
8179 addr
[num_elem
] = mac_resp
;
8180 len
[num_elem
] = ETH_ALEN
;
8183 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8185 addr
[num_elem
] = (const u8
*) identifier
;
8186 len
[num_elem
] = os_strlen(identifier
);
8189 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8190 addr
[num_elem
] = (const u8
*) code
;
8191 len
[num_elem
] = os_strlen(code
);
8193 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8195 wpa_hexdump_key(MSG_DEBUG
,
8196 "DPP: H(MAC-Responder | [identifier |] code)",
8197 hash
, curve
->hash_len
);
8198 Pr
= dpp_pkex_get_role_elem(curve
, 0);
8201 dpp_debug_print_key("DPP: Pr", Pr
);
8202 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
8205 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
8207 group
= EC_KEY_get0_group(Pr_ec
);
8210 group2
= EC_GROUP_dup(group
);
8213 Qr
= EC_POINT_new(group2
);
8215 EC_GROUP_free(group2
);
8218 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8220 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
8222 if (EC_POINT_is_at_infinity(group
, Qr
)) {
8223 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
8226 dpp_debug_print_point("DPP: Qr", group
, Qr
);
8230 BN_clear_free(hash_bn
);
8231 if (ret_group
&& Qr
)
8232 *ret_group
= group2
;
8234 EC_GROUP_free(group2
);
8243 #ifdef CONFIG_TESTING_OPTIONS
8244 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
8245 const struct dpp_curve_params
*curve
)
8253 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8258 point
= EC_POINT_new(group
);
8261 if (!ctx
|| !point
|| !x
|| !y
)
8264 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
8267 /* Generate a random y coordinate that results in a point that is not
8270 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
8273 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
8275 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
8276 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8277 * return an error from EC_POINT_set_affine_coordinates_GFp()
8278 * when the point is not on the curve. */
8280 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
8282 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
8285 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
8289 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
8290 curve
->prime_len
) < 0 ||
8291 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
8292 curve
->prime_len
) < 0)
8298 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
8301 EC_POINT_free(point
);
8303 EC_GROUP_free(group
);
8307 #endif /* CONFIG_TESTING_OPTIONS */
8310 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
8312 EC_KEY
*X_ec
= NULL
;
8313 const EC_POINT
*X_point
;
8314 BN_CTX
*bnctx
= NULL
;
8315 EC_GROUP
*group
= NULL
;
8316 EC_POINT
*Qi
= NULL
, *M
= NULL
;
8317 struct wpabuf
*M_buf
= NULL
;
8318 BIGNUM
*Mx
= NULL
, *My
= NULL
;
8319 struct wpabuf
*msg
= NULL
;
8321 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8323 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
8325 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8326 bnctx
= BN_CTX_new();
8329 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
8330 pkex
->identifier
, bnctx
, &group
);
8334 /* Generate a random ephemeral keypair x/X */
8335 #ifdef CONFIG_TESTING_OPTIONS
8336 if (dpp_pkex_ephemeral_key_override_len
) {
8337 const struct dpp_curve_params
*tmp_curve
;
8339 wpa_printf(MSG_INFO
,
8340 "DPP: TESTING - override ephemeral key x/X");
8341 pkex
->x
= dpp_set_keypair(&tmp_curve
,
8342 dpp_pkex_ephemeral_key_override
,
8343 dpp_pkex_ephemeral_key_override_len
);
8345 pkex
->x
= dpp_gen_keypair(curve
);
8347 #else /* CONFIG_TESTING_OPTIONS */
8348 pkex
->x
= dpp_gen_keypair(curve
);
8349 #endif /* CONFIG_TESTING_OPTIONS */
8354 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
8357 X_point
= EC_KEY_get0_public_key(X_ec
);
8360 dpp_debug_print_point("DPP: X", group
, X_point
);
8361 M
= EC_POINT_new(group
);
8364 if (!M
|| !Mx
|| !My
||
8365 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
8366 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
8368 dpp_debug_print_point("DPP: M", group
, M
);
8370 /* Initiator -> Responder: group, [identifier,] M */
8372 if (pkex
->identifier
)
8373 attr_len
+= 4 + os_strlen(pkex
->identifier
);
8374 attr_len
+= 4 + 2 * curve
->prime_len
;
8375 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
8379 #ifdef CONFIG_TESTING_OPTIONS
8380 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
8381 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
8382 goto skip_finite_cyclic_group
;
8384 #endif /* CONFIG_TESTING_OPTIONS */
8386 /* Finite Cyclic Group attribute */
8387 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
8388 wpabuf_put_le16(msg
, 2);
8389 wpabuf_put_le16(msg
, curve
->ike_group
);
8391 #ifdef CONFIG_TESTING_OPTIONS
8392 skip_finite_cyclic_group
:
8393 #endif /* CONFIG_TESTING_OPTIONS */
8395 /* Code Identifier attribute */
8396 if (pkex
->identifier
) {
8397 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
8398 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
8399 wpabuf_put_str(msg
, pkex
->identifier
);
8402 #ifdef CONFIG_TESTING_OPTIONS
8403 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8404 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
8407 #endif /* CONFIG_TESTING_OPTIONS */
8409 /* M in Encrypted Key attribute */
8410 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
8411 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
8413 #ifdef CONFIG_TESTING_OPTIONS
8414 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8415 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
8416 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
8420 #endif /* CONFIG_TESTING_OPTIONS */
8422 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
8423 curve
->prime_len
) < 0 ||
8424 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
8425 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
8426 curve
->prime_len
) < 0)
8437 EC_GROUP_free(group
);
8440 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
8447 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
8449 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
8453 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
8455 const char *identifier
,
8458 struct dpp_pkex
*pkex
;
8460 #ifdef CONFIG_TESTING_OPTIONS
8461 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
8462 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
8463 MAC2STR(dpp_pkex_own_mac_override
));
8464 own_mac
= dpp_pkex_own_mac_override
;
8466 #endif /* CONFIG_TESTING_OPTIONS */
8468 pkex
= os_zalloc(sizeof(*pkex
));
8471 pkex
->msg_ctx
= msg_ctx
;
8472 pkex
->initiator
= 1;
8474 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
8476 pkex
->identifier
= os_strdup(identifier
);
8477 if (!pkex
->identifier
)
8480 pkex
->code
= os_strdup(code
);
8483 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
8484 if (!pkex
->exchange_req
)
8488 dpp_pkex_free(pkex
);
8493 static struct wpabuf
*
8494 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
8495 enum dpp_status_error status
,
8496 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
8498 struct wpabuf
*msg
= NULL
;
8500 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8502 /* Initiator -> Responder: DPP Status, [identifier,] N */
8504 if (pkex
->identifier
)
8505 attr_len
+= 4 + os_strlen(pkex
->identifier
);
8506 attr_len
+= 4 + 2 * curve
->prime_len
;
8507 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
8511 #ifdef CONFIG_TESTING_OPTIONS
8512 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
8513 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
8517 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
8518 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
8521 #endif /* CONFIG_TESTING_OPTIONS */
8524 dpp_build_attr_status(msg
, status
);
8526 #ifdef CONFIG_TESTING_OPTIONS
8528 #endif /* CONFIG_TESTING_OPTIONS */
8530 /* Code Identifier attribute */
8531 if (pkex
->identifier
) {
8532 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
8533 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
8534 wpabuf_put_str(msg
, pkex
->identifier
);
8537 if (status
!= DPP_STATUS_OK
)
8538 goto skip_encrypted_key
;
8540 #ifdef CONFIG_TESTING_OPTIONS
8541 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
8542 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
8543 goto skip_encrypted_key
;
8545 #endif /* CONFIG_TESTING_OPTIONS */
8547 /* N in Encrypted Key attribute */
8548 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
8549 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
8551 #ifdef CONFIG_TESTING_OPTIONS
8552 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
8553 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
8554 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
8556 goto skip_encrypted_key
;
8558 #endif /* CONFIG_TESTING_OPTIONS */
8560 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
8561 curve
->prime_len
) < 0 ||
8562 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
8563 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
8564 curve
->prime_len
) < 0)
8568 if (status
== DPP_STATUS_BAD_GROUP
) {
8569 /* Finite Cyclic Group attribute */
8570 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
8571 wpabuf_put_le16(msg
, 2);
8572 wpabuf_put_le16(msg
, curve
->ike_group
);
8582 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
8583 const u8
*Mx
, size_t Mx_len
,
8584 const u8
*Nx
, size_t Nx_len
,
8586 const u8
*Kx
, size_t Kx_len
,
8587 u8
*z
, unsigned int hash_len
)
8589 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
8594 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
8597 /* HKDF-Extract(<>, IKM=K.x) */
8598 os_memset(salt
, 0, hash_len
);
8599 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
8601 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
8603 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
8604 info
= os_malloc(info_len
);
8608 os_memcpy(pos
, mac_init
, ETH_ALEN
);
8610 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
8612 os_memcpy(pos
, Mx
, Mx_len
);
8614 os_memcpy(pos
, Nx
, Nx_len
);
8616 os_memcpy(pos
, code
, os_strlen(code
));
8618 /* HKDF-Expand(PRK, info, L) */
8620 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
8622 else if (hash_len
== 48)
8623 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
8625 else if (hash_len
== 64)
8626 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
8631 os_memset(prk
, 0, hash_len
);
8635 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
8641 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
8642 const char *identifier
)
8644 if (!attr_id
&& identifier
) {
8645 wpa_printf(MSG_DEBUG
,
8646 "DPP: No PKEX code identifier received, but expected one");
8650 if (attr_id
&& !identifier
) {
8651 wpa_printf(MSG_DEBUG
,
8652 "DPP: PKEX code identifier received, but not expecting one");
8656 if (attr_id
&& identifier
&&
8657 (os_strlen(identifier
) != attr_id_len
||
8658 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
8659 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
8667 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
8668 struct dpp_bootstrap_info
*bi
,
8671 const char *identifier
,
8673 const u8
*buf
, size_t len
)
8675 const u8
*attr_group
, *attr_id
, *attr_key
;
8676 u16 attr_group_len
, attr_id_len
, attr_key_len
;
8677 const struct dpp_curve_params
*curve
= bi
->curve
;
8679 struct dpp_pkex
*pkex
= NULL
;
8680 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
8681 BN_CTX
*bnctx
= NULL
;
8682 EC_GROUP
*group
= NULL
;
8683 BIGNUM
*Mx
= NULL
, *My
= NULL
;
8684 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
8685 const EC_POINT
*Y_point
;
8686 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
8687 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
8691 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
8692 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8693 "PKEX counter t limit reached - ignore message");
8697 #ifdef CONFIG_TESTING_OPTIONS
8698 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
8699 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
8700 MAC2STR(dpp_pkex_peer_mac_override
));
8701 peer_mac
= dpp_pkex_peer_mac_override
;
8703 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
8704 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
8705 MAC2STR(dpp_pkex_own_mac_override
));
8706 own_mac
= dpp_pkex_own_mac_override
;
8708 #endif /* CONFIG_TESTING_OPTIONS */
8711 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
8713 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
8716 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
8718 if (!attr_group
|| attr_group_len
!= 2) {
8719 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8720 "Missing or invalid Finite Cyclic Group attribute");
8723 ike_group
= WPA_GET_LE16(attr_group
);
8724 if (ike_group
!= curve
->ike_group
) {
8725 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8726 "Mismatching PKEX curve: peer=%u own=%u",
8727 ike_group
, curve
->ike_group
);
8728 pkex
= os_zalloc(sizeof(*pkex
));
8733 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
8734 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
8735 if (!pkex
->exchange_resp
)
8740 /* M in Encrypted Key attribute */
8741 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
8743 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
8744 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
8745 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8746 "Missing Encrypted Key attribute");
8750 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8751 bnctx
= BN_CTX_new();
8754 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
8760 X
= EC_POINT_new(group
);
8761 M
= EC_POINT_new(group
);
8762 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
8763 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
8764 if (!X
|| !M
|| !Mx
|| !My
||
8765 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
8766 EC_POINT_is_at_infinity(group
, M
) ||
8767 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
8768 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
8769 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
8770 EC_POINT_is_at_infinity(group
, X
) ||
8771 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
8772 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
8773 "Invalid Encrypted Key value");
8777 dpp_debug_print_point("DPP: M", group
, M
);
8778 dpp_debug_print_point("DPP: X'", group
, X
);
8780 pkex
= os_zalloc(sizeof(*pkex
));
8783 pkex
->t
= bi
->pkex_t
;
8784 pkex
->msg_ctx
= msg_ctx
;
8786 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
8787 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
8789 pkex
->identifier
= os_strdup(identifier
);
8790 if (!pkex
->identifier
)
8793 pkex
->code
= os_strdup(code
);
8797 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
8799 X_ec
= EC_KEY_new();
8801 EC_KEY_set_group(X_ec
, group
) != 1 ||
8802 EC_KEY_set_public_key(X_ec
, X
) != 1)
8804 pkex
->x
= EVP_PKEY_new();
8806 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
8809 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8810 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
8814 /* Generate a random ephemeral keypair y/Y */
8815 #ifdef CONFIG_TESTING_OPTIONS
8816 if (dpp_pkex_ephemeral_key_override_len
) {
8817 const struct dpp_curve_params
*tmp_curve
;
8819 wpa_printf(MSG_INFO
,
8820 "DPP: TESTING - override ephemeral key y/Y");
8821 pkex
->y
= dpp_set_keypair(&tmp_curve
,
8822 dpp_pkex_ephemeral_key_override
,
8823 dpp_pkex_ephemeral_key_override_len
);
8825 pkex
->y
= dpp_gen_keypair(curve
);
8827 #else /* CONFIG_TESTING_OPTIONS */
8828 pkex
->y
= dpp_gen_keypair(curve
);
8829 #endif /* CONFIG_TESTING_OPTIONS */
8834 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
8837 Y_point
= EC_KEY_get0_public_key(Y_ec
);
8840 dpp_debug_print_point("DPP: Y", group
, Y_point
);
8841 N
= EC_POINT_new(group
);
8844 if (!N
|| !Nx
|| !Ny
||
8845 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
8846 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
8848 dpp_debug_print_point("DPP: N", group
, N
);
8850 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
8852 if (!pkex
->exchange_resp
)
8856 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
8859 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
8862 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
8864 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
8865 pkex
->Mx
, curve
->prime_len
,
8866 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
8867 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
8868 os_memset(Kx
, 0, Kx_len
);
8872 pkex
->exchange_done
= 1;
8887 EC_GROUP_free(group
);
8890 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
8891 dpp_pkex_free(pkex
);
8897 static struct wpabuf
*
8898 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
8899 const struct wpabuf
*A_pub
, const u8
*u
)
8901 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8902 struct wpabuf
*msg
= NULL
;
8903 size_t clear_len
, attr_len
;
8904 struct wpabuf
*clear
= NULL
;
8910 /* {A, u, [bootstrapping info]}z */
8911 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
8912 clear
= wpabuf_alloc(clear_len
);
8913 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8914 #ifdef CONFIG_TESTING_OPTIONS
8915 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
8917 #endif /* CONFIG_TESTING_OPTIONS */
8918 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
8922 #ifdef CONFIG_TESTING_OPTIONS
8923 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
8924 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
8925 goto skip_bootstrap_key
;
8927 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
8928 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
8929 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8930 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
8931 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
8933 goto skip_bootstrap_key
;
8935 #endif /* CONFIG_TESTING_OPTIONS */
8937 /* A in Bootstrap Key attribute */
8938 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
8939 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
8940 wpabuf_put_buf(clear
, A_pub
);
8942 #ifdef CONFIG_TESTING_OPTIONS
8944 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
8945 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
8946 goto skip_i_auth_tag
;
8948 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
8949 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
8950 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
8951 wpabuf_put_le16(clear
, curve
->hash_len
);
8952 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
8953 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
8954 goto skip_i_auth_tag
;
8956 #endif /* CONFIG_TESTING_OPTIONS */
8958 /* u in I-Auth tag attribute */
8959 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
8960 wpabuf_put_le16(clear
, curve
->hash_len
);
8961 wpabuf_put_data(clear
, u
, curve
->hash_len
);
8963 #ifdef CONFIG_TESTING_OPTIONS
8965 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
8966 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
8967 goto skip_wrapped_data
;
8969 #endif /* CONFIG_TESTING_OPTIONS */
8971 addr
[0] = wpabuf_head_u8(msg
) + 2;
8972 len
[0] = DPP_HDR_LEN
;
8975 len
[1] = sizeof(octet
);
8976 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8977 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8979 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8980 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8981 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8983 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8984 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
8985 wpabuf_head(clear
), wpabuf_len(clear
),
8986 2, addr
, len
, wrapped
) < 0)
8988 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
8989 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8991 #ifdef CONFIG_TESTING_OPTIONS
8992 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
8993 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
8994 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
8997 #endif /* CONFIG_TESTING_OPTIONS */
9010 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
9012 const u8
*buf
, size_t buflen
)
9014 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
9015 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
9016 EC_GROUP
*group
= NULL
;
9017 BN_CTX
*bnctx
= NULL
;
9018 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9019 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9020 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
9021 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9022 EC_KEY
*Y_ec
= NULL
;
9023 size_t Jx_len
, Kx_len
;
9024 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9027 u8 u
[DPP_MAX_HASH_LEN
];
9030 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
9033 #ifdef CONFIG_TESTING_OPTIONS
9034 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
9035 wpa_printf(MSG_INFO
,
9036 "DPP: TESTING - stop at PKEX Exchange Response");
9041 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9042 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9043 MAC2STR(dpp_pkex_peer_mac_override
));
9044 peer_mac
= dpp_pkex_peer_mac_override
;
9046 #endif /* CONFIG_TESTING_OPTIONS */
9048 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9050 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
9052 if (!attr_status
|| attr_status_len
!= 1) {
9053 dpp_pkex_fail(pkex
, "No DPP Status attribute");
9056 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
9058 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
9059 attr_group
= dpp_get_attr(buf
, buflen
,
9060 DPP_ATTR_FINITE_CYCLIC_GROUP
,
9062 if (attr_group
&& attr_group_len
== 2) {
9063 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9064 "Peer indicated mismatching PKEX group - proposed %u",
9065 WPA_GET_LE16(attr_group
));
9070 if (attr_status
[0] != DPP_STATUS_OK
) {
9071 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
9076 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
9078 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
9079 pkex
->identifier
)) {
9080 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
9084 /* N in Encrypted Key attribute */
9085 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
9087 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
9088 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
9092 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9093 bnctx
= BN_CTX_new();
9096 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
9097 pkex
->identifier
, bnctx
, &group
);
9102 Y
= EC_POINT_new(group
);
9103 N
= EC_POINT_new(group
);
9104 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9105 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9106 if (!Y
|| !N
|| !Nx
|| !Ny
||
9107 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
9108 EC_POINT_is_at_infinity(group
, N
) ||
9109 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
9110 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
9111 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
9112 EC_POINT_is_at_infinity(group
, Y
) ||
9113 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
9114 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
9118 dpp_debug_print_point("DPP: N", group
, N
);
9119 dpp_debug_print_point("DPP: Y'", group
, Y
);
9121 pkex
->exchange_done
= 1;
9123 /* ECDH: J = a * Y’ */
9124 Y_ec
= EC_KEY_new();
9126 EC_KEY_set_group(Y_ec
, group
) != 1 ||
9127 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
9129 pkex
->y
= EVP_PKEY_new();
9131 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
9133 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
9136 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9139 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9140 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9141 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9142 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9143 if (!A_pub
|| !Y_pub
|| !X_pub
)
9145 addr
[0] = pkex
->own_mac
;
9147 addr
[1] = wpabuf_head(A_pub
);
9148 len
[1] = wpabuf_len(A_pub
) / 2;
9149 addr
[2] = wpabuf_head(Y_pub
);
9150 len
[2] = wpabuf_len(Y_pub
) / 2;
9151 addr
[3] = wpabuf_head(X_pub
);
9152 len
[3] = wpabuf_len(X_pub
) / 2;
9153 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9155 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
9158 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
9161 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9164 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9166 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
9167 pkex
->Mx
, curve
->prime_len
,
9168 attr_key
/* N.x */, attr_key_len
/ 2,
9169 pkex
->code
, Kx
, Kx_len
,
9170 pkex
->z
, curve
->hash_len
);
9171 os_memset(Kx
, 0, Kx_len
);
9175 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
9190 EC_GROUP_free(group
);
9193 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
9198 static struct wpabuf
*
9199 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
9200 const struct wpabuf
*B_pub
, const u8
*v
)
9202 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9203 struct wpabuf
*msg
= NULL
;
9208 struct wpabuf
*clear
= NULL
;
9209 size_t clear_len
, attr_len
;
9211 /* {B, v [bootstrapping info]}z */
9212 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9213 clear
= wpabuf_alloc(clear_len
);
9214 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9215 #ifdef CONFIG_TESTING_OPTIONS
9216 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
9218 #endif /* CONFIG_TESTING_OPTIONS */
9219 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
9223 #ifdef CONFIG_TESTING_OPTIONS
9224 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9225 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9226 goto skip_bootstrap_key
;
9228 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9229 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9230 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9231 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9232 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9234 goto skip_bootstrap_key
;
9236 #endif /* CONFIG_TESTING_OPTIONS */
9238 /* B in Bootstrap Key attribute */
9239 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9240 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
9241 wpabuf_put_buf(clear
, B_pub
);
9243 #ifdef CONFIG_TESTING_OPTIONS
9245 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
9246 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
9247 goto skip_r_auth_tag
;
9249 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
9250 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
9251 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9252 wpabuf_put_le16(clear
, curve
->hash_len
);
9253 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
9254 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
9255 goto skip_r_auth_tag
;
9257 #endif /* CONFIG_TESTING_OPTIONS */
9259 /* v in R-Auth tag attribute */
9260 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9261 wpabuf_put_le16(clear
, curve
->hash_len
);
9262 wpabuf_put_data(clear
, v
, curve
->hash_len
);
9264 #ifdef CONFIG_TESTING_OPTIONS
9266 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
9267 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9268 goto skip_wrapped_data
;
9270 #endif /* CONFIG_TESTING_OPTIONS */
9272 addr
[0] = wpabuf_head_u8(msg
) + 2;
9273 len
[0] = DPP_HDR_LEN
;
9276 len
[1] = sizeof(octet
);
9277 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9278 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9280 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9281 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9282 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9284 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9285 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9286 wpabuf_head(clear
), wpabuf_len(clear
),
9287 2, addr
, len
, wrapped
) < 0)
9289 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9290 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9292 #ifdef CONFIG_TESTING_OPTIONS
9293 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
9294 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9295 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9298 #endif /* CONFIG_TESTING_OPTIONS */
9311 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
9313 const u8
*buf
, size_t buflen
)
9315 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9316 size_t Jx_len
, Lx_len
;
9317 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
9318 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
9319 const u8
*wrapped_data
, *b_key
, *peer_u
;
9320 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
9324 u8
*unwrapped
= NULL
;
9325 size_t unwrapped_len
= 0;
9326 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9327 struct wpabuf
*B_pub
= NULL
;
9328 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
9330 #ifdef CONFIG_TESTING_OPTIONS
9331 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
9332 wpa_printf(MSG_INFO
,
9333 "DPP: TESTING - stop at PKEX CR Request");
9337 #endif /* CONFIG_TESTING_OPTIONS */
9339 if (!pkex
->exchange_done
|| pkex
->failed
||
9340 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
9343 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
9345 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
9347 "Missing or invalid required Wrapped Data attribute");
9351 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9352 wrapped_data
, wrapped_data_len
);
9353 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
9354 unwrapped
= os_malloc(unwrapped_len
);
9359 len
[0] = DPP_HDR_LEN
;
9362 len
[1] = sizeof(octet
);
9363 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9364 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9366 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
9367 wrapped_data
, wrapped_data_len
,
9368 2, addr
, len
, unwrapped
) < 0) {
9370 "AES-SIV decryption failed - possible PKEX code mismatch");
9375 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
9376 unwrapped
, unwrapped_len
);
9378 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
9379 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
9383 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
9385 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
9386 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
9389 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
9391 if (!pkex
->peer_bootstrap_key
) {
9392 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
9395 dpp_debug_print_key("DPP: Peer bootstrap public key",
9396 pkex
->peer_bootstrap_key
);
9398 /* ECDH: J' = y * A' */
9399 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
9402 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9405 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9406 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
9407 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9408 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9409 if (!A_pub
|| !Y_pub
|| !X_pub
)
9411 addr
[0] = pkex
->peer_mac
;
9413 addr
[1] = wpabuf_head(A_pub
);
9414 len
[1] = wpabuf_len(A_pub
) / 2;
9415 addr
[2] = wpabuf_head(Y_pub
);
9416 len
[2] = wpabuf_len(Y_pub
) / 2;
9417 addr
[3] = wpabuf_head(X_pub
);
9418 len
[3] = wpabuf_len(X_pub
) / 2;
9419 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9422 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
9424 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
9425 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
9426 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
9427 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
9428 u
, curve
->hash_len
);
9429 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
9433 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
9435 /* ECDH: L = b * X' */
9436 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
9439 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
9442 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
9443 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9446 addr
[0] = pkex
->own_mac
;
9448 addr
[1] = wpabuf_head(B_pub
);
9449 len
[1] = wpabuf_len(B_pub
) / 2;
9450 addr
[2] = wpabuf_head(X_pub
);
9451 len
[2] = wpabuf_len(X_pub
) / 2;
9452 addr
[3] = wpabuf_head(Y_pub
);
9453 len
[3] = wpabuf_len(Y_pub
) / 2;
9454 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
9456 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
9458 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
9470 wpa_printf(MSG_DEBUG
,
9471 "DPP: PKEX Commit-Reveal Request processing failed");
9476 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
9477 const u8
*buf
, size_t buflen
)
9479 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9480 const u8
*wrapped_data
, *b_key
, *peer_v
;
9481 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
9485 u8
*unwrapped
= NULL
;
9486 size_t unwrapped_len
= 0;
9488 u8 v
[DPP_MAX_HASH_LEN
];
9490 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
9491 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9493 #ifdef CONFIG_TESTING_OPTIONS
9494 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
9495 wpa_printf(MSG_INFO
,
9496 "DPP: TESTING - stop at PKEX CR Response");
9500 #endif /* CONFIG_TESTING_OPTIONS */
9502 if (!pkex
->exchange_done
|| pkex
->failed
||
9503 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
9506 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
9508 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
9510 "Missing or invalid required Wrapped Data attribute");
9514 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9515 wrapped_data
, wrapped_data_len
);
9516 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
9517 unwrapped
= os_malloc(unwrapped_len
);
9522 len
[0] = DPP_HDR_LEN
;
9525 len
[1] = sizeof(octet
);
9526 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9527 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9529 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
9530 wrapped_data
, wrapped_data_len
,
9531 2, addr
, len
, unwrapped
) < 0) {
9533 "AES-SIV decryption failed - possible PKEX code mismatch");
9537 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
9538 unwrapped
, unwrapped_len
);
9540 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
9541 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
9545 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
9547 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
9548 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
9551 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
9553 if (!pkex
->peer_bootstrap_key
) {
9554 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
9557 dpp_debug_print_key("DPP: Peer bootstrap public key",
9558 pkex
->peer_bootstrap_key
);
9560 /* ECDH: L' = x * B' */
9561 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
9564 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
9567 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
9568 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
9569 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9570 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9571 if (!B_pub
|| !X_pub
|| !Y_pub
)
9573 addr
[0] = pkex
->peer_mac
;
9575 addr
[1] = wpabuf_head(B_pub
);
9576 len
[1] = wpabuf_len(B_pub
) / 2;
9577 addr
[2] = wpabuf_head(X_pub
);
9578 len
[2] = wpabuf_len(X_pub
) / 2;
9579 addr
[3] = wpabuf_head(Y_pub
);
9580 len
[3] = wpabuf_len(Y_pub
) / 2;
9581 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
9584 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
9586 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
9587 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
9588 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
9589 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
9590 v
, curve
->hash_len
);
9591 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
9595 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
9609 void dpp_pkex_free(struct dpp_pkex
*pkex
)
9614 os_free(pkex
->identifier
);
9615 os_free(pkex
->code
);
9616 EVP_PKEY_free(pkex
->x
);
9617 EVP_PKEY_free(pkex
->y
);
9618 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
9619 wpabuf_free(pkex
->exchange_req
);
9620 wpabuf_free(pkex
->exchange_resp
);
9625 #ifdef CONFIG_TESTING_OPTIONS
9626 char * dpp_corrupt_connector_signature(const char *connector
)
9628 char *tmp
, *pos
, *signed3
= NULL
;
9629 unsigned char *signature
= NULL
;
9630 size_t signature_len
= 0, signed3_len
;
9632 tmp
= os_zalloc(os_strlen(connector
) + 5);
9635 os_memcpy(tmp
, connector
, os_strlen(connector
));
9637 pos
= os_strchr(tmp
, '.');
9641 pos
= os_strchr(pos
+ 1, '.');
9646 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
9648 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
9649 if (!signature
|| signature_len
== 0)
9651 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
9652 signature
, signature_len
);
9653 signature
[signature_len
- 1] ^= 0x01;
9654 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
9655 signature
, signature_len
);
9656 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
9659 os_memcpy(pos
, signed3
, signed3_len
);
9660 pos
[signed3_len
] = '\0';
9661 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
9673 #endif /* CONFIG_TESTING_OPTIONS */
9678 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
9679 size_t net_access_key_len
)
9681 struct wpabuf
*pub
= NULL
;
9683 struct dpp_pfs
*pfs
;
9685 pfs
= os_zalloc(sizeof(*pfs
));
9689 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
9690 net_access_key_len
);
9692 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
9695 EVP_PKEY_free(own_key
);
9697 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
9701 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
9702 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
9706 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
9709 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
9710 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
9711 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
9712 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
9713 wpabuf_put_buf(pfs
->ie
, pub
);
9715 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
9726 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
9728 if (peer_ie_len
< 2)
9730 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
9731 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
9735 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
9737 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
9739 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
9742 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
9747 void dpp_pfs_free(struct dpp_pfs
*pfs
)
9751 crypto_ecdh_deinit(pfs
->ecdh
);
9752 wpabuf_free(pfs
->ie
);
9753 wpabuf_clear_free(pfs
->secret
);
9757 #endif /* CONFIG_DPP2 */
9760 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
9762 struct dpp_bootstrap_info
*bi
;
9763 unsigned int max_id
= 0;
9765 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
9766 if (bi
->id
> max_id
)
9773 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
9775 struct dpp_bootstrap_info
*bi
, *tmp
;
9781 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
9782 struct dpp_bootstrap_info
, list
) {
9783 if (id
&& bi
->id
!= id
)
9786 dl_list_del(&bi
->list
);
9787 dpp_bootstrap_info_free(bi
);
9791 return 0; /* flush succeeds regardless of entries found */
9792 return found
? 0 : -1;
9796 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
9799 struct dpp_bootstrap_info
*bi
;
9804 bi
= dpp_parse_uri(uri
);
9808 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
9809 bi
->id
= dpp_next_id(dpp
);
9810 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9815 struct dpp_bootstrap_info
* dpp_add_nfc_uri(struct dpp_global
*dpp
,
9818 struct dpp_bootstrap_info
*bi
;
9823 bi
= dpp_parse_uri(uri
);
9827 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
9828 bi
->id
= dpp_next_id(dpp
);
9829 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9834 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
9836 char *mac
= NULL
, *info
= NULL
, *curve
= NULL
;
9839 size_t privkey_len
= 0;
9841 struct dpp_bootstrap_info
*bi
;
9846 bi
= os_zalloc(sizeof(*bi
));
9850 if (os_strstr(cmd
, "type=qrcode"))
9851 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
9852 else if (os_strstr(cmd
, "type=pkex"))
9853 bi
->type
= DPP_BOOTSTRAP_PKEX
;
9854 else if (os_strstr(cmd
, "type=nfc-uri"))
9855 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
9859 bi
->chan
= get_param(cmd
, " chan=");
9860 mac
= get_param(cmd
, " mac=");
9861 info
= get_param(cmd
, " info=");
9862 curve
= get_param(cmd
, " curve=");
9863 key
= get_param(cmd
, " key=");
9866 privkey_len
= os_strlen(key
) / 2;
9867 privkey
= os_malloc(privkey_len
);
9869 hexstr2bin(key
, privkey
, privkey_len
) < 0)
9873 if (dpp_keygen(bi
, curve
, privkey
, privkey_len
) < 0 ||
9874 dpp_parse_uri_chan_list(bi
, bi
->chan
) < 0 ||
9875 dpp_parse_uri_mac(bi
, mac
) < 0 ||
9876 dpp_parse_uri_info(bi
, info
) < 0 ||
9877 dpp_gen_uri(bi
) < 0)
9880 bi
->id
= dpp_next_id(dpp
);
9881 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9888 str_clear_free(key
);
9889 bin_clear_free(privkey
, privkey_len
);
9890 dpp_bootstrap_info_free(bi
);
9895 struct dpp_bootstrap_info
*
9896 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
9898 struct dpp_bootstrap_info
*bi
;
9903 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
9911 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
9913 unsigned int id_val
;
9915 if (os_strcmp(id
, "*") == 0) {
9923 return dpp_bootstrap_del(dpp
, id_val
);
9927 struct dpp_bootstrap_info
*
9928 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
9931 struct dpp_bootstrap_info
*bi
;
9933 bi
= os_zalloc(sizeof(*bi
));
9936 bi
->id
= dpp_next_id(dpp
);
9937 bi
->type
= DPP_BOOTSTRAP_PKEX
;
9938 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
9941 bi
->curve
= pkex
->own_bi
->curve
;
9942 bi
->pubkey
= pkex
->peer_bootstrap_key
;
9943 pkex
->peer_bootstrap_key
= NULL
;
9944 if (dpp_bootstrap_key_hash(bi
) < 0) {
9945 dpp_bootstrap_info_free(bi
);
9948 dpp_pkex_free(pkex
);
9949 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
9954 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
9956 struct dpp_bootstrap_info
*bi
;
9958 bi
= dpp_bootstrap_get_id(dpp
, id
);
9965 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
9966 char *reply
, int reply_size
)
9968 struct dpp_bootstrap_info
*bi
;
9969 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
9971 bi
= dpp_bootstrap_get_id(dpp
, id
);
9974 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
9976 return os_snprintf(reply
, reply_size
, "type=%s\n"
9977 "mac_addr=" MACSTR
"\n"
9983 dpp_bootstrap_type_txt(bi
->type
),
9984 MAC2STR(bi
->mac_addr
),
9985 bi
->info
? bi
->info
: "",
9987 bi
->num_freq
== 1 ? bi
->freq
[0] : 0,
9993 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
9994 const u8
*r_bootstrap
,
9995 struct dpp_bootstrap_info
**own_bi
,
9996 struct dpp_bootstrap_info
**peer_bi
)
9998 struct dpp_bootstrap_info
*bi
;
10005 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10006 if (!*own_bi
&& bi
->own
&&
10007 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
10008 SHA256_MAC_LEN
) == 0) {
10009 wpa_printf(MSG_DEBUG
,
10010 "DPP: Found matching own bootstrapping information");
10014 if (!*peer_bi
&& !bi
->own
&&
10015 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
10016 SHA256_MAC_LEN
) == 0) {
10017 wpa_printf(MSG_DEBUG
,
10018 "DPP: Found matching peer bootstrapping information");
10022 if (*own_bi
&& *peer_bi
)
10029 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info
*own_bi
,
10030 struct dpp_bootstrap_info
*peer_bi
)
10032 unsigned int i
, freq
= 0;
10033 enum hostapd_hw_mode mode
;
10034 u8 op_class
, channel
;
10037 if (peer_bi
->num_freq
== 0)
10038 return 0; /* no channel preference/constraint */
10040 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
10041 if (own_bi
->num_freq
== 0 ||
10042 freq_included(own_bi
->freq
, own_bi
->num_freq
,
10043 peer_bi
->freq
[i
])) {
10044 freq
= peer_bi
->freq
[i
];
10049 wpa_printf(MSG_DEBUG
, "DPP: No common channel found");
10053 mode
= ieee80211_freq_to_channel_ext(freq
, 0, 0, &op_class
, &channel
);
10054 if (mode
== NUM_HOSTAPD_MODES
) {
10055 wpa_printf(MSG_DEBUG
,
10056 "DPP: Could not determine operating class or channel number for %u MHz",
10060 wpa_printf(MSG_DEBUG
,
10061 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10062 freq
, op_class
, channel
);
10063 os_snprintf(chan
, sizeof(chan
), "%u/%u", op_class
, channel
);
10064 os_free(own_bi
->chan
);
10065 own_bi
->chan
= os_strdup(chan
);
10066 own_bi
->freq
[0] = freq
;
10067 own_bi
->num_freq
= 1;
10068 os_free(peer_bi
->chan
);
10069 peer_bi
->chan
= os_strdup(chan
);
10070 peer_bi
->freq
[0] = freq
;
10071 peer_bi
->num_freq
= 1;
10073 return dpp_gen_uri(own_bi
);
10077 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info
*own_bi
,
10078 struct dpp_bootstrap_info
*peer_bi
)
10080 if (peer_bi
->curve
== own_bi
->curve
)
10083 wpa_printf(MSG_DEBUG
,
10084 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10086 EVP_PKEY_free(own_bi
->pubkey
);
10087 own_bi
->pubkey
= NULL
;
10089 if (dpp_keygen(own_bi
, peer_bi
->curve
->name
, NULL
, 0) < 0 ||
10090 dpp_gen_uri(own_bi
) < 0)
10095 dl_list_del(&own_bi
->list
);
10096 dpp_bootstrap_info_free(own_bi
);
10101 int dpp_nfc_update_bi(struct dpp_bootstrap_info
*own_bi
,
10102 struct dpp_bootstrap_info
*peer_bi
)
10104 if (dpp_nfc_update_bi_channel(own_bi
, peer_bi
) < 0 ||
10105 dpp_nfc_update_bi_key(own_bi
, peer_bi
) < 0)
10111 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
10113 struct dpp_configurator
*conf
;
10114 unsigned int max_id
= 0;
10116 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
10118 if (conf
->id
> max_id
)
10125 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
10127 char *curve
= NULL
;
10129 u8
*privkey
= NULL
;
10130 size_t privkey_len
= 0;
10132 struct dpp_configurator
*conf
= NULL
;
10134 curve
= get_param(cmd
, " curve=");
10135 key
= get_param(cmd
, " key=");
10138 privkey_len
= os_strlen(key
) / 2;
10139 privkey
= os_malloc(privkey_len
);
10141 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10145 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
10149 conf
->id
= dpp_next_configurator_id(dpp
);
10150 dl_list_add(&dpp
->configurator
, &conf
->list
);
10155 str_clear_free(key
);
10156 bin_clear_free(privkey
, privkey_len
);
10157 dpp_configurator_free(conf
);
10162 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
10164 struct dpp_configurator
*conf
, *tmp
;
10170 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
10171 struct dpp_configurator
, list
) {
10172 if (id
&& conf
->id
!= id
)
10175 dl_list_del(&conf
->list
);
10176 dpp_configurator_free(conf
);
10180 return 0; /* flush succeeds regardless of entries found */
10181 return found
? 0 : -1;
10185 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
10187 unsigned int id_val
;
10189 if (os_strcmp(id
, "*") == 0) {
10197 return dpp_configurator_del(dpp
, id_val
);
10201 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
10202 char *buf
, size_t buflen
)
10204 struct dpp_configurator
*conf
;
10206 conf
= dpp_configurator_get_id(dpp
, id
);
10210 return dpp_configurator_get_key(conf
, buf
, buflen
);
10216 int dpp_configurator_from_backup(struct dpp_global
*dpp
,
10217 struct dpp_asymmetric_key
*key
)
10219 struct dpp_configurator
*conf
;
10220 const EC_KEY
*eckey
;
10221 const EC_GROUP
*group
;
10223 const struct dpp_curve_params
*curve
;
10227 eckey
= EVP_PKEY_get0_EC_KEY(key
->csign
);
10230 group
= EC_KEY_get0_group(eckey
);
10233 nid
= EC_GROUP_get_curve_name(group
);
10234 curve
= dpp_get_curve_nid(nid
);
10236 wpa_printf(MSG_INFO
, "DPP: Unsupported group in c-sign-key");
10240 conf
= os_zalloc(sizeof(*conf
));
10243 conf
->curve
= curve
;
10244 conf
->csign
= key
->csign
;
10247 if (dpp_configurator_gen_kid(conf
) < 0) {
10248 dpp_configurator_free(conf
);
10252 conf
->id
= dpp_next_configurator_id(dpp
);
10253 dl_list_add(&dpp
->configurator
, &conf
->list
);
10258 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
10259 void *timeout_ctx
);
10262 static void dpp_connection_free(struct dpp_connection
*conn
)
10264 if (conn
->sock
>= 0) {
10265 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
10267 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
10268 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10271 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout
,
10273 wpabuf_free(conn
->msg
);
10274 wpabuf_free(conn
->msg_out
);
10275 dpp_auth_deinit(conn
->auth
);
10280 static void dpp_connection_remove(struct dpp_connection
*conn
)
10282 dl_list_del(&conn
->list
);
10283 dpp_connection_free(conn
);
10287 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
10289 struct dpp_connection
*conn
, *tmp
;
10291 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
10293 dpp_connection_remove(conn
);
10297 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
10299 struct dpp_connection
*conn
, *tmp
;
10301 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
10303 dpp_connection_remove(conn
);
10308 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
10310 struct dpp_relay_controller
*ctrl
, *tmp
;
10315 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
10316 struct dpp_relay_controller
, list
) {
10317 dl_list_del(&ctrl
->list
);
10318 dpp_relay_controller_free(ctrl
);
10322 #endif /* CONFIG_DPP2 */
10325 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
10327 struct dpp_global
*dpp
;
10329 dpp
= os_zalloc(sizeof(*dpp
));
10332 dpp
->msg_ctx
= config
->msg_ctx
;
10334 dpp
->cb_ctx
= config
->cb_ctx
;
10335 dpp
->process_conf_obj
= config
->process_conf_obj
;
10336 #endif /* CONFIG_DPP2 */
10338 dl_list_init(&dpp
->bootstrap
);
10339 dl_list_init(&dpp
->configurator
);
10341 dl_list_init(&dpp
->controllers
);
10342 dl_list_init(&dpp
->tcp_init
);
10343 #endif /* CONFIG_DPP2 */
10349 void dpp_global_clear(struct dpp_global
*dpp
)
10354 dpp_bootstrap_del(dpp
, 0);
10355 dpp_configurator_del(dpp
, 0);
10357 dpp_tcp_init_flush(dpp
);
10358 dpp_relay_flush_controllers(dpp
);
10359 dpp_controller_stop(dpp
);
10360 #endif /* CONFIG_DPP2 */
10364 void dpp_global_deinit(struct dpp_global
*dpp
)
10366 dpp_global_clear(dpp
);
10373 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
10374 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
10375 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
10379 int dpp_relay_add_controller(struct dpp_global
*dpp
,
10380 struct dpp_relay_config
*config
)
10382 struct dpp_relay_controller
*ctrl
;
10387 ctrl
= os_zalloc(sizeof(*ctrl
));
10390 dl_list_init(&ctrl
->conn
);
10391 ctrl
->global
= dpp
;
10392 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
10393 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
10394 ctrl
->cb_ctx
= config
->cb_ctx
;
10395 ctrl
->tx
= config
->tx
;
10396 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
10397 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
10402 static struct dpp_relay_controller
*
10403 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
10405 struct dpp_relay_controller
*ctrl
;
10410 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
10412 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
10420 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
10422 struct dpp_authentication
*auth
= conn
->auth
;
10424 if (auth
->peer_version
>= 2 &&
10425 auth
->conf_resp_status
== DPP_STATUS_OK
) {
10426 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
10427 auth
->waiting_conf_result
= 1;
10431 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
10432 dpp_connection_remove(conn
);
10436 static int dpp_tcp_send(struct dpp_connection
*conn
)
10440 if (!conn
->msg_out
) {
10441 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10442 conn
->write_eloop
= 0;
10445 res
= send(conn
->sock
,
10446 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
10447 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
10449 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
10451 dpp_connection_remove(conn
);
10455 conn
->msg_out_pos
+= res
;
10456 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
10457 wpa_printf(MSG_DEBUG
,
10458 "DPP: %u/%u bytes of message sent to Controller",
10459 (unsigned int) conn
->msg_out_pos
,
10460 (unsigned int) wpabuf_len(conn
->msg_out
));
10461 if (!conn
->write_eloop
&&
10462 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10463 dpp_conn_tx_ready
, conn
, NULL
) == 0)
10464 conn
->write_eloop
= 1;
10468 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
10469 wpabuf_free(conn
->msg_out
);
10470 conn
->msg_out
= NULL
;
10471 conn
->msg_out_pos
= 0;
10472 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10473 conn
->write_eloop
= 0;
10474 if (!conn
->read_eloop
&&
10475 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
10476 dpp_controller_rx
, conn
, NULL
) == 0)
10477 conn
->read_eloop
= 1;
10478 if (conn
->on_tcp_tx_complete_remove
) {
10479 dpp_connection_remove(conn
);
10480 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
10482 dpp_controller_gas_done(conn
);
10483 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
10484 conn
->on_tcp_tx_complete_auth_ok
= 0;
10485 dpp_controller_auth_success(conn
, 1);
10492 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
10494 struct dpp_authentication
*auth
= conn
->auth
;
10495 struct wpabuf
*buf
;
10496 int netrole_ap
= 0; /* TODO: make this configurable */
10498 buf
= dpp_build_conf_req_helper(auth
, "Test", netrole_ap
, NULL
, NULL
);
10500 wpa_printf(MSG_DEBUG
,
10501 "DPP: No configuration request data available");
10505 wpabuf_free(conn
->msg_out
);
10506 conn
->msg_out_pos
= 0;
10507 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
10508 if (!conn
->msg_out
) {
10512 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
10513 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
10514 wpabuf_len(buf
) - 1);
10517 if (dpp_tcp_send(conn
) == 1) {
10518 if (!conn
->write_eloop
) {
10519 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10523 conn
->write_eloop
= 1;
10529 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
10532 struct dpp_authentication
*auth
= conn
->auth
;
10537 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
10538 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
10539 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
10540 #ifdef CONFIG_TESTING_OPTIONS
10541 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
10542 wpa_printf(MSG_INFO
,
10543 "DPP: TESTING - stop at Authentication Confirm");
10544 if (auth
->configurator
) {
10545 /* Prevent GAS response */
10546 auth
->auth_success
= 0;
10550 #endif /* CONFIG_TESTING_OPTIONS */
10552 if (!auth
->configurator
)
10553 dpp_controller_start_gas_client(conn
);
10557 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
10559 struct dpp_connection
*conn
= eloop_ctx
;
10561 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
10562 dpp_tcp_send(conn
);
10566 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
10567 const struct hostapd_ip_addr
*ipaddr
,
10570 struct sockaddr_in
*dst
;
10572 struct sockaddr_in6
*dst6
;
10573 #endif /* CONFIG_IPV6 */
10575 switch (ipaddr
->af
) {
10577 dst
= (struct sockaddr_in
*) addr
;
10578 os_memset(dst
, 0, sizeof(*dst
));
10579 dst
->sin_family
= AF_INET
;
10580 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
10581 dst
->sin_port
= htons(port
);
10582 *addrlen
= sizeof(*dst
);
10586 dst6
= (struct sockaddr_in6
*) addr
;
10587 os_memset(dst6
, 0, sizeof(*dst6
));
10588 dst6
->sin6_family
= AF_INET6
;
10589 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
10590 sizeof(struct in6_addr
));
10591 dst6
->sin6_port
= htons(port
);
10592 *addrlen
= sizeof(*dst6
);
10594 #endif /* CONFIG_IPV6 */
10603 static struct dpp_connection
*
10604 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
10607 struct dpp_connection
*conn
;
10608 struct sockaddr_storage addr
;
10612 if (dl_list_len(&ctrl
->conn
) >= 15) {
10613 wpa_printf(MSG_DEBUG
,
10614 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
10618 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
10619 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
10622 conn
= os_zalloc(sizeof(*conn
));
10626 conn
->global
= ctrl
->global
;
10627 conn
->relay
= ctrl
;
10628 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
10631 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
10632 if (conn
->sock
< 0)
10634 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
10635 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
10637 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
10638 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
10643 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
10644 if (errno
!= EINPROGRESS
) {
10645 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
10651 * Continue connecting in the background; eloop will call us
10652 * once the connection is ready (or failed).
10656 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10657 dpp_conn_tx_ready
, conn
, NULL
) < 0)
10659 conn
->write_eloop
= 1;
10661 /* TODO: eloop timeout to clear a connection if it does not complete
10664 dl_list_add(&ctrl
->conn
, &conn
->list
);
10667 dpp_connection_free(conn
);
10672 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
10674 struct wpabuf
*msg
;
10676 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
10679 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
10680 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
10681 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
10682 wpabuf_put_data(msg
, buf
, len
);
10683 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
10688 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
10689 const u8
*buf
, size_t len
)
10691 u8 type
= hdr
[DPP_HDR_LEN
- 1];
10693 wpa_printf(MSG_DEBUG
,
10694 "DPP: Continue already established Relay/Controller connection for this session");
10695 wpabuf_free(conn
->msg_out
);
10696 conn
->msg_out_pos
= 0;
10697 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
10698 if (!conn
->msg_out
) {
10699 dpp_connection_remove(conn
);
10703 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
10705 if (type
== DPP_PA_CONFIGURATION_RESULT
)
10706 conn
->on_tcp_tx_complete_remove
= 1;
10707 dpp_tcp_send(conn
);
10712 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
10713 const u8
*buf
, size_t len
, unsigned int freq
,
10714 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
10716 struct dpp_relay_controller
*ctrl
;
10717 struct dpp_connection
*conn
;
10718 u8 type
= hdr
[DPP_HDR_LEN
- 1];
10720 /* Check if there is an already started session for this peer and if so,
10721 * continue that session (send this over TCP) and return 0.
10723 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
10724 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
10725 dl_list_for_each(ctrl
, &dpp
->controllers
,
10726 struct dpp_relay_controller
, list
) {
10727 dl_list_for_each(conn
, &ctrl
->conn
,
10728 struct dpp_connection
, list
) {
10729 if (os_memcmp(src
, conn
->mac_addr
,
10731 return dpp_relay_tx(conn
, hdr
, buf
, len
);
10739 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
10743 wpa_printf(MSG_DEBUG
,
10744 "DPP: Authentication Request for a configured Controller");
10745 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
10749 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
10750 if (!conn
->msg_out
) {
10751 dpp_connection_remove(conn
);
10754 /* Message will be sent in dpp_conn_tx_ready() */
10760 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
10763 struct dpp_relay_controller
*ctrl
;
10764 struct dpp_connection
*conn
, *found
= NULL
;
10765 struct wpabuf
*msg
;
10767 /* Check if there is a successfully completed authentication for this
10768 * and if so, continue that session (send this over TCP) and return 0.
10770 dl_list_for_each(ctrl
, &dpp
->controllers
,
10771 struct dpp_relay_controller
, list
) {
10774 dl_list_for_each(conn
, &ctrl
->conn
,
10775 struct dpp_connection
, list
) {
10776 if (os_memcmp(src
, conn
->mac_addr
,
10787 msg
= wpabuf_alloc(4 + 1 + data_len
);
10790 wpabuf_put_be32(msg
, 1 + data_len
);
10791 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
10792 wpabuf_put_data(msg
, data
, data_len
);
10793 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
10795 wpabuf_free(conn
->msg_out
);
10796 conn
->msg_out_pos
= 0;
10797 conn
->msg_out
= msg
;
10798 dpp_tcp_send(conn
);
10803 static void dpp_controller_free(struct dpp_controller
*ctrl
)
10805 struct dpp_connection
*conn
, *tmp
;
10810 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
10812 dpp_connection_remove(conn
);
10814 if (ctrl
->sock
>= 0) {
10816 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
10818 os_free(ctrl
->configurator_params
);
10823 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
10824 const u8
*hdr
, const u8
*buf
, size_t len
)
10826 const u8
*r_bootstrap
, *i_bootstrap
;
10827 u16 r_bootstrap_len
, i_bootstrap_len
;
10828 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
10833 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
10835 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
10837 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
10838 wpa_printf(MSG_INFO
,
10839 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
10842 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
10843 r_bootstrap
, r_bootstrap_len
);
10845 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
10847 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
10848 wpa_printf(MSG_INFO
,
10849 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
10852 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
10853 i_bootstrap
, i_bootstrap_len
);
10855 /* Try to find own and peer bootstrapping key matches based on the
10856 * received hash values */
10857 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
10858 &own_bi
, &peer_bi
);
10860 wpa_printf(MSG_INFO
,
10861 "No matching own bootstrapping key found - ignore message");
10866 wpa_printf(MSG_INFO
,
10867 "Already in DPP authentication exchange - ignore new one");
10871 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
10872 conn
->ctrl
->allowed_roles
,
10873 conn
->ctrl
->qr_mutual
,
10874 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
10876 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
10880 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
10882 conn
->ctrl
->configurator_params
) < 0) {
10883 dpp_connection_remove(conn
);
10887 wpabuf_free(conn
->msg_out
);
10888 conn
->msg_out_pos
= 0;
10889 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
10890 if (!conn
->msg_out
)
10892 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
10893 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
10894 wpabuf_len(conn
->auth
->resp_msg
) - 1);
10896 if (dpp_tcp_send(conn
) == 1) {
10897 if (!conn
->write_eloop
) {
10898 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10902 conn
->write_eloop
= 1;
10910 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
10911 const u8
*hdr
, const u8
*buf
, size_t len
)
10913 struct dpp_authentication
*auth
= conn
->auth
;
10914 struct wpabuf
*msg
;
10919 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
10921 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
10923 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
10924 wpa_printf(MSG_DEBUG
,
10925 "DPP: Start wait for full response");
10928 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
10929 dpp_connection_remove(conn
);
10933 wpabuf_free(conn
->msg_out
);
10934 conn
->msg_out_pos
= 0;
10935 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
10936 if (!conn
->msg_out
) {
10940 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
10941 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
10942 wpabuf_len(msg
) - 1);
10945 conn
->on_tcp_tx_complete_auth_ok
= 1;
10946 if (dpp_tcp_send(conn
) == 1) {
10947 if (!conn
->write_eloop
) {
10948 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10952 conn
->write_eloop
= 1;
10960 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
10961 const u8
*hdr
, const u8
*buf
, size_t len
)
10963 struct dpp_authentication
*auth
= conn
->auth
;
10965 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
10968 wpa_printf(MSG_DEBUG
,
10969 "DPP: No DPP Authentication in progress - drop");
10973 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
10974 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
10978 dpp_controller_auth_success(conn
, 0);
10983 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
10986 struct dpp_connection
*conn
= eloop_ctx
;
10988 if (!conn
->auth
->waiting_conf_result
)
10991 wpa_printf(MSG_DEBUG
,
10992 "DPP: Timeout while waiting for Connection Status Result");
10993 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
10994 DPP_EVENT_CONN_STATUS_RESULT
"timeout");
10995 dpp_connection_remove(conn
);
10999 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
11000 const u8
*hdr
, const u8
*buf
,
11003 struct dpp_authentication
*auth
= conn
->auth
;
11004 enum dpp_status_error status
;
11009 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
11011 if (!auth
|| !auth
->waiting_conf_result
) {
11012 wpa_printf(MSG_DEBUG
,
11013 "DPP: No DPP Configuration waiting for result - drop");
11017 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
11018 if (status
== DPP_STATUS_OK
&& auth
->send_conn_status
) {
11019 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11020 DPP_EVENT_CONF_SENT
"wait_conn_status=1");
11021 wpa_printf(MSG_DEBUG
, "DPP: Wait for Connection Status Result");
11022 eloop_cancel_timeout(
11023 dpp_controller_conn_status_result_wait_timeout
,
11025 eloop_register_timeout(
11026 16, 0, dpp_controller_conn_status_result_wait_timeout
,
11030 if (status
== DPP_STATUS_OK
)
11031 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11032 DPP_EVENT_CONF_SENT
);
11034 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11035 DPP_EVENT_CONF_FAILED
);
11036 return -1; /* to remove the completed connection */
11040 static int dpp_controller_rx_conn_status_result(struct dpp_connection
*conn
,
11041 const u8
*hdr
, const u8
*buf
,
11044 struct dpp_authentication
*auth
= conn
->auth
;
11045 enum dpp_status_error status
;
11046 u8 ssid
[SSID_MAX_LEN
];
11047 size_t ssid_len
= 0;
11048 char *channel_list
= NULL
;
11053 wpa_printf(MSG_DEBUG
, "DPP: Connection Status Result");
11055 if (!auth
|| !auth
->waiting_conn_status_result
) {
11056 wpa_printf(MSG_DEBUG
,
11057 "DPP: No DPP Configuration waiting for connection status result - drop");
11061 status
= dpp_conn_status_result_rx(auth
, hdr
, buf
, len
,
11062 ssid
, &ssid_len
, &channel_list
);
11063 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11064 DPP_EVENT_CONN_STATUS_RESULT
11065 "result=%d ssid=%s channel_list=%s",
11066 status
, wpa_ssid_txt(ssid
, ssid_len
),
11067 channel_list
? channel_list
: "N/A");
11068 os_free(channel_list
);
11069 return -1; /* to remove the completed connection */
11073 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
11076 const u8
*pos
, *end
;
11079 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
11083 if (end
- pos
< DPP_HDR_LEN
||
11084 WPA_GET_BE24(pos
) != OUI_WFA
||
11085 pos
[3] != DPP_OUI_TYPE
) {
11086 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
11091 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
11096 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
11097 pos
+= DPP_HDR_LEN
;
11099 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
11101 if (dpp_check_attrs(pos
, end
- pos
) < 0)
11105 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11106 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11107 conn
->freq
, msg
, len
);
11112 case DPP_PA_AUTHENTICATION_REQ
:
11113 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
11114 case DPP_PA_AUTHENTICATION_RESP
:
11115 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
11116 case DPP_PA_AUTHENTICATION_CONF
:
11117 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
11118 case DPP_PA_CONFIGURATION_RESULT
:
11119 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
11120 case DPP_PA_CONNECTION_STATUS_RESULT
:
11121 return dpp_controller_rx_conn_status_result(conn
, msg
, pos
,
11124 /* TODO: missing messages types */
11125 wpa_printf(MSG_DEBUG
,
11126 "DPP: Unsupported frame subtype %d", type
);
11132 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
11135 const u8
*pos
, *end
, *next
;
11137 const u8
*adv_proto
;
11139 struct wpabuf
*resp
, *buf
;
11140 struct dpp_authentication
*auth
= conn
->auth
;
11145 wpa_printf(MSG_DEBUG
,
11146 "DPP: Received DPP Configuration Request over TCP");
11148 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
11149 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11156 dialog_token
= *pos
++;
11159 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11160 slen
> end
- pos
|| slen
< 2)
11164 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11166 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11167 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11168 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11172 /* Query Request */
11175 slen
= WPA_GET_LE16(pos
);
11177 if (slen
> end
- pos
)
11180 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
11184 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
11190 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
11192 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
11193 wpabuf_put_u8(buf
, dialog_token
);
11194 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
11195 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
11197 dpp_write_adv_proto(buf
);
11198 dpp_write_gas_query(buf
, resp
);
11201 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11203 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
11204 wpabuf_free(conn
->msg_out
);
11205 conn
->msg_out_pos
= 0;
11206 conn
->msg_out
= buf
;
11207 conn
->on_tcp_tx_complete_gas_done
= 1;
11208 dpp_tcp_send(conn
);
11213 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
11215 struct dpp_authentication
*auth
= conn
->auth
;
11217 struct wpabuf
*msg
, *encaps
;
11218 enum dpp_status_error status
;
11220 wpa_printf(MSG_DEBUG
,
11221 "DPP: Configuration Response for local stack from TCP");
11223 res
= dpp_conf_resp_rx(auth
, resp
);
11226 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
11230 if (conn
->global
->process_conf_obj
)
11231 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
11236 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
11240 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
11241 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
11242 msg
= dpp_build_conf_result(auth
, status
);
11246 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11251 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
11252 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
11254 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
11256 wpabuf_free(conn
->msg_out
);
11257 conn
->msg_out_pos
= 0;
11258 conn
->msg_out
= encaps
;
11259 conn
->on_tcp_tx_complete_remove
= 1;
11260 dpp_tcp_send(conn
);
11262 /* This exchange will be terminated in the TX status handler */
11265 #else /* CONFIG_DPP2 */
11267 #endif /* CONFIG_DPP2 */
11271 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
11274 struct wpabuf
*buf
;
11276 const u8
*pos
, *end
, *next
, *adv_proto
;
11282 wpa_printf(MSG_DEBUG
,
11283 "DPP: Received DPP Configuration Response over TCP");
11288 dialog_token
= *pos
++;
11289 status
= WPA_GET_LE16(pos
);
11290 if (status
!= WLAN_STATUS_SUCCESS
) {
11291 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
11295 pos
+= 2; /* ignore GAS Comeback Delay */
11299 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11300 slen
> end
- pos
|| slen
< 2)
11304 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11306 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11307 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11308 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11312 /* Query Response */
11315 slen
= WPA_GET_LE16(pos
);
11317 if (slen
> end
- pos
)
11320 buf
= wpabuf_alloc(slen
);
11323 wpabuf_put_data(buf
, pos
, slen
);
11325 if (!conn
->relay
&& !conn
->ctrl
)
11326 return dpp_tcp_rx_gas_resp(conn
, buf
);
11328 if (!conn
->relay
) {
11329 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11333 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11334 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11335 dialog_token
, 0, buf
);
11341 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
11343 struct dpp_connection
*conn
= eloop_ctx
;
11347 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
11350 if (conn
->msg_len_octets
< 4) {
11353 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
11354 4 - conn
->msg_len_octets
, 0);
11356 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
11358 dpp_connection_remove(conn
);
11362 wpa_printf(MSG_DEBUG
,
11363 "DPP: No more data available over TCP");
11364 dpp_connection_remove(conn
);
11367 wpa_printf(MSG_DEBUG
,
11368 "DPP: Received %d/%d octet(s) of message length field",
11369 res
, (int) (4 - conn
->msg_len_octets
));
11370 conn
->msg_len_octets
+= res
;
11372 if (conn
->msg_len_octets
< 4) {
11373 wpa_printf(MSG_DEBUG
,
11374 "DPP: Need %d more octets of message length field",
11375 (int) (4 - conn
->msg_len_octets
));
11379 msglen
= WPA_GET_BE32(conn
->msg_len
);
11380 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
11381 if (msglen
> 65535) {
11382 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
11383 dpp_connection_remove(conn
);
11387 wpabuf_free(conn
->msg
);
11388 conn
->msg
= wpabuf_alloc(msglen
);
11392 wpa_printf(MSG_DEBUG
,
11393 "DPP: No buffer available for receiving the message");
11394 dpp_connection_remove(conn
);
11398 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
11399 (unsigned int) wpabuf_tailroom(conn
->msg
));
11401 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
11403 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
11404 dpp_connection_remove(conn
);
11408 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
11409 dpp_connection_remove(conn
);
11412 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
11413 wpabuf_put(conn
->msg
, res
);
11415 if (wpabuf_tailroom(conn
->msg
) > 0) {
11416 wpa_printf(MSG_DEBUG
,
11417 "DPP: Need %u more octets of message payload",
11418 (unsigned int) wpabuf_tailroom(conn
->msg
));
11422 conn
->msg_len_octets
= 0;
11423 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
11424 if (wpabuf_len(conn
->msg
) < 1) {
11425 dpp_connection_remove(conn
);
11429 pos
= wpabuf_head(conn
->msg
);
11431 case WLAN_PA_VENDOR_SPECIFIC
:
11432 if (dpp_controller_rx_action(conn
, pos
+ 1,
11433 wpabuf_len(conn
->msg
) - 1) < 0)
11434 dpp_connection_remove(conn
);
11436 case WLAN_PA_GAS_INITIAL_REQ
:
11437 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
11438 wpabuf_len(conn
->msg
) - 1) < 0)
11439 dpp_connection_remove(conn
);
11441 case WLAN_PA_GAS_INITIAL_RESP
:
11442 if (dpp_rx_gas_resp(conn
, pos
+ 1,
11443 wpabuf_len(conn
->msg
) - 1) < 0)
11444 dpp_connection_remove(conn
);
11447 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
11454 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
11456 struct dpp_controller
*ctrl
= eloop_ctx
;
11457 struct sockaddr_in addr
;
11458 socklen_t addr_len
= sizeof(addr
);
11460 struct dpp_connection
*conn
;
11462 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
11464 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
11466 wpa_printf(MSG_DEBUG
,
11467 "DPP: Failed to accept new connection: %s",
11471 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
11472 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
11474 conn
= os_zalloc(sizeof(*conn
));
11478 conn
->global
= ctrl
->global
;
11482 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
11483 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11488 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
11489 dpp_controller_rx
, conn
, NULL
) < 0)
11491 conn
->read_eloop
= 1;
11493 /* TODO: eloop timeout to expire connections that do not complete in
11494 * reasonable time */
11495 dl_list_add(&ctrl
->conn
, &conn
->list
);
11504 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
11505 const struct hostapd_ip_addr
*addr
, int port
)
11507 struct dpp_connection
*conn
;
11508 struct sockaddr_storage saddr
;
11510 const u8
*hdr
, *pos
, *end
;
11513 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
11514 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
11515 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
11517 dpp_auth_deinit(auth
);
11521 conn
= os_zalloc(sizeof(*conn
));
11523 dpp_auth_deinit(auth
);
11527 conn
->global
= dpp
;
11529 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
11530 if (conn
->sock
< 0)
11533 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
11534 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11539 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
11540 if (errno
!= EINPROGRESS
) {
11541 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
11547 * Continue connecting in the background; eloop will call us
11548 * once the connection is ready (or failed).
11552 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11553 dpp_conn_tx_ready
, conn
, NULL
) < 0)
11555 conn
->write_eloop
= 1;
11557 hdr
= wpabuf_head(auth
->req_msg
);
11558 end
= hdr
+ wpabuf_len(auth
->req_msg
);
11559 hdr
+= 2; /* skip Category and Actiom */
11560 pos
= hdr
+ DPP_HDR_LEN
;
11561 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
11562 if (!conn
->msg_out
)
11564 /* Message will be sent in dpp_conn_tx_ready() */
11566 /* TODO: eloop timeout to clear a connection if it does not complete
11568 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
11571 dpp_connection_free(conn
);
11576 int dpp_controller_start(struct dpp_global
*dpp
,
11577 struct dpp_controller_config
*config
)
11579 struct dpp_controller
*ctrl
;
11581 struct sockaddr_in sin
;
11584 if (!dpp
|| dpp
->controller
)
11587 ctrl
= os_zalloc(sizeof(*ctrl
));
11590 ctrl
->global
= dpp
;
11591 if (config
->configurator_params
)
11592 ctrl
->configurator_params
=
11593 os_strdup(config
->configurator_params
);
11594 dl_list_init(&ctrl
->conn
);
11595 /* TODO: configure these somehow */
11596 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
11597 ctrl
->qr_mutual
= 0;
11599 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
11600 if (ctrl
->sock
< 0)
11603 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
11604 &on
, sizeof(on
)) < 0) {
11605 wpa_printf(MSG_DEBUG
,
11606 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
11608 /* try to continue anyway */
11611 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
11612 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11618 os_memset(&sin
, 0, sizeof(sin
));
11619 sin
.sin_family
= AF_INET
;
11620 sin
.sin_addr
.s_addr
= INADDR_ANY
;
11621 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
11622 sin
.sin_port
= htons(port
);
11623 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
11624 wpa_printf(MSG_INFO
,
11625 "DPP: Failed to bind Controller TCP port: %s",
11629 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
11630 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
11631 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
11632 dpp_controller_tcp_cb
, ctrl
, NULL
))
11635 dpp
->controller
= ctrl
;
11636 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
11639 dpp_controller_free(ctrl
);
11644 void dpp_controller_stop(struct dpp_global
*dpp
)
11647 dpp_controller_free(dpp
->controller
);
11648 dpp
->controller
= NULL
;
11652 #endif /* CONFIG_DPP2 */