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 static struct dpp_authentication
* dpp_alloc_auth(void *msg_ctx
)
2340 struct dpp_authentication
*auth
;
2342 auth
= os_zalloc(sizeof(*auth
));
2345 auth
->msg_ctx
= msg_ctx
;
2346 auth
->conf_resp_status
= 255;
2351 struct dpp_authentication
* dpp_auth_init(void *msg_ctx
,
2352 struct dpp_bootstrap_info
*peer_bi
,
2353 struct dpp_bootstrap_info
*own_bi
,
2354 u8 dpp_allowed_roles
,
2355 unsigned int neg_freq
,
2356 struct hostapd_hw_modes
*own_modes
,
2359 struct dpp_authentication
*auth
;
2362 struct wpabuf
*pi
= NULL
;
2363 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
2364 #ifdef CONFIG_TESTING_OPTIONS
2365 u8 test_hash
[SHA256_MAC_LEN
];
2366 #endif /* CONFIG_TESTING_OPTIONS */
2368 auth
= dpp_alloc_auth(msg_ctx
);
2371 auth
->initiator
= 1;
2372 auth
->waiting_auth_resp
= 1;
2373 auth
->allowed_roles
= dpp_allowed_roles
;
2374 auth
->configurator
= !!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
);
2375 auth
->peer_bi
= peer_bi
;
2376 auth
->own_bi
= own_bi
;
2377 auth
->curve
= peer_bi
->curve
;
2379 if (dpp_autogen_bootstrap_key(auth
) < 0 ||
2380 dpp_prepare_channel_list(auth
, own_modes
, num_modes
) < 0)
2383 #ifdef CONFIG_TESTING_OPTIONS
2384 if (dpp_nonce_override_len
> 0) {
2385 wpa_printf(MSG_INFO
, "DPP: TESTING - override I-nonce");
2386 nonce_len
= dpp_nonce_override_len
;
2387 os_memcpy(auth
->i_nonce
, dpp_nonce_override
, nonce_len
);
2389 nonce_len
= auth
->curve
->nonce_len
;
2390 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2391 wpa_printf(MSG_ERROR
,
2392 "DPP: Failed to generate I-nonce");
2396 #else /* CONFIG_TESTING_OPTIONS */
2397 nonce_len
= auth
->curve
->nonce_len
;
2398 if (random_get_bytes(auth
->i_nonce
, nonce_len
)) {
2399 wpa_printf(MSG_ERROR
, "DPP: Failed to generate I-nonce");
2402 #endif /* CONFIG_TESTING_OPTIONS */
2403 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", auth
->i_nonce
, nonce_len
);
2405 #ifdef CONFIG_TESTING_OPTIONS
2406 if (dpp_protocol_key_override_len
) {
2407 const struct dpp_curve_params
*tmp_curve
;
2409 wpa_printf(MSG_INFO
,
2410 "DPP: TESTING - override protocol key");
2411 auth
->own_protocol_key
= dpp_set_keypair(
2412 &tmp_curve
, dpp_protocol_key_override
,
2413 dpp_protocol_key_override_len
);
2415 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2417 #else /* CONFIG_TESTING_OPTIONS */
2418 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
2419 #endif /* CONFIG_TESTING_OPTIONS */
2420 if (!auth
->own_protocol_key
)
2423 pi
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2427 /* ECDH: M = pI * BR */
2428 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_bi
->pubkey
,
2429 auth
->Mx
, &secret_len
) < 0)
2431 auth
->secret_len
= secret_len
;
2433 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
2434 auth
->Mx
, auth
->secret_len
);
2435 auth
->Mx_len
= auth
->secret_len
;
2437 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
2438 auth
->curve
->hash_len
) < 0)
2441 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
2442 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
2444 #ifdef CONFIG_TESTING_OPTIONS
2445 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2446 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
2447 r_pubkey_hash
= NULL
;
2448 } else if (dpp_test
== DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2449 wpa_printf(MSG_INFO
,
2450 "DPP: TESTING - invalid R-Bootstrap Key Hash");
2451 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
2452 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2453 r_pubkey_hash
= test_hash
;
2454 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2455 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
2456 i_pubkey_hash
= NULL
;
2457 } else if (dpp_test
== DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ
) {
2458 wpa_printf(MSG_INFO
,
2459 "DPP: TESTING - invalid I-Bootstrap Key Hash");
2460 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
2461 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
2462 i_pubkey_hash
= test_hash
;
2463 } else if (dpp_test
== DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ
) {
2464 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Proto Key");
2467 } else if (dpp_test
== DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ
) {
2468 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid I-Proto Key");
2470 pi
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
2471 if (!pi
|| dpp_test_gen_invalid_key(pi
, auth
->curve
) < 0)
2474 #endif /* CONFIG_TESTING_OPTIONS */
2476 auth
->req_msg
= dpp_auth_build_req(auth
, pi
, nonce_len
, r_pubkey_hash
,
2477 i_pubkey_hash
, neg_freq
);
2485 dpp_auth_deinit(auth
);
2491 static struct wpabuf
* dpp_build_conf_req_attr(struct dpp_authentication
*auth
,
2495 size_t json_len
, clear_len
;
2496 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
2500 wpa_printf(MSG_DEBUG
, "DPP: Build configuration request");
2502 nonce_len
= auth
->curve
->nonce_len
;
2503 if (random_get_bytes(auth
->e_nonce
, nonce_len
)) {
2504 wpa_printf(MSG_ERROR
, "DPP: Failed to generate E-nonce");
2507 wpa_hexdump(MSG_DEBUG
, "DPP: E-nonce", auth
->e_nonce
, nonce_len
);
2508 json_len
= os_strlen(json
);
2509 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configRequest JSON", json
, json_len
);
2511 /* { E-nonce, configAttrib }ke */
2512 clear_len
= 4 + nonce_len
+ 4 + json_len
;
2513 clear
= wpabuf_alloc(clear_len
);
2514 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
2515 #ifdef CONFIG_TESTING_OPTIONS
2516 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
)
2518 #endif /* CONFIG_TESTING_OPTIONS */
2519 msg
= wpabuf_alloc(attr_len
);
2523 #ifdef CONFIG_TESTING_OPTIONS
2524 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_REQ
) {
2525 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
2528 if (dpp_test
== DPP_TEST_INVALID_E_NONCE_CONF_REQ
) {
2529 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid E-nonce");
2530 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2531 wpabuf_put_le16(clear
, nonce_len
- 1);
2532 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
- 1);
2535 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_REQ
) {
2536 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
2537 goto skip_wrapped_data
;
2539 #endif /* CONFIG_TESTING_OPTIONS */
2542 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
2543 wpabuf_put_le16(clear
, nonce_len
);
2544 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
2546 #ifdef CONFIG_TESTING_OPTIONS
2548 if (dpp_test
== DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ
) {
2549 wpa_printf(MSG_INFO
, "DPP: TESTING - no configAttrib");
2550 goto skip_conf_attr_obj
;
2552 #endif /* CONFIG_TESTING_OPTIONS */
2555 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_ATTR_OBJ
);
2556 wpabuf_put_le16(clear
, json_len
);
2557 wpabuf_put_data(clear
, json
, json_len
);
2559 #ifdef CONFIG_TESTING_OPTIONS
2561 #endif /* CONFIG_TESTING_OPTIONS */
2563 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
2564 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2565 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2568 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
2569 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
2570 wpabuf_head(clear
), wpabuf_len(clear
),
2571 0, NULL
, NULL
, wrapped
) < 0)
2573 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
2574 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
2576 #ifdef CONFIG_TESTING_OPTIONS
2577 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ
) {
2578 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
2579 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
2582 #endif /* CONFIG_TESTING_OPTIONS */
2584 wpa_hexdump_buf(MSG_DEBUG
,
2585 "DPP: Configuration Request frame attributes", msg
);
2596 static void dpp_write_adv_proto(struct wpabuf
*buf
)
2598 /* Advertisement Protocol IE */
2599 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2600 wpabuf_put_u8(buf
, 8); /* Length */
2601 wpabuf_put_u8(buf
, 0x7f);
2602 wpabuf_put_u8(buf
, WLAN_EID_VENDOR_SPECIFIC
);
2603 wpabuf_put_u8(buf
, 5);
2604 wpabuf_put_be24(buf
, OUI_WFA
);
2605 wpabuf_put_u8(buf
, DPP_OUI_TYPE
);
2606 wpabuf_put_u8(buf
, 0x01);
2610 static void dpp_write_gas_query(struct wpabuf
*buf
, struct wpabuf
*query
)
2613 wpabuf_put_le16(buf
, wpabuf_len(query
));
2614 wpabuf_put_buf(buf
, query
);
2618 struct wpabuf
* dpp_build_conf_req(struct dpp_authentication
*auth
,
2621 struct wpabuf
*buf
, *conf_req
;
2623 conf_req
= dpp_build_conf_req_attr(auth
, json
);
2625 wpa_printf(MSG_DEBUG
,
2626 "DPP: No configuration request data available");
2630 buf
= gas_build_initial_req(0, 10 + 2 + wpabuf_len(conf_req
));
2632 wpabuf_free(conf_req
);
2636 dpp_write_adv_proto(buf
);
2637 dpp_write_gas_query(buf
, conf_req
);
2638 wpabuf_free(conf_req
);
2639 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: GAS Config Request", buf
);
2645 struct wpabuf
* dpp_build_conf_req_helper(struct dpp_authentication
*auth
,
2647 enum dpp_netrole netrole
,
2648 const char *mud_url
, int *opclasses
)
2650 size_t len
, name_len
;
2651 const char *tech
= "infra";
2652 const char *dpp_name
;
2653 struct wpabuf
*buf
, *json
;
2655 #ifdef CONFIG_TESTING_OPTIONS
2656 if (dpp_test
== DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ
) {
2657 static const char *bogus_tech
= "knfra";
2659 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Config Attr");
2662 #endif /* CONFIG_TESTING_OPTIONS */
2664 dpp_name
= name
? name
: "Test";
2665 name_len
= os_strlen(dpp_name
);
2667 len
= 100 + name_len
* 6 + 1 + int_array_len(opclasses
) * 4;
2668 if (mud_url
&& mud_url
[0])
2669 len
+= 10 + os_strlen(mud_url
);
2670 json
= wpabuf_alloc(len
);
2674 json_start_object(json
, NULL
);
2675 if (json_add_string_escape(json
, "name", dpp_name
, name_len
) < 0) {
2679 json_value_sep(json
);
2680 json_add_string(json
, "wi-fi_tech", tech
);
2681 json_value_sep(json
);
2682 json_add_string(json
, "netRole", dpp_netrole_str(netrole
));
2683 if (mud_url
&& mud_url
[0]) {
2684 json_value_sep(json
);
2685 json_add_string(json
, "mudurl", mud_url
);
2690 json_value_sep(json
);
2691 json_start_array(json
, "bandSupport");
2692 for (i
= 0; opclasses
[i
]; i
++)
2693 wpabuf_printf(json
, "%s%u", i
? "," : "", opclasses
[i
]);
2694 json_end_array(json
);
2696 json_end_object(json
);
2698 buf
= dpp_build_conf_req(auth
, wpabuf_head(json
));
2705 static void dpp_auth_success(struct dpp_authentication
*auth
)
2707 wpa_printf(MSG_DEBUG
,
2708 "DPP: Authentication success - clear temporary keys");
2709 os_memset(auth
->Mx
, 0, sizeof(auth
->Mx
));
2711 os_memset(auth
->Nx
, 0, sizeof(auth
->Nx
));
2713 os_memset(auth
->Lx
, 0, sizeof(auth
->Lx
));
2715 os_memset(auth
->k1
, 0, sizeof(auth
->k1
));
2716 os_memset(auth
->k2
, 0, sizeof(auth
->k2
));
2718 auth
->auth_success
= 1;
2722 static int dpp_gen_r_auth(struct dpp_authentication
*auth
, u8
*r_auth
)
2724 struct wpabuf
*pix
, *prx
, *bix
, *brx
;
2727 size_t i
, num_elem
= 0;
2732 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
2733 nonce_len
= auth
->curve
->nonce_len
;
2735 if (auth
->initiator
) {
2736 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2737 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2739 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2742 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2744 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2745 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2747 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2750 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2752 if (!pix
|| !prx
|| !brx
)
2755 addr
[num_elem
] = auth
->i_nonce
;
2756 len
[num_elem
] = nonce_len
;
2759 addr
[num_elem
] = auth
->r_nonce
;
2760 len
[num_elem
] = nonce_len
;
2763 addr
[num_elem
] = wpabuf_head(pix
);
2764 len
[num_elem
] = wpabuf_len(pix
) / 2;
2767 addr
[num_elem
] = wpabuf_head(prx
);
2768 len
[num_elem
] = wpabuf_len(prx
) / 2;
2772 addr
[num_elem
] = wpabuf_head(bix
);
2773 len
[num_elem
] = wpabuf_len(bix
) / 2;
2777 addr
[num_elem
] = wpabuf_head(brx
);
2778 len
[num_elem
] = wpabuf_len(brx
) / 2;
2781 addr
[num_elem
] = &zero
;
2785 wpa_printf(MSG_DEBUG
, "DPP: R-auth hash components");
2786 for (i
= 0; i
< num_elem
; i
++)
2787 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2788 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, r_auth
);
2790 wpa_hexdump(MSG_DEBUG
, "DPP: R-auth", r_auth
,
2791 auth
->curve
->hash_len
);
2801 static int dpp_gen_i_auth(struct dpp_authentication
*auth
, u8
*i_auth
)
2803 struct wpabuf
*pix
= NULL
, *prx
= NULL
, *bix
= NULL
, *brx
= NULL
;
2806 size_t i
, num_elem
= 0;
2811 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
2812 nonce_len
= auth
->curve
->nonce_len
;
2814 if (auth
->initiator
) {
2815 pix
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2816 prx
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2818 bix
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2823 brx
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2825 pix
= dpp_get_pubkey_point(auth
->peer_protocol_key
, 0);
2826 prx
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
2828 bix
= dpp_get_pubkey_point(auth
->peer_bi
->pubkey
, 0);
2833 brx
= dpp_get_pubkey_point(auth
->own_bi
->pubkey
, 0);
2835 if (!pix
|| !prx
|| !brx
)
2838 addr
[num_elem
] = auth
->r_nonce
;
2839 len
[num_elem
] = nonce_len
;
2842 addr
[num_elem
] = auth
->i_nonce
;
2843 len
[num_elem
] = nonce_len
;
2846 addr
[num_elem
] = wpabuf_head(prx
);
2847 len
[num_elem
] = wpabuf_len(prx
) / 2;
2850 addr
[num_elem
] = wpabuf_head(pix
);
2851 len
[num_elem
] = wpabuf_len(pix
) / 2;
2854 addr
[num_elem
] = wpabuf_head(brx
);
2855 len
[num_elem
] = wpabuf_len(brx
) / 2;
2859 addr
[num_elem
] = wpabuf_head(bix
);
2860 len
[num_elem
] = wpabuf_len(bix
) / 2;
2864 addr
[num_elem
] = &one
;
2868 wpa_printf(MSG_DEBUG
, "DPP: I-auth hash components");
2869 for (i
= 0; i
< num_elem
; i
++)
2870 wpa_hexdump(MSG_DEBUG
, "DPP: hash component", addr
[i
], len
[i
]);
2871 res
= dpp_hash_vector(auth
->curve
, num_elem
, addr
, len
, i_auth
);
2873 wpa_hexdump(MSG_DEBUG
, "DPP: I-auth", i_auth
,
2874 auth
->curve
->hash_len
);
2884 static int dpp_auth_derive_l_responder(struct dpp_authentication
*auth
)
2886 const EC_GROUP
*group
;
2888 EC_KEY
*BI
= NULL
, *bR
= NULL
, *pR
= NULL
;
2889 const EC_POINT
*BI_point
;
2891 BIGNUM
*lx
, *sum
, *q
;
2892 const BIGNUM
*bR_bn
, *pR_bn
;
2895 /* L = ((bR + pR) modulo q) * BI */
2897 bnctx
= BN_CTX_new();
2901 if (!bnctx
|| !sum
|| !q
|| !lx
)
2903 BI
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2906 BI_point
= EC_KEY_get0_public_key(BI
);
2907 group
= EC_KEY_get0_group(BI
);
2911 bR
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2912 pR
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
2915 bR_bn
= EC_KEY_get0_private_key(bR
);
2916 pR_bn
= EC_KEY_get0_private_key(pR
);
2917 if (!bR_bn
|| !pR_bn
)
2919 if (EC_GROUP_get_order(group
, q
, bnctx
) != 1 ||
2920 BN_mod_add(sum
, bR_bn
, pR_bn
, q
, bnctx
) != 1)
2922 l
= EC_POINT_new(group
);
2924 EC_POINT_mul(group
, l
, NULL
, BI_point
, sum
, bnctx
) != 1 ||
2925 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2927 wpa_printf(MSG_ERROR
,
2928 "OpenSSL: failed: %s",
2929 ERR_error_string(ERR_get_error(), NULL
));
2933 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2935 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2936 auth
->Lx_len
= auth
->secret_len
;
2939 EC_POINT_clear_free(l
);
2951 static int dpp_auth_derive_l_initiator(struct dpp_authentication
*auth
)
2953 const EC_GROUP
*group
;
2954 EC_POINT
*l
= NULL
, *sum
= NULL
;
2955 EC_KEY
*bI
= NULL
, *BR
= NULL
, *PR
= NULL
;
2956 const EC_POINT
*BR_point
, *PR_point
;
2959 const BIGNUM
*bI_bn
;
2962 /* L = bI * (BR + PR) */
2964 bnctx
= BN_CTX_new();
2968 BR
= EVP_PKEY_get1_EC_KEY(auth
->peer_bi
->pubkey
);
2969 PR
= EVP_PKEY_get1_EC_KEY(auth
->peer_protocol_key
);
2972 BR_point
= EC_KEY_get0_public_key(BR
);
2973 PR_point
= EC_KEY_get0_public_key(PR
);
2975 bI
= EVP_PKEY_get1_EC_KEY(auth
->own_bi
->pubkey
);
2978 group
= EC_KEY_get0_group(bI
);
2979 bI_bn
= EC_KEY_get0_private_key(bI
);
2980 if (!group
|| !bI_bn
)
2982 sum
= EC_POINT_new(group
);
2983 l
= EC_POINT_new(group
);
2985 EC_POINT_add(group
, sum
, BR_point
, PR_point
, bnctx
) != 1 ||
2986 EC_POINT_mul(group
, l
, NULL
, sum
, bI_bn
, bnctx
) != 1 ||
2987 EC_POINT_get_affine_coordinates_GFp(group
, l
, lx
, NULL
,
2989 wpa_printf(MSG_ERROR
,
2990 "OpenSSL: failed: %s",
2991 ERR_error_string(ERR_get_error(), NULL
));
2995 if (dpp_bn2bin_pad(lx
, auth
->Lx
, auth
->secret_len
) < 0)
2997 wpa_hexdump_key(MSG_DEBUG
, "DPP: L.x", auth
->Lx
, auth
->secret_len
);
2998 auth
->Lx_len
= auth
->secret_len
;
3001 EC_POINT_clear_free(l
);
3002 EC_POINT_clear_free(sum
);
3012 static int dpp_auth_build_resp_ok(struct dpp_authentication
*auth
)
3016 struct wpabuf
*msg
, *pr
= NULL
;
3017 u8 r_auth
[4 + DPP_MAX_HASH_LEN
];
3018 u8 wrapped_r_auth
[4 + DPP_MAX_HASH_LEN
+ AES_BLOCK_SIZE
], *w_r_auth
;
3019 size_t wrapped_r_auth_len
;
3021 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *r_nonce
, *i_nonce
;
3022 enum dpp_status_error status
= DPP_STATUS_OK
;
3023 #ifdef CONFIG_TESTING_OPTIONS
3024 u8 test_hash
[SHA256_MAC_LEN
];
3025 #endif /* CONFIG_TESTING_OPTIONS */
3027 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3031 #ifdef CONFIG_TESTING_OPTIONS
3032 if (dpp_nonce_override_len
> 0) {
3033 wpa_printf(MSG_INFO
, "DPP: TESTING - override R-nonce");
3034 nonce_len
= dpp_nonce_override_len
;
3035 os_memcpy(auth
->r_nonce
, dpp_nonce_override
, nonce_len
);
3037 nonce_len
= auth
->curve
->nonce_len
;
3038 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3039 wpa_printf(MSG_ERROR
,
3040 "DPP: Failed to generate R-nonce");
3044 #else /* CONFIG_TESTING_OPTIONS */
3045 nonce_len
= auth
->curve
->nonce_len
;
3046 if (random_get_bytes(auth
->r_nonce
, nonce_len
)) {
3047 wpa_printf(MSG_ERROR
, "DPP: Failed to generate R-nonce");
3050 #endif /* CONFIG_TESTING_OPTIONS */
3051 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", auth
->r_nonce
, nonce_len
);
3053 EVP_PKEY_free(auth
->own_protocol_key
);
3054 #ifdef CONFIG_TESTING_OPTIONS
3055 if (dpp_protocol_key_override_len
) {
3056 const struct dpp_curve_params
*tmp_curve
;
3058 wpa_printf(MSG_INFO
,
3059 "DPP: TESTING - override protocol key");
3060 auth
->own_protocol_key
= dpp_set_keypair(
3061 &tmp_curve
, dpp_protocol_key_override
,
3062 dpp_protocol_key_override_len
);
3064 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3066 #else /* CONFIG_TESTING_OPTIONS */
3067 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
3068 #endif /* CONFIG_TESTING_OPTIONS */
3069 if (!auth
->own_protocol_key
)
3072 pr
= dpp_get_pubkey_point(auth
->own_protocol_key
, 0);
3076 /* ECDH: N = pR * PI */
3077 if (dpp_ecdh(auth
->own_protocol_key
, auth
->peer_protocol_key
,
3078 auth
->Nx
, &secret_len
) < 0)
3081 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3082 auth
->Nx
, auth
->secret_len
);
3083 auth
->Nx_len
= auth
->secret_len
;
3085 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3086 auth
->curve
->hash_len
) < 0)
3089 if (auth
->own_bi
&& auth
->peer_bi
) {
3090 /* Mutual authentication */
3091 if (dpp_auth_derive_l_responder(auth
) < 0)
3095 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
3098 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
3099 WPA_PUT_LE16(r_auth
, DPP_ATTR_R_AUTH_TAG
);
3100 WPA_PUT_LE16(&r_auth
[2], auth
->curve
->hash_len
);
3101 if (dpp_gen_r_auth(auth
, r_auth
+ 4) < 0)
3103 #ifdef CONFIG_TESTING_OPTIONS
3104 if (dpp_test
== DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP
) {
3105 wpa_printf(MSG_INFO
, "DPP: TESTING - R-auth mismatch");
3106 r_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3108 #endif /* CONFIG_TESTING_OPTIONS */
3109 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3110 r_auth
, 4 + auth
->curve
->hash_len
,
3111 0, NULL
, NULL
, wrapped_r_auth
) < 0)
3113 wrapped_r_auth_len
= 4 + auth
->curve
->hash_len
+ AES_BLOCK_SIZE
;
3114 wpa_hexdump(MSG_DEBUG
, "DPP: {R-auth}ke",
3115 wrapped_r_auth
, wrapped_r_auth_len
);
3116 w_r_auth
= wrapped_r_auth
;
3118 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3120 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3122 i_pubkey_hash
= NULL
;
3124 i_nonce
= auth
->i_nonce
;
3125 r_nonce
= auth
->r_nonce
;
3127 #ifdef CONFIG_TESTING_OPTIONS
3128 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3129 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3130 r_pubkey_hash
= NULL
;
3131 } else if (dpp_test
==
3132 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3133 wpa_printf(MSG_INFO
,
3134 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3135 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3136 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3137 r_pubkey_hash
= test_hash
;
3138 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3139 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3140 i_pubkey_hash
= NULL
;
3141 } else if (dpp_test
==
3142 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3143 wpa_printf(MSG_INFO
,
3144 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3146 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3148 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3149 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3150 i_pubkey_hash
= test_hash
;
3151 } else if (dpp_test
== DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP
) {
3152 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Proto Key");
3155 } else if (dpp_test
== DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP
) {
3156 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid R-Proto Key");
3158 pr
= wpabuf_alloc(2 * auth
->curve
->prime_len
);
3159 if (!pr
|| dpp_test_gen_invalid_key(pr
, auth
->curve
) < 0)
3161 } else if (dpp_test
== DPP_TEST_NO_R_AUTH_AUTH_RESP
) {
3162 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth");
3164 wrapped_r_auth_len
= 0;
3165 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3166 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3168 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_RESP
) {
3169 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3171 } else if (dpp_test
== DPP_TEST_NO_R_NONCE_AUTH_RESP
) {
3172 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-nonce");
3174 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3175 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3178 #endif /* CONFIG_TESTING_OPTIONS */
3180 msg
= dpp_auth_build_resp(auth
, status
, pr
, nonce_len
,
3181 r_pubkey_hash
, i_pubkey_hash
,
3183 w_r_auth
, wrapped_r_auth_len
,
3187 wpabuf_free(auth
->resp_msg
);
3188 auth
->resp_msg
= msg
;
3196 static int dpp_auth_build_resp_status(struct dpp_authentication
*auth
,
3197 enum dpp_status_error status
)
3200 const u8
*r_pubkey_hash
, *i_pubkey_hash
, *i_nonce
;
3201 #ifdef CONFIG_TESTING_OPTIONS
3202 u8 test_hash
[SHA256_MAC_LEN
];
3203 #endif /* CONFIG_TESTING_OPTIONS */
3207 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Response");
3209 r_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3211 i_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3213 i_pubkey_hash
= NULL
;
3215 i_nonce
= auth
->i_nonce
;
3217 #ifdef CONFIG_TESTING_OPTIONS
3218 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3219 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3220 r_pubkey_hash
= NULL
;
3221 } else if (dpp_test
==
3222 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3223 wpa_printf(MSG_INFO
,
3224 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3225 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3226 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3227 r_pubkey_hash
= test_hash
;
3228 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3229 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3230 i_pubkey_hash
= NULL
;
3231 } else if (dpp_test
==
3232 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP
) {
3233 wpa_printf(MSG_INFO
,
3234 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3236 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3238 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3239 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3240 i_pubkey_hash
= test_hash
;
3241 } else if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_RESP
) {
3242 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3244 } else if (dpp_test
== DPP_TEST_NO_I_NONCE_AUTH_RESP
) {
3245 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-nonce");
3248 #endif /* CONFIG_TESTING_OPTIONS */
3250 msg
= dpp_auth_build_resp(auth
, status
, NULL
, auth
->curve
->nonce_len
,
3251 r_pubkey_hash
, i_pubkey_hash
,
3252 NULL
, i_nonce
, NULL
, 0, auth
->k1
);
3255 wpabuf_free(auth
->resp_msg
);
3256 auth
->resp_msg
= msg
;
3261 struct dpp_authentication
*
3262 dpp_auth_req_rx(void *msg_ctx
, u8 dpp_allowed_roles
, int qr_mutual
,
3263 struct dpp_bootstrap_info
*peer_bi
,
3264 struct dpp_bootstrap_info
*own_bi
,
3265 unsigned int freq
, const u8
*hdr
, const u8
*attr_start
,
3268 EVP_PKEY
*pi
= NULL
;
3269 EVP_PKEY_CTX
*ctx
= NULL
;
3273 u8
*unwrapped
= NULL
;
3274 size_t unwrapped_len
= 0;
3275 const u8
*wrapped_data
, *i_proto
, *i_nonce
, *i_capab
, *i_bootstrap
,
3277 u16 wrapped_data_len
, i_proto_len
, i_nonce_len
, i_capab_len
,
3278 i_bootstrap_len
, channel_len
;
3279 struct dpp_authentication
*auth
= NULL
;
3283 #endif /* CONFIG_DPP2 */
3285 #ifdef CONFIG_TESTING_OPTIONS
3286 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_REQ
) {
3287 wpa_printf(MSG_INFO
,
3288 "DPP: TESTING - stop at Authentication Request");
3291 #endif /* CONFIG_TESTING_OPTIONS */
3293 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3295 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3296 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
3297 "Missing or invalid required Wrapped Data attribute");
3300 wpa_hexdump(MSG_MSGDUMP
, "DPP: Wrapped Data",
3301 wrapped_data
, wrapped_data_len
);
3302 attr_len
= wrapped_data
- 4 - attr_start
;
3304 auth
= dpp_alloc_auth(msg_ctx
);
3307 auth
->peer_bi
= peer_bi
;
3308 auth
->own_bi
= own_bi
;
3309 auth
->curve
= own_bi
->curve
;
3310 auth
->curr_freq
= freq
;
3312 auth
->peer_version
= 1; /* default to the first version */
3314 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3317 if (version_len
< 1 || version
[0] == 0) {
3319 "Invalid Protocol Version attribute");
3322 auth
->peer_version
= version
[0];
3323 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3324 auth
->peer_version
);
3326 #endif /* CONFIG_DPP2 */
3328 channel
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_CHANNEL
,
3333 if (channel_len
< 2) {
3334 dpp_auth_fail(auth
, "Too short Channel attribute");
3338 neg_freq
= ieee80211_chan_to_freq(NULL
, channel
[0], channel
[1]);
3339 wpa_printf(MSG_DEBUG
,
3340 "DPP: Initiator requested different channel for negotiation: op_class=%u channel=%u --> freq=%d",
3341 channel
[0], channel
[1], neg_freq
);
3344 "Unsupported Channel attribute value");
3348 if (auth
->curr_freq
!= (unsigned int) neg_freq
) {
3349 wpa_printf(MSG_DEBUG
,
3350 "DPP: Changing negotiation channel from %u MHz to %u MHz",
3352 auth
->curr_freq
= neg_freq
;
3356 i_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_I_PROTOCOL_KEY
,
3360 "Missing required Initiator Protocol Key attribute");
3363 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Protocol Key",
3364 i_proto
, i_proto_len
);
3367 pi
= dpp_set_pubkey_point(own_bi
->pubkey
, i_proto
, i_proto_len
);
3369 dpp_auth_fail(auth
, "Invalid Initiator Protocol Key");
3372 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi
);
3374 if (dpp_ecdh(own_bi
->pubkey
, pi
, auth
->Mx
, &secret_len
) < 0)
3376 auth
->secret_len
= secret_len
;
3378 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (M.x)",
3379 auth
->Mx
, auth
->secret_len
);
3380 auth
->Mx_len
= auth
->secret_len
;
3382 if (dpp_derive_k1(auth
->Mx
, auth
->secret_len
, auth
->k1
,
3383 auth
->curve
->hash_len
) < 0)
3387 len
[0] = DPP_HDR_LEN
;
3388 addr
[1] = attr_start
;
3390 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3391 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3392 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3393 wrapped_data
, wrapped_data_len
);
3394 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3395 unwrapped
= os_malloc(unwrapped_len
);
3398 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3399 wrapped_data
, wrapped_data_len
,
3400 2, addr
, len
, unwrapped
) < 0) {
3401 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3404 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3405 unwrapped
, unwrapped_len
);
3407 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3408 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3412 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3414 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3415 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3418 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3419 os_memcpy(auth
->i_nonce
, i_nonce
, i_nonce_len
);
3421 i_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3422 DPP_ATTR_I_CAPABILITIES
,
3424 if (!i_capab
|| i_capab_len
< 1) {
3425 dpp_auth_fail(auth
, "Missing or invalid I-capabilities");
3428 auth
->i_capab
= i_capab
[0];
3429 wpa_printf(MSG_DEBUG
, "DPP: I-capabilities: 0x%02x", auth
->i_capab
);
3431 bin_clear_free(unwrapped
, unwrapped_len
);
3434 switch (auth
->i_capab
& DPP_CAPAB_ROLE_MASK
) {
3435 case DPP_CAPAB_ENROLLEE
:
3436 if (!(dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)) {
3437 wpa_printf(MSG_DEBUG
,
3438 "DPP: Local policy does not allow Configurator role");
3439 goto not_compatible
;
3441 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3442 auth
->configurator
= 1;
3444 case DPP_CAPAB_CONFIGURATOR
:
3445 if (!(dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
)) {
3446 wpa_printf(MSG_DEBUG
,
3447 "DPP: Local policy does not allow Enrollee role");
3448 goto not_compatible
;
3450 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3451 auth
->configurator
= 0;
3453 case DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
:
3454 if (dpp_allowed_roles
& DPP_CAPAB_ENROLLEE
) {
3455 wpa_printf(MSG_DEBUG
, "DPP: Acting as Enrollee");
3456 auth
->configurator
= 0;
3457 } else if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
) {
3458 wpa_printf(MSG_DEBUG
, "DPP: Acting as Configurator");
3459 auth
->configurator
= 1;
3461 wpa_printf(MSG_DEBUG
,
3462 "DPP: Local policy does not allow Configurator/Enrollee role");
3463 goto not_compatible
;
3467 wpa_printf(MSG_DEBUG
, "DPP: Unexpected role in I-capabilities");
3468 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3469 DPP_EVENT_FAIL
"Invalid role in I-capabilities 0x%02x",
3470 auth
->i_capab
& DPP_CAPAB_ROLE_MASK
);
3474 auth
->peer_protocol_key
= pi
;
3476 if (qr_mutual
&& !peer_bi
&& own_bi
->type
== DPP_BOOTSTRAP_QR_CODE
) {
3477 char hex
[SHA256_MAC_LEN
* 2 + 1];
3479 wpa_printf(MSG_DEBUG
,
3480 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time");
3481 if (dpp_auth_build_resp_status(auth
,
3482 DPP_STATUS_RESPONSE_PENDING
) < 0)
3484 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3485 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3487 if (i_bootstrap
&& i_bootstrap_len
== SHA256_MAC_LEN
) {
3488 auth
->response_pending
= 1;
3489 os_memcpy(auth
->waiting_pubkey_hash
,
3490 i_bootstrap
, i_bootstrap_len
);
3491 wpa_snprintf_hex(hex
, sizeof(hex
), i_bootstrap
,
3497 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_SCAN_PEER_QR_CODE
3501 if (dpp_auth_build_resp_ok(auth
) < 0)
3507 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3508 "i-capab=0x%02x", auth
->i_capab
);
3509 if (dpp_allowed_roles
& DPP_CAPAB_CONFIGURATOR
)
3510 auth
->configurator
= 1;
3512 auth
->configurator
= 0;
3513 auth
->peer_protocol_key
= pi
;
3515 if (dpp_auth_build_resp_status(auth
, DPP_STATUS_NOT_COMPATIBLE
) < 0)
3518 auth
->remove_on_tx_status
= 1;
3521 bin_clear_free(unwrapped
, unwrapped_len
);
3523 EVP_PKEY_CTX_free(ctx
);
3524 dpp_auth_deinit(auth
);
3529 int dpp_notify_new_qr_code(struct dpp_authentication
*auth
,
3530 struct dpp_bootstrap_info
*peer_bi
)
3532 if (!auth
|| !auth
->response_pending
||
3533 os_memcmp(auth
->waiting_pubkey_hash
, peer_bi
->pubkey_hash
,
3534 SHA256_MAC_LEN
) != 0)
3537 wpa_printf(MSG_DEBUG
,
3538 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with "
3539 MACSTR
, MAC2STR(auth
->peer_mac_addr
));
3540 auth
->peer_bi
= peer_bi
;
3542 if (dpp_auth_build_resp_ok(auth
) < 0)
3549 static struct wpabuf
* dpp_auth_build_conf(struct dpp_authentication
*auth
,
3550 enum dpp_status_error status
)
3553 u8 i_auth
[4 + DPP_MAX_HASH_LEN
];
3555 u8 r_nonce
[4 + DPP_MAX_NONCE_LEN
];
3558 size_t len
[2], attr_len
;
3560 u8
*wrapped_r_nonce
;
3561 u8
*attr_start
, *attr_end
;
3562 const u8
*r_pubkey_hash
, *i_pubkey_hash
;
3563 #ifdef CONFIG_TESTING_OPTIONS
3564 u8 test_hash
[SHA256_MAC_LEN
];
3565 #endif /* CONFIG_TESTING_OPTIONS */
3567 wpa_printf(MSG_DEBUG
, "DPP: Build Authentication Confirmation");
3569 i_auth_len
= 4 + auth
->curve
->hash_len
;
3570 r_nonce_len
= 4 + auth
->curve
->nonce_len
;
3571 /* Build DPP Authentication Confirmation frame attributes */
3572 attr_len
= 4 + 1 + 2 * (4 + SHA256_MAC_LEN
) +
3573 4 + i_auth_len
+ r_nonce_len
+ AES_BLOCK_SIZE
;
3574 #ifdef CONFIG_TESTING_OPTIONS
3575 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
)
3577 #endif /* CONFIG_TESTING_OPTIONS */
3578 msg
= dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF
, attr_len
);
3582 attr_start
= wpabuf_put(msg
, 0);
3584 r_pubkey_hash
= auth
->peer_bi
->pubkey_hash
;
3586 i_pubkey_hash
= auth
->own_bi
->pubkey_hash
;
3588 i_pubkey_hash
= NULL
;
3590 #ifdef CONFIG_TESTING_OPTIONS
3591 if (dpp_test
== DPP_TEST_NO_STATUS_AUTH_CONF
) {
3592 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
3594 } else if (dpp_test
== DPP_TEST_INVALID_STATUS_AUTH_CONF
) {
3595 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
3598 #endif /* CONFIG_TESTING_OPTIONS */
3601 dpp_build_attr_status(msg
, status
);
3603 #ifdef CONFIG_TESTING_OPTIONS
3605 if (dpp_test
== DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3606 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Bootstrap Key Hash");
3607 r_pubkey_hash
= NULL
;
3608 } else if (dpp_test
==
3609 DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3610 wpa_printf(MSG_INFO
,
3611 "DPP: TESTING - invalid R-Bootstrap Key Hash");
3612 os_memcpy(test_hash
, r_pubkey_hash
, SHA256_MAC_LEN
);
3613 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3614 r_pubkey_hash
= test_hash
;
3615 } else if (dpp_test
== DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3616 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Bootstrap Key Hash");
3617 i_pubkey_hash
= NULL
;
3618 } else if (dpp_test
==
3619 DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF
) {
3620 wpa_printf(MSG_INFO
,
3621 "DPP: TESTING - invalid I-Bootstrap Key Hash");
3623 os_memcpy(test_hash
, i_pubkey_hash
, SHA256_MAC_LEN
);
3625 os_memset(test_hash
, 0, SHA256_MAC_LEN
);
3626 test_hash
[SHA256_MAC_LEN
- 1] ^= 0x01;
3627 i_pubkey_hash
= test_hash
;
3629 #endif /* CONFIG_TESTING_OPTIONS */
3631 /* Responder Bootstrapping Key Hash */
3632 dpp_build_attr_r_bootstrap_key_hash(msg
, r_pubkey_hash
);
3634 /* Initiator Bootstrapping Key Hash (mutual authentication) */
3635 dpp_build_attr_i_bootstrap_key_hash(msg
, i_pubkey_hash
);
3637 #ifdef CONFIG_TESTING_OPTIONS
3638 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF
)
3639 goto skip_wrapped_data
;
3640 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3642 #endif /* CONFIG_TESTING_OPTIONS */
3644 attr_end
= wpabuf_put(msg
, 0);
3646 /* OUI, OUI type, Crypto Suite, DPP frame type */
3647 addr
[0] = wpabuf_head_u8(msg
) + 2;
3648 len
[0] = 3 + 1 + 1 + 1;
3649 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3651 /* Attributes before Wrapped Data */
3652 addr
[1] = attr_start
;
3653 len
[1] = attr_end
- attr_start
;
3654 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3656 if (status
== DPP_STATUS_OK
) {
3657 /* I-auth wrapped with ke */
3658 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3659 wpabuf_put_le16(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3660 wrapped_i_auth
= wpabuf_put(msg
, i_auth_len
+ AES_BLOCK_SIZE
);
3662 #ifdef CONFIG_TESTING_OPTIONS
3663 if (dpp_test
== DPP_TEST_NO_I_AUTH_AUTH_CONF
)
3665 #endif /* CONFIG_TESTING_OPTIONS */
3667 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |]
3669 WPA_PUT_LE16(i_auth
, DPP_ATTR_I_AUTH_TAG
);
3670 WPA_PUT_LE16(&i_auth
[2], auth
->curve
->hash_len
);
3671 if (dpp_gen_i_auth(auth
, i_auth
+ 4) < 0)
3674 #ifdef CONFIG_TESTING_OPTIONS
3675 if (dpp_test
== DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF
) {
3676 wpa_printf(MSG_INFO
, "DPP: TESTING - I-auth mismatch");
3677 i_auth
[4 + auth
->curve
->hash_len
/ 2] ^= 0x01;
3680 #endif /* CONFIG_TESTING_OPTIONS */
3681 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
3683 2, addr
, len
, wrapped_i_auth
) < 0)
3685 wpa_hexdump(MSG_DEBUG
, "DPP: {I-auth}ke",
3686 wrapped_i_auth
, i_auth_len
+ AES_BLOCK_SIZE
);
3688 /* R-nonce wrapped with k2 */
3689 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
3690 wpabuf_put_le16(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3691 wrapped_r_nonce
= wpabuf_put(msg
, r_nonce_len
+ AES_BLOCK_SIZE
);
3693 WPA_PUT_LE16(r_nonce
, DPP_ATTR_R_NONCE
);
3694 WPA_PUT_LE16(&r_nonce
[2], auth
->curve
->nonce_len
);
3695 os_memcpy(r_nonce
+ 4, auth
->r_nonce
, auth
->curve
->nonce_len
);
3697 if (aes_siv_encrypt(auth
->k2
, auth
->curve
->hash_len
,
3698 r_nonce
, r_nonce_len
,
3699 2, addr
, len
, wrapped_r_nonce
) < 0)
3701 wpa_hexdump(MSG_DEBUG
, "DPP: {R-nonce}k2",
3702 wrapped_r_nonce
, r_nonce_len
+ AES_BLOCK_SIZE
);
3705 #ifdef CONFIG_TESTING_OPTIONS
3706 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF
) {
3707 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
3708 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
3711 #endif /* CONFIG_TESTING_OPTIONS */
3713 wpa_hexdump_buf(MSG_DEBUG
,
3714 "DPP: Authentication Confirmation frame attributes",
3716 if (status
== DPP_STATUS_OK
)
3717 dpp_auth_success(auth
);
3728 dpp_auth_resp_rx_status(struct dpp_authentication
*auth
, const u8
*hdr
,
3729 const u8
*attr_start
, size_t attr_len
,
3730 const u8
*wrapped_data
, u16 wrapped_data_len
,
3731 enum dpp_status_error status
)
3735 u8
*unwrapped
= NULL
;
3736 size_t unwrapped_len
= 0;
3737 const u8
*i_nonce
, *r_capab
;
3738 u16 i_nonce_len
, r_capab_len
;
3740 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3741 wpa_printf(MSG_DEBUG
,
3742 "DPP: Responder reported incompatible roles");
3743 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3744 wpa_printf(MSG_DEBUG
,
3745 "DPP: Responder reported more time needed");
3747 wpa_printf(MSG_DEBUG
,
3748 "DPP: Responder reported failure (status %d)",
3750 dpp_auth_fail(auth
, "Responder reported failure");
3755 len
[0] = DPP_HDR_LEN
;
3756 addr
[1] = attr_start
;
3758 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
3759 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
3760 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
3761 wrapped_data
, wrapped_data_len
);
3762 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
3763 unwrapped
= os_malloc(unwrapped_len
);
3766 if (aes_siv_decrypt(auth
->k1
, auth
->curve
->hash_len
,
3767 wrapped_data
, wrapped_data_len
,
3768 2, addr
, len
, unwrapped
) < 0) {
3769 dpp_auth_fail(auth
, "AES-SIV decryption failed");
3772 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
3773 unwrapped
, unwrapped_len
);
3775 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
3776 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
3780 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
3782 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
3783 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
3786 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
3787 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
3788 dpp_auth_fail(auth
, "I-nonce mismatch");
3792 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
3793 DPP_ATTR_R_CAPABILITIES
,
3795 if (!r_capab
|| r_capab_len
< 1) {
3796 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
3799 auth
->r_capab
= r_capab
[0];
3800 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
3801 if (status
== DPP_STATUS_NOT_COMPATIBLE
) {
3802 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_NOT_COMPATIBLE
3803 "r-capab=0x%02x", auth
->r_capab
);
3804 } else if (status
== DPP_STATUS_RESPONSE_PENDING
) {
3805 u8 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
3807 if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
3808 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
3809 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3810 DPP_EVENT_FAIL
"Unexpected role in R-capabilities 0x%02x",
3813 wpa_printf(MSG_DEBUG
,
3814 "DPP: Continue waiting for full DPP Authentication Response");
3815 wpa_msg(auth
->msg_ctx
, MSG_INFO
,
3816 DPP_EVENT_RESPONSE_PENDING
"%s",
3817 auth
->tmp_own_bi
? auth
->tmp_own_bi
->uri
: "");
3821 bin_clear_free(unwrapped
, unwrapped_len
);
3826 dpp_auth_resp_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
3827 const u8
*attr_start
, size_t attr_len
)
3833 u8
*unwrapped
= NULL
, *unwrapped2
= NULL
;
3834 size_t unwrapped_len
= 0, unwrapped2_len
= 0;
3835 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *r_proto
,
3836 *r_nonce
, *i_nonce
, *r_capab
, *wrapped2
, *r_auth
;
3837 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
3838 r_proto_len
, r_nonce_len
, i_nonce_len
, r_capab_len
,
3839 wrapped2_len
, r_auth_len
;
3840 u8 r_auth2
[DPP_MAX_HASH_LEN
];
3845 #endif /* CONFIG_DPP2 */
3847 #ifdef CONFIG_TESTING_OPTIONS
3848 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_RESP
) {
3849 wpa_printf(MSG_INFO
,
3850 "DPP: TESTING - stop at Authentication Response");
3853 #endif /* CONFIG_TESTING_OPTIONS */
3855 if (!auth
->initiator
|| !auth
->peer_bi
) {
3856 dpp_auth_fail(auth
, "Unexpected Authentication Response");
3860 auth
->waiting_auth_resp
= 0;
3862 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
3864 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
3866 "Missing or invalid required Wrapped Data attribute");
3869 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
3870 wrapped_data
, wrapped_data_len
);
3872 attr_len
= wrapped_data
- 4 - attr_start
;
3874 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3875 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
3877 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
3879 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
3882 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
3883 r_bootstrap
, r_bootstrap_len
);
3884 if (os_memcmp(r_bootstrap
, auth
->peer_bi
->pubkey_hash
,
3885 SHA256_MAC_LEN
) != 0) {
3887 "Unexpected Responder Bootstrapping Key Hash value");
3888 wpa_hexdump(MSG_DEBUG
,
3889 "DPP: Expected Responder Bootstrapping Key Hash",
3890 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
3894 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
3895 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
3898 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
3900 "Invalid Initiator Bootstrapping Key Hash attribute");
3903 wpa_hexdump(MSG_MSGDUMP
,
3904 "DPP: Initiator Bootstrapping Key Hash",
3905 i_bootstrap
, i_bootstrap_len
);
3906 if (!auth
->own_bi
||
3907 os_memcmp(i_bootstrap
, auth
->own_bi
->pubkey_hash
,
3908 SHA256_MAC_LEN
) != 0) {
3910 "Initiator Bootstrapping Key Hash attribute did not match");
3913 } else if (auth
->own_bi
&& auth
->own_bi
->type
== DPP_BOOTSTRAP_PKEX
) {
3914 /* PKEX bootstrapping mandates use of mutual authentication */
3916 "Missing Initiator Bootstrapping Key Hash attribute");
3920 auth
->peer_version
= 1; /* default to the first version */
3922 version
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_PROTOCOL_VERSION
,
3925 if (version_len
< 1 || version
[0] == 0) {
3927 "Invalid Protocol Version attribute");
3930 auth
->peer_version
= version
[0];
3931 wpa_printf(MSG_DEBUG
, "DPP: Peer protocol version %u",
3932 auth
->peer_version
);
3934 #endif /* CONFIG_DPP2 */
3936 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
3938 if (!status
|| status_len
< 1) {
3940 "Missing or invalid required DPP Status attribute");
3943 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
3944 auth
->auth_resp_status
= status
[0];
3945 if (status
[0] != DPP_STATUS_OK
) {
3946 dpp_auth_resp_rx_status(auth
, hdr
, attr_start
,
3947 attr_len
, wrapped_data
,
3948 wrapped_data_len
, status
[0]);
3952 if (!i_bootstrap
&& auth
->own_bi
) {
3953 wpa_printf(MSG_DEBUG
,
3954 "DPP: Responder decided not to use mutual authentication");
3955 auth
->own_bi
= NULL
;
3958 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_AUTH_DIRECTION
"mutual=%d",
3959 auth
->own_bi
!= NULL
);
3961 r_proto
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_R_PROTOCOL_KEY
,
3965 "Missing required Responder Protocol Key attribute");
3968 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Protocol Key",
3969 r_proto
, r_proto_len
);
3972 pr
= dpp_set_pubkey_point(auth
->own_protocol_key
, r_proto
, r_proto_len
);
3974 dpp_auth_fail(auth
, "Invalid Responder Protocol Key");
3977 dpp_debug_print_key("Peer (Responder) Protocol Key", pr
);
3979 if (dpp_ecdh(auth
->own_protocol_key
, pr
, auth
->Nx
, &secret_len
) < 0) {
3980 dpp_auth_fail(auth
, "Failed to derive ECDH shared secret");
3983 EVP_PKEY_free(auth
->peer_protocol_key
);
3984 auth
->peer_protocol_key
= pr
;
3987 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
3988 auth
->Nx
, auth
->secret_len
);
3989 auth
->Nx_len
= auth
->secret_len
;
3991 if (dpp_derive_k2(auth
->Nx
, auth
->secret_len
, auth
->k2
,
3992 auth
->curve
->hash_len
) < 0)
3996 len
[0] = DPP_HDR_LEN
;
3997 addr
[1] = attr_start
;
3999 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4000 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4001 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4002 wrapped_data
, wrapped_data_len
);
4003 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4004 unwrapped
= os_malloc(unwrapped_len
);
4007 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4008 wrapped_data
, wrapped_data_len
,
4009 2, addr
, len
, unwrapped
) < 0) {
4010 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4013 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4014 unwrapped
, unwrapped_len
);
4016 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4017 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4021 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4023 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4024 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4027 wpa_hexdump(MSG_DEBUG
, "DPP: R-nonce", r_nonce
, r_nonce_len
);
4028 os_memcpy(auth
->r_nonce
, r_nonce
, r_nonce_len
);
4030 i_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_NONCE
,
4032 if (!i_nonce
|| i_nonce_len
!= auth
->curve
->nonce_len
) {
4033 dpp_auth_fail(auth
, "Missing or invalid I-nonce");
4036 wpa_hexdump(MSG_DEBUG
, "DPP: I-nonce", i_nonce
, i_nonce_len
);
4037 if (os_memcmp(auth
->i_nonce
, i_nonce
, i_nonce_len
) != 0) {
4038 dpp_auth_fail(auth
, "I-nonce mismatch");
4043 /* Mutual authentication */
4044 if (dpp_auth_derive_l_initiator(auth
) < 0)
4048 r_capab
= dpp_get_attr(unwrapped
, unwrapped_len
,
4049 DPP_ATTR_R_CAPABILITIES
,
4051 if (!r_capab
|| r_capab_len
< 1) {
4052 dpp_auth_fail(auth
, "Missing or invalid R-capabilities");
4055 auth
->r_capab
= r_capab
[0];
4056 wpa_printf(MSG_DEBUG
, "DPP: R-capabilities: 0x%02x", auth
->r_capab
);
4057 role
= auth
->r_capab
& DPP_CAPAB_ROLE_MASK
;
4058 if ((auth
->allowed_roles
==
4059 (DPP_CAPAB_CONFIGURATOR
| DPP_CAPAB_ENROLLEE
)) &&
4060 (role
== DPP_CAPAB_CONFIGURATOR
|| role
== DPP_CAPAB_ENROLLEE
)) {
4061 /* Peer selected its role, so move from "either role" to the
4062 * role that is compatible with peer's selection. */
4063 auth
->configurator
= role
== DPP_CAPAB_ENROLLEE
;
4064 wpa_printf(MSG_DEBUG
, "DPP: Acting as %s",
4065 auth
->configurator
? "Configurator" : "Enrollee");
4066 } else if ((auth
->configurator
&& role
!= DPP_CAPAB_ENROLLEE
) ||
4067 (!auth
->configurator
&& role
!= DPP_CAPAB_CONFIGURATOR
)) {
4068 wpa_printf(MSG_DEBUG
, "DPP: Incompatible role selection");
4069 wpa_msg(auth
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
4070 "Unexpected role in R-capabilities 0x%02x",
4072 if (role
!= DPP_CAPAB_ENROLLEE
&&
4073 role
!= DPP_CAPAB_CONFIGURATOR
)
4075 bin_clear_free(unwrapped
, unwrapped_len
);
4076 auth
->remove_on_tx_status
= 1;
4077 return dpp_auth_build_conf(auth
, DPP_STATUS_NOT_COMPATIBLE
);
4080 wrapped2
= dpp_get_attr(unwrapped
, unwrapped_len
,
4081 DPP_ATTR_WRAPPED_DATA
, &wrapped2_len
);
4082 if (!wrapped2
|| wrapped2_len
< AES_BLOCK_SIZE
) {
4084 "Missing or invalid Secondary Wrapped Data");
4088 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4089 wrapped2
, wrapped2_len
);
4091 if (dpp_derive_ke(auth
, auth
->ke
, auth
->curve
->hash_len
) < 0)
4094 unwrapped2_len
= wrapped2_len
- AES_BLOCK_SIZE
;
4095 unwrapped2
= os_malloc(unwrapped2_len
);
4098 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4099 wrapped2
, wrapped2_len
,
4100 0, NULL
, NULL
, unwrapped2
) < 0) {
4101 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4104 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4105 unwrapped2
, unwrapped2_len
);
4107 if (dpp_check_attrs(unwrapped2
, unwrapped2_len
) < 0) {
4109 "Invalid attribute in secondary unwrapped data");
4113 r_auth
= dpp_get_attr(unwrapped2
, unwrapped2_len
, DPP_ATTR_R_AUTH_TAG
,
4115 if (!r_auth
|| r_auth_len
!= auth
->curve
->hash_len
) {
4117 "Missing or invalid Responder Authenticating Tag");
4120 wpa_hexdump(MSG_DEBUG
, "DPP: Received Responder Authenticating Tag",
4121 r_auth
, r_auth_len
);
4122 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */
4123 if (dpp_gen_r_auth(auth
, r_auth2
) < 0)
4125 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Responder Authenticating Tag",
4126 r_auth2
, r_auth_len
);
4127 if (os_memcmp(r_auth
, r_auth2
, r_auth_len
) != 0) {
4128 dpp_auth_fail(auth
, "Mismatching Responder Authenticating Tag");
4129 bin_clear_free(unwrapped
, unwrapped_len
);
4130 bin_clear_free(unwrapped2
, unwrapped2_len
);
4131 auth
->remove_on_tx_status
= 1;
4132 return dpp_auth_build_conf(auth
, DPP_STATUS_AUTH_FAILURE
);
4135 bin_clear_free(unwrapped
, unwrapped_len
);
4136 bin_clear_free(unwrapped2
, unwrapped2_len
);
4138 #ifdef CONFIG_TESTING_OPTIONS
4139 if (dpp_test
== DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF
) {
4140 wpa_printf(MSG_INFO
,
4141 "DPP: TESTING - Authentication Response in place of Confirm");
4142 if (dpp_auth_build_resp_ok(auth
) < 0)
4144 return wpabuf_dup(auth
->resp_msg
);
4146 #endif /* CONFIG_TESTING_OPTIONS */
4148 return dpp_auth_build_conf(auth
, DPP_STATUS_OK
);
4151 bin_clear_free(unwrapped
, unwrapped_len
);
4152 bin_clear_free(unwrapped2
, unwrapped2_len
);
4158 static int dpp_auth_conf_rx_failure(struct dpp_authentication
*auth
,
4160 const u8
*attr_start
, size_t attr_len
,
4161 const u8
*wrapped_data
,
4162 u16 wrapped_data_len
,
4163 enum dpp_status_error status
)
4167 u8
*unwrapped
= NULL
;
4168 size_t unwrapped_len
= 0;
4172 /* Authentication Confirm failure cases are expected to include
4173 * {R-nonce}k2 in the Wrapped Data attribute. */
4176 len
[0] = DPP_HDR_LEN
;
4177 addr
[1] = attr_start
;
4179 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4180 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4181 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4182 wrapped_data
, wrapped_data_len
);
4183 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4184 unwrapped
= os_malloc(unwrapped_len
);
4186 dpp_auth_fail(auth
, "Authentication failed");
4189 if (aes_siv_decrypt(auth
->k2
, auth
->curve
->hash_len
,
4190 wrapped_data
, wrapped_data_len
,
4191 2, addr
, len
, unwrapped
) < 0) {
4192 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4195 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4196 unwrapped
, unwrapped_len
);
4198 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4199 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4203 r_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_NONCE
,
4205 if (!r_nonce
|| r_nonce_len
!= auth
->curve
->nonce_len
) {
4206 dpp_auth_fail(auth
, "DPP: Missing or invalid R-nonce");
4209 if (os_memcmp(r_nonce
, auth
->r_nonce
, r_nonce_len
) != 0) {
4210 wpa_hexdump(MSG_DEBUG
, "DPP: Received R-nonce",
4211 r_nonce
, r_nonce_len
);
4212 wpa_hexdump(MSG_DEBUG
, "DPP: Expected R-nonce",
4213 auth
->r_nonce
, r_nonce_len
);
4214 dpp_auth_fail(auth
, "R-nonce mismatch");
4218 if (status
== DPP_STATUS_NOT_COMPATIBLE
)
4219 dpp_auth_fail(auth
, "Peer reported incompatible R-capab role");
4220 else if (status
== DPP_STATUS_AUTH_FAILURE
)
4221 dpp_auth_fail(auth
, "Peer reported authentication failure)");
4224 bin_clear_free(unwrapped
, unwrapped_len
);
4229 int dpp_auth_conf_rx(struct dpp_authentication
*auth
, const u8
*hdr
,
4230 const u8
*attr_start
, size_t attr_len
)
4232 const u8
*r_bootstrap
, *i_bootstrap
, *wrapped_data
, *status
, *i_auth
;
4233 u16 r_bootstrap_len
, i_bootstrap_len
, wrapped_data_len
, status_len
,
4237 u8
*unwrapped
= NULL
;
4238 size_t unwrapped_len
= 0;
4239 u8 i_auth2
[DPP_MAX_HASH_LEN
];
4241 #ifdef CONFIG_TESTING_OPTIONS
4242 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
4243 wpa_printf(MSG_INFO
,
4244 "DPP: TESTING - stop at Authentication Confirm");
4247 #endif /* CONFIG_TESTING_OPTIONS */
4249 if (auth
->initiator
|| !auth
->own_bi
|| !auth
->waiting_auth_conf
) {
4250 wpa_printf(MSG_DEBUG
,
4251 "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d",
4252 auth
->initiator
, !!auth
->own_bi
,
4253 auth
->waiting_auth_conf
);
4254 dpp_auth_fail(auth
, "Unexpected Authentication Confirm");
4258 auth
->waiting_auth_conf
= 0;
4260 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
4262 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
4264 "Missing or invalid required Wrapped Data attribute");
4267 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
4268 wrapped_data
, wrapped_data_len
);
4270 attr_len
= wrapped_data
- 4 - attr_start
;
4272 r_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4273 DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
4275 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
4277 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
4280 wpa_hexdump(MSG_DEBUG
, "DPP: Responder Bootstrapping Key Hash",
4281 r_bootstrap
, r_bootstrap_len
);
4282 if (os_memcmp(r_bootstrap
, auth
->own_bi
->pubkey_hash
,
4283 SHA256_MAC_LEN
) != 0) {
4284 wpa_hexdump(MSG_DEBUG
,
4285 "DPP: Expected Responder Bootstrapping Key Hash",
4286 auth
->peer_bi
->pubkey_hash
, SHA256_MAC_LEN
);
4288 "Responder Bootstrapping Key Hash mismatch");
4292 i_bootstrap
= dpp_get_attr(attr_start
, attr_len
,
4293 DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
4296 if (i_bootstrap_len
!= SHA256_MAC_LEN
) {
4298 "Invalid Initiator Bootstrapping Key Hash attribute");
4301 wpa_hexdump(MSG_MSGDUMP
,
4302 "DPP: Initiator Bootstrapping Key Hash",
4303 i_bootstrap
, i_bootstrap_len
);
4304 if (!auth
->peer_bi
||
4305 os_memcmp(i_bootstrap
, auth
->peer_bi
->pubkey_hash
,
4306 SHA256_MAC_LEN
) != 0) {
4308 "Initiator Bootstrapping Key Hash mismatch");
4311 } else if (auth
->peer_bi
) {
4312 /* Mutual authentication and peer did not include its
4313 * Bootstrapping Key Hash attribute. */
4315 "Missing Initiator Bootstrapping Key Hash attribute");
4319 status
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_STATUS
,
4321 if (!status
|| status_len
< 1) {
4323 "Missing or invalid required DPP Status attribute");
4326 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
4327 if (status
[0] == DPP_STATUS_NOT_COMPATIBLE
||
4328 status
[0] == DPP_STATUS_AUTH_FAILURE
)
4329 return dpp_auth_conf_rx_failure(auth
, hdr
, attr_start
,
4330 attr_len
, wrapped_data
,
4331 wrapped_data_len
, status
[0]);
4333 if (status
[0] != DPP_STATUS_OK
) {
4334 dpp_auth_fail(auth
, "Authentication failed");
4339 len
[0] = DPP_HDR_LEN
;
4340 addr
[1] = attr_start
;
4342 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
4343 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
4344 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
4345 wrapped_data
, wrapped_data_len
);
4346 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
4347 unwrapped
= os_malloc(unwrapped_len
);
4350 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
4351 wrapped_data
, wrapped_data_len
,
4352 2, addr
, len
, unwrapped
) < 0) {
4353 dpp_auth_fail(auth
, "AES-SIV decryption failed");
4356 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
4357 unwrapped
, unwrapped_len
);
4359 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
4360 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
4364 i_auth
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
4366 if (!i_auth
|| i_auth_len
!= auth
->curve
->hash_len
) {
4368 "Missing or invalid Initiator Authenticating Tag");
4371 wpa_hexdump(MSG_DEBUG
, "DPP: Received Initiator Authenticating Tag",
4372 i_auth
, i_auth_len
);
4373 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */
4374 if (dpp_gen_i_auth(auth
, i_auth2
) < 0)
4376 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated Initiator Authenticating Tag",
4377 i_auth2
, i_auth_len
);
4378 if (os_memcmp(i_auth
, i_auth2
, i_auth_len
) != 0) {
4379 dpp_auth_fail(auth
, "Mismatching Initiator Authenticating Tag");
4383 bin_clear_free(unwrapped
, unwrapped_len
);
4384 dpp_auth_success(auth
);
4387 bin_clear_free(unwrapped
, unwrapped_len
);
4392 static int bin_str_eq(const char *val
, size_t len
, const char *cmp
)
4394 return os_strlen(cmp
) == len
&& os_memcmp(val
, cmp
, len
) == 0;
4398 struct dpp_configuration
* dpp_configuration_alloc(const char *type
)
4400 struct dpp_configuration
*conf
;
4404 conf
= os_zalloc(sizeof(*conf
));
4408 end
= os_strchr(type
, ' ');
4412 len
= os_strlen(type
);
4414 if (bin_str_eq(type
, len
, "psk"))
4415 conf
->akm
= DPP_AKM_PSK
;
4416 else if (bin_str_eq(type
, len
, "sae"))
4417 conf
->akm
= DPP_AKM_SAE
;
4418 else if (bin_str_eq(type
, len
, "psk-sae") ||
4419 bin_str_eq(type
, len
, "psk+sae"))
4420 conf
->akm
= DPP_AKM_PSK_SAE
;
4421 else if (bin_str_eq(type
, len
, "sae-dpp") ||
4422 bin_str_eq(type
, len
, "dpp+sae"))
4423 conf
->akm
= DPP_AKM_SAE_DPP
;
4424 else if (bin_str_eq(type
, len
, "psk-sae-dpp") ||
4425 bin_str_eq(type
, len
, "dpp+psk+sae"))
4426 conf
->akm
= DPP_AKM_PSK_SAE_DPP
;
4427 else if (bin_str_eq(type
, len
, "dpp"))
4428 conf
->akm
= DPP_AKM_DPP
;
4434 dpp_configuration_free(conf
);
4439 int dpp_akm_psk(enum dpp_akm akm
)
4441 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4442 akm
== DPP_AKM_PSK_SAE_DPP
;
4446 int dpp_akm_sae(enum dpp_akm akm
)
4448 return akm
== DPP_AKM_SAE
|| akm
== DPP_AKM_PSK_SAE
||
4449 akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4453 int dpp_akm_legacy(enum dpp_akm akm
)
4455 return akm
== DPP_AKM_PSK
|| akm
== DPP_AKM_PSK_SAE
||
4460 int dpp_akm_dpp(enum dpp_akm akm
)
4462 return akm
== DPP_AKM_DPP
|| akm
== DPP_AKM_SAE_DPP
||
4463 akm
== DPP_AKM_PSK_SAE_DPP
;
4467 int dpp_akm_ver2(enum dpp_akm akm
)
4469 return akm
== DPP_AKM_SAE_DPP
|| akm
== DPP_AKM_PSK_SAE_DPP
;
4473 int dpp_configuration_valid(const struct dpp_configuration
*conf
)
4475 if (conf
->ssid_len
== 0)
4477 if (dpp_akm_psk(conf
->akm
) && !conf
->passphrase
&& !conf
->psk_set
)
4479 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
)
4485 void dpp_configuration_free(struct dpp_configuration
*conf
)
4489 str_clear_free(conf
->passphrase
);
4490 os_free(conf
->group_id
);
4491 bin_clear_free(conf
, sizeof(*conf
));
4495 static int dpp_configuration_parse_helper(struct dpp_authentication
*auth
,
4496 const char *cmd
, int idx
)
4498 const char *pos
, *end
;
4499 struct dpp_configuration
*conf_sta
= NULL
, *conf_ap
= NULL
;
4500 struct dpp_configuration
*conf
= NULL
;
4502 pos
= os_strstr(cmd
, " conf=sta-");
4504 conf_sta
= dpp_configuration_alloc(pos
+ 10);
4507 conf_sta
->netrole
= DPP_NETROLE_STA
;
4511 pos
= os_strstr(cmd
, " conf=ap-");
4513 conf_ap
= dpp_configuration_alloc(pos
+ 9);
4516 conf_ap
->netrole
= DPP_NETROLE_AP
;
4520 pos
= os_strstr(cmd
, " conf=configurator");
4522 auth
->provision_configurator
= 1;
4527 pos
= os_strstr(cmd
, " ssid=");
4530 end
= os_strchr(pos
, ' ');
4531 conf
->ssid_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4532 conf
->ssid_len
/= 2;
4533 if (conf
->ssid_len
> sizeof(conf
->ssid
) ||
4534 hexstr2bin(pos
, conf
->ssid
, conf
->ssid_len
) < 0)
4537 #ifdef CONFIG_TESTING_OPTIONS
4538 /* use a default SSID for legacy testing reasons */
4539 os_memcpy(conf
->ssid
, "test", 4);
4541 #else /* CONFIG_TESTING_OPTIONS */
4543 #endif /* CONFIG_TESTING_OPTIONS */
4546 pos
= os_strstr(cmd
, " ssid_charset=");
4549 wpa_printf(MSG_INFO
,
4550 "DPP: ssid64 option (ssid_charset param) not allowed for AP enrollee");
4553 conf
->ssid_charset
= atoi(pos
+ 14);
4556 pos
= os_strstr(cmd
, " pass=");
4561 end
= os_strchr(pos
, ' ');
4562 pass_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4564 if (pass_len
> 63 || pass_len
< 8)
4566 conf
->passphrase
= os_zalloc(pass_len
+ 1);
4567 if (!conf
->passphrase
||
4568 hexstr2bin(pos
, (u8
*) conf
->passphrase
, pass_len
) < 0)
4572 pos
= os_strstr(cmd
, " psk=");
4575 if (hexstr2bin(pos
, conf
->psk
, PMK_LEN
) < 0)
4580 pos
= os_strstr(cmd
, " group_id=");
4582 size_t group_id_len
;
4585 end
= os_strchr(pos
, ' ');
4586 group_id_len
= end
? (size_t) (end
- pos
) : os_strlen(pos
);
4587 conf
->group_id
= os_malloc(group_id_len
+ 1);
4588 if (!conf
->group_id
)
4590 os_memcpy(conf
->group_id
, pos
, group_id_len
);
4591 conf
->group_id
[group_id_len
] = '\0';
4594 pos
= os_strstr(cmd
, " expiry=");
4599 val
= strtol(pos
, NULL
, 0);
4602 conf
->netaccesskey_expiry
= val
;
4605 if (!dpp_configuration_valid(conf
))
4609 auth
->conf_sta
= conf_sta
;
4610 auth
->conf_ap
= conf_ap
;
4611 } else if (idx
== 1) {
4612 auth
->conf2_sta
= conf_sta
;
4613 auth
->conf2_ap
= conf_ap
;
4620 dpp_configuration_free(conf_sta
);
4621 dpp_configuration_free(conf_ap
);
4626 static int dpp_configuration_parse(struct dpp_authentication
*auth
,
4634 pos
= os_strstr(cmd
, " @CONF-OBJ-SEP@ ");
4636 return dpp_configuration_parse_helper(auth
, cmd
, 0);
4639 tmp
= os_malloc(len
+ 1);
4642 os_memcpy(tmp
, cmd
, len
);
4644 res
= dpp_configuration_parse_helper(auth
, cmd
, 0);
4645 str_clear_free(tmp
);
4648 res
= dpp_configuration_parse_helper(auth
, cmd
+ len
, 1);
4653 dpp_configuration_free(auth
->conf_sta
);
4654 dpp_configuration_free(auth
->conf2_sta
);
4655 dpp_configuration_free(auth
->conf_ap
);
4656 dpp_configuration_free(auth
->conf2_ap
);
4661 static struct dpp_configurator
*
4662 dpp_configurator_get_id(struct dpp_global
*dpp
, unsigned int id
)
4664 struct dpp_configurator
*conf
;
4669 dl_list_for_each(conf
, &dpp
->configurator
,
4670 struct dpp_configurator
, list
) {
4678 int dpp_set_configurator(struct dpp_global
*dpp
, void *msg_ctx
,
4679 struct dpp_authentication
*auth
,
4688 if (cmd
[0] != ' ') {
4691 len
= os_strlen(cmd
);
4692 tmp
= os_malloc(len
+ 2);
4696 os_memcpy(tmp
+ 1, cmd
, len
+ 1);
4700 wpa_printf(MSG_DEBUG
, "DPP: Set configurator parameters: %s", cmd
);
4702 pos
= os_strstr(cmd
, " configurator=");
4705 auth
->conf
= dpp_configurator_get_id(dpp
, atoi(pos
));
4707 wpa_printf(MSG_INFO
,
4708 "DPP: Could not find the specified configurator");
4713 pos
= os_strstr(cmd
, " conn_status=");
4716 auth
->send_conn_status
= atoi(pos
);
4719 pos
= os_strstr(cmd
, " akm_use_selector=");
4722 auth
->akm_use_selector
= atoi(pos
);
4725 if (dpp_configuration_parse(auth
, cmd
) < 0) {
4726 wpa_msg(msg_ctx
, MSG_INFO
,
4727 "DPP: Failed to set configurator parameters");
4737 static void dpp_free_asymmetric_key(struct dpp_asymmetric_key
*key
)
4740 struct dpp_asymmetric_key
*next
= key
->next
;
4742 EVP_PKEY_free(key
->csign
);
4743 str_clear_free(key
->config_template
);
4744 str_clear_free(key
->connector_template
);
4751 void dpp_auth_deinit(struct dpp_authentication
*auth
)
4757 dpp_configuration_free(auth
->conf_ap
);
4758 dpp_configuration_free(auth
->conf2_ap
);
4759 dpp_configuration_free(auth
->conf_sta
);
4760 dpp_configuration_free(auth
->conf2_sta
);
4761 EVP_PKEY_free(auth
->own_protocol_key
);
4762 EVP_PKEY_free(auth
->peer_protocol_key
);
4763 wpabuf_free(auth
->req_msg
);
4764 wpabuf_free(auth
->resp_msg
);
4765 wpabuf_free(auth
->conf_req
);
4766 for (i
= 0; i
< auth
->num_conf_obj
; i
++) {
4767 struct dpp_config_obj
*conf
= &auth
->conf_obj
[i
];
4769 os_free(conf
->connector
);
4770 wpabuf_free(conf
->c_sign_key
);
4772 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
4773 wpabuf_free(auth
->net_access_key
);
4774 dpp_bootstrap_info_free(auth
->tmp_own_bi
);
4775 #ifdef CONFIG_TESTING_OPTIONS
4776 os_free(auth
->config_obj_override
);
4777 os_free(auth
->discovery_override
);
4778 os_free(auth
->groups_override
);
4779 #endif /* CONFIG_TESTING_OPTIONS */
4780 bin_clear_free(auth
, sizeof(*auth
));
4784 static struct wpabuf
*
4785 dpp_build_conf_start(struct dpp_authentication
*auth
,
4786 struct dpp_configuration
*conf
, size_t tailroom
)
4790 #ifdef CONFIG_TESTING_OPTIONS
4791 if (auth
->discovery_override
)
4792 tailroom
+= os_strlen(auth
->discovery_override
);
4793 #endif /* CONFIG_TESTING_OPTIONS */
4795 buf
= wpabuf_alloc(200 + tailroom
);
4798 json_start_object(buf
, NULL
);
4799 json_add_string(buf
, "wi-fi_tech", "infra");
4800 json_value_sep(buf
);
4801 #ifdef CONFIG_TESTING_OPTIONS
4802 if (auth
->discovery_override
) {
4803 wpa_printf(MSG_DEBUG
, "DPP: TESTING - discovery override: '%s'",
4804 auth
->discovery_override
);
4805 wpabuf_put_str(buf
, "\"discovery\":");
4806 wpabuf_put_str(buf
, auth
->discovery_override
);
4807 json_value_sep(buf
);
4810 #endif /* CONFIG_TESTING_OPTIONS */
4811 json_start_object(buf
, "discovery");
4812 if (((!conf
->ssid_charset
|| auth
->peer_version
< 2) &&
4813 json_add_string_escape(buf
, "ssid", conf
->ssid
,
4814 conf
->ssid_len
) < 0) ||
4815 ((conf
->ssid_charset
&& auth
->peer_version
>= 2) &&
4816 json_add_base64url(buf
, "ssid64", conf
->ssid
,
4817 conf
->ssid_len
) < 0)) {
4821 if (conf
->ssid_charset
> 0) {
4822 json_value_sep(buf
);
4823 json_add_int(buf
, "ssid_charset", conf
->ssid_charset
);
4825 json_end_object(buf
);
4826 json_value_sep(buf
);
4832 static int dpp_build_jwk(struct wpabuf
*buf
, const char *name
, EVP_PKEY
*key
,
4833 const char *kid
, const struct dpp_curve_params
*curve
)
4839 pub
= dpp_get_pubkey_point(key
, 0);
4843 json_start_object(buf
, name
);
4844 json_add_string(buf
, "kty", "EC");
4845 json_value_sep(buf
);
4846 json_add_string(buf
, "crv", curve
->jwk_crv
);
4847 json_value_sep(buf
);
4848 pos
= wpabuf_head(pub
);
4849 if (json_add_base64url(buf
, "x", pos
, curve
->prime_len
) < 0)
4851 json_value_sep(buf
);
4852 pos
+= curve
->prime_len
;
4853 if (json_add_base64url(buf
, "y", pos
, curve
->prime_len
) < 0)
4856 json_value_sep(buf
);
4857 json_add_string(buf
, "kid", kid
);
4859 json_end_object(buf
);
4867 static void dpp_build_legacy_cred_params(struct wpabuf
*buf
,
4868 struct dpp_configuration
*conf
)
4870 if (conf
->passphrase
&& os_strlen(conf
->passphrase
) < 64) {
4871 json_add_string_escape(buf
, "pass", conf
->passphrase
,
4872 os_strlen(conf
->passphrase
));
4873 } else if (conf
->psk_set
) {
4874 char psk
[2 * sizeof(conf
->psk
) + 1];
4876 wpa_snprintf_hex(psk
, sizeof(psk
),
4877 conf
->psk
, sizeof(conf
->psk
));
4878 json_add_string(buf
, "psk_hex", psk
);
4879 forced_memzero(psk
, sizeof(psk
));
4884 static const char * dpp_netrole_str(enum dpp_netrole netrole
)
4887 case DPP_NETROLE_STA
:
4889 case DPP_NETROLE_AP
:
4891 case DPP_NETROLE_CONFIGURATOR
:
4892 return "configurator";
4899 static struct wpabuf
*
4900 dpp_build_conf_obj_dpp(struct dpp_authentication
*auth
,
4901 struct dpp_configuration
*conf
)
4903 struct wpabuf
*buf
= NULL
;
4904 char *signed1
= NULL
, *signed2
= NULL
, *signed3
= NULL
;
4906 const struct dpp_curve_params
*curve
;
4907 struct wpabuf
*jws_prot_hdr
;
4908 size_t signed1_len
, signed2_len
, signed3_len
;
4909 struct wpabuf
*dppcon
= NULL
;
4910 unsigned char *signature
= NULL
;
4911 const unsigned char *p
;
4912 size_t signature_len
;
4913 EVP_MD_CTX
*md_ctx
= NULL
;
4914 ECDSA_SIG
*sig
= NULL
;
4916 const EVP_MD
*sign_md
;
4917 const BIGNUM
*r
, *s
;
4918 size_t extra_len
= 1000;
4921 const char *akm_str
;
4924 wpa_printf(MSG_INFO
,
4925 "DPP: No configurator specified - cannot generate DPP config object");
4928 curve
= auth
->conf
->curve
;
4929 if (curve
->hash_len
== SHA256_MAC_LEN
) {
4930 sign_md
= EVP_sha256();
4931 } else if (curve
->hash_len
== SHA384_MAC_LEN
) {
4932 sign_md
= EVP_sha384();
4933 } else if (curve
->hash_len
== SHA512_MAC_LEN
) {
4934 sign_md
= EVP_sha512();
4936 wpa_printf(MSG_DEBUG
, "DPP: Unknown signature algorithm");
4941 if (dpp_akm_ver2(akm
) && auth
->peer_version
< 2) {
4942 wpa_printf(MSG_DEBUG
,
4943 "DPP: Convert DPP+legacy credential to DPP-only for peer that does not support version 2");
4947 #ifdef CONFIG_TESTING_OPTIONS
4948 if (auth
->groups_override
)
4949 extra_len
+= os_strlen(auth
->groups_override
);
4950 #endif /* CONFIG_TESTING_OPTIONS */
4953 extra_len
+= os_strlen(conf
->group_id
);
4955 /* Connector (JSON dppCon object) */
4956 dppcon
= wpabuf_alloc(extra_len
+ 2 * auth
->curve
->prime_len
* 4 / 3);
4959 #ifdef CONFIG_TESTING_OPTIONS
4960 if (auth
->groups_override
) {
4961 wpabuf_put_u8(dppcon
, '{');
4962 if (auth
->groups_override
) {
4963 wpa_printf(MSG_DEBUG
,
4964 "DPP: TESTING - groups override: '%s'",
4965 auth
->groups_override
);
4966 wpabuf_put_str(dppcon
, "\"groups\":");
4967 wpabuf_put_str(dppcon
, auth
->groups_override
);
4968 json_value_sep(dppcon
);
4972 #endif /* CONFIG_TESTING_OPTIONS */
4973 json_start_object(dppcon
, NULL
);
4974 json_start_array(dppcon
, "groups");
4975 json_start_object(dppcon
, NULL
);
4976 json_add_string(dppcon
, "groupId",
4977 conf
->group_id
? conf
->group_id
: "*");
4978 json_value_sep(dppcon
);
4979 json_add_string(dppcon
, "netRole", dpp_netrole_str(conf
->netrole
));
4980 json_end_object(dppcon
);
4981 json_end_array(dppcon
);
4982 json_value_sep(dppcon
);
4983 #ifdef CONFIG_TESTING_OPTIONS
4985 #endif /* CONFIG_TESTING_OPTIONS */
4986 if (dpp_build_jwk(dppcon
, "netAccessKey", auth
->peer_protocol_key
, NULL
,
4988 wpa_printf(MSG_DEBUG
, "DPP: Failed to build netAccessKey JWK");
4991 if (conf
->netaccesskey_expiry
) {
4995 if (os_gmtime(conf
->netaccesskey_expiry
, &tm
) < 0) {
4996 wpa_printf(MSG_DEBUG
,
4997 "DPP: Failed to generate expiry string");
5000 os_snprintf(expiry
, sizeof(expiry
),
5001 "%04u-%02u-%02uT%02u:%02u:%02uZ",
5002 tm
.year
, tm
.month
, tm
.day
,
5003 tm
.hour
, tm
.min
, tm
.sec
);
5004 json_value_sep(dppcon
);
5005 json_add_string(dppcon
, "expiry", expiry
);
5007 json_end_object(dppcon
);
5008 wpa_printf(MSG_DEBUG
, "DPP: dppCon: %s",
5009 (const char *) wpabuf_head(dppcon
));
5011 jws_prot_hdr
= wpabuf_alloc(100);
5014 json_start_object(jws_prot_hdr
, NULL
);
5015 json_add_string(jws_prot_hdr
, "typ", "dppCon");
5016 json_value_sep(jws_prot_hdr
);
5017 json_add_string(jws_prot_hdr
, "kid", auth
->conf
->kid
);
5018 json_value_sep(jws_prot_hdr
);
5019 json_add_string(jws_prot_hdr
, "alg", curve
->jws_alg
);
5020 json_end_object(jws_prot_hdr
);
5021 signed1
= base64_url_encode(wpabuf_head(jws_prot_hdr
),
5022 wpabuf_len(jws_prot_hdr
),
5024 wpabuf_free(jws_prot_hdr
);
5025 signed2
= base64_url_encode(wpabuf_head(dppcon
), wpabuf_len(dppcon
),
5027 if (!signed1
|| !signed2
)
5030 md_ctx
= EVP_MD_CTX_create();
5035 if (EVP_DigestSignInit(md_ctx
, NULL
, sign_md
, NULL
,
5036 auth
->conf
->csign
) != 1) {
5037 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignInit failed: %s",
5038 ERR_error_string(ERR_get_error(), NULL
));
5041 if (EVP_DigestSignUpdate(md_ctx
, signed1
, signed1_len
) != 1 ||
5042 EVP_DigestSignUpdate(md_ctx
, dot
, 1) != 1 ||
5043 EVP_DigestSignUpdate(md_ctx
, signed2
, signed2_len
) != 1) {
5044 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignUpdate failed: %s",
5045 ERR_error_string(ERR_get_error(), NULL
));
5048 if (EVP_DigestSignFinal(md_ctx
, NULL
, &signature_len
) != 1) {
5049 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5050 ERR_error_string(ERR_get_error(), NULL
));
5053 signature
= os_malloc(signature_len
);
5056 if (EVP_DigestSignFinal(md_ctx
, signature
, &signature_len
) != 1) {
5057 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestSignFinal failed: %s",
5058 ERR_error_string(ERR_get_error(), NULL
));
5061 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (DER)",
5062 signature
, signature_len
);
5063 /* Convert to raw coordinates r,s */
5065 sig
= d2i_ECDSA_SIG(NULL
, &p
, signature_len
);
5068 ECDSA_SIG_get0(sig
, &r
, &s
);
5069 if (dpp_bn2bin_pad(r
, signature
, curve
->prime_len
) < 0 ||
5070 dpp_bn2bin_pad(s
, signature
+ curve
->prime_len
,
5071 curve
->prime_len
) < 0)
5073 signature_len
= 2 * curve
->prime_len
;
5074 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector ECDSA signature (raw r,s)",
5075 signature
, signature_len
);
5076 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
5080 incl_legacy
= dpp_akm_psk(akm
) || dpp_akm_sae(akm
);
5082 tailroom
+= 2 * curve
->prime_len
* 4 / 3 + os_strlen(auth
->conf
->kid
);
5083 tailroom
+= signed1_len
+ signed2_len
+ signed3_len
;
5086 buf
= dpp_build_conf_start(auth
, conf
, tailroom
);
5090 if (auth
->akm_use_selector
&& dpp_akm_ver2(akm
))
5091 akm_str
= dpp_akm_selector_str(akm
);
5093 akm_str
= dpp_akm_str(akm
);
5094 json_start_object(buf
, "cred");
5095 json_add_string(buf
, "akm", akm_str
);
5096 json_value_sep(buf
);
5098 dpp_build_legacy_cred_params(buf
, conf
);
5099 json_value_sep(buf
);
5101 wpabuf_put_str(buf
, "\"signedConnector\":\"");
5102 wpabuf_put_str(buf
, signed1
);
5103 wpabuf_put_u8(buf
, '.');
5104 wpabuf_put_str(buf
, signed2
);
5105 wpabuf_put_u8(buf
, '.');
5106 wpabuf_put_str(buf
, signed3
);
5107 wpabuf_put_str(buf
, "\"");
5108 json_value_sep(buf
);
5109 if (dpp_build_jwk(buf
, "csign", auth
->conf
->csign
, auth
->conf
->kid
,
5111 wpa_printf(MSG_DEBUG
, "DPP: Failed to build csign JWK");
5115 json_end_object(buf
);
5116 json_end_object(buf
);
5118 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object",
5119 wpabuf_head(buf
), wpabuf_len(buf
));
5122 EVP_MD_CTX_destroy(md_ctx
);
5123 ECDSA_SIG_free(sig
);
5128 wpabuf_free(dppcon
);
5131 wpa_printf(MSG_DEBUG
, "DPP: Failed to build configuration object");
5138 static struct wpabuf
*
5139 dpp_build_conf_obj_legacy(struct dpp_authentication
*auth
,
5140 struct dpp_configuration
*conf
)
5143 const char *akm_str
;
5145 buf
= dpp_build_conf_start(auth
, conf
, 1000);
5149 if (auth
->akm_use_selector
&& dpp_akm_ver2(conf
->akm
))
5150 akm_str
= dpp_akm_selector_str(conf
->akm
);
5152 akm_str
= dpp_akm_str(conf
->akm
);
5153 json_start_object(buf
, "cred");
5154 json_add_string(buf
, "akm", akm_str
);
5155 json_value_sep(buf
);
5156 dpp_build_legacy_cred_params(buf
, conf
);
5157 json_end_object(buf
);
5158 json_end_object(buf
);
5160 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Configuration Object (legacy)",
5161 wpabuf_head(buf
), wpabuf_len(buf
));
5167 static struct wpabuf
*
5168 dpp_build_conf_obj(struct dpp_authentication
*auth
, enum dpp_netrole netrole
,
5171 struct dpp_configuration
*conf
= NULL
;
5173 #ifdef CONFIG_TESTING_OPTIONS
5174 if (auth
->config_obj_override
) {
5177 wpa_printf(MSG_DEBUG
, "DPP: Testing - Config Object override");
5178 return wpabuf_alloc_copy(auth
->config_obj_override
,
5179 os_strlen(auth
->config_obj_override
));
5181 #endif /* CONFIG_TESTING_OPTIONS */
5184 if (netrole
== DPP_NETROLE_STA
)
5185 conf
= auth
->conf_sta
;
5186 else if (netrole
== DPP_NETROLE_AP
)
5187 conf
= auth
->conf_ap
;
5188 } else if (idx
== 1) {
5189 if (netrole
== DPP_NETROLE_STA
)
5190 conf
= auth
->conf2_sta
;
5191 else if (netrole
== DPP_NETROLE_AP
)
5192 conf
= auth
->conf2_ap
;
5196 wpa_printf(MSG_DEBUG
,
5197 "DPP: No configuration available for Enrollee(%s) - reject configuration request",
5198 dpp_netrole_str(netrole
));
5202 if (dpp_akm_dpp(conf
->akm
))
5203 return dpp_build_conf_obj_dpp(auth
, conf
);
5204 return dpp_build_conf_obj_legacy(auth
, conf
);
5210 static struct wpabuf
* dpp_build_conf_params(void)
5214 /* TODO: proper template values */
5215 const char *conf_template
= "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
5216 const char *connector_template
= NULL
;
5218 len
= 100 + os_strlen(conf_template
);
5219 if (connector_template
)
5220 len
+= os_strlen(connector_template
);
5221 buf
= wpabuf_alloc(len
);
5226 * DPPConfigurationParameters ::= SEQUENCE {
5227 * configurationTemplate UTF8String,
5228 * connectorTemplate UTF8String OPTIONAL}
5231 asn1_put_utf8string(buf
, conf_template
);
5232 if (connector_template
)
5233 asn1_put_utf8string(buf
, connector_template
);
5234 return asn1_encaps(buf
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5238 static struct wpabuf
* dpp_build_attribute(void)
5240 struct wpabuf
*conf_params
, *attr
;
5243 * aa-DPPConfigurationParameters ATTRIBUTE ::=
5244 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
5246 * Attribute ::= SEQUENCE {
5247 * type OBJECT IDENTIFIER,
5248 * values SET SIZE(1..MAX) OF Type
5250 conf_params
= dpp_build_conf_params();
5251 conf_params
= asn1_encaps(conf_params
, ASN1_CLASS_UNIVERSAL
,
5256 attr
= wpabuf_alloc(100 + wpabuf_len(conf_params
));
5258 wpabuf_clear_free(conf_params
);
5262 asn1_put_oid(attr
, &asn1_dpp_config_params_oid
);
5263 wpabuf_put_buf(attr
, conf_params
);
5264 wpabuf_clear_free(conf_params
);
5266 return asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5270 static struct wpabuf
* dpp_build_key_alg(const struct dpp_curve_params
*curve
)
5272 const struct asn1_oid
*oid
;
5273 struct wpabuf
*params
, *res
;
5275 switch (curve
->ike_group
) {
5277 oid
= &asn1_prime256v1_oid
;
5280 oid
= &asn1_secp384r1_oid
;
5283 oid
= &asn1_secp521r1_oid
;
5286 oid
= &asn1_brainpoolP256r1_oid
;
5289 oid
= &asn1_brainpoolP384r1_oid
;
5292 oid
= &asn1_brainpoolP512r1_oid
;
5298 params
= wpabuf_alloc(20);
5301 asn1_put_oid(params
, oid
); /* namedCurve */
5303 res
= asn1_build_alg_id(&asn1_ec_public_key_oid
, params
);
5304 wpabuf_free(params
);
5309 static struct wpabuf
* dpp_build_key_pkg(struct dpp_authentication
*auth
)
5311 struct wpabuf
*key
= NULL
, *attr
, *alg
, *priv_key
= NULL
;
5313 unsigned char *der
= NULL
;
5316 eckey
= EVP_PKEY_get0_EC_KEY(auth
->conf
->csign
);
5320 EC_KEY_set_enc_flags(eckey
, EC_PKEY_NO_PUBKEY
);
5321 der_len
= i2d_ECPrivateKey(eckey
, &der
);
5323 priv_key
= wpabuf_alloc_copy(der
, der_len
);
5326 alg
= dpp_build_key_alg(auth
->conf
->curve
);
5328 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
5329 attr
= dpp_build_attribute();
5330 attr
= asn1_encaps(attr
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SET
);
5331 if (!priv_key
|| !attr
|| !alg
)
5335 * OneAsymmetricKey ::= SEQUENCE {
5337 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
5338 * privateKey PrivateKey,
5339 * attributes [0] Attributes OPTIONAL,
5341 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
5346 key
= wpabuf_alloc(100 + wpabuf_len(alg
) + wpabuf_len(priv_key
) +
5351 asn1_put_integer(key
, 1); /* version = v2(1) */
5353 /* PrivateKeyAlgorithmIdentifier */
5354 wpabuf_put_buf(key
, alg
);
5356 /* PrivateKey ::= OCTET STRING */
5357 asn1_put_octet_string(key
, priv_key
);
5359 /* [0] Attributes OPTIONAL */
5360 asn1_put_hdr(key
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0, wpabuf_len(attr
));
5361 wpabuf_put_buf(key
, attr
);
5364 wpabuf_clear_free(attr
);
5365 wpabuf_clear_free(priv_key
);
5369 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
5371 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
5373 * OneAsymmetricKey ::= SEQUENCE
5375 return asn1_encaps(asn1_encaps(key
,
5376 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
),
5377 ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5381 static struct wpabuf
* dpp_build_pbkdf2_alg_id(const struct wpabuf
*salt
,
5384 struct wpabuf
*params
= NULL
, *buf
= NULL
, *prf
= NULL
;
5385 const struct asn1_oid
*oid
;
5388 * PBKDF2-params ::= SEQUENCE {
5390 * specified OCTET STRING,
5391 * otherSource AlgorithmIdentifier}
5392 * iterationCount INTEGER (1..MAX),
5393 * keyLength INTEGER (1..MAX),
5394 * prf AlgorithmIdentifier}
5396 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
5397 * on Configurator signing key length, prf is
5398 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
5402 oid
= &asn1_pbkdf2_hmac_sha256_oid
;
5403 else if (hash_len
== 48)
5404 oid
= &asn1_pbkdf2_hmac_sha384_oid
;
5405 else if (hash_len
== 64)
5406 oid
= &asn1_pbkdf2_hmac_sha512_oid
;
5409 prf
= asn1_build_alg_id(oid
, NULL
);
5412 params
= wpabuf_alloc(100 + wpabuf_len(salt
) + wpabuf_len(prf
));
5415 asn1_put_octet_string(params
, salt
); /* salt.specified */
5416 asn1_put_integer(params
, 1000); /* iterationCount */
5417 asn1_put_integer(params
, hash_len
); /* keyLength */
5418 wpabuf_put_buf(params
, prf
);
5419 params
= asn1_encaps(params
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5422 buf
= asn1_build_alg_id(&asn1_pbkdf2_oid
, params
);
5424 wpabuf_free(params
);
5430 static struct wpabuf
*
5431 dpp_build_pw_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5432 const struct wpabuf
*cont_enc_key
)
5434 struct wpabuf
*pwri
= NULL
, *enc_key
= NULL
, *key_der_alg
= NULL
,
5435 *key_enc_alg
= NULL
, *salt
;
5436 u8 kek
[DPP_MAX_HASH_LEN
];
5440 salt
= wpabuf_alloc(64);
5441 if (!salt
|| os_get_random(wpabuf_put(salt
, 64), 64) < 0)
5443 wpa_hexdump_buf(MSG_DEBUG
, "DPP: PBKDF2 salt", salt
);
5445 /* TODO: For initial testing, use ke as the key. Replace this with a
5446 * new key once that has been defined. */
5448 key_len
= auth
->curve
->hash_len
;
5449 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
5451 if (dpp_pbkdf2(hash_len
, key
, key_len
, wpabuf_head(salt
), 64, 1000,
5453 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
5456 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
5459 enc_key
= wpabuf_alloc(hash_len
+ AES_BLOCK_SIZE
);
5461 aes_siv_encrypt(kek
, hash_len
, wpabuf_head(cont_enc_key
),
5462 wpabuf_len(cont_enc_key
), 0, NULL
, NULL
,
5463 wpabuf_put(enc_key
, hash_len
+ AES_BLOCK_SIZE
)) < 0)
5465 wpa_hexdump_buf(MSG_DEBUG
, "DPP: encryptedKey", enc_key
);
5468 * PasswordRecipientInfo ::= SEQUENCE {
5469 * version CMSVersion,
5470 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
5471 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
5472 * encryptedKey EncryptedKey}
5474 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
5475 * parameters contains PBKDF2-params SEQUENCE.
5478 key_der_alg
= dpp_build_pbkdf2_alg_id(salt
, hash_len
);
5479 key_enc_alg
= asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid
, NULL
);
5480 if (!key_der_alg
|| !key_enc_alg
)
5482 pwri
= wpabuf_alloc(100 + wpabuf_len(key_der_alg
) +
5483 wpabuf_len(key_enc_alg
) + wpabuf_len(enc_key
));
5488 asn1_put_integer(pwri
, 0);
5490 /* [0] KeyDerivationAlgorithmIdentifier */
5491 asn1_put_hdr(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 1, 0,
5492 wpabuf_len(key_der_alg
));
5493 wpabuf_put_buf(pwri
, key_der_alg
);
5495 /* KeyEncryptionAlgorithmIdentifier */
5496 wpabuf_put_buf(pwri
, key_enc_alg
);
5498 /* EncryptedKey ::= OCTET STRING */
5499 asn1_put_octet_string(pwri
, enc_key
);
5502 wpabuf_clear_free(key_der_alg
);
5503 wpabuf_free(key_enc_alg
);
5504 wpabuf_free(enc_key
);
5506 forced_memzero(kek
, sizeof(kek
));
5507 return asn1_encaps(pwri
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5511 static struct wpabuf
*
5512 dpp_build_recipient_info(struct dpp_authentication
*auth
, size_t hash_len
,
5513 const struct wpabuf
*cont_enc_key
)
5515 struct wpabuf
*pwri
;
5518 * RecipientInfo ::= CHOICE {
5519 * ktri KeyTransRecipientInfo,
5520 * kari [1] KeyAgreeRecipientInfo,
5521 * kekri [2] KEKRecipientInfo,
5522 * pwri [3] PasswordRecipientInfo,
5523 * ori [4] OtherRecipientInfo}
5525 * Shall always use the pwri CHOICE.
5528 pwri
= dpp_build_pw_recipient_info(auth
, hash_len
, cont_enc_key
);
5529 return asn1_encaps(pwri
, ASN1_CLASS_CONTEXT_SPECIFIC
, 3);
5533 static struct wpabuf
*
5534 dpp_build_enc_cont_info(struct dpp_authentication
*auth
, size_t hash_len
,
5535 const struct wpabuf
*cont_enc_key
)
5537 struct wpabuf
*key_pkg
, *enc_cont_info
= NULL
, *enc_cont
= NULL
,
5539 const struct asn1_oid
*oid
;
5540 size_t enc_cont_len
;
5543 * EncryptedContentInfo ::= SEQUENCE {
5544 * contentType ContentType,
5545 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
5546 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
5550 oid
= &asn1_aes_siv_cmac_aead_256_oid
;
5551 else if (hash_len
== 48)
5552 oid
= &asn1_aes_siv_cmac_aead_384_oid
;
5553 else if (hash_len
== 64)
5554 oid
= &asn1_aes_siv_cmac_aead_512_oid
;
5558 key_pkg
= dpp_build_key_pkg(auth
);
5559 enc_alg
= asn1_build_alg_id(oid
, NULL
);
5560 if (!key_pkg
|| !enc_alg
)
5563 wpa_hexdump_buf_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
5566 enc_cont_len
= wpabuf_len(key_pkg
) + AES_BLOCK_SIZE
;
5567 enc_cont
= wpabuf_alloc(enc_cont_len
);
5569 aes_siv_encrypt(wpabuf_head(cont_enc_key
), wpabuf_len(cont_enc_key
),
5570 wpabuf_head(key_pkg
), wpabuf_len(key_pkg
),
5572 wpabuf_put(enc_cont
, enc_cont_len
)) < 0)
5575 enc_cont_info
= wpabuf_alloc(100 + wpabuf_len(enc_alg
) +
5576 wpabuf_len(enc_cont
));
5580 /* ContentType ::= OBJECT IDENTIFIER */
5581 asn1_put_oid(enc_cont_info
, &asn1_dpp_asymmetric_key_package_oid
);
5583 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
5584 wpabuf_put_buf(enc_cont_info
, enc_alg
);
5586 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
5587 * EncryptedContent ::= OCTET STRING */
5588 asn1_put_hdr(enc_cont_info
, ASN1_CLASS_CONTEXT_SPECIFIC
, 0, 0,
5589 wpabuf_len(enc_cont
));
5590 wpabuf_put_buf(enc_cont_info
, enc_cont
);
5593 wpabuf_clear_free(key_pkg
);
5594 wpabuf_free(enc_cont
);
5595 wpabuf_free(enc_alg
);
5596 return enc_cont_info
;
5600 static struct wpabuf
* dpp_gen_random(size_t len
)
5604 key
= wpabuf_alloc(len
);
5605 if (!key
|| os_get_random(wpabuf_put(key
, len
), len
) < 0) {
5609 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: content-encryption key", key
);
5614 static struct wpabuf
* dpp_build_enveloped_data(struct dpp_authentication
*auth
)
5616 struct wpabuf
*env
= NULL
;
5617 struct wpabuf
*recipient_info
= NULL
, *enc_cont_info
= NULL
;
5618 struct wpabuf
*cont_enc_key
= NULL
;
5622 wpa_printf(MSG_DEBUG
,
5623 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
5627 if (!auth
->provision_configurator
) {
5628 wpa_printf(MSG_DEBUG
,
5629 "DPP: Configurator provisioning not allowed");
5633 wpa_printf(MSG_DEBUG
, "DPP: Building DPPEnvelopedData");
5635 hash_len
= auth
->conf
->curve
->hash_len
;
5636 cont_enc_key
= dpp_gen_random(hash_len
);
5639 recipient_info
= dpp_build_recipient_info(auth
, hash_len
, cont_enc_key
);
5640 enc_cont_info
= dpp_build_enc_cont_info(auth
, hash_len
, cont_enc_key
);
5641 if (!recipient_info
|| !enc_cont_info
)
5644 env
= wpabuf_alloc(wpabuf_len(recipient_info
) +
5645 wpabuf_len(enc_cont_info
) +
5651 * DPPEnvelopedData ::= EnvelopedData
5653 * EnvelopedData ::= SEQUENCE {
5654 * version CMSVersion,
5655 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
5656 * recipientInfos RecipientInfos,
5657 * encryptedContentInfo EncryptedContentInfo,
5658 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
5660 * For DPP, version is 3, both originatorInfo and
5661 * unprotectedAttrs are omitted, and recipientInfos contains a single
5665 /* EnvelopedData.version = 3 */
5666 asn1_put_integer(env
, 3);
5668 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
5669 asn1_put_set(env
, recipient_info
);
5671 /* EncryptedContentInfo ::= SEQUENCE */
5672 asn1_put_sequence(env
, enc_cont_info
);
5674 env
= asn1_encaps(env
, ASN1_CLASS_UNIVERSAL
, ASN1_TAG_SEQUENCE
);
5675 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: DPPEnvelopedData", env
);
5677 wpabuf_clear_free(cont_enc_key
);
5678 wpabuf_clear_free(recipient_info
);
5679 wpabuf_free(enc_cont_info
);
5687 #endif /* CONFIG_DPP2 */
5690 static struct wpabuf
*
5691 dpp_build_conf_resp(struct dpp_authentication
*auth
, const u8
*e_nonce
,
5692 u16 e_nonce_len
, enum dpp_netrole netrole
)
5694 struct wpabuf
*conf
= NULL
, *conf2
= NULL
, *env_data
= NULL
;
5695 size_t clear_len
, attr_len
;
5696 struct wpabuf
*clear
= NULL
, *msg
= NULL
;
5700 enum dpp_status_error status
;
5702 if (netrole
== DPP_NETROLE_CONFIGURATOR
) {
5704 env_data
= dpp_build_enveloped_data(auth
);
5705 #endif /* CONFIG_DPP2 */
5707 conf
= dpp_build_conf_obj(auth
, netrole
, 0);
5709 wpa_hexdump_ascii(MSG_DEBUG
,
5710 "DPP: configurationObject JSON",
5711 wpabuf_head(conf
), wpabuf_len(conf
));
5712 conf2
= dpp_build_conf_obj(auth
, netrole
, 1);
5715 status
= (conf
|| env_data
) ? DPP_STATUS_OK
:
5716 DPP_STATUS_CONFIGURE_FAILURE
;
5717 auth
->conf_resp_status
= status
;
5719 /* { E-nonce, configurationObject[, sendConnStatus]}ke */
5720 clear_len
= 4 + e_nonce_len
;
5722 clear_len
+= 4 + wpabuf_len(conf
);
5724 clear_len
+= 4 + wpabuf_len(conf2
);
5726 clear_len
+= 4 + wpabuf_len(env_data
);
5727 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5728 netrole
== DPP_NETROLE_STA
)
5730 clear
= wpabuf_alloc(clear_len
);
5731 attr_len
= 4 + 1 + 4 + clear_len
+ AES_BLOCK_SIZE
;
5732 #ifdef CONFIG_TESTING_OPTIONS
5733 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
)
5735 #endif /* CONFIG_TESTING_OPTIONS */
5736 msg
= wpabuf_alloc(attr_len
);
5740 #ifdef CONFIG_TESTING_OPTIONS
5741 if (dpp_test
== DPP_TEST_NO_E_NONCE_CONF_RESP
) {
5742 wpa_printf(MSG_INFO
, "DPP: TESTING - no E-nonce");
5745 if (dpp_test
== DPP_TEST_E_NONCE_MISMATCH_CONF_RESP
) {
5746 wpa_printf(MSG_INFO
, "DPP: TESTING - E-nonce mismatch");
5747 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5748 wpabuf_put_le16(clear
, e_nonce_len
);
5749 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
- 1);
5750 wpabuf_put_u8(clear
, e_nonce
[e_nonce_len
- 1] ^ 0x01);
5753 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_CONF_RESP
) {
5754 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
5755 goto skip_wrapped_data
;
5757 #endif /* CONFIG_TESTING_OPTIONS */
5760 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
5761 wpabuf_put_le16(clear
, e_nonce_len
);
5762 wpabuf_put_data(clear
, e_nonce
, e_nonce_len
);
5764 #ifdef CONFIG_TESTING_OPTIONS
5766 if (dpp_test
== DPP_TEST_NO_CONFIG_OBJ_CONF_RESP
) {
5767 wpa_printf(MSG_INFO
, "DPP: TESTING - Config Object");
5768 goto skip_config_obj
;
5770 #endif /* CONFIG_TESTING_OPTIONS */
5773 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5774 wpabuf_put_le16(clear
, wpabuf_len(conf
));
5775 wpabuf_put_buf(clear
, conf
);
5777 if (auth
->peer_version
>= 2 && conf2
) {
5778 wpabuf_put_le16(clear
, DPP_ATTR_CONFIG_OBJ
);
5779 wpabuf_put_le16(clear
, wpabuf_len(conf2
));
5780 wpabuf_put_buf(clear
, conf2
);
5782 wpa_printf(MSG_DEBUG
,
5783 "DPP: Second Config Object available, but peer does not support more than one");
5786 wpabuf_put_le16(clear
, DPP_ATTR_ENVELOPED_DATA
);
5787 wpabuf_put_le16(clear
, wpabuf_len(env_data
));
5788 wpabuf_put_buf(clear
, env_data
);
5791 if (auth
->peer_version
>= 2 && auth
->send_conn_status
&&
5792 netrole
== DPP_NETROLE_STA
) {
5793 wpa_printf(MSG_DEBUG
, "DPP: sendConnStatus");
5794 wpabuf_put_le16(clear
, DPP_ATTR_SEND_CONN_STATUS
);
5795 wpabuf_put_le16(clear
, 0);
5798 #ifdef CONFIG_TESTING_OPTIONS
5800 if (dpp_test
== DPP_TEST_NO_STATUS_CONF_RESP
) {
5801 wpa_printf(MSG_INFO
, "DPP: TESTING - Status");
5804 if (dpp_test
== DPP_TEST_INVALID_STATUS_CONF_RESP
) {
5805 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
5808 #endif /* CONFIG_TESTING_OPTIONS */
5811 dpp_build_attr_status(msg
, status
);
5813 #ifdef CONFIG_TESTING_OPTIONS
5815 #endif /* CONFIG_TESTING_OPTIONS */
5817 addr
[0] = wpabuf_head(msg
);
5818 len
[0] = wpabuf_len(msg
);
5819 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
5821 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
5822 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5823 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5825 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
5826 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
5827 wpabuf_head(clear
), wpabuf_len(clear
),
5828 1, addr
, len
, wrapped
) < 0)
5830 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5831 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
5833 #ifdef CONFIG_TESTING_OPTIONS
5834 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP
) {
5835 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
5836 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
5839 #endif /* CONFIG_TESTING_OPTIONS */
5841 wpa_hexdump_buf(MSG_DEBUG
,
5842 "DPP: Configuration Response attributes", msg
);
5844 wpabuf_clear_free(conf
);
5845 wpabuf_clear_free(conf2
);
5846 wpabuf_clear_free(env_data
);
5847 wpabuf_clear_free(clear
);
5858 dpp_conf_req_rx(struct dpp_authentication
*auth
, const u8
*attr_start
,
5861 const u8
*wrapped_data
, *e_nonce
, *config_attr
;
5862 u16 wrapped_data_len
, e_nonce_len
, config_attr_len
;
5863 u8
*unwrapped
= NULL
;
5864 size_t unwrapped_len
= 0;
5865 struct wpabuf
*resp
= NULL
;
5866 struct json_token
*root
= NULL
, *token
;
5867 enum dpp_netrole netrole
;
5869 #ifdef CONFIG_TESTING_OPTIONS
5870 if (dpp_test
== DPP_TEST_STOP_AT_CONF_REQ
) {
5871 wpa_printf(MSG_INFO
,
5872 "DPP: TESTING - stop at Config Request");
5875 #endif /* CONFIG_TESTING_OPTIONS */
5877 if (dpp_check_attrs(attr_start
, attr_len
) < 0) {
5878 dpp_auth_fail(auth
, "Invalid attribute in config request");
5882 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
5884 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
5886 "Missing or invalid required Wrapped Data attribute");
5890 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
5891 wrapped_data
, wrapped_data_len
);
5892 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
5893 unwrapped
= os_malloc(unwrapped_len
);
5896 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
5897 wrapped_data
, wrapped_data_len
,
5898 0, NULL
, NULL
, unwrapped
) < 0) {
5899 dpp_auth_fail(auth
, "AES-SIV decryption failed");
5902 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
5903 unwrapped
, unwrapped_len
);
5905 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
5906 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
5910 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
5911 DPP_ATTR_ENROLLEE_NONCE
,
5913 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
5915 "Missing or invalid Enrollee Nonce attribute");
5918 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
5919 os_memcpy(auth
->e_nonce
, e_nonce
, e_nonce_len
);
5921 config_attr
= dpp_get_attr(unwrapped
, unwrapped_len
,
5922 DPP_ATTR_CONFIG_ATTR_OBJ
,
5926 "Missing or invalid Config Attributes attribute");
5929 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Config Attributes",
5930 config_attr
, config_attr_len
);
5932 root
= json_parse((const char *) config_attr
, config_attr_len
);
5934 dpp_auth_fail(auth
, "Could not parse Config Attributes");
5938 token
= json_get_member(root
, "name");
5939 if (!token
|| token
->type
!= JSON_STRING
) {
5940 dpp_auth_fail(auth
, "No Config Attributes - name");
5943 wpa_printf(MSG_DEBUG
, "DPP: Enrollee name = '%s'", token
->string
);
5945 token
= json_get_member(root
, "wi-fi_tech");
5946 if (!token
|| token
->type
!= JSON_STRING
) {
5947 dpp_auth_fail(auth
, "No Config Attributes - wi-fi_tech");
5950 wpa_printf(MSG_DEBUG
, "DPP: wi-fi_tech = '%s'", token
->string
);
5951 if (os_strcmp(token
->string
, "infra") != 0) {
5952 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech '%s'",
5954 dpp_auth_fail(auth
, "Unsupported wi-fi_tech");
5958 token
= json_get_member(root
, "netRole");
5959 if (!token
|| token
->type
!= JSON_STRING
) {
5960 dpp_auth_fail(auth
, "No Config Attributes - netRole");
5963 wpa_printf(MSG_DEBUG
, "DPP: netRole = '%s'", token
->string
);
5964 if (os_strcmp(token
->string
, "sta") == 0) {
5965 netrole
= DPP_NETROLE_STA
;
5966 } else if (os_strcmp(token
->string
, "ap") == 0) {
5967 netrole
= DPP_NETROLE_AP
;
5968 } else if (os_strcmp(token
->string
, "configurator") == 0) {
5969 netrole
= DPP_NETROLE_CONFIGURATOR
;
5971 wpa_printf(MSG_DEBUG
, "DPP: Unsupported netRole '%s'",
5973 dpp_auth_fail(auth
, "Unsupported netRole");
5977 token
= json_get_member(root
, "mudurl");
5978 if (token
&& token
->type
== JSON_STRING
)
5979 wpa_printf(MSG_DEBUG
, "DPP: mudurl = '%s'", token
->string
);
5981 token
= json_get_member(root
, "bandSupport");
5982 if (token
&& token
->type
== JSON_ARRAY
) {
5983 wpa_printf(MSG_DEBUG
, "DPP: bandSupport");
5984 token
= token
->child
;
5986 if (token
->type
!= JSON_NUMBER
)
5987 wpa_printf(MSG_DEBUG
,
5988 "DPP: Invalid bandSupport array member type");
5990 wpa_printf(MSG_DEBUG
,
5991 "DPP: Supported global operating class: %d",
5993 token
= token
->sibling
;
5997 resp
= dpp_build_conf_resp(auth
, e_nonce
, e_nonce_len
, netrole
);
6006 static struct wpabuf
*
6007 dpp_parse_jws_prot_hdr(const struct dpp_curve_params
*curve
,
6008 const u8
*prot_hdr
, u16 prot_hdr_len
,
6009 const EVP_MD
**ret_md
)
6011 struct json_token
*root
, *token
;
6012 struct wpabuf
*kid
= NULL
;
6014 root
= json_parse((const char *) prot_hdr
, prot_hdr_len
);
6016 wpa_printf(MSG_DEBUG
,
6017 "DPP: JSON parsing failed for JWS Protected Header");
6021 if (root
->type
!= JSON_OBJECT
) {
6022 wpa_printf(MSG_DEBUG
,
6023 "DPP: JWS Protected Header root is not an object");
6027 token
= json_get_member(root
, "typ");
6028 if (!token
|| token
->type
!= JSON_STRING
) {
6029 wpa_printf(MSG_DEBUG
, "DPP: No typ string value found");
6032 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header typ=%s",
6034 if (os_strcmp(token
->string
, "dppCon") != 0) {
6035 wpa_printf(MSG_DEBUG
,
6036 "DPP: Unsupported JWS Protected Header typ=%s",
6041 token
= json_get_member(root
, "alg");
6042 if (!token
|| token
->type
!= JSON_STRING
) {
6043 wpa_printf(MSG_DEBUG
, "DPP: No alg string value found");
6046 wpa_printf(MSG_DEBUG
, "DPP: JWS Protected Header alg=%s",
6048 if (os_strcmp(token
->string
, curve
->jws_alg
) != 0) {
6049 wpa_printf(MSG_DEBUG
,
6050 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)",
6051 token
->string
, curve
->jws_alg
);
6054 if (os_strcmp(token
->string
, "ES256") == 0 ||
6055 os_strcmp(token
->string
, "BS256") == 0)
6056 *ret_md
= EVP_sha256();
6057 else if (os_strcmp(token
->string
, "ES384") == 0 ||
6058 os_strcmp(token
->string
, "BS384") == 0)
6059 *ret_md
= EVP_sha384();
6060 else if (os_strcmp(token
->string
, "ES512") == 0 ||
6061 os_strcmp(token
->string
, "BS512") == 0)
6062 *ret_md
= EVP_sha512();
6066 wpa_printf(MSG_DEBUG
,
6067 "DPP: Unsupported JWS Protected Header alg=%s",
6072 kid
= json_get_member_base64url(root
, "kid");
6074 wpa_printf(MSG_DEBUG
, "DPP: No kid string value found");
6077 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWS Protected Header kid (decoded)",
6086 static int dpp_parse_cred_legacy(struct dpp_config_obj
*conf
,
6087 struct json_token
*cred
)
6089 struct json_token
*pass
, *psk_hex
;
6091 wpa_printf(MSG_DEBUG
, "DPP: Legacy akm=psk credential");
6093 pass
= json_get_member(cred
, "pass");
6094 psk_hex
= json_get_member(cred
, "psk_hex");
6096 if (pass
&& pass
->type
== JSON_STRING
) {
6097 size_t len
= os_strlen(pass
->string
);
6099 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: Legacy passphrase",
6101 if (len
< 8 || len
> 63)
6103 os_strlcpy(conf
->passphrase
, pass
->string
,
6104 sizeof(conf
->passphrase
));
6105 } else if (psk_hex
&& psk_hex
->type
== JSON_STRING
) {
6106 if (dpp_akm_sae(conf
->akm
) && !dpp_akm_psk(conf
->akm
)) {
6107 wpa_printf(MSG_DEBUG
,
6108 "DPP: Unexpected psk_hex with akm=sae");
6111 if (os_strlen(psk_hex
->string
) != PMK_LEN
* 2 ||
6112 hexstr2bin(psk_hex
->string
, conf
->psk
, PMK_LEN
) < 0) {
6113 wpa_printf(MSG_DEBUG
, "DPP: Invalid psk_hex encoding");
6116 wpa_hexdump_key(MSG_DEBUG
, "DPP: Legacy PSK",
6117 conf
->psk
, PMK_LEN
);
6120 wpa_printf(MSG_DEBUG
, "DPP: No pass or psk_hex strings found");
6124 if (dpp_akm_sae(conf
->akm
) && !conf
->passphrase
[0]) {
6125 wpa_printf(MSG_DEBUG
, "DPP: No pass for sae found");
6133 static EVP_PKEY
* dpp_parse_jwk(struct json_token
*jwk
,
6134 const struct dpp_curve_params
**key_curve
)
6136 struct json_token
*token
;
6137 const struct dpp_curve_params
*curve
;
6138 struct wpabuf
*x
= NULL
, *y
= NULL
;
6140 EVP_PKEY
*pkey
= NULL
;
6142 token
= json_get_member(jwk
, "kty");
6143 if (!token
|| token
->type
!= JSON_STRING
) {
6144 wpa_printf(MSG_DEBUG
, "DPP: No kty in JWK");
6147 if (os_strcmp(token
->string
, "EC") != 0) {
6148 wpa_printf(MSG_DEBUG
, "DPP: Unexpected JWK kty '%s'",
6153 token
= json_get_member(jwk
, "crv");
6154 if (!token
|| token
->type
!= JSON_STRING
) {
6155 wpa_printf(MSG_DEBUG
, "DPP: No crv in JWK");
6158 curve
= dpp_get_curve_jwk_crv(token
->string
);
6160 wpa_printf(MSG_DEBUG
, "DPP: Unsupported JWK crv '%s'",
6165 x
= json_get_member_base64url(jwk
, "x");
6167 wpa_printf(MSG_DEBUG
, "DPP: No x in JWK");
6170 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK x", x
);
6171 if (wpabuf_len(x
) != curve
->prime_len
) {
6172 wpa_printf(MSG_DEBUG
,
6173 "DPP: Unexpected JWK x length %u (expected %u for curve %s)",
6174 (unsigned int) wpabuf_len(x
),
6175 (unsigned int) curve
->prime_len
, curve
->name
);
6179 y
= json_get_member_base64url(jwk
, "y");
6181 wpa_printf(MSG_DEBUG
, "DPP: No y in JWK");
6184 wpa_hexdump_buf(MSG_DEBUG
, "DPP: JWK y", y
);
6185 if (wpabuf_len(y
) != curve
->prime_len
) {
6186 wpa_printf(MSG_DEBUG
,
6187 "DPP: Unexpected JWK y length %u (expected %u for curve %s)",
6188 (unsigned int) wpabuf_len(y
),
6189 (unsigned int) curve
->prime_len
, curve
->name
);
6193 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
6195 wpa_printf(MSG_DEBUG
, "DPP: Could not prepare group for JWK");
6199 pkey
= dpp_set_pubkey_point_group(group
, wpabuf_head(x
), wpabuf_head(y
),
6201 EC_GROUP_free(group
);
6212 int dpp_key_expired(const char *timestamp
, os_time_t
*expiry
)
6215 unsigned int year
, month
, day
, hour
, min
, sec
;
6219 /* ISO 8601 date and time:
6221 * YYYY-MM-DDTHH:MM:SSZ
6222 * YYYY-MM-DDTHH:MM:SS+03:00
6224 if (os_strlen(timestamp
) < 19) {
6225 wpa_printf(MSG_DEBUG
,
6226 "DPP: Too short timestamp - assume expired key");
6229 if (sscanf(timestamp
, "%04u-%02u-%02uT%02u:%02u:%02u",
6230 &year
, &month
, &day
, &hour
, &min
, &sec
) != 6) {
6231 wpa_printf(MSG_DEBUG
,
6232 "DPP: Failed to parse expiration day - assume expired key");
6236 if (os_mktime(year
, month
, day
, hour
, min
, sec
, &utime
) < 0) {
6237 wpa_printf(MSG_DEBUG
,
6238 "DPP: Invalid date/time information - assume expired key");
6242 pos
= timestamp
+ 19;
6243 if (*pos
== 'Z' || *pos
== '\0') {
6244 /* In UTC - no need to adjust */
6245 } else if (*pos
== '-' || *pos
== '+') {
6248 /* Adjust local time to UTC */
6249 items
= sscanf(pos
+ 1, "%02u:%02u", &hour
, &min
);
6251 wpa_printf(MSG_DEBUG
,
6252 "DPP: Invalid time zone designator (%s) - assume expired key",
6257 utime
+= 3600 * hour
;
6259 utime
-= 3600 * hour
;
6267 wpa_printf(MSG_DEBUG
,
6268 "DPP: Invalid time zone designator (%s) - assume expired key",
6275 if (os_get_time(&now
) < 0) {
6276 wpa_printf(MSG_DEBUG
,
6277 "DPP: Cannot get current time - assume expired key");
6281 if (now
.sec
> utime
) {
6282 wpa_printf(MSG_DEBUG
, "DPP: Key has expired (%lu < %lu)",
6291 static int dpp_parse_connector(struct dpp_authentication
*auth
,
6292 struct dpp_config_obj
*conf
,
6293 const unsigned char *payload
,
6296 struct json_token
*root
, *groups
, *netkey
, *token
;
6298 EVP_PKEY
*key
= NULL
;
6299 const struct dpp_curve_params
*curve
;
6300 unsigned int rules
= 0;
6302 root
= json_parse((const char *) payload
, payload_len
);
6304 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
6308 groups
= json_get_member(root
, "groups");
6309 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
6310 wpa_printf(MSG_DEBUG
, "DPP: No groups array found");
6313 for (token
= groups
->child
; token
; token
= token
->sibling
) {
6314 struct json_token
*id
, *role
;
6316 id
= json_get_member(token
, "groupId");
6317 if (!id
|| id
->type
!= JSON_STRING
) {
6318 wpa_printf(MSG_DEBUG
, "DPP: Missing groupId string");
6322 role
= json_get_member(token
, "netRole");
6323 if (!role
|| role
->type
!= JSON_STRING
) {
6324 wpa_printf(MSG_DEBUG
, "DPP: Missing netRole string");
6327 wpa_printf(MSG_DEBUG
,
6328 "DPP: connector group: groupId='%s' netRole='%s'",
6329 id
->string
, role
->string
);
6335 wpa_printf(MSG_DEBUG
,
6336 "DPP: Connector includes no groups");
6340 token
= json_get_member(root
, "expiry");
6341 if (!token
|| token
->type
!= JSON_STRING
) {
6342 wpa_printf(MSG_DEBUG
,
6343 "DPP: No expiry string found - connector does not expire");
6345 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
6346 if (dpp_key_expired(token
->string
,
6347 &auth
->net_access_key_expiry
)) {
6348 wpa_printf(MSG_DEBUG
,
6349 "DPP: Connector (netAccessKey) has expired");
6354 netkey
= json_get_member(root
, "netAccessKey");
6355 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
6356 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
6360 key
= dpp_parse_jwk(netkey
, &curve
);
6363 dpp_debug_print_key("DPP: Received netAccessKey", key
);
6365 if (EVP_PKEY_cmp(key
, auth
->own_protocol_key
) != 1) {
6366 wpa_printf(MSG_DEBUG
,
6367 "DPP: netAccessKey in connector does not match own protocol key");
6368 #ifdef CONFIG_TESTING_OPTIONS
6369 if (auth
->ignore_netaccesskey_mismatch
) {
6370 wpa_printf(MSG_DEBUG
,
6371 "DPP: TESTING - skip netAccessKey mismatch");
6375 #else /* CONFIG_TESTING_OPTIONS */
6377 #endif /* CONFIG_TESTING_OPTIONS */
6388 static int dpp_check_pubkey_match(EVP_PKEY
*pub
, struct wpabuf
*r_hash
)
6390 struct wpabuf
*uncomp
;
6392 u8 hash
[SHA256_MAC_LEN
];
6396 if (wpabuf_len(r_hash
) != SHA256_MAC_LEN
)
6398 uncomp
= dpp_get_pubkey_point(pub
, 1);
6401 addr
[0] = wpabuf_head(uncomp
);
6402 len
[0] = wpabuf_len(uncomp
);
6403 wpa_hexdump(MSG_DEBUG
, "DPP: Uncompressed public key",
6405 res
= sha256_vector(1, addr
, len
, hash
);
6406 wpabuf_free(uncomp
);
6409 if (os_memcmp(hash
, wpabuf_head(r_hash
), SHA256_MAC_LEN
) != 0) {
6410 wpa_printf(MSG_DEBUG
,
6411 "DPP: Received hash value does not match calculated public key hash value");
6412 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated hash",
6413 hash
, SHA256_MAC_LEN
);
6420 static void dpp_copy_csign(struct dpp_config_obj
*conf
, EVP_PKEY
*csign
)
6422 unsigned char *der
= NULL
;
6425 der_len
= i2d_PUBKEY(csign
, &der
);
6428 wpabuf_free(conf
->c_sign_key
);
6429 conf
->c_sign_key
= wpabuf_alloc_copy(der
, der_len
);
6434 static void dpp_copy_netaccesskey(struct dpp_authentication
*auth
,
6435 struct dpp_config_obj
*conf
)
6437 unsigned char *der
= NULL
;
6441 eckey
= EVP_PKEY_get1_EC_KEY(auth
->own_protocol_key
);
6445 der_len
= i2d_ECPrivateKey(eckey
, &der
);
6450 wpabuf_free(auth
->net_access_key
);
6451 auth
->net_access_key
= wpabuf_alloc_copy(der
, der_len
);
6457 struct dpp_signed_connector_info
{
6458 unsigned char *payload
;
6462 static enum dpp_status_error
6463 dpp_process_signed_connector(struct dpp_signed_connector_info
*info
,
6464 EVP_PKEY
*csign_pub
, const char *connector
)
6466 enum dpp_status_error ret
= 255;
6467 const char *pos
, *end
, *signed_start
, *signed_end
;
6468 struct wpabuf
*kid
= NULL
;
6469 unsigned char *prot_hdr
= NULL
, *signature
= NULL
;
6470 size_t prot_hdr_len
= 0, signature_len
= 0;
6471 const EVP_MD
*sign_md
= NULL
;
6472 unsigned char *der
= NULL
;
6475 EVP_MD_CTX
*md_ctx
= NULL
;
6476 ECDSA_SIG
*sig
= NULL
;
6477 BIGNUM
*r
= NULL
, *s
= NULL
;
6478 const struct dpp_curve_params
*curve
;
6480 const EC_GROUP
*group
;
6483 eckey
= EVP_PKEY_get1_EC_KEY(csign_pub
);
6486 group
= EC_KEY_get0_group(eckey
);
6489 nid
= EC_GROUP_get_curve_name(group
);
6490 curve
= dpp_get_curve_nid(nid
);
6493 wpa_printf(MSG_DEBUG
, "DPP: C-sign-key group: %s", curve
->jwk_crv
);
6494 os_memset(info
, 0, sizeof(*info
));
6496 signed_start
= pos
= connector
;
6497 end
= os_strchr(pos
, '.');
6499 wpa_printf(MSG_DEBUG
, "DPP: Missing dot(1) in signedConnector");
6500 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6503 prot_hdr
= base64_url_decode(pos
, end
- pos
, &prot_hdr_len
);
6505 wpa_printf(MSG_DEBUG
,
6506 "DPP: Failed to base64url decode signedConnector JWS Protected Header");
6507 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6510 wpa_hexdump_ascii(MSG_DEBUG
,
6511 "DPP: signedConnector - JWS Protected Header",
6512 prot_hdr
, prot_hdr_len
);
6513 kid
= dpp_parse_jws_prot_hdr(curve
, prot_hdr
, prot_hdr_len
, &sign_md
);
6515 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6518 if (wpabuf_len(kid
) != SHA256_MAC_LEN
) {
6519 wpa_printf(MSG_DEBUG
,
6520 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)",
6521 (unsigned int) wpabuf_len(kid
), SHA256_MAC_LEN
);
6522 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6527 end
= os_strchr(pos
, '.');
6529 wpa_printf(MSG_DEBUG
,
6530 "DPP: Missing dot(2) in signedConnector");
6531 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6534 signed_end
= end
- 1;
6535 info
->payload
= base64_url_decode(pos
, end
- pos
, &info
->payload_len
);
6536 if (!info
->payload
) {
6537 wpa_printf(MSG_DEBUG
,
6538 "DPP: Failed to base64url decode signedConnector JWS Payload");
6539 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6542 wpa_hexdump_ascii(MSG_DEBUG
,
6543 "DPP: signedConnector - JWS Payload",
6544 info
->payload
, info
->payload_len
);
6546 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
6548 wpa_printf(MSG_DEBUG
,
6549 "DPP: Failed to base64url decode signedConnector signature");
6550 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6553 wpa_hexdump(MSG_DEBUG
, "DPP: signedConnector - signature",
6554 signature
, signature_len
);
6556 if (dpp_check_pubkey_match(csign_pub
, kid
) < 0) {
6557 ret
= DPP_STATUS_NO_MATCH
;
6561 if (signature_len
& 0x01) {
6562 wpa_printf(MSG_DEBUG
,
6563 "DPP: Unexpected signedConnector signature length (%d)",
6564 (int) signature_len
);
6565 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6569 /* JWS Signature encodes the signature (r,s) as two octet strings. Need
6570 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
6571 r
= BN_bin2bn(signature
, signature_len
/ 2, NULL
);
6572 s
= BN_bin2bn(signature
+ signature_len
/ 2, signature_len
/ 2, NULL
);
6573 sig
= ECDSA_SIG_new();
6574 if (!r
|| !s
|| !sig
|| ECDSA_SIG_set0(sig
, r
, s
) != 1)
6579 der_len
= i2d_ECDSA_SIG(sig
, &der
);
6581 wpa_printf(MSG_DEBUG
, "DPP: Could not DER encode signature");
6584 wpa_hexdump(MSG_DEBUG
, "DPP: DER encoded signature", der
, der_len
);
6585 md_ctx
= EVP_MD_CTX_create();
6590 if (EVP_DigestVerifyInit(md_ctx
, NULL
, sign_md
, NULL
, csign_pub
) != 1) {
6591 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyInit failed: %s",
6592 ERR_error_string(ERR_get_error(), NULL
));
6595 if (EVP_DigestVerifyUpdate(md_ctx
, signed_start
,
6596 signed_end
- signed_start
+ 1) != 1) {
6597 wpa_printf(MSG_DEBUG
, "DPP: EVP_DigestVerifyUpdate failed: %s",
6598 ERR_error_string(ERR_get_error(), NULL
));
6601 res
= EVP_DigestVerifyFinal(md_ctx
, der
, der_len
);
6603 wpa_printf(MSG_DEBUG
,
6604 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
6605 res
, ERR_error_string(ERR_get_error(), NULL
));
6606 ret
= DPP_STATUS_INVALID_CONNECTOR
;
6610 ret
= DPP_STATUS_OK
;
6613 EVP_MD_CTX_destroy(md_ctx
);
6617 ECDSA_SIG_free(sig
);
6625 static int dpp_parse_cred_dpp(struct dpp_authentication
*auth
,
6626 struct dpp_config_obj
*conf
,
6627 struct json_token
*cred
)
6629 struct dpp_signed_connector_info info
;
6630 struct json_token
*token
, *csign
;
6632 EVP_PKEY
*csign_pub
= NULL
;
6633 const struct dpp_curve_params
*key_curve
= NULL
;
6634 const char *signed_connector
;
6636 os_memset(&info
, 0, sizeof(info
));
6638 if (dpp_akm_psk(conf
->akm
) || dpp_akm_sae(conf
->akm
)) {
6639 wpa_printf(MSG_DEBUG
,
6640 "DPP: Legacy credential included in Connector credential");
6641 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6645 wpa_printf(MSG_DEBUG
, "DPP: Connector credential");
6647 csign
= json_get_member(cred
, "csign");
6648 if (!csign
|| csign
->type
!= JSON_OBJECT
) {
6649 wpa_printf(MSG_DEBUG
, "DPP: No csign JWK in JSON");
6653 csign_pub
= dpp_parse_jwk(csign
, &key_curve
);
6655 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse csign JWK");
6658 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub
);
6660 token
= json_get_member(cred
, "signedConnector");
6661 if (!token
|| token
->type
!= JSON_STRING
) {
6662 wpa_printf(MSG_DEBUG
, "DPP: No signedConnector string found");
6665 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: signedConnector",
6666 token
->string
, os_strlen(token
->string
));
6667 signed_connector
= token
->string
;
6669 if (os_strchr(signed_connector
, '"') ||
6670 os_strchr(signed_connector
, '\n')) {
6671 wpa_printf(MSG_DEBUG
,
6672 "DPP: Unexpected character in signedConnector");
6676 if (dpp_process_signed_connector(&info
, csign_pub
,
6677 signed_connector
) != DPP_STATUS_OK
)
6680 if (dpp_parse_connector(auth
, conf
,
6681 info
.payload
, info
.payload_len
) < 0) {
6682 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse connector");
6686 os_free(conf
->connector
);
6687 conf
->connector
= os_strdup(signed_connector
);
6689 dpp_copy_csign(conf
, csign_pub
);
6690 dpp_copy_netaccesskey(auth
, conf
);
6694 EVP_PKEY_free(csign_pub
);
6695 os_free(info
.payload
);
6700 const char * dpp_akm_str(enum dpp_akm akm
)
6709 case DPP_AKM_PSK_SAE
:
6711 case DPP_AKM_SAE_DPP
:
6713 case DPP_AKM_PSK_SAE_DPP
:
6714 return "dpp+psk+sae";
6721 const char * dpp_akm_selector_str(enum dpp_akm akm
)
6727 return "000FAC02+000FAC06";
6730 case DPP_AKM_PSK_SAE
:
6731 return "000FAC02+000FAC06+000FAC08";
6732 case DPP_AKM_SAE_DPP
:
6733 return "506F9A02+000FAC08";
6734 case DPP_AKM_PSK_SAE_DPP
:
6735 return "506F9A02+000FAC08+000FAC02+000FAC06";
6742 static enum dpp_akm
dpp_akm_from_str(const char *akm
)
6745 int dpp
= 0, psk
= 0, sae
= 0;
6747 if (os_strcmp(akm
, "psk") == 0)
6749 if (os_strcmp(akm
, "sae") == 0)
6751 if (os_strcmp(akm
, "psk+sae") == 0)
6752 return DPP_AKM_PSK_SAE
;
6753 if (os_strcmp(akm
, "dpp") == 0)
6755 if (os_strcmp(akm
, "dpp+sae") == 0)
6756 return DPP_AKM_SAE_DPP
;
6757 if (os_strcmp(akm
, "dpp+psk+sae") == 0)
6758 return DPP_AKM_PSK_SAE_DPP
;
6762 if (os_strlen(pos
) < 8)
6764 if (os_strncasecmp(pos
, "506F9A02", 8) == 0)
6766 else if (os_strncasecmp(pos
, "000FAC02", 8) == 0)
6768 else if (os_strncasecmp(pos
, "000FAC06", 8) == 0)
6770 else if (os_strncasecmp(pos
, "000FAC08", 8) == 0)
6778 if (dpp
&& psk
&& sae
)
6779 return DPP_AKM_PSK_SAE_DPP
;
6781 return DPP_AKM_SAE_DPP
;
6785 return DPP_AKM_PSK_SAE
;
6791 return DPP_AKM_UNKNOWN
;
6795 static int dpp_parse_conf_obj(struct dpp_authentication
*auth
,
6796 const u8
*conf_obj
, u16 conf_obj_len
)
6799 struct json_token
*root
, *token
, *discovery
, *cred
;
6800 struct dpp_config_obj
*conf
;
6801 struct wpabuf
*ssid64
= NULL
;
6803 root
= json_parse((const char *) conf_obj
, conf_obj_len
);
6806 if (root
->type
!= JSON_OBJECT
) {
6807 dpp_auth_fail(auth
, "JSON root is not an object");
6811 token
= json_get_member(root
, "wi-fi_tech");
6812 if (!token
|| token
->type
!= JSON_STRING
) {
6813 dpp_auth_fail(auth
, "No wi-fi_tech string value found");
6816 if (os_strcmp(token
->string
, "infra") != 0) {
6817 wpa_printf(MSG_DEBUG
, "DPP: Unsupported wi-fi_tech value: '%s'",
6819 dpp_auth_fail(auth
, "Unsupported wi-fi_tech value");
6823 discovery
= json_get_member(root
, "discovery");
6824 if (!discovery
|| discovery
->type
!= JSON_OBJECT
) {
6825 dpp_auth_fail(auth
, "No discovery object in JSON");
6829 ssid64
= json_get_member_base64url(discovery
, "ssid64");
6831 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid64",
6832 wpabuf_head(ssid64
), wpabuf_len(ssid64
));
6833 if (wpabuf_len(ssid64
) > SSID_MAX_LEN
) {
6834 dpp_auth_fail(auth
, "Too long discovery::ssid64 value");
6838 token
= json_get_member(discovery
, "ssid");
6839 if (!token
|| token
->type
!= JSON_STRING
) {
6841 "No discovery::ssid string value found");
6844 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: discovery::ssid",
6845 token
->string
, os_strlen(token
->string
));
6846 if (os_strlen(token
->string
) > SSID_MAX_LEN
) {
6848 "Too long discovery::ssid string value");
6853 if (auth
->num_conf_obj
== DPP_MAX_CONF_OBJ
) {
6854 wpa_printf(MSG_DEBUG
,
6855 "DPP: No room for this many Config Objects - ignore this one");
6859 conf
= &auth
->conf_obj
[auth
->num_conf_obj
++];
6862 conf
->ssid_len
= wpabuf_len(ssid64
);
6863 os_memcpy(conf
->ssid
, wpabuf_head(ssid64
), conf
->ssid_len
);
6865 conf
->ssid_len
= os_strlen(token
->string
);
6866 os_memcpy(conf
->ssid
, token
->string
, conf
->ssid_len
);
6869 token
= json_get_member(discovery
, "ssid_charset");
6870 if (token
&& token
->type
== JSON_NUMBER
) {
6871 conf
->ssid_charset
= token
->number
;
6872 wpa_printf(MSG_DEBUG
, "DPP: ssid_charset=%d",
6873 conf
->ssid_charset
);
6876 cred
= json_get_member(root
, "cred");
6877 if (!cred
|| cred
->type
!= JSON_OBJECT
) {
6878 dpp_auth_fail(auth
, "No cred object in JSON");
6882 token
= json_get_member(cred
, "akm");
6883 if (!token
|| token
->type
!= JSON_STRING
) {
6884 dpp_auth_fail(auth
, "No cred::akm string value found");
6887 conf
->akm
= dpp_akm_from_str(token
->string
);
6889 if (dpp_akm_legacy(conf
->akm
)) {
6890 if (dpp_parse_cred_legacy(conf
, cred
) < 0)
6892 } else if (dpp_akm_dpp(conf
->akm
)) {
6893 if (dpp_parse_cred_dpp(auth
, conf
, cred
) < 0)
6896 wpa_printf(MSG_DEBUG
, "DPP: Unsupported akm: %s",
6898 dpp_auth_fail(auth
, "Unsupported akm");
6902 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing completed successfully");
6905 wpabuf_free(ssid64
);
6913 struct dpp_enveloped_data
{
6915 size_t enc_cont_len
;
6919 size_t pbkdf2_key_len
;
6920 size_t prf_hash_len
;
6924 static int dpp_parse_recipient_infos(const u8
*pos
, size_t len
,
6925 struct dpp_enveloped_data
*data
)
6927 struct asn1_hdr hdr
;
6928 const u8
*end
= pos
+ len
;
6929 const u8
*next
, *e_end
;
6930 struct asn1_oid oid
;
6935 wpa_hexdump(MSG_MSGDUMP
, "DPP: RecipientInfos", pos
, len
);
6938 * RecipientInfo ::= CHOICE {
6939 * ktri KeyTransRecipientInfo,
6940 * kari [1] KeyAgreeRecipientInfo,
6941 * kekri [2] KEKRecipientInfo,
6942 * pwri [3] PasswordRecipientInfo,
6943 * ori [4] OtherRecipientInfo}
6945 * Shall always use the pwri CHOICE.
6948 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6949 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 3) {
6950 wpa_printf(MSG_DEBUG
,
6951 "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
6952 hdr
.class, hdr
.tag
);
6955 wpa_hexdump(MSG_MSGDUMP
, "DPP: PasswordRecipientInfo",
6956 hdr
.payload
, hdr
.length
);
6958 end
= pos
+ hdr
.length
;
6961 * PasswordRecipientInfo ::= SEQUENCE {
6962 * version CMSVersion,
6963 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
6964 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
6965 * encryptedKey EncryptedKey}
6967 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
6968 * parameters contains PBKDF2-params SEQUENCE.
6971 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
6975 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
6978 wpa_printf(MSG_DEBUG
, "DPP: pwri.version != 0");
6982 wpa_hexdump(MSG_MSGDUMP
, "DPP: Remaining PasswordRecipientInfo after version",
6985 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
6986 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
6987 wpa_printf(MSG_DEBUG
,
6988 "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
6989 hdr
.class, hdr
.tag
);
6993 e_end
= pos
+ hdr
.length
;
6995 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
6996 if (asn1_get_alg_id(pos
, e_end
- pos
, &oid
, ¶ms
, ¶ms_len
,
6999 if (!asn1_oid_equal(&oid
, &asn1_pbkdf2_oid
)) {
7002 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7003 wpa_printf(MSG_DEBUG
,
7004 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
7010 * PBKDF2-params ::= SEQUENCE {
7012 * specified OCTET STRING,
7013 * otherSource AlgorithmIdentifier}
7014 * iterationCount INTEGER (1..MAX),
7015 * keyLength INTEGER (1..MAX),
7016 * prf AlgorithmIdentifier}
7018 * salt is an 64 octet value, iterationCount is 1000, keyLength is based
7019 * on Configurator signing key length, prf is
7020 * id-hmacWithSHA{256,384,512} based on Configurator signing key.
7023 asn1_get_sequence(params
, params_len
, &hdr
, &e_end
) < 0)
7027 if (asn1_get_next(pos
, e_end
- pos
, &hdr
) < 0 ||
7028 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7029 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7030 wpa_printf(MSG_DEBUG
,
7031 "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
7032 hdr
.class, hdr
.tag
);
7035 wpa_hexdump(MSG_MSGDUMP
, "DPP: salt.specified",
7036 hdr
.payload
, hdr
.length
);
7037 if (hdr
.length
!= 64) {
7038 wpa_printf(MSG_DEBUG
, "DPP: Unexpected salt length %u",
7042 data
->salt
= hdr
.payload
;
7043 pos
= hdr
.payload
+ hdr
.length
;
7045 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7048 wpa_printf(MSG_DEBUG
, "DPP: Unexpected iterationCount %d", val
);
7052 if (asn1_get_integer(pos
, e_end
- pos
, &val
, &pos
) < 0)
7054 if (val
!= 32 && val
!= 48 && val
!= 64) {
7055 wpa_printf(MSG_DEBUG
, "DPP: Unexpected keyLength %d", val
);
7058 data
->pbkdf2_key_len
= val
;
7060 if (asn1_get_sequence(pos
, e_end
- pos
, &hdr
, NULL
) < 0 ||
7061 asn1_get_oid(hdr
.payload
, hdr
.length
, &oid
, &pos
) < 0) {
7062 wpa_printf(MSG_DEBUG
, "DPP: Could not parse prf");
7065 if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha256_oid
)) {
7066 data
->prf_hash_len
= 32;
7067 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha384_oid
)) {
7068 data
->prf_hash_len
= 48;
7069 } else if (asn1_oid_equal(&oid
, &asn1_pbkdf2_hmac_sha512_oid
)) {
7070 data
->prf_hash_len
= 64;
7074 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7075 wpa_printf(MSG_DEBUG
, "DPP: Unexpected PBKDF2-params.prf %s",
7082 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
7084 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
7086 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
7087 * id-alg-AES-SIV-CMAC-aed-512. */
7088 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7090 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7091 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7092 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7095 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7096 wpa_printf(MSG_DEBUG
,
7097 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
7103 * encryptedKey EncryptedKey
7105 * EncryptedKey ::= OCTET STRING
7107 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7108 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7109 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7110 wpa_printf(MSG_DEBUG
,
7111 "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
7112 hdr
.class, hdr
.tag
);
7115 wpa_hexdump(MSG_MSGDUMP
, "DPP: pwri.encryptedKey",
7116 hdr
.payload
, hdr
.length
);
7117 data
->enc_key
= hdr
.payload
;
7118 data
->enc_key_len
= hdr
.length
;
7124 static int dpp_parse_encrypted_content_info(const u8
*pos
, const u8
*end
,
7125 struct dpp_enveloped_data
*data
)
7127 struct asn1_hdr hdr
;
7128 struct asn1_oid oid
;
7131 * EncryptedContentInfo ::= SEQUENCE {
7132 * contentType ContentType,
7133 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
7134 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL}
7136 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7138 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContentInfo",
7139 hdr
.payload
, hdr
.length
);
7141 wpa_hexdump(MSG_DEBUG
,
7142 "DPP: Unexpected extra data after EncryptedContentInfo",
7150 /* ContentType ::= OBJECT IDENTIFIER */
7151 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0) {
7152 wpa_printf(MSG_DEBUG
, "DPP: Could not parse ContentType");
7155 if (!asn1_oid_equal(&oid
, &asn1_dpp_asymmetric_key_package_oid
)) {
7158 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7159 wpa_printf(MSG_DEBUG
, "DPP: Unexpected ContentType %s", buf
);
7163 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
7164 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, NULL
, NULL
, &pos
) < 0)
7166 if (!asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_256_oid
) &&
7167 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_384_oid
) &&
7168 !asn1_oid_equal(&oid
, &asn1_aes_siv_cmac_aead_512_oid
)) {
7171 asn1_oid_to_str(&oid
, buf
, sizeof(buf
));
7172 wpa_printf(MSG_DEBUG
,
7173 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
7177 /* ignore optional parameters */
7179 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
7180 * EncryptedContent ::= OCTET STRING */
7181 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7182 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7183 wpa_printf(MSG_DEBUG
,
7184 "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
7185 hdr
.class, hdr
.tag
);
7188 wpa_hexdump(MSG_MSGDUMP
, "DPP: EncryptedContent",
7189 hdr
.payload
, hdr
.length
);
7190 data
->enc_cont
= hdr
.payload
;
7191 data
->enc_cont_len
= hdr
.length
;
7196 static int dpp_parse_enveloped_data(const u8
*env_data
, size_t env_data_len
,
7197 struct dpp_enveloped_data
*data
)
7199 struct asn1_hdr hdr
;
7200 const u8
*pos
, *end
;
7203 os_memset(data
, 0, sizeof(*data
));
7206 * DPPEnvelopedData ::= EnvelopedData
7208 * EnvelopedData ::= SEQUENCE {
7209 * version CMSVersion,
7210 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
7211 * recipientInfos RecipientInfos,
7212 * encryptedContentInfo EncryptedContentInfo,
7213 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL}
7215 * CMSVersion ::= INTEGER
7217 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
7219 * For DPP, version is 3, both originatorInfo and
7220 * unprotectedAttrs are omitted, and recipientInfos contains a single
7223 if (asn1_get_sequence(env_data
, env_data_len
, &hdr
, &end
) < 0)
7226 if (end
< env_data
+ env_data_len
) {
7227 wpa_hexdump(MSG_DEBUG
,
7228 "DPP: Unexpected extra data after DPPEnvelopedData",
7229 end
, env_data
+ env_data_len
- end
);
7233 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7236 wpa_printf(MSG_DEBUG
, "DPP: EnvelopedData.version != 3");
7240 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7241 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7242 wpa_printf(MSG_DEBUG
,
7243 "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
7244 hdr
.class, hdr
.tag
);
7248 if (dpp_parse_recipient_infos(hdr
.payload
, hdr
.length
, data
) < 0)
7250 return dpp_parse_encrypted_content_info(hdr
.payload
+ hdr
.length
, end
,
7255 static struct dpp_asymmetric_key
*
7256 dpp_parse_one_asymmetric_key(const u8
*buf
, size_t len
)
7258 struct asn1_hdr hdr
;
7259 const u8
*pos
= buf
, *end
= buf
+ len
, *next
;
7263 struct asn1_oid oid
;
7265 struct dpp_asymmetric_key
*key
;
7268 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: OneAsymmetricKey", buf
, len
);
7270 key
= os_zalloc(sizeof(*key
));
7275 * OneAsymmetricKey ::= SEQUENCE {
7277 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
7278 * privateKey PrivateKey,
7279 * attributes [0] Attributes OPTIONAL,
7281 * [[2: publicKey [1] BIT STRING OPTIONAL ]],
7285 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &end
) < 0)
7289 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
7290 if (asn1_get_integer(pos
, end
- pos
, &val
, &pos
) < 0)
7293 wpa_printf(MSG_DEBUG
,
7294 "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
7299 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
7300 if (asn1_get_alg_id(pos
, end
- pos
, &oid
, ¶ms
, ¶ms_len
,
7303 if (!asn1_oid_equal(&oid
, &asn1_ec_public_key_oid
)) {
7304 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7305 wpa_printf(MSG_DEBUG
,
7306 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
7310 wpa_hexdump(MSG_MSGDUMP
, "DPP: PrivateKeyAlgorithmIdentifier params",
7311 params
, params_len
);
7313 * ECParameters ::= CHOICE {
7314 * namedCurve OBJECT IDENTIFIER
7315 * -- implicitCurve NULL
7316 * -- specifiedCurve SpecifiedECDomain}
7318 if (!params
|| asn1_get_oid(params
, params_len
, &oid
, &next
) < 0) {
7319 wpa_printf(MSG_DEBUG
,
7320 "DPP: Could not parse ECParameters.namedCurve");
7323 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7324 wpa_printf(MSG_MSGDUMP
, "DPP: namedCurve %s", txt
);
7325 /* Assume the curve is identified within ECPrivateKey, so that this
7326 * separate indication is not really needed. */
7329 * PrivateKey ::= OCTET STRING
7330 * (Contains DER encoding of ECPrivateKey)
7332 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7333 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7334 hdr
.tag
!= ASN1_TAG_OCTETSTRING
) {
7335 wpa_printf(MSG_DEBUG
,
7336 "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
7337 hdr
.class, hdr
.tag
);
7340 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: PrivateKey",
7341 hdr
.payload
, hdr
.length
);
7342 pos
= hdr
.payload
+ hdr
.length
;
7343 eckey
= d2i_ECPrivateKey(NULL
, &hdr
.payload
, hdr
.length
);
7345 wpa_printf(MSG_INFO
,
7346 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
7347 ERR_error_string(ERR_get_error(), NULL
));
7350 key
->csign
= EVP_PKEY_new();
7351 if (!key
->csign
|| EVP_PKEY_assign_EC_KEY(key
->csign
, eckey
) != 1) {
7355 if (wpa_debug_show_keys
)
7356 dpp_debug_print_key("DPP: Received c-sign-key", key
->csign
);
7359 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
7361 * Exactly one instance of type Attribute in OneAsymmetricKey.
7363 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7364 hdr
.class != ASN1_CLASS_CONTEXT_SPECIFIC
|| hdr
.tag
!= 0) {
7365 wpa_printf(MSG_DEBUG
,
7366 "DPP: Expected [0] Attributes - found class %d tag 0x%x",
7367 hdr
.class, hdr
.tag
);
7370 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: Attributes",
7371 hdr
.payload
, hdr
.length
);
7372 if (hdr
.payload
+ hdr
.length
< end
) {
7373 wpa_hexdump_key(MSG_MSGDUMP
,
7374 "DPP: Ignore additional data at the end of OneAsymmetricKey",
7375 hdr
.payload
+ hdr
.length
,
7376 end
- (hdr
.payload
+ hdr
.length
));
7379 end
= hdr
.payload
+ hdr
.length
;
7381 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7382 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7383 wpa_printf(MSG_DEBUG
,
7384 "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
7385 hdr
.class, hdr
.tag
);
7388 if (hdr
.payload
+ hdr
.length
< end
) {
7389 wpa_hexdump_key(MSG_MSGDUMP
,
7390 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
7391 hdr
.payload
+ hdr
.length
,
7392 end
- (hdr
.payload
+ hdr
.length
));
7395 end
= hdr
.payload
+ hdr
.length
;
7398 * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
7399 * aa-DPPConfigurationParameters,
7400 * ... -- For local profiles
7403 * aa-DPPConfigurationParameters ATTRIBUTE ::=
7404 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
7406 * Attribute ::= SEQUENCE {
7407 * type OBJECT IDENTIFIER,
7408 * values SET SIZE(1..MAX) OF Type
7410 * Exactly one instance of ATTRIBUTE in attrValues.
7412 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7415 wpa_hexdump_key(MSG_MSGDUMP
,
7416 "DPP: Ignore additional data at the end of ATTRIBUTE",
7422 if (asn1_get_oid(pos
, end
- pos
, &oid
, &pos
) < 0)
7424 if (!asn1_oid_equal(&oid
, &asn1_dpp_config_params_oid
)) {
7425 asn1_oid_to_str(&oid
, txt
, sizeof(txt
));
7426 wpa_printf(MSG_DEBUG
,
7427 "DPP: Unexpected Attribute identifier %s", txt
);
7431 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7432 hdr
.class != ASN1_CLASS_UNIVERSAL
|| hdr
.tag
!= ASN1_TAG_SET
) {
7433 wpa_printf(MSG_DEBUG
,
7434 "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
7435 hdr
.class, hdr
.tag
);
7439 end
= hdr
.payload
+ hdr
.length
;
7442 * DPPConfigurationParameters ::= SEQUENCE {
7443 * configurationTemplate UTF8String,
7444 * connectorTemplate UTF8String OPTIONAL}
7447 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPConfigurationParameters",
7449 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0)
7452 wpa_hexdump_key(MSG_MSGDUMP
,
7453 "DPP: Ignore additional data after DPPConfigurationParameters",
7459 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7460 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7461 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7462 wpa_printf(MSG_DEBUG
,
7463 "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
7464 hdr
.class, hdr
.tag
);
7467 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: configurationTemplate",
7468 hdr
.payload
, hdr
.length
);
7469 key
->config_template
= os_zalloc(hdr
.length
+ 1);
7470 if (!key
->config_template
)
7472 os_memcpy(key
->config_template
, hdr
.payload
, hdr
.length
);
7474 pos
= hdr
.payload
+ hdr
.length
;
7477 if (asn1_get_next(pos
, end
- pos
, &hdr
) < 0 ||
7478 hdr
.class != ASN1_CLASS_UNIVERSAL
||
7479 hdr
.tag
!= ASN1_TAG_UTF8STRING
) {
7480 wpa_printf(MSG_DEBUG
,
7481 "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
7482 hdr
.class, hdr
.tag
);
7485 wpa_hexdump_ascii_key(MSG_MSGDUMP
, "DPP: connectorTemplate",
7486 hdr
.payload
, hdr
.length
);
7487 key
->connector_template
= os_zalloc(hdr
.length
+ 1);
7488 if (!key
->connector_template
)
7490 os_memcpy(key
->connector_template
, hdr
.payload
, hdr
.length
);
7495 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse OneAsymmetricKey");
7496 dpp_free_asymmetric_key(key
);
7501 static struct dpp_asymmetric_key
*
7502 dpp_parse_dpp_asymmetric_key_package(const u8
*key_pkg
, size_t key_pkg_len
)
7504 struct asn1_hdr hdr
;
7505 const u8
*pos
= key_pkg
, *end
= key_pkg
+ key_pkg_len
;
7506 struct dpp_asymmetric_key
*first
= NULL
, *last
= NULL
, *key
;
7508 wpa_hexdump_key(MSG_MSGDUMP
, "DPP: DPPAsymmetricKeyPackage",
7509 key_pkg
, key_pkg_len
);
7512 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
7514 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
7517 if (asn1_get_sequence(pos
, end
- pos
, &hdr
, &pos
) < 0 ||
7518 !(key
= dpp_parse_one_asymmetric_key(hdr
.payload
,
7520 dpp_free_asymmetric_key(first
);
7535 static int dpp_conf_resp_env_data(struct dpp_authentication
*auth
,
7536 const u8
*env_data
, size_t env_data_len
)
7540 u8 kek
[DPP_MAX_HASH_LEN
];
7541 u8 cont_encr_key
[DPP_MAX_HASH_LEN
];
7542 size_t cont_encr_key_len
;
7546 struct dpp_enveloped_data data
;
7547 struct dpp_asymmetric_key
*keys
;
7549 wpa_hexdump(MSG_DEBUG
, "DPP: DPPEnvelopedData", env_data
, env_data_len
);
7551 if (dpp_parse_enveloped_data(env_data
, env_data_len
, &data
) < 0)
7554 /* TODO: For initial testing, use ke as the key. Replace this with a
7555 * new key once that has been defined. */
7557 key_len
= auth
->curve
->hash_len
;
7558 wpa_hexdump_key(MSG_DEBUG
, "DPP: PBKDF2 key", key
, key_len
);
7560 if (dpp_pbkdf2(data
.prf_hash_len
, key
, key_len
, data
.salt
, 64, 1000,
7561 kek
, data
.pbkdf2_key_len
)) {
7562 wpa_printf(MSG_DEBUG
, "DPP: PBKDF2 failed");
7565 wpa_hexdump_key(MSG_DEBUG
, "DPP: key-encryption key from PBKDF2",
7566 kek
, data
.pbkdf2_key_len
);
7568 if (data
.enc_key_len
< AES_BLOCK_SIZE
||
7569 data
.enc_key_len
> sizeof(cont_encr_key
) + AES_BLOCK_SIZE
) {
7570 wpa_printf(MSG_DEBUG
, "DPP: Invalid encryptedKey length");
7573 res
= aes_siv_decrypt(kek
, data
.pbkdf2_key_len
,
7574 data
.enc_key
, data
.enc_key_len
,
7575 0, NULL
, NULL
, cont_encr_key
);
7576 forced_memzero(kek
, data
.pbkdf2_key_len
);
7578 wpa_printf(MSG_DEBUG
,
7579 "DPP: AES-SIV decryption of encryptedKey failed");
7582 cont_encr_key_len
= data
.enc_key_len
- AES_BLOCK_SIZE
;
7583 wpa_hexdump_key(MSG_DEBUG
, "DPP: content-encryption key",
7584 cont_encr_key
, cont_encr_key_len
);
7586 if (data
.enc_cont_len
< AES_BLOCK_SIZE
)
7588 key_pkg_len
= data
.enc_cont_len
- AES_BLOCK_SIZE
;
7589 key_pkg
= os_malloc(key_pkg_len
);
7592 res
= aes_siv_decrypt(cont_encr_key
, cont_encr_key_len
,
7593 data
.enc_cont
, data
.enc_cont_len
,
7594 0, NULL
, NULL
, key_pkg
);
7595 forced_memzero(cont_encr_key
, cont_encr_key_len
);
7597 bin_clear_free(key_pkg
, key_pkg_len
);
7598 wpa_printf(MSG_DEBUG
,
7599 "DPP: AES-SIV decryption of encryptedContent failed");
7603 keys
= dpp_parse_dpp_asymmetric_key_package(key_pkg
, key_pkg_len
);
7604 bin_clear_free(key_pkg
, key_pkg_len
);
7605 dpp_free_asymmetric_key(auth
->conf_key_pkg
);
7606 auth
->conf_key_pkg
= keys
;
7608 return keys
!= NULL
;;
7611 #endif /* CONFIG_DPP2 */
7614 int dpp_conf_resp_rx(struct dpp_authentication
*auth
,
7615 const struct wpabuf
*resp
)
7617 const u8
*wrapped_data
, *e_nonce
, *status
, *conf_obj
;
7618 u16 wrapped_data_len
, e_nonce_len
, status_len
, conf_obj_len
;
7623 u8
*unwrapped
= NULL
;
7624 size_t unwrapped_len
= 0;
7627 auth
->conf_resp_status
= 255;
7629 if (dpp_check_attrs(wpabuf_head(resp
), wpabuf_len(resp
)) < 0) {
7630 dpp_auth_fail(auth
, "Invalid attribute in config response");
7634 wrapped_data
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7635 DPP_ATTR_WRAPPED_DATA
,
7637 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7639 "Missing or invalid required Wrapped Data attribute");
7643 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7644 wrapped_data
, wrapped_data_len
);
7645 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7646 unwrapped
= os_malloc(unwrapped_len
);
7650 addr
[0] = wpabuf_head(resp
);
7651 len
[0] = wrapped_data
- 4 - (const u8
*) wpabuf_head(resp
);
7652 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD", addr
[0], len
[0]);
7654 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7655 wrapped_data
, wrapped_data_len
,
7656 1, addr
, len
, unwrapped
) < 0) {
7657 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7660 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7661 unwrapped
, unwrapped_len
);
7663 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7664 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7668 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7669 DPP_ATTR_ENROLLEE_NONCE
,
7671 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7673 "Missing or invalid Enrollee Nonce attribute");
7676 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7677 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7678 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7682 status
= dpp_get_attr(wpabuf_head(resp
), wpabuf_len(resp
),
7683 DPP_ATTR_STATUS
, &status_len
);
7684 if (!status
|| status_len
< 1) {
7686 "Missing or invalid required DPP Status attribute");
7689 auth
->conf_resp_status
= status
[0];
7690 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7691 if (status
[0] != DPP_STATUS_OK
) {
7692 dpp_auth_fail(auth
, "Configurator rejected configuration");
7696 env_data
= dpp_get_attr(unwrapped
, unwrapped_len
,
7697 DPP_ATTR_ENVELOPED_DATA
, &env_data_len
);
7700 dpp_conf_resp_env_data(auth
, env_data
, env_data_len
) < 0)
7702 #endif /* CONFIG_DPP2 */
7704 conf_obj
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONFIG_OBJ
,
7706 if (!conf_obj
&& !env_data
) {
7708 "Missing required Configuration Object attribute");
7712 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: configurationObject JSON",
7713 conf_obj
, conf_obj_len
);
7714 if (dpp_parse_conf_obj(auth
, conf_obj
, conf_obj_len
) < 0)
7716 conf_obj
= dpp_get_attr_next(conf_obj
, unwrapped
, unwrapped_len
,
7717 DPP_ATTR_CONFIG_OBJ
,
7722 status
= dpp_get_attr(unwrapped
, unwrapped_len
,
7723 DPP_ATTR_SEND_CONN_STATUS
, &status_len
);
7725 wpa_printf(MSG_DEBUG
,
7726 "DPP: Configurator requested connection status result");
7727 auth
->conn_status_requested
= 1;
7729 #endif /* CONFIG_DPP2 */
7741 enum dpp_status_error
dpp_conf_result_rx(struct dpp_authentication
*auth
,
7743 const u8
*attr_start
, size_t attr_len
)
7745 const u8
*wrapped_data
, *status
, *e_nonce
;
7746 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7749 u8
*unwrapped
= NULL
;
7750 size_t unwrapped_len
= 0;
7751 enum dpp_status_error ret
= 256;
7753 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7755 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7757 "Missing or invalid required Wrapped Data attribute");
7760 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7761 wrapped_data
, wrapped_data_len
);
7763 attr_len
= wrapped_data
- 4 - attr_start
;
7766 len
[0] = DPP_HDR_LEN
;
7767 addr
[1] = attr_start
;
7769 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7770 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7771 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7772 wrapped_data
, wrapped_data_len
);
7773 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7774 unwrapped
= os_malloc(unwrapped_len
);
7777 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7778 wrapped_data
, wrapped_data_len
,
7779 2, addr
, len
, unwrapped
) < 0) {
7780 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7783 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7784 unwrapped
, unwrapped_len
);
7786 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7787 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7791 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7792 DPP_ATTR_ENROLLEE_NONCE
,
7794 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7796 "Missing or invalid Enrollee Nonce attribute");
7799 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7800 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7801 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7802 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7803 auth
->e_nonce
, e_nonce_len
);
7807 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_STATUS
,
7809 if (!status
|| status_len
< 1) {
7811 "Missing or invalid required DPP Status attribute");
7814 wpa_printf(MSG_DEBUG
, "DPP: Status %u", status
[0]);
7818 bin_clear_free(unwrapped
, unwrapped_len
);
7823 struct wpabuf
* dpp_build_conf_result(struct dpp_authentication
*auth
,
7824 enum dpp_status_error status
)
7826 struct wpabuf
*msg
, *clear
;
7827 size_t nonce_len
, clear_len
, attr_len
;
7832 nonce_len
= auth
->curve
->nonce_len
;
7833 clear_len
= 5 + 4 + nonce_len
;
7834 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
7835 clear
= wpabuf_alloc(clear_len
);
7836 msg
= dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT
, attr_len
);
7841 dpp_build_attr_status(clear
, status
);
7844 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
7845 wpabuf_put_le16(clear
, nonce_len
);
7846 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
7848 /* OUI, OUI type, Crypto Suite, DPP frame type */
7849 addr
[0] = wpabuf_head_u8(msg
) + 2;
7850 len
[0] = 3 + 1 + 1 + 1;
7851 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7853 /* Attributes before Wrapped Data (none) */
7854 addr
[1] = wpabuf_put(msg
, 0);
7856 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7859 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
7860 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7861 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
7863 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
7864 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
7865 wpabuf_head(clear
), wpabuf_len(clear
),
7866 2, addr
, len
, wrapped
) < 0)
7869 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Configuration Result attributes", msg
);
7879 static int valid_channel_list(const char *val
)
7882 if (!((*val
>= '0' && *val
<= '9') ||
7883 *val
== '/' || *val
== ','))
7892 enum dpp_status_error
dpp_conn_status_result_rx(struct dpp_authentication
*auth
,
7894 const u8
*attr_start
,
7896 u8
*ssid
, size_t *ssid_len
,
7897 char **channel_list
)
7899 const u8
*wrapped_data
, *status
, *e_nonce
;
7900 u16 wrapped_data_len
, status_len
, e_nonce_len
;
7903 u8
*unwrapped
= NULL
;
7904 size_t unwrapped_len
= 0;
7905 enum dpp_status_error ret
= 256;
7906 struct json_token
*root
= NULL
, *token
;
7907 struct wpabuf
*ssid64
;
7910 *channel_list
= NULL
;
7912 wrapped_data
= dpp_get_attr(attr_start
, attr_len
, DPP_ATTR_WRAPPED_DATA
,
7914 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
7916 "Missing or invalid required Wrapped Data attribute");
7919 wpa_hexdump(MSG_DEBUG
, "DPP: Wrapped data",
7920 wrapped_data
, wrapped_data_len
);
7922 attr_len
= wrapped_data
- 4 - attr_start
;
7925 len
[0] = DPP_HDR_LEN
;
7926 addr
[1] = attr_start
;
7928 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
7929 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
7930 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
7931 wrapped_data
, wrapped_data_len
);
7932 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
7933 unwrapped
= os_malloc(unwrapped_len
);
7936 if (aes_siv_decrypt(auth
->ke
, auth
->curve
->hash_len
,
7937 wrapped_data
, wrapped_data_len
,
7938 2, addr
, len
, unwrapped
) < 0) {
7939 dpp_auth_fail(auth
, "AES-SIV decryption failed");
7942 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
7943 unwrapped
, unwrapped_len
);
7945 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
7946 dpp_auth_fail(auth
, "Invalid attribute in unwrapped data");
7950 e_nonce
= dpp_get_attr(unwrapped
, unwrapped_len
,
7951 DPP_ATTR_ENROLLEE_NONCE
,
7953 if (!e_nonce
|| e_nonce_len
!= auth
->curve
->nonce_len
) {
7955 "Missing or invalid Enrollee Nonce attribute");
7958 wpa_hexdump(MSG_DEBUG
, "DPP: Enrollee Nonce", e_nonce
, e_nonce_len
);
7959 if (os_memcmp(e_nonce
, auth
->e_nonce
, e_nonce_len
) != 0) {
7960 dpp_auth_fail(auth
, "Enrollee Nonce mismatch");
7961 wpa_hexdump(MSG_DEBUG
, "DPP: Expected Enrollee Nonce",
7962 auth
->e_nonce
, e_nonce_len
);
7966 status
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_CONN_STATUS
,
7970 "Missing required DPP Connection Status attribute");
7973 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
7974 status
, status_len
);
7976 root
= json_parse((const char *) status
, status_len
);
7978 dpp_auth_fail(auth
, "Could not parse connStatus");
7982 ssid64
= json_get_member_base64url(root
, "ssid64");
7983 if (ssid64
&& wpabuf_len(ssid64
) <= SSID_MAX_LEN
) {
7984 *ssid_len
= wpabuf_len(ssid64
);
7985 os_memcpy(ssid
, wpabuf_head(ssid64
), *ssid_len
);
7987 wpabuf_free(ssid64
);
7989 token
= json_get_member(root
, "channelList");
7990 if (token
&& token
->type
== JSON_STRING
&&
7991 valid_channel_list(token
->string
))
7992 *channel_list
= os_strdup(token
->string
);
7994 token
= json_get_member(root
, "result");
7995 if (!token
|| token
->type
!= JSON_NUMBER
) {
7996 dpp_auth_fail(auth
, "No connStatus - result");
7999 wpa_printf(MSG_DEBUG
, "DPP: result %d", token
->number
);
8000 ret
= token
->number
;
8004 bin_clear_free(unwrapped
, unwrapped_len
);
8009 struct wpabuf
* dpp_build_conn_status_result(struct dpp_authentication
*auth
,
8010 enum dpp_status_error result
,
8011 const u8
*ssid
, size_t ssid_len
,
8012 const char *channel_list
)
8014 struct wpabuf
*msg
= NULL
, *clear
= NULL
, *json
;
8015 size_t nonce_len
, clear_len
, attr_len
;
8020 json
= wpabuf_alloc(1000);
8023 json_start_object(json
, NULL
);
8024 json_add_int(json
, "result", result
);
8026 json_value_sep(json
);
8027 if (json_add_base64url(json
, "ssid64", ssid
, ssid_len
) < 0)
8031 json_value_sep(json
);
8032 json_add_string(json
, "channelList", channel_list
);
8034 json_end_object(json
);
8035 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: connStatus JSON",
8036 wpabuf_head(json
), wpabuf_len(json
));
8038 nonce_len
= auth
->curve
->nonce_len
;
8039 clear_len
= 5 + 4 + nonce_len
+ 4 + wpabuf_len(json
);
8040 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
8041 clear
= wpabuf_alloc(clear_len
);
8042 msg
= dpp_alloc_msg(DPP_PA_CONNECTION_STATUS_RESULT
, attr_len
);
8047 wpabuf_put_le16(clear
, DPP_ATTR_ENROLLEE_NONCE
);
8048 wpabuf_put_le16(clear
, nonce_len
);
8049 wpabuf_put_data(clear
, auth
->e_nonce
, nonce_len
);
8051 /* DPP Connection Status */
8052 wpabuf_put_le16(clear
, DPP_ATTR_CONN_STATUS
);
8053 wpabuf_put_le16(clear
, wpabuf_len(json
));
8054 wpabuf_put_buf(clear
, json
);
8056 /* OUI, OUI type, Crypto Suite, DPP frame type */
8057 addr
[0] = wpabuf_head_u8(msg
) + 2;
8058 len
[0] = 3 + 1 + 1 + 1;
8059 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
8061 /* Attributes before Wrapped Data (none) */
8062 addr
[1] = wpabuf_put(msg
, 0);
8064 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
8067 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
8068 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8069 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
8071 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
8072 if (aes_siv_encrypt(auth
->ke
, auth
->curve
->hash_len
,
8073 wpabuf_head(clear
), wpabuf_len(clear
),
8074 2, addr
, len
, wrapped
) < 0)
8077 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Connection Status Result attributes",
8089 #endif /* CONFIG_DPP2 */
8092 void dpp_configurator_free(struct dpp_configurator
*conf
)
8096 EVP_PKEY_free(conf
->csign
);
8102 int dpp_configurator_get_key(const struct dpp_configurator
*conf
, char *buf
,
8106 int key_len
, ret
= -1;
8107 unsigned char *key
= NULL
;
8112 eckey
= EVP_PKEY_get1_EC_KEY(conf
->csign
);
8116 key_len
= i2d_ECPrivateKey(eckey
, &key
);
8118 ret
= wpa_snprintf_hex(buf
, buflen
, key
, key_len
);
8126 static int dpp_configurator_gen_kid(struct dpp_configurator
*conf
)
8128 struct wpabuf
*csign_pub
= NULL
;
8129 u8 kid_hash
[SHA256_MAC_LEN
];
8134 csign_pub
= dpp_get_pubkey_point(conf
->csign
, 1);
8136 wpa_printf(MSG_INFO
, "DPP: Failed to extract C-sign-key");
8140 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */
8141 addr
[0] = wpabuf_head(csign_pub
);
8142 len
[0] = wpabuf_len(csign_pub
);
8143 res
= sha256_vector(1, addr
, len
, kid_hash
);
8144 wpabuf_free(csign_pub
);
8146 wpa_printf(MSG_DEBUG
,
8147 "DPP: Failed to derive kid for C-sign-key");
8151 conf
->kid
= base64_url_encode(kid_hash
, sizeof(kid_hash
), NULL
);
8152 return conf
->kid
? 0 : -1;
8156 struct dpp_configurator
*
8157 dpp_keygen_configurator(const char *curve
, const u8
*privkey
,
8160 struct dpp_configurator
*conf
;
8162 conf
= os_zalloc(sizeof(*conf
));
8167 conf
->curve
= &dpp_curves
[0];
8169 conf
->curve
= dpp_get_curve_name(curve
);
8171 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8178 conf
->csign
= dpp_set_keypair(&conf
->curve
, privkey
,
8181 conf
->csign
= dpp_gen_keypair(conf
->curve
);
8186 if (dpp_configurator_gen_kid(conf
) < 0)
8190 dpp_configurator_free(conf
);
8195 int dpp_configurator_own_config(struct dpp_authentication
*auth
,
8196 const char *curve
, int ap
)
8198 struct wpabuf
*conf_obj
;
8202 wpa_printf(MSG_DEBUG
, "DPP: No configurator specified");
8207 auth
->curve
= &dpp_curves
[0];
8209 auth
->curve
= dpp_get_curve_name(curve
);
8211 wpa_printf(MSG_INFO
, "DPP: Unsupported curve: %s",
8216 wpa_printf(MSG_DEBUG
,
8217 "DPP: Building own configuration/connector with curve %s",
8220 auth
->own_protocol_key
= dpp_gen_keypair(auth
->curve
);
8221 if (!auth
->own_protocol_key
)
8223 dpp_copy_netaccesskey(auth
, &auth
->conf_obj
[0]);
8224 auth
->peer_protocol_key
= auth
->own_protocol_key
;
8225 dpp_copy_csign(&auth
->conf_obj
[0], auth
->conf
->csign
);
8227 conf_obj
= dpp_build_conf_obj(auth
, ap
, 0);
8229 wpabuf_free(auth
->conf_obj
[0].c_sign_key
);
8230 auth
->conf_obj
[0].c_sign_key
= NULL
;
8233 ret
= dpp_parse_conf_obj(auth
, wpabuf_head(conf_obj
),
8234 wpabuf_len(conf_obj
));
8236 wpabuf_free(conf_obj
);
8237 auth
->peer_protocol_key
= NULL
;
8242 static int dpp_compatible_netrole(const char *role1
, const char *role2
)
8244 return (os_strcmp(role1
, "sta") == 0 && os_strcmp(role2
, "ap") == 0) ||
8245 (os_strcmp(role1
, "ap") == 0 && os_strcmp(role2
, "sta") == 0);
8249 static int dpp_connector_compatible_group(struct json_token
*root
,
8250 const char *group_id
,
8251 const char *net_role
)
8253 struct json_token
*groups
, *token
;
8255 groups
= json_get_member(root
, "groups");
8256 if (!groups
|| groups
->type
!= JSON_ARRAY
)
8259 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8260 struct json_token
*id
, *role
;
8262 id
= json_get_member(token
, "groupId");
8263 if (!id
|| id
->type
!= JSON_STRING
)
8266 role
= json_get_member(token
, "netRole");
8267 if (!role
|| role
->type
!= JSON_STRING
)
8270 if (os_strcmp(id
->string
, "*") != 0 &&
8271 os_strcmp(group_id
, "*") != 0 &&
8272 os_strcmp(id
->string
, group_id
) != 0)
8275 if (dpp_compatible_netrole(role
->string
, net_role
))
8283 static int dpp_connector_match_groups(struct json_token
*own_root
,
8284 struct json_token
*peer_root
)
8286 struct json_token
*groups
, *token
;
8288 groups
= json_get_member(peer_root
, "groups");
8289 if (!groups
|| groups
->type
!= JSON_ARRAY
) {
8290 wpa_printf(MSG_DEBUG
, "DPP: No peer groups array found");
8294 for (token
= groups
->child
; token
; token
= token
->sibling
) {
8295 struct json_token
*id
, *role
;
8297 id
= json_get_member(token
, "groupId");
8298 if (!id
|| id
->type
!= JSON_STRING
) {
8299 wpa_printf(MSG_DEBUG
,
8300 "DPP: Missing peer groupId string");
8304 role
= json_get_member(token
, "netRole");
8305 if (!role
|| role
->type
!= JSON_STRING
) {
8306 wpa_printf(MSG_DEBUG
,
8307 "DPP: Missing peer groups::netRole string");
8310 wpa_printf(MSG_DEBUG
,
8311 "DPP: peer connector group: groupId='%s' netRole='%s'",
8312 id
->string
, role
->string
);
8313 if (dpp_connector_compatible_group(own_root
, id
->string
,
8315 wpa_printf(MSG_DEBUG
,
8316 "DPP: Compatible group/netRole in own connector");
8325 static int dpp_derive_pmk(const u8
*Nx
, size_t Nx_len
, u8
*pmk
,
8326 unsigned int hash_len
)
8328 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
8329 const char *info
= "DPP PMK";
8332 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8334 /* HKDF-Extract(<>, N.x) */
8335 os_memset(salt
, 0, hash_len
);
8336 if (dpp_hmac(hash_len
, salt
, hash_len
, Nx
, Nx_len
, prk
) < 0)
8338 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)",
8341 /* HKDF-Expand(PRK, info, L) */
8342 res
= dpp_hkdf_expand(hash_len
, prk
, hash_len
, info
, pmk
, hash_len
);
8343 os_memset(prk
, 0, hash_len
);
8347 wpa_hexdump_key(MSG_DEBUG
, "DPP: PMK = HKDF-Expand(PRK, info, L)",
8353 static int dpp_derive_pmkid(const struct dpp_curve_params
*curve
,
8354 EVP_PKEY
*own_key
, EVP_PKEY
*peer_key
, u8
*pmkid
)
8356 struct wpabuf
*nkx
, *pkx
;
8360 u8 hash
[SHA256_MAC_LEN
];
8362 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8363 nkx
= dpp_get_pubkey_point(own_key
, 0);
8364 pkx
= dpp_get_pubkey_point(peer_key
, 0);
8367 addr
[0] = wpabuf_head(nkx
);
8368 len
[0] = wpabuf_len(nkx
) / 2;
8369 addr
[1] = wpabuf_head(pkx
);
8370 len
[1] = wpabuf_len(pkx
) / 2;
8371 if (len
[0] != len
[1])
8373 if (os_memcmp(addr
[0], addr
[1], len
[0]) > 0) {
8374 addr
[0] = wpabuf_head(pkx
);
8375 addr
[1] = wpabuf_head(nkx
);
8377 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 1", addr
[0], len
[0]);
8378 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash payload 2", addr
[1], len
[1]);
8379 res
= sha256_vector(2, addr
, len
, hash
);
8382 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID hash output", hash
, SHA256_MAC_LEN
);
8383 os_memcpy(pmkid
, hash
, PMKID_LEN
);
8384 wpa_hexdump(MSG_DEBUG
, "DPP: PMKID", pmkid
, PMKID_LEN
);
8393 enum dpp_status_error
8394 dpp_peer_intro(struct dpp_introduction
*intro
, const char *own_connector
,
8395 const u8
*net_access_key
, size_t net_access_key_len
,
8396 const u8
*csign_key
, size_t csign_key_len
,
8397 const u8
*peer_connector
, size_t peer_connector_len
,
8400 struct json_token
*root
= NULL
, *netkey
, *token
;
8401 struct json_token
*own_root
= NULL
;
8402 enum dpp_status_error ret
= 255, res
;
8403 EVP_PKEY
*own_key
= NULL
, *peer_key
= NULL
;
8404 struct wpabuf
*own_key_pub
= NULL
;
8405 const struct dpp_curve_params
*curve
, *own_curve
;
8406 struct dpp_signed_connector_info info
;
8407 const unsigned char *p
;
8408 EVP_PKEY
*csign
= NULL
;
8409 char *signed_connector
= NULL
;
8410 const char *pos
, *end
;
8411 unsigned char *own_conn
= NULL
;
8412 size_t own_conn_len
;
8414 u8 Nx
[DPP_MAX_SHARED_SECRET_LEN
];
8416 os_memset(intro
, 0, sizeof(*intro
));
8417 os_memset(&info
, 0, sizeof(info
));
8422 csign
= d2i_PUBKEY(NULL
, &p
, csign_key_len
);
8424 wpa_printf(MSG_ERROR
,
8425 "DPP: Failed to parse local C-sign-key information");
8429 own_key
= dpp_set_keypair(&own_curve
, net_access_key
,
8430 net_access_key_len
);
8432 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
8436 pos
= os_strchr(own_connector
, '.');
8438 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the first dot (.)");
8442 end
= os_strchr(pos
, '.');
8444 wpa_printf(MSG_DEBUG
, "DPP: Own connector is missing the second dot (.)");
8447 own_conn
= base64_url_decode(pos
, end
- pos
, &own_conn_len
);
8449 wpa_printf(MSG_DEBUG
,
8450 "DPP: Failed to base64url decode own signedConnector JWS Payload");
8454 own_root
= json_parse((const char *) own_conn
, own_conn_len
);
8456 wpa_printf(MSG_DEBUG
, "DPP: Failed to parse local connector");
8460 wpa_hexdump_ascii(MSG_DEBUG
, "DPP: Peer signedConnector",
8461 peer_connector
, peer_connector_len
);
8462 signed_connector
= os_malloc(peer_connector_len
+ 1);
8463 if (!signed_connector
)
8465 os_memcpy(signed_connector
, peer_connector
, peer_connector_len
);
8466 signed_connector
[peer_connector_len
] = '\0';
8468 res
= dpp_process_signed_connector(&info
, csign
, signed_connector
);
8469 if (res
!= DPP_STATUS_OK
) {
8474 root
= json_parse((const char *) info
.payload
, info
.payload_len
);
8476 wpa_printf(MSG_DEBUG
, "DPP: JSON parsing of connector failed");
8477 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8481 if (!dpp_connector_match_groups(own_root
, root
)) {
8482 wpa_printf(MSG_DEBUG
,
8483 "DPP: Peer connector does not include compatible group netrole with own connector");
8484 ret
= DPP_STATUS_NO_MATCH
;
8488 token
= json_get_member(root
, "expiry");
8489 if (!token
|| token
->type
!= JSON_STRING
) {
8490 wpa_printf(MSG_DEBUG
,
8491 "DPP: No expiry string found - connector does not expire");
8493 wpa_printf(MSG_DEBUG
, "DPP: expiry = %s", token
->string
);
8494 if (dpp_key_expired(token
->string
, expiry
)) {
8495 wpa_printf(MSG_DEBUG
,
8496 "DPP: Connector (netAccessKey) has expired");
8497 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8502 netkey
= json_get_member(root
, "netAccessKey");
8503 if (!netkey
|| netkey
->type
!= JSON_OBJECT
) {
8504 wpa_printf(MSG_DEBUG
, "DPP: No netAccessKey object found");
8505 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8509 peer_key
= dpp_parse_jwk(netkey
, &curve
);
8511 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8514 dpp_debug_print_key("DPP: Received netAccessKey", peer_key
);
8516 if (own_curve
!= curve
) {
8517 wpa_printf(MSG_DEBUG
,
8518 "DPP: Mismatching netAccessKey curves (%s != %s)",
8519 own_curve
->name
, curve
->name
);
8520 ret
= DPP_STATUS_INVALID_CONNECTOR
;
8524 /* ECDH: N = nk * PK */
8525 if (dpp_ecdh(own_key
, peer_key
, Nx
, &Nx_len
) < 0)
8528 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (N.x)",
8531 /* PMK = HKDF(<>, "DPP PMK", N.x) */
8532 if (dpp_derive_pmk(Nx
, Nx_len
, intro
->pmk
, curve
->hash_len
) < 0) {
8533 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMK");
8536 intro
->pmk_len
= curve
->hash_len
;
8538 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
8539 if (dpp_derive_pmkid(curve
, own_key
, peer_key
, intro
->pmkid
) < 0) {
8540 wpa_printf(MSG_ERROR
, "DPP: Failed to derive PMKID");
8544 ret
= DPP_STATUS_OK
;
8546 if (ret
!= DPP_STATUS_OK
)
8547 os_memset(intro
, 0, sizeof(*intro
));
8548 os_memset(Nx
, 0, sizeof(Nx
));
8550 os_free(signed_connector
);
8551 os_free(info
.payload
);
8552 EVP_PKEY_free(own_key
);
8553 wpabuf_free(own_key_pub
);
8554 EVP_PKEY_free(peer_key
);
8555 EVP_PKEY_free(csign
);
8557 json_free(own_root
);
8562 static EVP_PKEY
* dpp_pkex_get_role_elem(const struct dpp_curve_params
*curve
,
8566 size_t len
= curve
->prime_len
;
8570 switch (curve
->ike_group
) {
8572 x
= init
? pkex_init_x_p256
: pkex_resp_x_p256
;
8573 y
= init
? pkex_init_y_p256
: pkex_resp_y_p256
;
8576 x
= init
? pkex_init_x_p384
: pkex_resp_x_p384
;
8577 y
= init
? pkex_init_y_p384
: pkex_resp_y_p384
;
8580 x
= init
? pkex_init_x_p521
: pkex_resp_x_p521
;
8581 y
= init
? pkex_init_y_p521
: pkex_resp_y_p521
;
8584 x
= init
? pkex_init_x_bp_p256r1
: pkex_resp_x_bp_p256r1
;
8585 y
= init
? pkex_init_y_bp_p256r1
: pkex_resp_y_bp_p256r1
;
8588 x
= init
? pkex_init_x_bp_p384r1
: pkex_resp_x_bp_p384r1
;
8589 y
= init
? pkex_init_y_bp_p384r1
: pkex_resp_y_bp_p384r1
;
8592 x
= init
? pkex_init_x_bp_p512r1
: pkex_resp_x_bp_p512r1
;
8593 y
= init
? pkex_init_y_bp_p512r1
: pkex_resp_y_bp_p512r1
;
8599 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8602 res
= dpp_set_pubkey_point_group(group
, x
, y
, len
);
8603 EC_GROUP_free(group
);
8608 static EC_POINT
* dpp_pkex_derive_Qi(const struct dpp_curve_params
*curve
,
8609 const u8
*mac_init
, const char *code
,
8610 const char *identifier
, BN_CTX
*bnctx
,
8611 EC_GROUP
**ret_group
)
8613 u8 hash
[DPP_MAX_HASH_LEN
];
8616 unsigned int num_elem
= 0;
8617 EC_POINT
*Qi
= NULL
;
8618 EVP_PKEY
*Pi
= NULL
;
8619 EC_KEY
*Pi_ec
= NULL
;
8620 const EC_POINT
*Pi_point
;
8621 BIGNUM
*hash_bn
= NULL
;
8622 const EC_GROUP
*group
= NULL
;
8623 EC_GROUP
*group2
= NULL
;
8625 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8627 wpa_printf(MSG_DEBUG
, "DPP: MAC-Initiator: " MACSTR
, MAC2STR(mac_init
));
8628 addr
[num_elem
] = mac_init
;
8629 len
[num_elem
] = ETH_ALEN
;
8632 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8634 addr
[num_elem
] = (const u8
*) identifier
;
8635 len
[num_elem
] = os_strlen(identifier
);
8638 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8639 addr
[num_elem
] = (const u8
*) code
;
8640 len
[num_elem
] = os_strlen(code
);
8642 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8644 wpa_hexdump_key(MSG_DEBUG
,
8645 "DPP: H(MAC-Initiator | [identifier |] code)",
8646 hash
, curve
->hash_len
);
8647 Pi
= dpp_pkex_get_role_elem(curve
, 1);
8650 dpp_debug_print_key("DPP: Pi", Pi
);
8651 Pi_ec
= EVP_PKEY_get1_EC_KEY(Pi
);
8654 Pi_point
= EC_KEY_get0_public_key(Pi_ec
);
8656 group
= EC_KEY_get0_group(Pi_ec
);
8659 group2
= EC_GROUP_dup(group
);
8662 Qi
= EC_POINT_new(group2
);
8664 EC_GROUP_free(group2
);
8667 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8669 EC_POINT_mul(group2
, Qi
, NULL
, Pi_point
, hash_bn
, bnctx
) != 1)
8671 if (EC_POINT_is_at_infinity(group
, Qi
)) {
8672 wpa_printf(MSG_INFO
, "DPP: Qi is the point-at-infinity");
8675 dpp_debug_print_point("DPP: Qi", group
, Qi
);
8679 BN_clear_free(hash_bn
);
8680 if (ret_group
&& Qi
)
8681 *ret_group
= group2
;
8683 EC_GROUP_free(group2
);
8692 static EC_POINT
* dpp_pkex_derive_Qr(const struct dpp_curve_params
*curve
,
8693 const u8
*mac_resp
, const char *code
,
8694 const char *identifier
, BN_CTX
*bnctx
,
8695 EC_GROUP
**ret_group
)
8697 u8 hash
[DPP_MAX_HASH_LEN
];
8700 unsigned int num_elem
= 0;
8701 EC_POINT
*Qr
= NULL
;
8702 EVP_PKEY
*Pr
= NULL
;
8703 EC_KEY
*Pr_ec
= NULL
;
8704 const EC_POINT
*Pr_point
;
8705 BIGNUM
*hash_bn
= NULL
;
8706 const EC_GROUP
*group
= NULL
;
8707 EC_GROUP
*group2
= NULL
;
8709 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
8711 wpa_printf(MSG_DEBUG
, "DPP: MAC-Responder: " MACSTR
, MAC2STR(mac_resp
));
8712 addr
[num_elem
] = mac_resp
;
8713 len
[num_elem
] = ETH_ALEN
;
8716 wpa_printf(MSG_DEBUG
, "DPP: code identifier: %s",
8718 addr
[num_elem
] = (const u8
*) identifier
;
8719 len
[num_elem
] = os_strlen(identifier
);
8722 wpa_hexdump_ascii_key(MSG_DEBUG
, "DPP: code", code
, os_strlen(code
));
8723 addr
[num_elem
] = (const u8
*) code
;
8724 len
[num_elem
] = os_strlen(code
);
8726 if (dpp_hash_vector(curve
, num_elem
, addr
, len
, hash
) < 0)
8728 wpa_hexdump_key(MSG_DEBUG
,
8729 "DPP: H(MAC-Responder | [identifier |] code)",
8730 hash
, curve
->hash_len
);
8731 Pr
= dpp_pkex_get_role_elem(curve
, 0);
8734 dpp_debug_print_key("DPP: Pr", Pr
);
8735 Pr_ec
= EVP_PKEY_get1_EC_KEY(Pr
);
8738 Pr_point
= EC_KEY_get0_public_key(Pr_ec
);
8740 group
= EC_KEY_get0_group(Pr_ec
);
8743 group2
= EC_GROUP_dup(group
);
8746 Qr
= EC_POINT_new(group2
);
8748 EC_GROUP_free(group2
);
8751 hash_bn
= BN_bin2bn(hash
, curve
->hash_len
, NULL
);
8753 EC_POINT_mul(group2
, Qr
, NULL
, Pr_point
, hash_bn
, bnctx
) != 1)
8755 if (EC_POINT_is_at_infinity(group
, Qr
)) {
8756 wpa_printf(MSG_INFO
, "DPP: Qr is the point-at-infinity");
8759 dpp_debug_print_point("DPP: Qr", group
, Qr
);
8763 BN_clear_free(hash_bn
);
8764 if (ret_group
&& Qr
)
8765 *ret_group
= group2
;
8767 EC_GROUP_free(group2
);
8776 #ifdef CONFIG_TESTING_OPTIONS
8777 static int dpp_test_gen_invalid_key(struct wpabuf
*msg
,
8778 const struct dpp_curve_params
*curve
)
8786 group
= EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve
->name
));
8791 point
= EC_POINT_new(group
);
8794 if (!ctx
|| !point
|| !x
|| !y
)
8797 if (BN_rand(x
, curve
->prime_len
* 8, 0, 0) != 1)
8800 /* Generate a random y coordinate that results in a point that is not
8803 if (BN_rand(y
, curve
->prime_len
* 8, 0, 0) != 1)
8806 if (EC_POINT_set_affine_coordinates_GFp(group
, point
, x
, y
,
8808 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
8809 /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
8810 * return an error from EC_POINT_set_affine_coordinates_GFp()
8811 * when the point is not on the curve. */
8813 #else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
8815 #endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
8818 if (!EC_POINT_is_on_curve(group
, point
, ctx
))
8822 if (dpp_bn2bin_pad(x
, wpabuf_put(msg
, curve
->prime_len
),
8823 curve
->prime_len
) < 0 ||
8824 dpp_bn2bin_pad(y
, wpabuf_put(msg
, curve
->prime_len
),
8825 curve
->prime_len
) < 0)
8831 wpa_printf(MSG_INFO
, "DPP: Failed to generate invalid key");
8834 EC_POINT_free(point
);
8836 EC_GROUP_free(group
);
8840 #endif /* CONFIG_TESTING_OPTIONS */
8843 static struct wpabuf
* dpp_pkex_build_exchange_req(struct dpp_pkex
*pkex
)
8845 EC_KEY
*X_ec
= NULL
;
8846 const EC_POINT
*X_point
;
8847 BN_CTX
*bnctx
= NULL
;
8848 EC_GROUP
*group
= NULL
;
8849 EC_POINT
*Qi
= NULL
, *M
= NULL
;
8850 struct wpabuf
*M_buf
= NULL
;
8851 BIGNUM
*Mx
= NULL
, *My
= NULL
;
8852 struct wpabuf
*msg
= NULL
;
8854 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
8856 wpa_printf(MSG_DEBUG
, "DPP: Build PKEX Exchange Request");
8858 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
8859 bnctx
= BN_CTX_new();
8862 Qi
= dpp_pkex_derive_Qi(curve
, pkex
->own_mac
, pkex
->code
,
8863 pkex
->identifier
, bnctx
, &group
);
8867 /* Generate a random ephemeral keypair x/X */
8868 #ifdef CONFIG_TESTING_OPTIONS
8869 if (dpp_pkex_ephemeral_key_override_len
) {
8870 const struct dpp_curve_params
*tmp_curve
;
8872 wpa_printf(MSG_INFO
,
8873 "DPP: TESTING - override ephemeral key x/X");
8874 pkex
->x
= dpp_set_keypair(&tmp_curve
,
8875 dpp_pkex_ephemeral_key_override
,
8876 dpp_pkex_ephemeral_key_override_len
);
8878 pkex
->x
= dpp_gen_keypair(curve
);
8880 #else /* CONFIG_TESTING_OPTIONS */
8881 pkex
->x
= dpp_gen_keypair(curve
);
8882 #endif /* CONFIG_TESTING_OPTIONS */
8887 X_ec
= EVP_PKEY_get1_EC_KEY(pkex
->x
);
8890 X_point
= EC_KEY_get0_public_key(X_ec
);
8893 dpp_debug_print_point("DPP: X", group
, X_point
);
8894 M
= EC_POINT_new(group
);
8897 if (!M
|| !Mx
|| !My
||
8898 EC_POINT_add(group
, M
, X_point
, Qi
, bnctx
) != 1 ||
8899 EC_POINT_get_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1)
8901 dpp_debug_print_point("DPP: M", group
, M
);
8903 /* Initiator -> Responder: group, [identifier,] M */
8905 if (pkex
->identifier
)
8906 attr_len
+= 4 + os_strlen(pkex
->identifier
);
8907 attr_len
+= 4 + 2 * curve
->prime_len
;
8908 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ
, attr_len
);
8912 #ifdef CONFIG_TESTING_OPTIONS
8913 if (dpp_test
== DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ
) {
8914 wpa_printf(MSG_INFO
, "DPP: TESTING - no Finite Cyclic Group");
8915 goto skip_finite_cyclic_group
;
8917 #endif /* CONFIG_TESTING_OPTIONS */
8919 /* Finite Cyclic Group attribute */
8920 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
8921 wpabuf_put_le16(msg
, 2);
8922 wpabuf_put_le16(msg
, curve
->ike_group
);
8924 #ifdef CONFIG_TESTING_OPTIONS
8925 skip_finite_cyclic_group
:
8926 #endif /* CONFIG_TESTING_OPTIONS */
8928 /* Code Identifier attribute */
8929 if (pkex
->identifier
) {
8930 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
8931 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
8932 wpabuf_put_str(msg
, pkex
->identifier
);
8935 #ifdef CONFIG_TESTING_OPTIONS
8936 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8937 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
8940 #endif /* CONFIG_TESTING_OPTIONS */
8942 /* M in Encrypted Key attribute */
8943 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
8944 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
8946 #ifdef CONFIG_TESTING_OPTIONS
8947 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ
) {
8948 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
8949 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
8953 #endif /* CONFIG_TESTING_OPTIONS */
8955 if (dpp_bn2bin_pad(Mx
, wpabuf_put(msg
, curve
->prime_len
),
8956 curve
->prime_len
) < 0 ||
8957 dpp_bn2bin_pad(Mx
, pkex
->Mx
, curve
->prime_len
) < 0 ||
8958 dpp_bn2bin_pad(My
, wpabuf_put(msg
, curve
->prime_len
),
8959 curve
->prime_len
) < 0)
8970 EC_GROUP_free(group
);
8973 wpa_printf(MSG_INFO
, "DPP: Failed to build PKEX Exchange Request");
8980 static void dpp_pkex_fail(struct dpp_pkex
*pkex
, const char *txt
)
8982 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
"%s", txt
);
8986 struct dpp_pkex
* dpp_pkex_init(void *msg_ctx
, struct dpp_bootstrap_info
*bi
,
8988 const char *identifier
,
8991 struct dpp_pkex
*pkex
;
8993 #ifdef CONFIG_TESTING_OPTIONS
8994 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
8995 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
8996 MAC2STR(dpp_pkex_own_mac_override
));
8997 own_mac
= dpp_pkex_own_mac_override
;
8999 #endif /* CONFIG_TESTING_OPTIONS */
9001 pkex
= os_zalloc(sizeof(*pkex
));
9004 pkex
->msg_ctx
= msg_ctx
;
9005 pkex
->initiator
= 1;
9007 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9009 pkex
->identifier
= os_strdup(identifier
);
9010 if (!pkex
->identifier
)
9013 pkex
->code
= os_strdup(code
);
9016 pkex
->exchange_req
= dpp_pkex_build_exchange_req(pkex
);
9017 if (!pkex
->exchange_req
)
9021 dpp_pkex_free(pkex
);
9026 static struct wpabuf
*
9027 dpp_pkex_build_exchange_resp(struct dpp_pkex
*pkex
,
9028 enum dpp_status_error status
,
9029 const BIGNUM
*Nx
, const BIGNUM
*Ny
)
9031 struct wpabuf
*msg
= NULL
;
9033 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9035 /* Initiator -> Responder: DPP Status, [identifier,] N */
9037 if (pkex
->identifier
)
9038 attr_len
+= 4 + os_strlen(pkex
->identifier
);
9039 attr_len
+= 4 + 2 * curve
->prime_len
;
9040 msg
= dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP
, attr_len
);
9044 #ifdef CONFIG_TESTING_OPTIONS
9045 if (dpp_test
== DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP
) {
9046 wpa_printf(MSG_INFO
, "DPP: TESTING - no Status");
9050 if (dpp_test
== DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP
) {
9051 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Status");
9054 #endif /* CONFIG_TESTING_OPTIONS */
9057 dpp_build_attr_status(msg
, status
);
9059 #ifdef CONFIG_TESTING_OPTIONS
9061 #endif /* CONFIG_TESTING_OPTIONS */
9063 /* Code Identifier attribute */
9064 if (pkex
->identifier
) {
9065 wpabuf_put_le16(msg
, DPP_ATTR_CODE_IDENTIFIER
);
9066 wpabuf_put_le16(msg
, os_strlen(pkex
->identifier
));
9067 wpabuf_put_str(msg
, pkex
->identifier
);
9070 if (status
!= DPP_STATUS_OK
)
9071 goto skip_encrypted_key
;
9073 #ifdef CONFIG_TESTING_OPTIONS
9074 if (dpp_test
== DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9075 wpa_printf(MSG_INFO
, "DPP: TESTING - no Encrypted Key");
9076 goto skip_encrypted_key
;
9078 #endif /* CONFIG_TESTING_OPTIONS */
9080 /* N in Encrypted Key attribute */
9081 wpabuf_put_le16(msg
, DPP_ATTR_ENCRYPTED_KEY
);
9082 wpabuf_put_le16(msg
, 2 * curve
->prime_len
);
9084 #ifdef CONFIG_TESTING_OPTIONS
9085 if (dpp_test
== DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP
) {
9086 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Encrypted Key");
9087 if (dpp_test_gen_invalid_key(msg
, curve
) < 0)
9089 goto skip_encrypted_key
;
9091 #endif /* CONFIG_TESTING_OPTIONS */
9093 if (dpp_bn2bin_pad(Nx
, wpabuf_put(msg
, curve
->prime_len
),
9094 curve
->prime_len
) < 0 ||
9095 dpp_bn2bin_pad(Nx
, pkex
->Nx
, curve
->prime_len
) < 0 ||
9096 dpp_bn2bin_pad(Ny
, wpabuf_put(msg
, curve
->prime_len
),
9097 curve
->prime_len
) < 0)
9101 if (status
== DPP_STATUS_BAD_GROUP
) {
9102 /* Finite Cyclic Group attribute */
9103 wpabuf_put_le16(msg
, DPP_ATTR_FINITE_CYCLIC_GROUP
);
9104 wpabuf_put_le16(msg
, 2);
9105 wpabuf_put_le16(msg
, curve
->ike_group
);
9115 static int dpp_pkex_derive_z(const u8
*mac_init
, const u8
*mac_resp
,
9116 const u8
*Mx
, size_t Mx_len
,
9117 const u8
*Nx
, size_t Nx_len
,
9119 const u8
*Kx
, size_t Kx_len
,
9120 u8
*z
, unsigned int hash_len
)
9122 u8 salt
[DPP_MAX_HASH_LEN
], prk
[DPP_MAX_HASH_LEN
];
9127 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9130 /* HKDF-Extract(<>, IKM=K.x) */
9131 os_memset(salt
, 0, hash_len
);
9132 if (dpp_hmac(hash_len
, salt
, hash_len
, Kx
, Kx_len
, prk
) < 0)
9134 wpa_hexdump_key(MSG_DEBUG
, "DPP: PRK = HKDF-Extract(<>, IKM)",
9136 info_len
= 2 * ETH_ALEN
+ Mx_len
+ Nx_len
+ os_strlen(code
);
9137 info
= os_malloc(info_len
);
9141 os_memcpy(pos
, mac_init
, ETH_ALEN
);
9143 os_memcpy(pos
, mac_resp
, ETH_ALEN
);
9145 os_memcpy(pos
, Mx
, Mx_len
);
9147 os_memcpy(pos
, Nx
, Nx_len
);
9149 os_memcpy(pos
, code
, os_strlen(code
));
9151 /* HKDF-Expand(PRK, info, L) */
9153 res
= hmac_sha256_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9155 else if (hash_len
== 48)
9156 res
= hmac_sha384_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9158 else if (hash_len
== 64)
9159 res
= hmac_sha512_kdf(prk
, hash_len
, NULL
, info
, info_len
,
9164 os_memset(prk
, 0, hash_len
);
9168 wpa_hexdump_key(MSG_DEBUG
, "DPP: z = HKDF-Expand(PRK, info, L)",
9174 static int dpp_pkex_identifier_match(const u8
*attr_id
, u16 attr_id_len
,
9175 const char *identifier
)
9177 if (!attr_id
&& identifier
) {
9178 wpa_printf(MSG_DEBUG
,
9179 "DPP: No PKEX code identifier received, but expected one");
9183 if (attr_id
&& !identifier
) {
9184 wpa_printf(MSG_DEBUG
,
9185 "DPP: PKEX code identifier received, but not expecting one");
9189 if (attr_id
&& identifier
&&
9190 (os_strlen(identifier
) != attr_id_len
||
9191 os_memcmp(identifier
, attr_id
, attr_id_len
) != 0)) {
9192 wpa_printf(MSG_DEBUG
, "DPP: PKEX code identifier mismatch");
9200 struct dpp_pkex
* dpp_pkex_rx_exchange_req(void *msg_ctx
,
9201 struct dpp_bootstrap_info
*bi
,
9204 const char *identifier
,
9206 const u8
*buf
, size_t len
)
9208 const u8
*attr_group
, *attr_id
, *attr_key
;
9209 u16 attr_group_len
, attr_id_len
, attr_key_len
;
9210 const struct dpp_curve_params
*curve
= bi
->curve
;
9212 struct dpp_pkex
*pkex
= NULL
;
9213 EC_POINT
*Qi
= NULL
, *Qr
= NULL
, *M
= NULL
, *X
= NULL
, *N
= NULL
;
9214 BN_CTX
*bnctx
= NULL
;
9215 EC_GROUP
*group
= NULL
;
9216 BIGNUM
*Mx
= NULL
, *My
= NULL
;
9217 EC_KEY
*Y_ec
= NULL
, *X_ec
= NULL
;;
9218 const EC_POINT
*Y_point
;
9219 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9220 u8 Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9224 if (bi
->pkex_t
>= PKEX_COUNTER_T_LIMIT
) {
9225 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9226 "PKEX counter t limit reached - ignore message");
9230 #ifdef CONFIG_TESTING_OPTIONS
9231 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9232 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9233 MAC2STR(dpp_pkex_peer_mac_override
));
9234 peer_mac
= dpp_pkex_peer_mac_override
;
9236 if (!is_zero_ether_addr(dpp_pkex_own_mac_override
)) {
9237 wpa_printf(MSG_INFO
, "DPP: TESTING - own_mac override " MACSTR
,
9238 MAC2STR(dpp_pkex_own_mac_override
));
9239 own_mac
= dpp_pkex_own_mac_override
;
9241 #endif /* CONFIG_TESTING_OPTIONS */
9244 attr_id
= dpp_get_attr(buf
, len
, DPP_ATTR_CODE_IDENTIFIER
,
9246 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
, identifier
))
9249 attr_group
= dpp_get_attr(buf
, len
, DPP_ATTR_FINITE_CYCLIC_GROUP
,
9251 if (!attr_group
|| attr_group_len
!= 2) {
9252 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9253 "Missing or invalid Finite Cyclic Group attribute");
9256 ike_group
= WPA_GET_LE16(attr_group
);
9257 if (ike_group
!= curve
->ike_group
) {
9258 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9259 "Mismatching PKEX curve: peer=%u own=%u",
9260 ike_group
, curve
->ike_group
);
9261 pkex
= os_zalloc(sizeof(*pkex
));
9266 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(
9267 pkex
, DPP_STATUS_BAD_GROUP
, NULL
, NULL
);
9268 if (!pkex
->exchange_resp
)
9273 /* M in Encrypted Key attribute */
9274 attr_key
= dpp_get_attr(buf
, len
, DPP_ATTR_ENCRYPTED_KEY
,
9276 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2 ||
9277 attr_key_len
/ 2 > DPP_MAX_SHARED_SECRET_LEN
) {
9278 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9279 "Missing Encrypted Key attribute");
9283 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
9284 bnctx
= BN_CTX_new();
9287 Qi
= dpp_pkex_derive_Qi(curve
, peer_mac
, code
, identifier
, bnctx
,
9293 X
= EC_POINT_new(group
);
9294 M
= EC_POINT_new(group
);
9295 Mx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9296 My
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9297 if (!X
|| !M
|| !Mx
|| !My
||
9298 EC_POINT_set_affine_coordinates_GFp(group
, M
, Mx
, My
, bnctx
) != 1 ||
9299 EC_POINT_is_at_infinity(group
, M
) ||
9300 !EC_POINT_is_on_curve(group
, M
, bnctx
) ||
9301 EC_POINT_invert(group
, Qi
, bnctx
) != 1 ||
9302 EC_POINT_add(group
, X
, M
, Qi
, bnctx
) != 1 ||
9303 EC_POINT_is_at_infinity(group
, X
) ||
9304 !EC_POINT_is_on_curve(group
, X
, bnctx
)) {
9305 wpa_msg(msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9306 "Invalid Encrypted Key value");
9310 dpp_debug_print_point("DPP: M", group
, M
);
9311 dpp_debug_print_point("DPP: X'", group
, X
);
9313 pkex
= os_zalloc(sizeof(*pkex
));
9316 pkex
->t
= bi
->pkex_t
;
9317 pkex
->msg_ctx
= msg_ctx
;
9319 os_memcpy(pkex
->own_mac
, own_mac
, ETH_ALEN
);
9320 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9322 pkex
->identifier
= os_strdup(identifier
);
9323 if (!pkex
->identifier
)
9326 pkex
->code
= os_strdup(code
);
9330 os_memcpy(pkex
->Mx
, attr_key
, attr_key_len
/ 2);
9332 X_ec
= EC_KEY_new();
9334 EC_KEY_set_group(X_ec
, group
) != 1 ||
9335 EC_KEY_set_public_key(X_ec
, X
) != 1)
9337 pkex
->x
= EVP_PKEY_new();
9339 EVP_PKEY_set1_EC_KEY(pkex
->x
, X_ec
) != 1)
9342 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
9343 Qr
= dpp_pkex_derive_Qr(curve
, own_mac
, code
, identifier
, bnctx
, NULL
);
9347 /* Generate a random ephemeral keypair y/Y */
9348 #ifdef CONFIG_TESTING_OPTIONS
9349 if (dpp_pkex_ephemeral_key_override_len
) {
9350 const struct dpp_curve_params
*tmp_curve
;
9352 wpa_printf(MSG_INFO
,
9353 "DPP: TESTING - override ephemeral key y/Y");
9354 pkex
->y
= dpp_set_keypair(&tmp_curve
,
9355 dpp_pkex_ephemeral_key_override
,
9356 dpp_pkex_ephemeral_key_override_len
);
9358 pkex
->y
= dpp_gen_keypair(curve
);
9360 #else /* CONFIG_TESTING_OPTIONS */
9361 pkex
->y
= dpp_gen_keypair(curve
);
9362 #endif /* CONFIG_TESTING_OPTIONS */
9367 Y_ec
= EVP_PKEY_get1_EC_KEY(pkex
->y
);
9370 Y_point
= EC_KEY_get0_public_key(Y_ec
);
9373 dpp_debug_print_point("DPP: Y", group
, Y_point
);
9374 N
= EC_POINT_new(group
);
9377 if (!N
|| !Nx
|| !Ny
||
9378 EC_POINT_add(group
, N
, Y_point
, Qr
, bnctx
) != 1 ||
9379 EC_POINT_get_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1)
9381 dpp_debug_print_point("DPP: N", group
, N
);
9383 pkex
->exchange_resp
= dpp_pkex_build_exchange_resp(pkex
, DPP_STATUS_OK
,
9385 if (!pkex
->exchange_resp
)
9389 if (dpp_ecdh(pkex
->y
, pkex
->x
, Kx
, &Kx_len
) < 0)
9392 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9395 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9397 res
= dpp_pkex_derive_z(pkex
->peer_mac
, pkex
->own_mac
,
9398 pkex
->Mx
, curve
->prime_len
,
9399 pkex
->Nx
, curve
->prime_len
, pkex
->code
,
9400 Kx
, Kx_len
, pkex
->z
, curve
->hash_len
);
9401 os_memset(Kx
, 0, Kx_len
);
9405 pkex
->exchange_done
= 1;
9420 EC_GROUP_free(group
);
9423 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Request processing failed");
9424 dpp_pkex_free(pkex
);
9430 static struct wpabuf
*
9431 dpp_pkex_build_commit_reveal_req(struct dpp_pkex
*pkex
,
9432 const struct wpabuf
*A_pub
, const u8
*u
)
9434 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9435 struct wpabuf
*msg
= NULL
;
9436 size_t clear_len
, attr_len
;
9437 struct wpabuf
*clear
= NULL
;
9443 /* {A, u, [bootstrapping info]}z */
9444 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9445 clear
= wpabuf_alloc(clear_len
);
9446 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9447 #ifdef CONFIG_TESTING_OPTIONS
9448 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
)
9450 #endif /* CONFIG_TESTING_OPTIONS */
9451 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ
, attr_len
);
9455 #ifdef CONFIG_TESTING_OPTIONS
9456 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9457 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9458 goto skip_bootstrap_key
;
9460 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ
) {
9461 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9462 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9463 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9464 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9466 goto skip_bootstrap_key
;
9468 #endif /* CONFIG_TESTING_OPTIONS */
9470 /* A in Bootstrap Key attribute */
9471 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9472 wpabuf_put_le16(clear
, wpabuf_len(A_pub
));
9473 wpabuf_put_buf(clear
, A_pub
);
9475 #ifdef CONFIG_TESTING_OPTIONS
9477 if (dpp_test
== DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ
) {
9478 wpa_printf(MSG_INFO
, "DPP: TESTING - no I-Auth tag");
9479 goto skip_i_auth_tag
;
9481 if (dpp_test
== DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ
) {
9482 wpa_printf(MSG_INFO
, "DPP: TESTING - I-Auth tag mismatch");
9483 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9484 wpabuf_put_le16(clear
, curve
->hash_len
);
9485 wpabuf_put_data(clear
, u
, curve
->hash_len
- 1);
9486 wpabuf_put_u8(clear
, u
[curve
->hash_len
- 1] ^ 0x01);
9487 goto skip_i_auth_tag
;
9489 #endif /* CONFIG_TESTING_OPTIONS */
9491 /* u in I-Auth tag attribute */
9492 wpabuf_put_le16(clear
, DPP_ATTR_I_AUTH_TAG
);
9493 wpabuf_put_le16(clear
, curve
->hash_len
);
9494 wpabuf_put_data(clear
, u
, curve
->hash_len
);
9496 #ifdef CONFIG_TESTING_OPTIONS
9498 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ
) {
9499 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9500 goto skip_wrapped_data
;
9502 #endif /* CONFIG_TESTING_OPTIONS */
9504 addr
[0] = wpabuf_head_u8(msg
) + 2;
9505 len
[0] = DPP_HDR_LEN
;
9508 len
[1] = sizeof(octet
);
9509 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9510 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9512 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9513 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9514 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9516 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9517 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9518 wpabuf_head(clear
), wpabuf_len(clear
),
9519 2, addr
, len
, wrapped
) < 0)
9521 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9522 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9524 #ifdef CONFIG_TESTING_OPTIONS
9525 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ
) {
9526 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9527 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9530 #endif /* CONFIG_TESTING_OPTIONS */
9543 struct wpabuf
* dpp_pkex_rx_exchange_resp(struct dpp_pkex
*pkex
,
9545 const u8
*buf
, size_t buflen
)
9547 const u8
*attr_status
, *attr_id
, *attr_key
, *attr_group
;
9548 u16 attr_status_len
, attr_id_len
, attr_key_len
, attr_group_len
;
9549 EC_GROUP
*group
= NULL
;
9550 BN_CTX
*bnctx
= NULL
;
9551 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9552 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9553 EC_POINT
*Qr
= NULL
, *Y
= NULL
, *N
= NULL
;
9554 BIGNUM
*Nx
= NULL
, *Ny
= NULL
;
9555 EC_KEY
*Y_ec
= NULL
;
9556 size_t Jx_len
, Kx_len
;
9557 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
], Kx
[DPP_MAX_SHARED_SECRET_LEN
];
9560 u8 u
[DPP_MAX_HASH_LEN
];
9563 if (pkex
->failed
|| pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
9566 #ifdef CONFIG_TESTING_OPTIONS
9567 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP
) {
9568 wpa_printf(MSG_INFO
,
9569 "DPP: TESTING - stop at PKEX Exchange Response");
9574 if (!is_zero_ether_addr(dpp_pkex_peer_mac_override
)) {
9575 wpa_printf(MSG_INFO
, "DPP: TESTING - peer_mac override " MACSTR
,
9576 MAC2STR(dpp_pkex_peer_mac_override
));
9577 peer_mac
= dpp_pkex_peer_mac_override
;
9579 #endif /* CONFIG_TESTING_OPTIONS */
9581 os_memcpy(pkex
->peer_mac
, peer_mac
, ETH_ALEN
);
9583 attr_status
= dpp_get_attr(buf
, buflen
, DPP_ATTR_STATUS
,
9585 if (!attr_status
|| attr_status_len
!= 1) {
9586 dpp_pkex_fail(pkex
, "No DPP Status attribute");
9589 wpa_printf(MSG_DEBUG
, "DPP: Status %u", attr_status
[0]);
9591 if (attr_status
[0] == DPP_STATUS_BAD_GROUP
) {
9592 attr_group
= dpp_get_attr(buf
, buflen
,
9593 DPP_ATTR_FINITE_CYCLIC_GROUP
,
9595 if (attr_group
&& attr_group_len
== 2) {
9596 wpa_msg(pkex
->msg_ctx
, MSG_INFO
, DPP_EVENT_FAIL
9597 "Peer indicated mismatching PKEX group - proposed %u",
9598 WPA_GET_LE16(attr_group
));
9603 if (attr_status
[0] != DPP_STATUS_OK
) {
9604 dpp_pkex_fail(pkex
, "PKEX failed (peer indicated failure)");
9609 attr_id
= dpp_get_attr(buf
, buflen
, DPP_ATTR_CODE_IDENTIFIER
,
9611 if (!dpp_pkex_identifier_match(attr_id
, attr_id_len
,
9612 pkex
->identifier
)) {
9613 dpp_pkex_fail(pkex
, "PKEX code identifier mismatch");
9617 /* N in Encrypted Key attribute */
9618 attr_key
= dpp_get_attr(buf
, buflen
, DPP_ATTR_ENCRYPTED_KEY
,
9620 if (!attr_key
|| attr_key_len
& 0x01 || attr_key_len
< 2) {
9621 dpp_pkex_fail(pkex
, "Missing Encrypted Key attribute");
9625 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
9626 bnctx
= BN_CTX_new();
9629 Qr
= dpp_pkex_derive_Qr(curve
, pkex
->peer_mac
, pkex
->code
,
9630 pkex
->identifier
, bnctx
, &group
);
9635 Y
= EC_POINT_new(group
);
9636 N
= EC_POINT_new(group
);
9637 Nx
= BN_bin2bn(attr_key
, attr_key_len
/ 2, NULL
);
9638 Ny
= BN_bin2bn(attr_key
+ attr_key_len
/ 2, attr_key_len
/ 2, NULL
);
9639 if (!Y
|| !N
|| !Nx
|| !Ny
||
9640 EC_POINT_set_affine_coordinates_GFp(group
, N
, Nx
, Ny
, bnctx
) != 1 ||
9641 EC_POINT_is_at_infinity(group
, N
) ||
9642 !EC_POINT_is_on_curve(group
, N
, bnctx
) ||
9643 EC_POINT_invert(group
, Qr
, bnctx
) != 1 ||
9644 EC_POINT_add(group
, Y
, N
, Qr
, bnctx
) != 1 ||
9645 EC_POINT_is_at_infinity(group
, Y
) ||
9646 !EC_POINT_is_on_curve(group
, Y
, bnctx
)) {
9647 dpp_pkex_fail(pkex
, "Invalid Encrypted Key value");
9651 dpp_debug_print_point("DPP: N", group
, N
);
9652 dpp_debug_print_point("DPP: Y'", group
, Y
);
9654 pkex
->exchange_done
= 1;
9656 /* ECDH: J = a * Y’ */
9657 Y_ec
= EC_KEY_new();
9659 EC_KEY_set_group(Y_ec
, group
) != 1 ||
9660 EC_KEY_set_public_key(Y_ec
, Y
) != 1)
9662 pkex
->y
= EVP_PKEY_new();
9664 EVP_PKEY_set1_EC_KEY(pkex
->y
, Y_ec
) != 1)
9666 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->y
, Jx
, &Jx_len
) < 0)
9669 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9672 /* u = HMAC(J.x, MAC-Initiator | A.x | Y’.x | X.x ) */
9673 A_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9674 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9675 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9676 if (!A_pub
|| !Y_pub
|| !X_pub
)
9678 addr
[0] = pkex
->own_mac
;
9680 addr
[1] = wpabuf_head(A_pub
);
9681 len
[1] = wpabuf_len(A_pub
) / 2;
9682 addr
[2] = wpabuf_head(Y_pub
);
9683 len
[2] = wpabuf_len(Y_pub
) / 2;
9684 addr
[3] = wpabuf_head(X_pub
);
9685 len
[3] = wpabuf_len(X_pub
) / 2;
9686 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9688 wpa_hexdump(MSG_DEBUG
, "DPP: u", u
, curve
->hash_len
);
9691 if (dpp_ecdh(pkex
->x
, pkex
->y
, Kx
, &Kx_len
) < 0)
9694 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (K.x)",
9697 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
9699 res
= dpp_pkex_derive_z(pkex
->own_mac
, pkex
->peer_mac
,
9700 pkex
->Mx
, curve
->prime_len
,
9701 attr_key
/* N.x */, attr_key_len
/ 2,
9702 pkex
->code
, Kx
, Kx_len
,
9703 pkex
->z
, curve
->hash_len
);
9704 os_memset(Kx
, 0, Kx_len
);
9708 msg
= dpp_pkex_build_commit_reveal_req(pkex
, A_pub
, u
);
9723 EC_GROUP_free(group
);
9726 wpa_printf(MSG_DEBUG
, "DPP: PKEX Exchange Response processing failed");
9731 static struct wpabuf
*
9732 dpp_pkex_build_commit_reveal_resp(struct dpp_pkex
*pkex
,
9733 const struct wpabuf
*B_pub
, const u8
*v
)
9735 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9736 struct wpabuf
*msg
= NULL
;
9741 struct wpabuf
*clear
= NULL
;
9742 size_t clear_len
, attr_len
;
9744 /* {B, v [bootstrapping info]}z */
9745 clear_len
= 4 + 2 * curve
->prime_len
+ 4 + curve
->hash_len
;
9746 clear
= wpabuf_alloc(clear_len
);
9747 attr_len
= 4 + clear_len
+ AES_BLOCK_SIZE
;
9748 #ifdef CONFIG_TESTING_OPTIONS
9749 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
)
9751 #endif /* CONFIG_TESTING_OPTIONS */
9752 msg
= dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP
, attr_len
);
9756 #ifdef CONFIG_TESTING_OPTIONS
9757 if (dpp_test
== DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9758 wpa_printf(MSG_INFO
, "DPP: TESTING - no Bootstrap Key");
9759 goto skip_bootstrap_key
;
9761 if (dpp_test
== DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP
) {
9762 wpa_printf(MSG_INFO
, "DPP: TESTING - invalid Bootstrap Key");
9763 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9764 wpabuf_put_le16(clear
, 2 * curve
->prime_len
);
9765 if (dpp_test_gen_invalid_key(clear
, curve
) < 0)
9767 goto skip_bootstrap_key
;
9769 #endif /* CONFIG_TESTING_OPTIONS */
9771 /* B in Bootstrap Key attribute */
9772 wpabuf_put_le16(clear
, DPP_ATTR_BOOTSTRAP_KEY
);
9773 wpabuf_put_le16(clear
, wpabuf_len(B_pub
));
9774 wpabuf_put_buf(clear
, B_pub
);
9776 #ifdef CONFIG_TESTING_OPTIONS
9778 if (dpp_test
== DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP
) {
9779 wpa_printf(MSG_INFO
, "DPP: TESTING - no R-Auth tag");
9780 goto skip_r_auth_tag
;
9782 if (dpp_test
== DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP
) {
9783 wpa_printf(MSG_INFO
, "DPP: TESTING - R-Auth tag mismatch");
9784 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9785 wpabuf_put_le16(clear
, curve
->hash_len
);
9786 wpabuf_put_data(clear
, v
, curve
->hash_len
- 1);
9787 wpabuf_put_u8(clear
, v
[curve
->hash_len
- 1] ^ 0x01);
9788 goto skip_r_auth_tag
;
9790 #endif /* CONFIG_TESTING_OPTIONS */
9792 /* v in R-Auth tag attribute */
9793 wpabuf_put_le16(clear
, DPP_ATTR_R_AUTH_TAG
);
9794 wpabuf_put_le16(clear
, curve
->hash_len
);
9795 wpabuf_put_data(clear
, v
, curve
->hash_len
);
9797 #ifdef CONFIG_TESTING_OPTIONS
9799 if (dpp_test
== DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP
) {
9800 wpa_printf(MSG_INFO
, "DPP: TESTING - no Wrapped Data");
9801 goto skip_wrapped_data
;
9803 #endif /* CONFIG_TESTING_OPTIONS */
9805 addr
[0] = wpabuf_head_u8(msg
) + 2;
9806 len
[0] = DPP_HDR_LEN
;
9809 len
[1] = sizeof(octet
);
9810 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9811 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9813 wpabuf_put_le16(msg
, DPP_ATTR_WRAPPED_DATA
);
9814 wpabuf_put_le16(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9815 wrapped
= wpabuf_put(msg
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9817 wpa_hexdump_buf(MSG_DEBUG
, "DPP: AES-SIV cleartext", clear
);
9818 if (aes_siv_encrypt(pkex
->z
, curve
->hash_len
,
9819 wpabuf_head(clear
), wpabuf_len(clear
),
9820 2, addr
, len
, wrapped
) < 0)
9822 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9823 wrapped
, wpabuf_len(clear
) + AES_BLOCK_SIZE
);
9825 #ifdef CONFIG_TESTING_OPTIONS
9826 if (dpp_test
== DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP
) {
9827 wpa_printf(MSG_INFO
, "DPP: TESTING - attr after Wrapped Data");
9828 dpp_build_attr_status(msg
, DPP_STATUS_OK
);
9831 #endif /* CONFIG_TESTING_OPTIONS */
9844 struct wpabuf
* dpp_pkex_rx_commit_reveal_req(struct dpp_pkex
*pkex
,
9846 const u8
*buf
, size_t buflen
)
9848 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
9849 size_t Jx_len
, Lx_len
;
9850 u8 Jx
[DPP_MAX_SHARED_SECRET_LEN
];
9851 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
9852 const u8
*wrapped_data
, *b_key
, *peer_u
;
9853 u16 wrapped_data_len
, b_key_len
, peer_u_len
= 0;
9857 u8
*unwrapped
= NULL
;
9858 size_t unwrapped_len
= 0;
9859 struct wpabuf
*msg
= NULL
, *A_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
9860 struct wpabuf
*B_pub
= NULL
;
9861 u8 u
[DPP_MAX_HASH_LEN
], v
[DPP_MAX_HASH_LEN
];
9863 #ifdef CONFIG_TESTING_OPTIONS
9864 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_REQ
) {
9865 wpa_printf(MSG_INFO
,
9866 "DPP: TESTING - stop at PKEX CR Request");
9870 #endif /* CONFIG_TESTING_OPTIONS */
9872 if (!pkex
->exchange_done
|| pkex
->failed
||
9873 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| pkex
->initiator
)
9876 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
9878 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
9880 "Missing or invalid required Wrapped Data attribute");
9884 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
9885 wrapped_data
, wrapped_data_len
);
9886 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
9887 unwrapped
= os_malloc(unwrapped_len
);
9892 len
[0] = DPP_HDR_LEN
;
9895 len
[1] = sizeof(octet
);
9896 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
9897 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
9899 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
9900 wrapped_data
, wrapped_data_len
,
9901 2, addr
, len
, unwrapped
) < 0) {
9903 "AES-SIV decryption failed - possible PKEX code mismatch");
9908 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
9909 unwrapped
, unwrapped_len
);
9911 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
9912 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
9916 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
9918 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
9919 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
9922 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
9924 if (!pkex
->peer_bootstrap_key
) {
9925 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
9928 dpp_debug_print_key("DPP: Peer bootstrap public key",
9929 pkex
->peer_bootstrap_key
);
9931 /* ECDH: J' = y * A' */
9932 if (dpp_ecdh(pkex
->y
, pkex
->peer_bootstrap_key
, Jx
, &Jx_len
) < 0)
9935 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (J.x)",
9938 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
9939 A_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
9940 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
9941 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
9942 if (!A_pub
|| !Y_pub
|| !X_pub
)
9944 addr
[0] = pkex
->peer_mac
;
9946 addr
[1] = wpabuf_head(A_pub
);
9947 len
[1] = wpabuf_len(A_pub
) / 2;
9948 addr
[2] = wpabuf_head(Y_pub
);
9949 len
[2] = wpabuf_len(Y_pub
) / 2;
9950 addr
[3] = wpabuf_head(X_pub
);
9951 len
[3] = wpabuf_len(X_pub
) / 2;
9952 if (dpp_hmac_vector(curve
->hash_len
, Jx
, Jx_len
, 4, addr
, len
, u
) < 0)
9955 peer_u
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_I_AUTH_TAG
,
9957 if (!peer_u
|| peer_u_len
!= curve
->hash_len
||
9958 os_memcmp(peer_u
, u
, curve
->hash_len
) != 0) {
9959 dpp_pkex_fail(pkex
, "No valid u (I-Auth tag) found");
9960 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated u'",
9961 u
, curve
->hash_len
);
9962 wpa_hexdump(MSG_DEBUG
, "DPP: Received u", peer_u
, peer_u_len
);
9966 wpa_printf(MSG_DEBUG
, "DPP: Valid u (I-Auth tag) received");
9968 /* ECDH: L = b * X' */
9969 if (dpp_ecdh(pkex
->own_bi
->pubkey
, pkex
->x
, Lx
, &Lx_len
) < 0)
9972 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
9975 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
9976 B_pub
= dpp_get_pubkey_point(pkex
->own_bi
->pubkey
, 0);
9979 addr
[0] = pkex
->own_mac
;
9981 addr
[1] = wpabuf_head(B_pub
);
9982 len
[1] = wpabuf_len(B_pub
) / 2;
9983 addr
[2] = wpabuf_head(X_pub
);
9984 len
[2] = wpabuf_len(X_pub
) / 2;
9985 addr
[3] = wpabuf_head(Y_pub
);
9986 len
[3] = wpabuf_len(Y_pub
) / 2;
9987 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
9989 wpa_hexdump(MSG_DEBUG
, "DPP: v", v
, curve
->hash_len
);
9991 msg
= dpp_pkex_build_commit_reveal_resp(pkex
, B_pub
, v
);
10000 wpabuf_free(Y_pub
);
10003 wpa_printf(MSG_DEBUG
,
10004 "DPP: PKEX Commit-Reveal Request processing failed");
10009 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex
*pkex
, const u8
*hdr
,
10010 const u8
*buf
, size_t buflen
)
10012 const struct dpp_curve_params
*curve
= pkex
->own_bi
->curve
;
10013 const u8
*wrapped_data
, *b_key
, *peer_v
;
10014 u16 wrapped_data_len
, b_key_len
, peer_v_len
= 0;
10018 u8
*unwrapped
= NULL
;
10019 size_t unwrapped_len
= 0;
10021 u8 v
[DPP_MAX_HASH_LEN
];
10023 u8 Lx
[DPP_MAX_SHARED_SECRET_LEN
];
10024 struct wpabuf
*B_pub
= NULL
, *X_pub
= NULL
, *Y_pub
= NULL
;
10026 #ifdef CONFIG_TESTING_OPTIONS
10027 if (dpp_test
== DPP_TEST_STOP_AT_PKEX_CR_RESP
) {
10028 wpa_printf(MSG_INFO
,
10029 "DPP: TESTING - stop at PKEX CR Response");
10033 #endif /* CONFIG_TESTING_OPTIONS */
10035 if (!pkex
->exchange_done
|| pkex
->failed
||
10036 pkex
->t
>= PKEX_COUNTER_T_LIMIT
|| !pkex
->initiator
)
10039 wrapped_data
= dpp_get_attr(buf
, buflen
, DPP_ATTR_WRAPPED_DATA
,
10040 &wrapped_data_len
);
10041 if (!wrapped_data
|| wrapped_data_len
< AES_BLOCK_SIZE
) {
10042 dpp_pkex_fail(pkex
,
10043 "Missing or invalid required Wrapped Data attribute");
10047 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV ciphertext",
10048 wrapped_data
, wrapped_data_len
);
10049 unwrapped_len
= wrapped_data_len
- AES_BLOCK_SIZE
;
10050 unwrapped
= os_malloc(unwrapped_len
);
10055 len
[0] = DPP_HDR_LEN
;
10058 len
[1] = sizeof(octet
);
10059 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[0]", addr
[0], len
[0]);
10060 wpa_hexdump(MSG_DEBUG
, "DDP: AES-SIV AD[1]", addr
[1], len
[1]);
10062 if (aes_siv_decrypt(pkex
->z
, curve
->hash_len
,
10063 wrapped_data
, wrapped_data_len
,
10064 2, addr
, len
, unwrapped
) < 0) {
10065 dpp_pkex_fail(pkex
,
10066 "AES-SIV decryption failed - possible PKEX code mismatch");
10070 wpa_hexdump(MSG_DEBUG
, "DPP: AES-SIV cleartext",
10071 unwrapped
, unwrapped_len
);
10073 if (dpp_check_attrs(unwrapped
, unwrapped_len
) < 0) {
10074 dpp_pkex_fail(pkex
, "Invalid attribute in unwrapped data");
10078 b_key
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_BOOTSTRAP_KEY
,
10080 if (!b_key
|| b_key_len
!= 2 * curve
->prime_len
) {
10081 dpp_pkex_fail(pkex
, "No valid peer bootstrapping key found");
10084 pkex
->peer_bootstrap_key
= dpp_set_pubkey_point(pkex
->x
, b_key
,
10086 if (!pkex
->peer_bootstrap_key
) {
10087 dpp_pkex_fail(pkex
, "Peer bootstrapping key is invalid");
10090 dpp_debug_print_key("DPP: Peer bootstrap public key",
10091 pkex
->peer_bootstrap_key
);
10093 /* ECDH: L' = x * B' */
10094 if (dpp_ecdh(pkex
->x
, pkex
->peer_bootstrap_key
, Lx
, &Lx_len
) < 0)
10097 wpa_hexdump_key(MSG_DEBUG
, "DPP: ECDH shared secret (L.x)",
10100 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
10101 B_pub
= dpp_get_pubkey_point(pkex
->peer_bootstrap_key
, 0);
10102 X_pub
= dpp_get_pubkey_point(pkex
->x
, 0);
10103 Y_pub
= dpp_get_pubkey_point(pkex
->y
, 0);
10104 if (!B_pub
|| !X_pub
|| !Y_pub
)
10106 addr
[0] = pkex
->peer_mac
;
10108 addr
[1] = wpabuf_head(B_pub
);
10109 len
[1] = wpabuf_len(B_pub
) / 2;
10110 addr
[2] = wpabuf_head(X_pub
);
10111 len
[2] = wpabuf_len(X_pub
) / 2;
10112 addr
[3] = wpabuf_head(Y_pub
);
10113 len
[3] = wpabuf_len(Y_pub
) / 2;
10114 if (dpp_hmac_vector(curve
->hash_len
, Lx
, Lx_len
, 4, addr
, len
, v
) < 0)
10117 peer_v
= dpp_get_attr(unwrapped
, unwrapped_len
, DPP_ATTR_R_AUTH_TAG
,
10119 if (!peer_v
|| peer_v_len
!= curve
->hash_len
||
10120 os_memcmp(peer_v
, v
, curve
->hash_len
) != 0) {
10121 dpp_pkex_fail(pkex
, "No valid v (R-Auth tag) found");
10122 wpa_hexdump(MSG_DEBUG
, "DPP: Calculated v'",
10123 v
, curve
->hash_len
);
10124 wpa_hexdump(MSG_DEBUG
, "DPP: Received v", peer_v
, peer_v_len
);
10128 wpa_printf(MSG_DEBUG
, "DPP: Valid v (R-Auth tag) received");
10132 wpabuf_free(B_pub
);
10133 wpabuf_free(X_pub
);
10134 wpabuf_free(Y_pub
);
10135 os_free(unwrapped
);
10142 void dpp_pkex_free(struct dpp_pkex
*pkex
)
10147 os_free(pkex
->identifier
);
10148 os_free(pkex
->code
);
10149 EVP_PKEY_free(pkex
->x
);
10150 EVP_PKEY_free(pkex
->y
);
10151 EVP_PKEY_free(pkex
->peer_bootstrap_key
);
10152 wpabuf_free(pkex
->exchange_req
);
10153 wpabuf_free(pkex
->exchange_resp
);
10158 #ifdef CONFIG_TESTING_OPTIONS
10159 char * dpp_corrupt_connector_signature(const char *connector
)
10161 char *tmp
, *pos
, *signed3
= NULL
;
10162 unsigned char *signature
= NULL
;
10163 size_t signature_len
= 0, signed3_len
;
10165 tmp
= os_zalloc(os_strlen(connector
) + 5);
10168 os_memcpy(tmp
, connector
, os_strlen(connector
));
10170 pos
= os_strchr(tmp
, '.');
10174 pos
= os_strchr(pos
+ 1, '.');
10179 wpa_printf(MSG_DEBUG
, "DPP: Original base64url encoded signature: %s",
10181 signature
= base64_url_decode(pos
, os_strlen(pos
), &signature_len
);
10182 if (!signature
|| signature_len
== 0)
10184 wpa_hexdump(MSG_DEBUG
, "DPP: Original Connector signature",
10185 signature
, signature_len
);
10186 signature
[signature_len
- 1] ^= 0x01;
10187 wpa_hexdump(MSG_DEBUG
, "DPP: Corrupted Connector signature",
10188 signature
, signature_len
);
10189 signed3
= base64_url_encode(signature
, signature_len
, &signed3_len
);
10192 os_memcpy(pos
, signed3
, signed3_len
);
10193 pos
[signed3_len
] = '\0';
10194 wpa_printf(MSG_DEBUG
, "DPP: Corrupted base64url encoded signature: %s",
10198 os_free(signature
);
10206 #endif /* CONFIG_TESTING_OPTIONS */
10211 struct dpp_pfs
* dpp_pfs_init(const u8
*net_access_key
,
10212 size_t net_access_key_len
)
10214 struct wpabuf
*pub
= NULL
;
10216 struct dpp_pfs
*pfs
;
10218 pfs
= os_zalloc(sizeof(*pfs
));
10222 own_key
= dpp_set_keypair(&pfs
->curve
, net_access_key
,
10223 net_access_key_len
);
10225 wpa_printf(MSG_ERROR
, "DPP: Failed to parse own netAccessKey");
10228 EVP_PKEY_free(own_key
);
10230 pfs
->ecdh
= crypto_ecdh_init(pfs
->curve
->ike_group
);
10234 pub
= crypto_ecdh_get_pubkey(pfs
->ecdh
, 0);
10235 pub
= wpabuf_zeropad(pub
, pfs
->curve
->prime_len
);
10239 pfs
->ie
= wpabuf_alloc(5 + wpabuf_len(pub
));
10242 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXTENSION
);
10243 wpabuf_put_u8(pfs
->ie
, 1 + 2 + wpabuf_len(pub
));
10244 wpabuf_put_u8(pfs
->ie
, WLAN_EID_EXT_OWE_DH_PARAM
);
10245 wpabuf_put_le16(pfs
->ie
, pfs
->curve
->ike_group
);
10246 wpabuf_put_buf(pfs
->ie
, pub
);
10248 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Diffie-Hellman Parameter element",
10259 int dpp_pfs_process(struct dpp_pfs
*pfs
, const u8
*peer_ie
, size_t peer_ie_len
)
10261 if (peer_ie_len
< 2)
10263 if (WPA_GET_LE16(peer_ie
) != pfs
->curve
->ike_group
) {
10264 wpa_printf(MSG_DEBUG
, "DPP: Peer used different group for PFS");
10268 pfs
->secret
= crypto_ecdh_set_peerkey(pfs
->ecdh
, 0, peer_ie
+ 2,
10270 pfs
->secret
= wpabuf_zeropad(pfs
->secret
, pfs
->curve
->prime_len
);
10271 if (!pfs
->secret
) {
10272 wpa_printf(MSG_DEBUG
, "DPP: Invalid peer DH public key");
10275 wpa_hexdump_buf_key(MSG_DEBUG
, "DPP: DH shared secret", pfs
->secret
);
10280 void dpp_pfs_free(struct dpp_pfs
*pfs
)
10284 crypto_ecdh_deinit(pfs
->ecdh
);
10285 wpabuf_free(pfs
->ie
);
10286 wpabuf_clear_free(pfs
->secret
);
10290 #endif /* CONFIG_DPP2 */
10293 static unsigned int dpp_next_id(struct dpp_global
*dpp
)
10295 struct dpp_bootstrap_info
*bi
;
10296 unsigned int max_id
= 0;
10298 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10299 if (bi
->id
> max_id
)
10306 static int dpp_bootstrap_del(struct dpp_global
*dpp
, unsigned int id
)
10308 struct dpp_bootstrap_info
*bi
, *tmp
;
10314 dl_list_for_each_safe(bi
, tmp
, &dpp
->bootstrap
,
10315 struct dpp_bootstrap_info
, list
) {
10316 if (id
&& bi
->id
!= id
)
10319 dl_list_del(&bi
->list
);
10320 dpp_bootstrap_info_free(bi
);
10324 return 0; /* flush succeeds regardless of entries found */
10325 return found
? 0 : -1;
10329 struct dpp_bootstrap_info
* dpp_add_qr_code(struct dpp_global
*dpp
,
10332 struct dpp_bootstrap_info
*bi
;
10337 bi
= dpp_parse_uri(uri
);
10341 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10342 bi
->id
= dpp_next_id(dpp
);
10343 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10348 struct dpp_bootstrap_info
* dpp_add_nfc_uri(struct dpp_global
*dpp
,
10351 struct dpp_bootstrap_info
*bi
;
10356 bi
= dpp_parse_uri(uri
);
10360 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10361 bi
->id
= dpp_next_id(dpp
);
10362 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10367 int dpp_bootstrap_gen(struct dpp_global
*dpp
, const char *cmd
)
10369 char *mac
= NULL
, *info
= NULL
, *curve
= NULL
;
10371 u8
*privkey
= NULL
;
10372 size_t privkey_len
= 0;
10374 struct dpp_bootstrap_info
*bi
;
10379 bi
= os_zalloc(sizeof(*bi
));
10383 if (os_strstr(cmd
, "type=qrcode"))
10384 bi
->type
= DPP_BOOTSTRAP_QR_CODE
;
10385 else if (os_strstr(cmd
, "type=pkex"))
10386 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10387 else if (os_strstr(cmd
, "type=nfc-uri"))
10388 bi
->type
= DPP_BOOTSTRAP_NFC_URI
;
10392 bi
->chan
= get_param(cmd
, " chan=");
10393 mac
= get_param(cmd
, " mac=");
10394 info
= get_param(cmd
, " info=");
10395 curve
= get_param(cmd
, " curve=");
10396 key
= get_param(cmd
, " key=");
10399 privkey_len
= os_strlen(key
) / 2;
10400 privkey
= os_malloc(privkey_len
);
10402 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10406 if (dpp_keygen(bi
, curve
, privkey
, privkey_len
) < 0 ||
10407 dpp_parse_uri_chan_list(bi
, bi
->chan
) < 0 ||
10408 dpp_parse_uri_mac(bi
, mac
) < 0 ||
10409 dpp_parse_uri_info(bi
, info
) < 0 ||
10410 dpp_gen_uri(bi
) < 0)
10413 bi
->id
= dpp_next_id(dpp
);
10414 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10421 str_clear_free(key
);
10422 bin_clear_free(privkey
, privkey_len
);
10423 dpp_bootstrap_info_free(bi
);
10428 struct dpp_bootstrap_info
*
10429 dpp_bootstrap_get_id(struct dpp_global
*dpp
, unsigned int id
)
10431 struct dpp_bootstrap_info
*bi
;
10436 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10444 int dpp_bootstrap_remove(struct dpp_global
*dpp
, const char *id
)
10446 unsigned int id_val
;
10448 if (os_strcmp(id
, "*") == 0) {
10456 return dpp_bootstrap_del(dpp
, id_val
);
10460 struct dpp_bootstrap_info
*
10461 dpp_pkex_finish(struct dpp_global
*dpp
, struct dpp_pkex
*pkex
, const u8
*peer
,
10464 struct dpp_bootstrap_info
*bi
;
10466 bi
= os_zalloc(sizeof(*bi
));
10469 bi
->id
= dpp_next_id(dpp
);
10470 bi
->type
= DPP_BOOTSTRAP_PKEX
;
10471 os_memcpy(bi
->mac_addr
, peer
, ETH_ALEN
);
10473 bi
->freq
[0] = freq
;
10474 bi
->curve
= pkex
->own_bi
->curve
;
10475 bi
->pubkey
= pkex
->peer_bootstrap_key
;
10476 pkex
->peer_bootstrap_key
= NULL
;
10477 if (dpp_bootstrap_key_hash(bi
) < 0) {
10478 dpp_bootstrap_info_free(bi
);
10481 dpp_pkex_free(pkex
);
10482 dl_list_add(&dpp
->bootstrap
, &bi
->list
);
10487 const char * dpp_bootstrap_get_uri(struct dpp_global
*dpp
, unsigned int id
)
10489 struct dpp_bootstrap_info
*bi
;
10491 bi
= dpp_bootstrap_get_id(dpp
, id
);
10498 int dpp_bootstrap_info(struct dpp_global
*dpp
, int id
,
10499 char *reply
, int reply_size
)
10501 struct dpp_bootstrap_info
*bi
;
10502 char pkhash
[2 * SHA256_MAC_LEN
+ 1];
10504 bi
= dpp_bootstrap_get_id(dpp
, id
);
10507 wpa_snprintf_hex(pkhash
, sizeof(pkhash
), bi
->pubkey_hash
,
10509 return os_snprintf(reply
, reply_size
, "type=%s\n"
10510 "mac_addr=" MACSTR
"\n"
10516 dpp_bootstrap_type_txt(bi
->type
),
10517 MAC2STR(bi
->mac_addr
),
10518 bi
->info
? bi
->info
: "",
10520 bi
->num_freq
== 1 ? bi
->freq
[0] : 0,
10526 void dpp_bootstrap_find_pair(struct dpp_global
*dpp
, const u8
*i_bootstrap
,
10527 const u8
*r_bootstrap
,
10528 struct dpp_bootstrap_info
**own_bi
,
10529 struct dpp_bootstrap_info
**peer_bi
)
10531 struct dpp_bootstrap_info
*bi
;
10538 dl_list_for_each(bi
, &dpp
->bootstrap
, struct dpp_bootstrap_info
, list
) {
10539 if (!*own_bi
&& bi
->own
&&
10540 os_memcmp(bi
->pubkey_hash
, r_bootstrap
,
10541 SHA256_MAC_LEN
) == 0) {
10542 wpa_printf(MSG_DEBUG
,
10543 "DPP: Found matching own bootstrapping information");
10547 if (!*peer_bi
&& !bi
->own
&&
10548 os_memcmp(bi
->pubkey_hash
, i_bootstrap
,
10549 SHA256_MAC_LEN
) == 0) {
10550 wpa_printf(MSG_DEBUG
,
10551 "DPP: Found matching peer bootstrapping information");
10555 if (*own_bi
&& *peer_bi
)
10562 static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info
*own_bi
,
10563 struct dpp_bootstrap_info
*peer_bi
)
10565 unsigned int i
, freq
= 0;
10566 enum hostapd_hw_mode mode
;
10567 u8 op_class
, channel
;
10570 if (peer_bi
->num_freq
== 0)
10571 return 0; /* no channel preference/constraint */
10573 for (i
= 0; i
< peer_bi
->num_freq
; i
++) {
10574 if (own_bi
->num_freq
== 0 ||
10575 freq_included(own_bi
->freq
, own_bi
->num_freq
,
10576 peer_bi
->freq
[i
])) {
10577 freq
= peer_bi
->freq
[i
];
10582 wpa_printf(MSG_DEBUG
, "DPP: No common channel found");
10586 mode
= ieee80211_freq_to_channel_ext(freq
, 0, 0, &op_class
, &channel
);
10587 if (mode
== NUM_HOSTAPD_MODES
) {
10588 wpa_printf(MSG_DEBUG
,
10589 "DPP: Could not determine operating class or channel number for %u MHz",
10593 wpa_printf(MSG_DEBUG
,
10594 "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover",
10595 freq
, op_class
, channel
);
10596 os_snprintf(chan
, sizeof(chan
), "%u/%u", op_class
, channel
);
10597 os_free(own_bi
->chan
);
10598 own_bi
->chan
= os_strdup(chan
);
10599 own_bi
->freq
[0] = freq
;
10600 own_bi
->num_freq
= 1;
10601 os_free(peer_bi
->chan
);
10602 peer_bi
->chan
= os_strdup(chan
);
10603 peer_bi
->freq
[0] = freq
;
10604 peer_bi
->num_freq
= 1;
10606 return dpp_gen_uri(own_bi
);
10610 static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info
*own_bi
,
10611 struct dpp_bootstrap_info
*peer_bi
)
10613 if (peer_bi
->curve
== own_bi
->curve
)
10616 wpa_printf(MSG_DEBUG
,
10617 "DPP: Update own bootstrapping key to match peer curve from NFC handover");
10619 EVP_PKEY_free(own_bi
->pubkey
);
10620 own_bi
->pubkey
= NULL
;
10622 if (dpp_keygen(own_bi
, peer_bi
->curve
->name
, NULL
, 0) < 0 ||
10623 dpp_gen_uri(own_bi
) < 0)
10628 dl_list_del(&own_bi
->list
);
10629 dpp_bootstrap_info_free(own_bi
);
10634 int dpp_nfc_update_bi(struct dpp_bootstrap_info
*own_bi
,
10635 struct dpp_bootstrap_info
*peer_bi
)
10637 if (dpp_nfc_update_bi_channel(own_bi
, peer_bi
) < 0 ||
10638 dpp_nfc_update_bi_key(own_bi
, peer_bi
) < 0)
10644 static unsigned int dpp_next_configurator_id(struct dpp_global
*dpp
)
10646 struct dpp_configurator
*conf
;
10647 unsigned int max_id
= 0;
10649 dl_list_for_each(conf
, &dpp
->configurator
, struct dpp_configurator
,
10651 if (conf
->id
> max_id
)
10658 int dpp_configurator_add(struct dpp_global
*dpp
, const char *cmd
)
10660 char *curve
= NULL
;
10662 u8
*privkey
= NULL
;
10663 size_t privkey_len
= 0;
10665 struct dpp_configurator
*conf
= NULL
;
10667 curve
= get_param(cmd
, " curve=");
10668 key
= get_param(cmd
, " key=");
10671 privkey_len
= os_strlen(key
) / 2;
10672 privkey
= os_malloc(privkey_len
);
10674 hexstr2bin(key
, privkey
, privkey_len
) < 0)
10678 conf
= dpp_keygen_configurator(curve
, privkey
, privkey_len
);
10682 conf
->id
= dpp_next_configurator_id(dpp
);
10683 dl_list_add(&dpp
->configurator
, &conf
->list
);
10688 str_clear_free(key
);
10689 bin_clear_free(privkey
, privkey_len
);
10690 dpp_configurator_free(conf
);
10695 static int dpp_configurator_del(struct dpp_global
*dpp
, unsigned int id
)
10697 struct dpp_configurator
*conf
, *tmp
;
10703 dl_list_for_each_safe(conf
, tmp
, &dpp
->configurator
,
10704 struct dpp_configurator
, list
) {
10705 if (id
&& conf
->id
!= id
)
10708 dl_list_del(&conf
->list
);
10709 dpp_configurator_free(conf
);
10713 return 0; /* flush succeeds regardless of entries found */
10714 return found
? 0 : -1;
10718 int dpp_configurator_remove(struct dpp_global
*dpp
, const char *id
)
10720 unsigned int id_val
;
10722 if (os_strcmp(id
, "*") == 0) {
10730 return dpp_configurator_del(dpp
, id_val
);
10734 int dpp_configurator_get_key_id(struct dpp_global
*dpp
, unsigned int id
,
10735 char *buf
, size_t buflen
)
10737 struct dpp_configurator
*conf
;
10739 conf
= dpp_configurator_get_id(dpp
, id
);
10743 return dpp_configurator_get_key(conf
, buf
, buflen
);
10749 int dpp_configurator_from_backup(struct dpp_global
*dpp
,
10750 struct dpp_asymmetric_key
*key
)
10752 struct dpp_configurator
*conf
;
10753 const EC_KEY
*eckey
;
10754 const EC_GROUP
*group
;
10756 const struct dpp_curve_params
*curve
;
10760 eckey
= EVP_PKEY_get0_EC_KEY(key
->csign
);
10763 group
= EC_KEY_get0_group(eckey
);
10766 nid
= EC_GROUP_get_curve_name(group
);
10767 curve
= dpp_get_curve_nid(nid
);
10769 wpa_printf(MSG_INFO
, "DPP: Unsupported group in c-sign-key");
10773 conf
= os_zalloc(sizeof(*conf
));
10776 conf
->curve
= curve
;
10777 conf
->csign
= key
->csign
;
10780 if (dpp_configurator_gen_kid(conf
) < 0) {
10781 dpp_configurator_free(conf
);
10785 conf
->id
= dpp_next_configurator_id(dpp
);
10786 dl_list_add(&dpp
->configurator
, &conf
->list
);
10791 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
10792 void *timeout_ctx
);
10795 static void dpp_connection_free(struct dpp_connection
*conn
)
10797 if (conn
->sock
>= 0) {
10798 wpa_printf(MSG_DEBUG
, "DPP: Close Controller socket %d",
10800 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_READ
);
10801 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10804 eloop_cancel_timeout(dpp_controller_conn_status_result_wait_timeout
,
10806 wpabuf_free(conn
->msg
);
10807 wpabuf_free(conn
->msg_out
);
10808 dpp_auth_deinit(conn
->auth
);
10813 static void dpp_connection_remove(struct dpp_connection
*conn
)
10815 dl_list_del(&conn
->list
);
10816 dpp_connection_free(conn
);
10820 static void dpp_tcp_init_flush(struct dpp_global
*dpp
)
10822 struct dpp_connection
*conn
, *tmp
;
10824 dl_list_for_each_safe(conn
, tmp
, &dpp
->tcp_init
, struct dpp_connection
,
10826 dpp_connection_remove(conn
);
10830 static void dpp_relay_controller_free(struct dpp_relay_controller
*ctrl
)
10832 struct dpp_connection
*conn
, *tmp
;
10834 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
10836 dpp_connection_remove(conn
);
10841 static void dpp_relay_flush_controllers(struct dpp_global
*dpp
)
10843 struct dpp_relay_controller
*ctrl
, *tmp
;
10848 dl_list_for_each_safe(ctrl
, tmp
, &dpp
->controllers
,
10849 struct dpp_relay_controller
, list
) {
10850 dl_list_del(&ctrl
->list
);
10851 dpp_relay_controller_free(ctrl
);
10855 #endif /* CONFIG_DPP2 */
10858 struct dpp_global
* dpp_global_init(struct dpp_global_config
*config
)
10860 struct dpp_global
*dpp
;
10862 dpp
= os_zalloc(sizeof(*dpp
));
10865 dpp
->msg_ctx
= config
->msg_ctx
;
10867 dpp
->cb_ctx
= config
->cb_ctx
;
10868 dpp
->process_conf_obj
= config
->process_conf_obj
;
10869 #endif /* CONFIG_DPP2 */
10871 dl_list_init(&dpp
->bootstrap
);
10872 dl_list_init(&dpp
->configurator
);
10874 dl_list_init(&dpp
->controllers
);
10875 dl_list_init(&dpp
->tcp_init
);
10876 #endif /* CONFIG_DPP2 */
10882 void dpp_global_clear(struct dpp_global
*dpp
)
10887 dpp_bootstrap_del(dpp
, 0);
10888 dpp_configurator_del(dpp
, 0);
10890 dpp_tcp_init_flush(dpp
);
10891 dpp_relay_flush_controllers(dpp
);
10892 dpp_controller_stop(dpp
);
10893 #endif /* CONFIG_DPP2 */
10897 void dpp_global_deinit(struct dpp_global
*dpp
)
10899 dpp_global_clear(dpp
);
10906 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
);
10907 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
);
10908 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
10912 int dpp_relay_add_controller(struct dpp_global
*dpp
,
10913 struct dpp_relay_config
*config
)
10915 struct dpp_relay_controller
*ctrl
;
10920 ctrl
= os_zalloc(sizeof(*ctrl
));
10923 dl_list_init(&ctrl
->conn
);
10924 ctrl
->global
= dpp
;
10925 os_memcpy(&ctrl
->ipaddr
, config
->ipaddr
, sizeof(*config
->ipaddr
));
10926 os_memcpy(ctrl
->pkhash
, config
->pkhash
, SHA256_MAC_LEN
);
10927 ctrl
->cb_ctx
= config
->cb_ctx
;
10928 ctrl
->tx
= config
->tx
;
10929 ctrl
->gas_resp_tx
= config
->gas_resp_tx
;
10930 dl_list_add(&dpp
->controllers
, &ctrl
->list
);
10935 static struct dpp_relay_controller
*
10936 dpp_relay_controller_get(struct dpp_global
*dpp
, const u8
*pkhash
)
10938 struct dpp_relay_controller
*ctrl
;
10943 dl_list_for_each(ctrl
, &dpp
->controllers
, struct dpp_relay_controller
,
10945 if (os_memcmp(pkhash
, ctrl
->pkhash
, SHA256_MAC_LEN
) == 0)
10953 static void dpp_controller_gas_done(struct dpp_connection
*conn
)
10955 struct dpp_authentication
*auth
= conn
->auth
;
10957 if (auth
->peer_version
>= 2 &&
10958 auth
->conf_resp_status
== DPP_STATUS_OK
) {
10959 wpa_printf(MSG_DEBUG
, "DPP: Wait for Configuration Result");
10960 auth
->waiting_conf_result
= 1;
10964 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
, DPP_EVENT_CONF_SENT
);
10965 dpp_connection_remove(conn
);
10969 static int dpp_tcp_send(struct dpp_connection
*conn
)
10973 if (!conn
->msg_out
) {
10974 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
10975 conn
->write_eloop
= 0;
10978 res
= send(conn
->sock
,
10979 wpabuf_head_u8(conn
->msg_out
) + conn
->msg_out_pos
,
10980 wpabuf_len(conn
->msg_out
) - conn
->msg_out_pos
, 0);
10982 wpa_printf(MSG_DEBUG
, "DPP: Failed to send buffer: %s",
10984 dpp_connection_remove(conn
);
10988 conn
->msg_out_pos
+= res
;
10989 if (wpabuf_len(conn
->msg_out
) > conn
->msg_out_pos
) {
10990 wpa_printf(MSG_DEBUG
,
10991 "DPP: %u/%u bytes of message sent to Controller",
10992 (unsigned int) conn
->msg_out_pos
,
10993 (unsigned int) wpabuf_len(conn
->msg_out
));
10994 if (!conn
->write_eloop
&&
10995 eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
10996 dpp_conn_tx_ready
, conn
, NULL
) == 0)
10997 conn
->write_eloop
= 1;
11001 wpa_printf(MSG_DEBUG
, "DPP: Full message sent over TCP");
11002 wpabuf_free(conn
->msg_out
);
11003 conn
->msg_out
= NULL
;
11004 conn
->msg_out_pos
= 0;
11005 eloop_unregister_sock(conn
->sock
, EVENT_TYPE_WRITE
);
11006 conn
->write_eloop
= 0;
11007 if (!conn
->read_eloop
&&
11008 eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
11009 dpp_controller_rx
, conn
, NULL
) == 0)
11010 conn
->read_eloop
= 1;
11011 if (conn
->on_tcp_tx_complete_remove
) {
11012 dpp_connection_remove(conn
);
11013 } else if (conn
->ctrl
&& conn
->on_tcp_tx_complete_gas_done
&&
11015 dpp_controller_gas_done(conn
);
11016 } else if (conn
->on_tcp_tx_complete_auth_ok
) {
11017 conn
->on_tcp_tx_complete_auth_ok
= 0;
11018 dpp_controller_auth_success(conn
, 1);
11025 static void dpp_controller_start_gas_client(struct dpp_connection
*conn
)
11027 struct dpp_authentication
*auth
= conn
->auth
;
11028 struct wpabuf
*buf
;
11029 int netrole_ap
= 0; /* TODO: make this configurable */
11031 buf
= dpp_build_conf_req_helper(auth
, "Test", netrole_ap
, NULL
, NULL
);
11033 wpa_printf(MSG_DEBUG
,
11034 "DPP: No configuration request data available");
11038 wpabuf_free(conn
->msg_out
);
11039 conn
->msg_out_pos
= 0;
11040 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(buf
) - 1);
11041 if (!conn
->msg_out
) {
11045 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(buf
) - 1);
11046 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(buf
) + 1,
11047 wpabuf_len(buf
) - 1);
11050 if (dpp_tcp_send(conn
) == 1) {
11051 if (!conn
->write_eloop
) {
11052 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11056 conn
->write_eloop
= 1;
11062 static void dpp_controller_auth_success(struct dpp_connection
*conn
,
11065 struct dpp_authentication
*auth
= conn
->auth
;
11070 wpa_printf(MSG_DEBUG
, "DPP: Authentication succeeded");
11071 wpa_msg(conn
->global
->msg_ctx
, MSG_INFO
,
11072 DPP_EVENT_AUTH_SUCCESS
"init=%d", initiator
);
11073 #ifdef CONFIG_TESTING_OPTIONS
11074 if (dpp_test
== DPP_TEST_STOP_AT_AUTH_CONF
) {
11075 wpa_printf(MSG_INFO
,
11076 "DPP: TESTING - stop at Authentication Confirm");
11077 if (auth
->configurator
) {
11078 /* Prevent GAS response */
11079 auth
->auth_success
= 0;
11083 #endif /* CONFIG_TESTING_OPTIONS */
11085 if (!auth
->configurator
)
11086 dpp_controller_start_gas_client(conn
);
11090 static void dpp_conn_tx_ready(int sock
, void *eloop_ctx
, void *sock_ctx
)
11092 struct dpp_connection
*conn
= eloop_ctx
;
11094 wpa_printf(MSG_DEBUG
, "DPP: TCP socket %d ready for TX", sock
);
11095 dpp_tcp_send(conn
);
11099 static int dpp_ipaddr_to_sockaddr(struct sockaddr
*addr
, socklen_t
*addrlen
,
11100 const struct hostapd_ip_addr
*ipaddr
,
11103 struct sockaddr_in
*dst
;
11105 struct sockaddr_in6
*dst6
;
11106 #endif /* CONFIG_IPV6 */
11108 switch (ipaddr
->af
) {
11110 dst
= (struct sockaddr_in
*) addr
;
11111 os_memset(dst
, 0, sizeof(*dst
));
11112 dst
->sin_family
= AF_INET
;
11113 dst
->sin_addr
.s_addr
= ipaddr
->u
.v4
.s_addr
;
11114 dst
->sin_port
= htons(port
);
11115 *addrlen
= sizeof(*dst
);
11119 dst6
= (struct sockaddr_in6
*) addr
;
11120 os_memset(dst6
, 0, sizeof(*dst6
));
11121 dst6
->sin6_family
= AF_INET6
;
11122 os_memcpy(&dst6
->sin6_addr
, &ipaddr
->u
.v6
,
11123 sizeof(struct in6_addr
));
11124 dst6
->sin6_port
= htons(port
);
11125 *addrlen
= sizeof(*dst6
);
11127 #endif /* CONFIG_IPV6 */
11136 static struct dpp_connection
*
11137 dpp_relay_new_conn(struct dpp_relay_controller
*ctrl
, const u8
*src
,
11140 struct dpp_connection
*conn
;
11141 struct sockaddr_storage addr
;
11145 if (dl_list_len(&ctrl
->conn
) >= 15) {
11146 wpa_printf(MSG_DEBUG
,
11147 "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one");
11151 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &addr
, &addrlen
,
11152 &ctrl
->ipaddr
, DPP_TCP_PORT
) < 0)
11155 conn
= os_zalloc(sizeof(*conn
));
11159 conn
->global
= ctrl
->global
;
11160 conn
->relay
= ctrl
;
11161 os_memcpy(conn
->mac_addr
, src
, ETH_ALEN
);
11164 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
11165 if (conn
->sock
< 0)
11167 wpa_printf(MSG_DEBUG
, "DPP: TCP relay socket %d connection to %s",
11168 conn
->sock
, hostapd_ip_txt(&ctrl
->ipaddr
, txt
, sizeof(txt
)));
11170 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
11171 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
11176 if (connect(conn
->sock
, (struct sockaddr
*) &addr
, addrlen
) < 0) {
11177 if (errno
!= EINPROGRESS
) {
11178 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
11184 * Continue connecting in the background; eloop will call us
11185 * once the connection is ready (or failed).
11189 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11190 dpp_conn_tx_ready
, conn
, NULL
) < 0)
11192 conn
->write_eloop
= 1;
11194 /* TODO: eloop timeout to clear a connection if it does not complete
11197 dl_list_add(&ctrl
->conn
, &conn
->list
);
11200 dpp_connection_free(conn
);
11205 static struct wpabuf
* dpp_tcp_encaps(const u8
*hdr
, const u8
*buf
, size_t len
)
11207 struct wpabuf
*msg
;
11209 msg
= wpabuf_alloc(4 + 1 + DPP_HDR_LEN
+ len
);
11212 wpabuf_put_be32(msg
, 1 + DPP_HDR_LEN
+ len
);
11213 wpabuf_put_u8(msg
, WLAN_PA_VENDOR_SPECIFIC
);
11214 wpabuf_put_data(msg
, hdr
, DPP_HDR_LEN
);
11215 wpabuf_put_data(msg
, buf
, len
);
11216 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11221 static int dpp_relay_tx(struct dpp_connection
*conn
, const u8
*hdr
,
11222 const u8
*buf
, size_t len
)
11224 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11226 wpa_printf(MSG_DEBUG
,
11227 "DPP: Continue already established Relay/Controller connection for this session");
11228 wpabuf_free(conn
->msg_out
);
11229 conn
->msg_out_pos
= 0;
11230 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11231 if (!conn
->msg_out
) {
11232 dpp_connection_remove(conn
);
11236 /* TODO: for proto ver 1, need to do remove connection based on GAS Resp
11238 if (type
== DPP_PA_CONFIGURATION_RESULT
)
11239 conn
->on_tcp_tx_complete_remove
= 1;
11240 dpp_tcp_send(conn
);
11245 int dpp_relay_rx_action(struct dpp_global
*dpp
, const u8
*src
, const u8
*hdr
,
11246 const u8
*buf
, size_t len
, unsigned int freq
,
11247 const u8
*i_bootstrap
, const u8
*r_bootstrap
)
11249 struct dpp_relay_controller
*ctrl
;
11250 struct dpp_connection
*conn
;
11251 u8 type
= hdr
[DPP_HDR_LEN
- 1];
11253 /* Check if there is an already started session for this peer and if so,
11254 * continue that session (send this over TCP) and return 0.
11256 if (type
!= DPP_PA_PEER_DISCOVERY_REQ
&&
11257 type
!= DPP_PA_PEER_DISCOVERY_RESP
) {
11258 dl_list_for_each(ctrl
, &dpp
->controllers
,
11259 struct dpp_relay_controller
, list
) {
11260 dl_list_for_each(conn
, &ctrl
->conn
,
11261 struct dpp_connection
, list
) {
11262 if (os_memcmp(src
, conn
->mac_addr
,
11264 return dpp_relay_tx(conn
, hdr
, buf
, len
);
11272 ctrl
= dpp_relay_controller_get(dpp
, r_bootstrap
);
11276 wpa_printf(MSG_DEBUG
,
11277 "DPP: Authentication Request for a configured Controller");
11278 conn
= dpp_relay_new_conn(ctrl
, src
, freq
);
11282 conn
->msg_out
= dpp_tcp_encaps(hdr
, buf
, len
);
11283 if (!conn
->msg_out
) {
11284 dpp_connection_remove(conn
);
11287 /* Message will be sent in dpp_conn_tx_ready() */
11293 int dpp_relay_rx_gas_req(struct dpp_global
*dpp
, const u8
*src
, const u8
*data
,
11296 struct dpp_relay_controller
*ctrl
;
11297 struct dpp_connection
*conn
, *found
= NULL
;
11298 struct wpabuf
*msg
;
11300 /* Check if there is a successfully completed authentication for this
11301 * and if so, continue that session (send this over TCP) and return 0.
11303 dl_list_for_each(ctrl
, &dpp
->controllers
,
11304 struct dpp_relay_controller
, list
) {
11307 dl_list_for_each(conn
, &ctrl
->conn
,
11308 struct dpp_connection
, list
) {
11309 if (os_memcmp(src
, conn
->mac_addr
,
11320 msg
= wpabuf_alloc(4 + 1 + data_len
);
11323 wpabuf_put_be32(msg
, 1 + data_len
);
11324 wpabuf_put_u8(msg
, WLAN_PA_GAS_INITIAL_REQ
);
11325 wpabuf_put_data(msg
, data
, data_len
);
11326 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", msg
);
11328 wpabuf_free(conn
->msg_out
);
11329 conn
->msg_out_pos
= 0;
11330 conn
->msg_out
= msg
;
11331 dpp_tcp_send(conn
);
11336 static void dpp_controller_free(struct dpp_controller
*ctrl
)
11338 struct dpp_connection
*conn
, *tmp
;
11343 dl_list_for_each_safe(conn
, tmp
, &ctrl
->conn
, struct dpp_connection
,
11345 dpp_connection_remove(conn
);
11347 if (ctrl
->sock
>= 0) {
11349 eloop_unregister_sock(ctrl
->sock
, EVENT_TYPE_READ
);
11351 os_free(ctrl
->configurator_params
);
11356 static int dpp_controller_rx_auth_req(struct dpp_connection
*conn
,
11357 const u8
*hdr
, const u8
*buf
, size_t len
)
11359 const u8
*r_bootstrap
, *i_bootstrap
;
11360 u16 r_bootstrap_len
, i_bootstrap_len
;
11361 struct dpp_bootstrap_info
*own_bi
= NULL
, *peer_bi
= NULL
;
11366 wpa_printf(MSG_DEBUG
, "DPP: Authentication Request");
11368 r_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_R_BOOTSTRAP_KEY_HASH
,
11370 if (!r_bootstrap
|| r_bootstrap_len
!= SHA256_MAC_LEN
) {
11371 wpa_printf(MSG_INFO
,
11372 "Missing or invalid required Responder Bootstrapping Key Hash attribute");
11375 wpa_hexdump(MSG_MSGDUMP
, "DPP: Responder Bootstrapping Key Hash",
11376 r_bootstrap
, r_bootstrap_len
);
11378 i_bootstrap
= dpp_get_attr(buf
, len
, DPP_ATTR_I_BOOTSTRAP_KEY_HASH
,
11380 if (!i_bootstrap
|| i_bootstrap_len
!= SHA256_MAC_LEN
) {
11381 wpa_printf(MSG_INFO
,
11382 "Missing or invalid required Initiator Bootstrapping Key Hash attribute");
11385 wpa_hexdump(MSG_MSGDUMP
, "DPP: Initiator Bootstrapping Key Hash",
11386 i_bootstrap
, i_bootstrap_len
);
11388 /* Try to find own and peer bootstrapping key matches based on the
11389 * received hash values */
11390 dpp_bootstrap_find_pair(conn
->ctrl
->global
, i_bootstrap
, r_bootstrap
,
11391 &own_bi
, &peer_bi
);
11393 wpa_printf(MSG_INFO
,
11394 "No matching own bootstrapping key found - ignore message");
11399 wpa_printf(MSG_INFO
,
11400 "Already in DPP authentication exchange - ignore new one");
11404 conn
->auth
= dpp_auth_req_rx(conn
->ctrl
->global
->msg_ctx
,
11405 conn
->ctrl
->allowed_roles
,
11406 conn
->ctrl
->qr_mutual
,
11407 peer_bi
, own_bi
, -1, hdr
, buf
, len
);
11409 wpa_printf(MSG_DEBUG
, "DPP: No response generated");
11413 if (dpp_set_configurator(conn
->ctrl
->global
, conn
->ctrl
->global
->msg_ctx
,
11415 conn
->ctrl
->configurator_params
) < 0) {
11416 dpp_connection_remove(conn
);
11420 wpabuf_free(conn
->msg_out
);
11421 conn
->msg_out_pos
= 0;
11422 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(conn
->auth
->resp_msg
) - 1);
11423 if (!conn
->msg_out
)
11425 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(conn
->auth
->resp_msg
) - 1);
11426 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(conn
->auth
->resp_msg
) + 1,
11427 wpabuf_len(conn
->auth
->resp_msg
) - 1);
11429 if (dpp_tcp_send(conn
) == 1) {
11430 if (!conn
->write_eloop
) {
11431 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11435 conn
->write_eloop
= 1;
11443 static int dpp_controller_rx_auth_resp(struct dpp_connection
*conn
,
11444 const u8
*hdr
, const u8
*buf
, size_t len
)
11446 struct dpp_authentication
*auth
= conn
->auth
;
11447 struct wpabuf
*msg
;
11452 wpa_printf(MSG_DEBUG
, "DPP: Authentication Response");
11454 msg
= dpp_auth_resp_rx(auth
, hdr
, buf
, len
);
11456 if (auth
->auth_resp_status
== DPP_STATUS_RESPONSE_PENDING
) {
11457 wpa_printf(MSG_DEBUG
,
11458 "DPP: Start wait for full response");
11461 wpa_printf(MSG_DEBUG
, "DPP: No confirm generated");
11462 dpp_connection_remove(conn
);
11466 wpabuf_free(conn
->msg_out
);
11467 conn
->msg_out_pos
= 0;
11468 conn
->msg_out
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11469 if (!conn
->msg_out
) {
11473 wpabuf_put_be32(conn
->msg_out
, wpabuf_len(msg
) - 1);
11474 wpabuf_put_data(conn
->msg_out
, wpabuf_head_u8(msg
) + 1,
11475 wpabuf_len(msg
) - 1);
11478 conn
->on_tcp_tx_complete_auth_ok
= 1;
11479 if (dpp_tcp_send(conn
) == 1) {
11480 if (!conn
->write_eloop
) {
11481 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
11485 conn
->write_eloop
= 1;
11493 static int dpp_controller_rx_auth_conf(struct dpp_connection
*conn
,
11494 const u8
*hdr
, const u8
*buf
, size_t len
)
11496 struct dpp_authentication
*auth
= conn
->auth
;
11498 wpa_printf(MSG_DEBUG
, "DPP: Authentication Confirmation");
11501 wpa_printf(MSG_DEBUG
,
11502 "DPP: No DPP Authentication in progress - drop");
11506 if (dpp_auth_conf_rx(auth
, hdr
, buf
, len
) < 0) {
11507 wpa_printf(MSG_DEBUG
, "DPP: Authentication failed");
11511 dpp_controller_auth_success(conn
, 0);
11516 static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx
,
11519 struct dpp_connection
*conn
= eloop_ctx
;
11521 if (!conn
->auth
->waiting_conf_result
)
11524 wpa_printf(MSG_DEBUG
,
11525 "DPP: Timeout while waiting for Connection Status Result");
11526 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11527 DPP_EVENT_CONN_STATUS_RESULT
"timeout");
11528 dpp_connection_remove(conn
);
11532 static int dpp_controller_rx_conf_result(struct dpp_connection
*conn
,
11533 const u8
*hdr
, const u8
*buf
,
11536 struct dpp_authentication
*auth
= conn
->auth
;
11537 enum dpp_status_error status
;
11542 wpa_printf(MSG_DEBUG
, "DPP: Configuration Result");
11544 if (!auth
|| !auth
->waiting_conf_result
) {
11545 wpa_printf(MSG_DEBUG
,
11546 "DPP: No DPP Configuration waiting for result - drop");
11550 status
= dpp_conf_result_rx(auth
, hdr
, buf
, len
);
11551 if (status
== DPP_STATUS_OK
&& auth
->send_conn_status
) {
11552 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11553 DPP_EVENT_CONF_SENT
"wait_conn_status=1");
11554 wpa_printf(MSG_DEBUG
, "DPP: Wait for Connection Status Result");
11555 eloop_cancel_timeout(
11556 dpp_controller_conn_status_result_wait_timeout
,
11558 eloop_register_timeout(
11559 16, 0, dpp_controller_conn_status_result_wait_timeout
,
11563 if (status
== DPP_STATUS_OK
)
11564 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11565 DPP_EVENT_CONF_SENT
);
11567 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11568 DPP_EVENT_CONF_FAILED
);
11569 return -1; /* to remove the completed connection */
11573 static int dpp_controller_rx_conn_status_result(struct dpp_connection
*conn
,
11574 const u8
*hdr
, const u8
*buf
,
11577 struct dpp_authentication
*auth
= conn
->auth
;
11578 enum dpp_status_error status
;
11579 u8 ssid
[SSID_MAX_LEN
];
11580 size_t ssid_len
= 0;
11581 char *channel_list
= NULL
;
11586 wpa_printf(MSG_DEBUG
, "DPP: Connection Status Result");
11588 if (!auth
|| !auth
->waiting_conn_status_result
) {
11589 wpa_printf(MSG_DEBUG
,
11590 "DPP: No DPP Configuration waiting for connection status result - drop");
11594 status
= dpp_conn_status_result_rx(auth
, hdr
, buf
, len
,
11595 ssid
, &ssid_len
, &channel_list
);
11596 wpa_msg(conn
->ctrl
->global
->msg_ctx
, MSG_INFO
,
11597 DPP_EVENT_CONN_STATUS_RESULT
11598 "result=%d ssid=%s channel_list=%s",
11599 status
, wpa_ssid_txt(ssid
, ssid_len
),
11600 channel_list
? channel_list
: "N/A");
11601 os_free(channel_list
);
11602 return -1; /* to remove the completed connection */
11606 static int dpp_controller_rx_action(struct dpp_connection
*conn
, const u8
*msg
,
11609 const u8
*pos
, *end
;
11612 wpa_printf(MSG_DEBUG
, "DPP: Received DPP Action frame over TCP");
11616 if (end
- pos
< DPP_HDR_LEN
||
11617 WPA_GET_BE24(pos
) != OUI_WFA
||
11618 pos
[3] != DPP_OUI_TYPE
) {
11619 wpa_printf(MSG_DEBUG
, "DPP: Unrecognized header");
11624 wpa_printf(MSG_DEBUG
, "DPP: Unsupported Crypto Suite %u",
11629 wpa_printf(MSG_DEBUG
, "DPP: Received message type %u", type
);
11630 pos
+= DPP_HDR_LEN
;
11632 wpa_hexdump(MSG_MSGDUMP
, "DPP: Received message attributes",
11634 if (dpp_check_attrs(pos
, end
- pos
) < 0)
11638 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11639 conn
->relay
->tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11640 conn
->freq
, msg
, len
);
11645 case DPP_PA_AUTHENTICATION_REQ
:
11646 return dpp_controller_rx_auth_req(conn
, msg
, pos
, end
- pos
);
11647 case DPP_PA_AUTHENTICATION_RESP
:
11648 return dpp_controller_rx_auth_resp(conn
, msg
, pos
, end
- pos
);
11649 case DPP_PA_AUTHENTICATION_CONF
:
11650 return dpp_controller_rx_auth_conf(conn
, msg
, pos
, end
- pos
);
11651 case DPP_PA_CONFIGURATION_RESULT
:
11652 return dpp_controller_rx_conf_result(conn
, msg
, pos
, end
- pos
);
11653 case DPP_PA_CONNECTION_STATUS_RESULT
:
11654 return dpp_controller_rx_conn_status_result(conn
, msg
, pos
,
11657 /* TODO: missing messages types */
11658 wpa_printf(MSG_DEBUG
,
11659 "DPP: Unsupported frame subtype %d", type
);
11665 static int dpp_controller_rx_gas_req(struct dpp_connection
*conn
, const u8
*msg
,
11668 const u8
*pos
, *end
, *next
;
11670 const u8
*adv_proto
;
11672 struct wpabuf
*resp
, *buf
;
11673 struct dpp_authentication
*auth
= conn
->auth
;
11678 wpa_printf(MSG_DEBUG
,
11679 "DPP: Received DPP Configuration Request over TCP");
11681 if (!conn
->ctrl
|| !auth
|| !auth
->auth_success
) {
11682 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11689 dialog_token
= *pos
++;
11692 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11693 slen
> end
- pos
|| slen
< 2)
11697 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11699 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11700 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11701 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11705 /* Query Request */
11708 slen
= WPA_GET_LE16(pos
);
11710 if (slen
> end
- pos
)
11713 resp
= dpp_conf_req_rx(auth
, pos
, slen
);
11717 buf
= wpabuf_alloc(4 + 18 + wpabuf_len(resp
));
11723 wpabuf_put_be32(buf
, 18 + wpabuf_len(resp
));
11725 wpabuf_put_u8(buf
, WLAN_PA_GAS_INITIAL_RESP
);
11726 wpabuf_put_u8(buf
, dialog_token
);
11727 wpabuf_put_le16(buf
, WLAN_STATUS_SUCCESS
);
11728 wpabuf_put_le16(buf
, 0); /* GAS Comeback Delay */
11730 dpp_write_adv_proto(buf
);
11731 dpp_write_gas_query(buf
, resp
);
11734 /* Send Config Response over TCP; GAS fragmentation is taken care of by
11736 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", buf
);
11737 wpabuf_free(conn
->msg_out
);
11738 conn
->msg_out_pos
= 0;
11739 conn
->msg_out
= buf
;
11740 conn
->on_tcp_tx_complete_gas_done
= 1;
11741 dpp_tcp_send(conn
);
11746 static int dpp_tcp_rx_gas_resp(struct dpp_connection
*conn
, struct wpabuf
*resp
)
11748 struct dpp_authentication
*auth
= conn
->auth
;
11750 struct wpabuf
*msg
, *encaps
;
11751 enum dpp_status_error status
;
11753 wpa_printf(MSG_DEBUG
,
11754 "DPP: Configuration Response for local stack from TCP");
11756 res
= dpp_conf_resp_rx(auth
, resp
);
11759 wpa_printf(MSG_DEBUG
, "DPP: Configuration attempt failed");
11763 if (conn
->global
->process_conf_obj
)
11764 res
= conn
->global
->process_conf_obj(conn
->global
->cb_ctx
,
11769 if (auth
->peer_version
< 2 || auth
->conf_resp_status
!= DPP_STATUS_OK
)
11773 wpa_printf(MSG_DEBUG
, "DPP: Send DPP Configuration Result");
11774 status
= res
< 0 ? DPP_STATUS_CONFIG_REJECTED
: DPP_STATUS_OK
;
11775 msg
= dpp_build_conf_result(auth
, status
);
11779 encaps
= wpabuf_alloc(4 + wpabuf_len(msg
) - 1);
11784 wpabuf_put_be32(encaps
, wpabuf_len(msg
) - 1);
11785 wpabuf_put_data(encaps
, wpabuf_head_u8(msg
) + 1, wpabuf_len(msg
) - 1);
11787 wpa_hexdump_buf(MSG_MSGDUMP
, "DPP: Outgoing TCP message", encaps
);
11789 wpabuf_free(conn
->msg_out
);
11790 conn
->msg_out_pos
= 0;
11791 conn
->msg_out
= encaps
;
11792 conn
->on_tcp_tx_complete_remove
= 1;
11793 dpp_tcp_send(conn
);
11795 /* This exchange will be terminated in the TX status handler */
11798 #else /* CONFIG_DPP2 */
11800 #endif /* CONFIG_DPP2 */
11804 static int dpp_rx_gas_resp(struct dpp_connection
*conn
, const u8
*msg
,
11807 struct wpabuf
*buf
;
11809 const u8
*pos
, *end
, *next
, *adv_proto
;
11815 wpa_printf(MSG_DEBUG
,
11816 "DPP: Received DPP Configuration Response over TCP");
11821 dialog_token
= *pos
++;
11822 status
= WPA_GET_LE16(pos
);
11823 if (status
!= WLAN_STATUS_SUCCESS
) {
11824 wpa_printf(MSG_DEBUG
, "DPP: Unexpected Status Code %u", status
);
11828 pos
+= 2; /* ignore GAS Comeback Delay */
11832 if (*adv_proto
!= WLAN_EID_ADV_PROTO
||
11833 slen
> end
- pos
|| slen
< 2)
11837 pos
++; /* skip QueryRespLenLimit and PAME-BI */
11839 if (slen
!= 8 || *pos
!= WLAN_EID_VENDOR_SPECIFIC
||
11840 pos
[1] != 5 || WPA_GET_BE24(&pos
[2]) != OUI_WFA
||
11841 pos
[5] != DPP_OUI_TYPE
|| pos
[6] != 0x01)
11845 /* Query Response */
11848 slen
= WPA_GET_LE16(pos
);
11850 if (slen
> end
- pos
)
11853 buf
= wpabuf_alloc(slen
);
11856 wpabuf_put_data(buf
, pos
, slen
);
11858 if (!conn
->relay
&& !conn
->ctrl
)
11859 return dpp_tcp_rx_gas_resp(conn
, buf
);
11861 if (!conn
->relay
) {
11862 wpa_printf(MSG_DEBUG
, "DPP: No matching exchange in progress");
11866 wpa_printf(MSG_DEBUG
, "DPP: Relay - send over WLAN");
11867 conn
->relay
->gas_resp_tx(conn
->relay
->cb_ctx
, conn
->mac_addr
,
11868 dialog_token
, 0, buf
);
11874 static void dpp_controller_rx(int sd
, void *eloop_ctx
, void *sock_ctx
)
11876 struct dpp_connection
*conn
= eloop_ctx
;
11880 wpa_printf(MSG_DEBUG
, "DPP: TCP data available for reading (sock %d)",
11883 if (conn
->msg_len_octets
< 4) {
11886 res
= recv(sd
, &conn
->msg_len
[conn
->msg_len_octets
],
11887 4 - conn
->msg_len_octets
, 0);
11889 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s",
11891 dpp_connection_remove(conn
);
11895 wpa_printf(MSG_DEBUG
,
11896 "DPP: No more data available over TCP");
11897 dpp_connection_remove(conn
);
11900 wpa_printf(MSG_DEBUG
,
11901 "DPP: Received %d/%d octet(s) of message length field",
11902 res
, (int) (4 - conn
->msg_len_octets
));
11903 conn
->msg_len_octets
+= res
;
11905 if (conn
->msg_len_octets
< 4) {
11906 wpa_printf(MSG_DEBUG
,
11907 "DPP: Need %d more octets of message length field",
11908 (int) (4 - conn
->msg_len_octets
));
11912 msglen
= WPA_GET_BE32(conn
->msg_len
);
11913 wpa_printf(MSG_DEBUG
, "DPP: Message length: %u", msglen
);
11914 if (msglen
> 65535) {
11915 wpa_printf(MSG_INFO
, "DPP: Unexpectedly long message");
11916 dpp_connection_remove(conn
);
11920 wpabuf_free(conn
->msg
);
11921 conn
->msg
= wpabuf_alloc(msglen
);
11925 wpa_printf(MSG_DEBUG
,
11926 "DPP: No buffer available for receiving the message");
11927 dpp_connection_remove(conn
);
11931 wpa_printf(MSG_DEBUG
, "DPP: Need %u more octets of message payload",
11932 (unsigned int) wpabuf_tailroom(conn
->msg
));
11934 res
= recv(sd
, wpabuf_put(conn
->msg
, 0), wpabuf_tailroom(conn
->msg
), 0);
11936 wpa_printf(MSG_DEBUG
, "DPP: recv failed: %s", strerror(errno
));
11937 dpp_connection_remove(conn
);
11941 wpa_printf(MSG_DEBUG
, "DPP: No more data available over TCP");
11942 dpp_connection_remove(conn
);
11945 wpa_printf(MSG_DEBUG
, "DPP: Received %d octets", res
);
11946 wpabuf_put(conn
->msg
, res
);
11948 if (wpabuf_tailroom(conn
->msg
) > 0) {
11949 wpa_printf(MSG_DEBUG
,
11950 "DPP: Need %u more octets of message payload",
11951 (unsigned int) wpabuf_tailroom(conn
->msg
));
11955 conn
->msg_len_octets
= 0;
11956 wpa_hexdump_buf(MSG_DEBUG
, "DPP: Received TCP message", conn
->msg
);
11957 if (wpabuf_len(conn
->msg
) < 1) {
11958 dpp_connection_remove(conn
);
11962 pos
= wpabuf_head(conn
->msg
);
11964 case WLAN_PA_VENDOR_SPECIFIC
:
11965 if (dpp_controller_rx_action(conn
, pos
+ 1,
11966 wpabuf_len(conn
->msg
) - 1) < 0)
11967 dpp_connection_remove(conn
);
11969 case WLAN_PA_GAS_INITIAL_REQ
:
11970 if (dpp_controller_rx_gas_req(conn
, pos
+ 1,
11971 wpabuf_len(conn
->msg
) - 1) < 0)
11972 dpp_connection_remove(conn
);
11974 case WLAN_PA_GAS_INITIAL_RESP
:
11975 if (dpp_rx_gas_resp(conn
, pos
+ 1,
11976 wpabuf_len(conn
->msg
) - 1) < 0)
11977 dpp_connection_remove(conn
);
11980 wpa_printf(MSG_DEBUG
, "DPP: Ignore unsupported message type %u",
11987 static void dpp_controller_tcp_cb(int sd
, void *eloop_ctx
, void *sock_ctx
)
11989 struct dpp_controller
*ctrl
= eloop_ctx
;
11990 struct sockaddr_in addr
;
11991 socklen_t addr_len
= sizeof(addr
);
11993 struct dpp_connection
*conn
;
11995 wpa_printf(MSG_DEBUG
, "DPP: New TCP connection");
11997 fd
= accept(ctrl
->sock
, (struct sockaddr
*) &addr
, &addr_len
);
11999 wpa_printf(MSG_DEBUG
,
12000 "DPP: Failed to accept new connection: %s",
12004 wpa_printf(MSG_DEBUG
, "DPP: Connection from %s:%d",
12005 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
12007 conn
= os_zalloc(sizeof(*conn
));
12011 conn
->global
= ctrl
->global
;
12015 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12016 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12021 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_READ
,
12022 dpp_controller_rx
, conn
, NULL
) < 0)
12024 conn
->read_eloop
= 1;
12026 /* TODO: eloop timeout to expire connections that do not complete in
12027 * reasonable time */
12028 dl_list_add(&ctrl
->conn
, &conn
->list
);
12037 int dpp_tcp_init(struct dpp_global
*dpp
, struct dpp_authentication
*auth
,
12038 const struct hostapd_ip_addr
*addr
, int port
)
12040 struct dpp_connection
*conn
;
12041 struct sockaddr_storage saddr
;
12043 const u8
*hdr
, *pos
, *end
;
12046 wpa_printf(MSG_DEBUG
, "DPP: Initialize TCP connection to %s port %d",
12047 hostapd_ip_txt(addr
, txt
, sizeof(txt
)), port
);
12048 if (dpp_ipaddr_to_sockaddr((struct sockaddr
*) &saddr
, &addrlen
,
12050 dpp_auth_deinit(auth
);
12054 conn
= os_zalloc(sizeof(*conn
));
12056 dpp_auth_deinit(auth
);
12060 conn
->global
= dpp
;
12062 conn
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12063 if (conn
->sock
< 0)
12066 if (fcntl(conn
->sock
, F_SETFL
, O_NONBLOCK
) != 0) {
12067 wpa_printf(MSG_DEBUG
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12072 if (connect(conn
->sock
, (struct sockaddr
*) &saddr
, addrlen
) < 0) {
12073 if (errno
!= EINPROGRESS
) {
12074 wpa_printf(MSG_DEBUG
, "DPP: Failed to connect: %s",
12080 * Continue connecting in the background; eloop will call us
12081 * once the connection is ready (or failed).
12085 if (eloop_register_sock(conn
->sock
, EVENT_TYPE_WRITE
,
12086 dpp_conn_tx_ready
, conn
, NULL
) < 0)
12088 conn
->write_eloop
= 1;
12090 hdr
= wpabuf_head(auth
->req_msg
);
12091 end
= hdr
+ wpabuf_len(auth
->req_msg
);
12092 hdr
+= 2; /* skip Category and Actiom */
12093 pos
= hdr
+ DPP_HDR_LEN
;
12094 conn
->msg_out
= dpp_tcp_encaps(hdr
, pos
, end
- pos
);
12095 if (!conn
->msg_out
)
12097 /* Message will be sent in dpp_conn_tx_ready() */
12099 /* TODO: eloop timeout to clear a connection if it does not complete
12101 dl_list_add(&dpp
->tcp_init
, &conn
->list
);
12104 dpp_connection_free(conn
);
12109 int dpp_controller_start(struct dpp_global
*dpp
,
12110 struct dpp_controller_config
*config
)
12112 struct dpp_controller
*ctrl
;
12114 struct sockaddr_in sin
;
12117 if (!dpp
|| dpp
->controller
)
12120 ctrl
= os_zalloc(sizeof(*ctrl
));
12123 ctrl
->global
= dpp
;
12124 if (config
->configurator_params
)
12125 ctrl
->configurator_params
=
12126 os_strdup(config
->configurator_params
);
12127 dl_list_init(&ctrl
->conn
);
12128 /* TODO: configure these somehow */
12129 ctrl
->allowed_roles
= DPP_CAPAB_ENROLLEE
| DPP_CAPAB_CONFIGURATOR
;
12130 ctrl
->qr_mutual
= 0;
12132 ctrl
->sock
= socket(AF_INET
, SOCK_STREAM
, 0);
12133 if (ctrl
->sock
< 0)
12136 if (setsockopt(ctrl
->sock
, SOL_SOCKET
, SO_REUSEADDR
,
12137 &on
, sizeof(on
)) < 0) {
12138 wpa_printf(MSG_DEBUG
,
12139 "DPP: setsockopt(SO_REUSEADDR) failed: %s",
12141 /* try to continue anyway */
12144 if (fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0) {
12145 wpa_printf(MSG_INFO
, "DPP: fnctl(O_NONBLOCK) failed: %s",
12151 os_memset(&sin
, 0, sizeof(sin
));
12152 sin
.sin_family
= AF_INET
;
12153 sin
.sin_addr
.s_addr
= INADDR_ANY
;
12154 port
= config
->tcp_port
? config
->tcp_port
: DPP_TCP_PORT
;
12155 sin
.sin_port
= htons(port
);
12156 if (bind(ctrl
->sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
12157 wpa_printf(MSG_INFO
,
12158 "DPP: Failed to bind Controller TCP port: %s",
12162 if (listen(ctrl
->sock
, 10 /* max backlog */) < 0 ||
12163 fcntl(ctrl
->sock
, F_SETFL
, O_NONBLOCK
) < 0 ||
12164 eloop_register_sock(ctrl
->sock
, EVENT_TYPE_READ
,
12165 dpp_controller_tcp_cb
, ctrl
, NULL
))
12168 dpp
->controller
= ctrl
;
12169 wpa_printf(MSG_DEBUG
, "DPP: Controller started on TCP port %d", port
);
12172 dpp_controller_free(ctrl
);
12177 void dpp_controller_stop(struct dpp_global
*dpp
)
12180 dpp_controller_free(dpp
->controller
);
12181 dpp
->controller
= NULL
;
12185 #endif /* CONFIG_DPP2 */